diff options
Diffstat (limited to 'drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c')
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 122 |
1 files changed, 96 insertions, 26 deletions
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 0c885a8a0e9f..40d8a03a141d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -129,6 +129,25 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) return 0; } +static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev) +{ + unsigned int status; + unsigned long timeout; + + /* Reset */ + mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL); + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check bus status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC.\n"); + return -EIO; + } + status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); + } while ((status & 0x2) == 0); + return 0; +} + /* Reset the device */ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { @@ -139,12 +158,6 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) mfc_debug_enter(); if (IS_MFCV6_PLUS(dev)) { - /* Reset IP */ - /* except RISC, reset */ - mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); - /* reset release */ - mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); - /* Zero Initialization of MFC registers */ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); @@ -153,8 +166,17 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); - /* Reset */ - mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + /* check bus reset control before reset */ + if (dev->risc_on) + if (s5p_mfc_bus_reset(dev)) + return -EIO; + /* Reset + * set RISC_ON to 0 during power_on & wake_up. + * V6 needs RISC_ON set to 0 during reset also. + */ + if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev))) + mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); } else { @@ -226,6 +248,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); s5p_mfc_clock_on(); + dev->risc_on = 0; ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); @@ -238,8 +261,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); - if (IS_MFCV6_PLUS(dev)) + if (IS_MFCV6_PLUS(dev)) { + dev->risc_on = 1; mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + } else mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); @@ -328,6 +353,58 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) return ret; } +static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev) +{ + int ret; + + /* Release reset signal to the RISC */ + dev->risc_on = 1; + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { + mfc_err("Failed to reset MFCV8\n"); + return -EIO; + } + mfc_debug(2, "Write command to wakeup MFCV8\n"); + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFCV8 - timeout\n"); + return ret; + } + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { + mfc_err("Failed to wakeup MFC\n"); + return -EIO; + } + return ret; +} + +static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev) +{ + int ret; + + /* Send MFC wakeup command */ + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFC - timeout\n"); + return ret; + } + + /* Release reset signal to the RISC */ + if (IS_MFCV6_PLUS(dev)) { + dev->risc_on = 1; + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + } else { + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + } + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { + mfc_err("Failed to wakeup MFC\n"); + return -EIO; + } + return ret; +} + int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { int ret; @@ -336,9 +413,11 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); s5p_mfc_clock_on(); + dev->risc_on = 0; ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); + s5p_mfc_clock_off(); return ret; } mfc_debug(2, "Done MFC reset..\n"); @@ -347,23 +426,16 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); - /* 3. Initialize firmware */ - ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); - if (ret) { - mfc_err("Failed to send command to MFC - timeout\n"); - return ret; - } - /* 4. Release reset signal to the RISC */ - if (IS_MFCV6_PLUS(dev)) - mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + /* 3. Send MFC wakeup command and wait for completion*/ + if (IS_MFCV8(dev)) + ret = s5p_mfc_v8_wait_wakeup(dev); else - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); - mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { - mfc_err("Failed to load firmware\n"); - return -EIO; - } + ret = s5p_mfc_wait_wakeup(dev); + s5p_mfc_clock_off(); + if (ret) + return ret; + dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_MFC_R2H_CMD_WAKEUP_RET) { @@ -396,7 +468,6 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) } set_work_bit_irqsave(ctx); - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { @@ -422,7 +493,6 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) { ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occurred */ if (s5p_mfc_wait_for_done_ctx(ctx, |