diff options
Diffstat (limited to 'drivers/media/platform/s5p-mfc')
-rw-r--r-- | drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc.c | 51 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 4 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 122 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 12 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 65 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 13 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 32 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 10 |
9 files changed, 201 insertions, 109 deletions
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index 51cb2dd0e13a..83e01f3466e9 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -71,6 +71,7 @@ #define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 #define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 +#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110 #define S5P_FIMV_FW_VERSION_V6 0xf000 #define S5P_FIMV_INSTANCE_ID_V6 0xf008 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 96fe33f0a045..fbfdf03b9054 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -159,6 +159,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) } clear_bit(0, &dev->hw_lock); spin_unlock_irqrestore(&dev->irqlock, flags); + + /* De-init MFC */ + s5p_mfc_deinit_hw(dev); + /* Double check if there is at least one instance running. * If no instance is in memory than no firmware should be present */ if (dev->num_inst > 0) { @@ -220,11 +224,14 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) size_t dec_y_addr; unsigned int frame_type; - dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + /* Make sure we actually have a new frame before continuing. */ frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) + return; + dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); /* Copy timestamp / timecode from decoded src to dst and set - appropriate flags */ + appropriate flags. */ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); list_for_each_entry(dst_buf, &ctx->dst_queue, list) { if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) { @@ -250,6 +257,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) dst_buf->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME; break; + default: + /* Don't know how to handle + S5P_FIMV_DECODE_FRAME_OTHER_FRAME. */ + mfc_debug(2, "Unexpected frame type: %d\n", + frame_type); } break; } @@ -334,8 +346,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, ctx->state = MFCINST_RES_CHANGE_INIT; s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); return; @@ -407,8 +418,7 @@ leave_handle_frame: clear_work_bit(ctx); s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); /* if suspending, wake up device and do not try_run again*/ if (test_bit(0, &dev->enter_suspend)) @@ -455,8 +465,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, break; } } - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); s5p_mfc_clock_off(); wake_up_dev(dev, reason, err); @@ -510,8 +519,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, } s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); @@ -549,16 +557,14 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, } else { ctx->dpb_flush_flag = 0; } - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); wake_up(&ctx->queue); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); @@ -635,8 +641,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) mfc_err("post_frame_start() failed\n"); s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - BUG(); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { @@ -815,7 +820,7 @@ static int s5p_mfc_open(struct file *file) ret = -ENOENT; goto err_queue_init; } - q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { @@ -837,7 +842,7 @@ static int s5p_mfc_open(struct file *file) ret = -ENOENT; goto err_queue_init; } - q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { @@ -1284,11 +1289,17 @@ static int s5p_mfc_suspend(struct device *dev) m_dev->int_cond, msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err("Waiting for hardware to finish timed out\n"); + clear_bit(0, &m_dev->enter_suspend); return -EIO; } } - return s5p_mfc_sleep(m_dev); + ret = s5p_mfc_sleep(m_dev); + if (ret) { + clear_bit(0, &m_dev->enter_suspend); + clear_bit(0, &m_dev->hw_lock); + } + return ret; } static int s5p_mfc_resume(struct device *dev) @@ -1302,7 +1313,7 @@ static int s5p_mfc_resume(struct device *dev) } #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int s5p_mfc_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 3e41ca1293ed..15f7663dd9f5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -237,8 +237,6 @@ struct s5p_mfc_variant { /** * struct s5p_mfc_priv_buf - represents internal used buffer - * @alloc: allocation-specific context for each buffer - * (videobuf2 allocator) * @ofs: offset of each buffer, will be used for MFC * @virt: kernel virtual address, only valid when the * buffer accessed by driver @@ -246,7 +244,6 @@ struct s5p_mfc_variant { * @size: size of the buffer */ struct s5p_mfc_priv_buf { - void *alloc; unsigned long ofs; void *virt; dma_addr_t dma; @@ -340,6 +337,7 @@ struct s5p_mfc_dev { struct s5p_mfc_hw_cmds *mfc_cmds; const struct s5p_mfc_regs *mfc_regs; enum s5p_mfc_fw_ver fw_ver; + bool risc_on; /* indicates if RISC is on or off */ }; /** 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, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index a98fe023deaf..c6c3452ccca1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -269,15 +269,13 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1); strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(1, 0, 0); /* * This is only a mem-to-mem video device. The capture and output * device capability flags are left only for backward compatibility * and are scheduled for removal. */ - cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_VIDEO_OUTPUT_MPLANE; + cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -334,7 +332,6 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) MFCINST_RES_CHANGE_END)) { /* If the MFC is parsing the header, * so wait until it is finished */ - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } @@ -740,12 +737,12 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) ctx->state < MFCINST_ABORT) { ctrl->val = ctx->pb_count; break; - } else if (ctx->state != MFCINST_INIT) { + } else if (ctx->state != MFCINST_INIT && + ctx->state != MFCINST_RES_CHANGE_END) { v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); return -EINVAL; } /* Should wait for the header to be parsed */ - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); if (ctx->state >= MFCINST_HEAD_PARSED && @@ -1057,7 +1054,6 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) { ctx->state = MFCINST_FLUSH; 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_DPB_FLUSH_RET, 0)) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index a904a1c7bb21..bd64f1dcbdb5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -32,7 +32,7 @@ #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" -#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12MT +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M #define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 static struct s5p_mfc_fmt formats[] = { @@ -67,8 +67,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, }, { .name = "H264 Encoded Stream", @@ -690,6 +689,16 @@ static struct mfc_control controls[] = { .step = 1, .default_value = 0, }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Minimum number of output bufs", + .minimum = 1, + .maximum = 32, + .step = 1, + .default_value = 1, + .is_volatile = 1, + }, }; #define NUM_CTRLS ARRAY_SIZE(controls) @@ -938,15 +947,13 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1); strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; - cap->version = KERNEL_VERSION(1, 0, 0); /* * This is only a mem-to-mem video device. The capture and output * device capability flags are left only for backward compatibility * and are scheduled for removal. */ - cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_VIDEO_OUTPUT_MPLANE; + cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1137,6 +1144,11 @@ static int vidioc_reqbufs(struct file *file, void *priv, (reqbufs->memory != V4L2_MEMORY_USERPTR)) return -EINVAL; if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (reqbufs->count == 0) { + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + ctx->capture_state = QUEUE_FREE; + return ret; + } if (ctx->capture_state != QUEUE_FREE) { mfc_err("invalid capture state: %d\n", ctx->capture_state); @@ -1158,6 +1170,14 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -ENOMEM; } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (reqbufs->count == 0) { + mfc_debug(2, "Freeing buffers\n"); + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, + ctx); + ctx->output_state = QUEUE_FREE; + return ret; + } if (ctx->output_state != QUEUE_FREE) { mfc_err("invalid output state: %d\n", ctx->output_state); @@ -1624,8 +1644,39 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } +static int s5p_mfc_enc_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); + struct s5p_mfc_dev *dev = ctx->dev; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + break; + } else if (ctx->state != MFCINST_INIT) { + v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); + return -EINVAL; + } + /* Should wait for the header to be produced */ + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + } else { + v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); + return -EINVAL; + } + break; + } + return 0; +} + static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { .s_ctrl = s5p_mfc_enc_s_ctrl, + .g_volatile_ctrl = s5p_mfc_enc_g_v_ctrl, }; static int vidioc_s_parm(struct file *file, void *priv, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 7cf07963187d..0c4fcf2dfd09 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1178,7 +1178,6 @@ static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); } @@ -1192,7 +1191,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) last_frame = MFC_DEC_LAST_FRAME; s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_decode_one_frame_v5(ctx, last_frame); return 0; } @@ -1212,7 +1210,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); if (temp_vb->b->v4l2_planes[0].bytesused == 0) { last_frame = MFC_DEC_LAST_FRAME; mfc_debug(2, "Setting ctx->state to FINISHING\n"); @@ -1273,7 +1270,6 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); mfc_debug(2, "encoding buffer with index=%d state=%d\n", src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); s5p_mfc_encode_one_frame_v5(ctx); @@ -1297,7 +1293,6 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_init_decode_v5(ctx); } @@ -1317,7 +1312,6 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_init_encode_v5(ctx); } @@ -1352,7 +1346,6 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); if (ret) { mfc_err("Failed to alloc frame mem\n"); @@ -1396,6 +1389,8 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) * Now obtaining frames from MFC buffer */ s5p_mfc_clock_on(); + s5p_mfc_clean_ctx_int_flags(ctx); + if (ctx->type == MFCINST_DECODER) { s5p_mfc_set_dec_desc_buffer(ctx); switch (ctx->state) { @@ -1406,12 +1401,10 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); break; case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, ctx); break; case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, ctx); break; @@ -1444,12 +1437,10 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) ret = s5p_mfc_run_enc_frame(ctx); break; case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, ctx); break; case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, ctx); break; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 8798b14bacce..9aea179943ce 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1394,7 +1394,6 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) if (flush) { dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); writel(ctx->inst_no, mfc_regs->instance_id); s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_H2R_CMD_FLUSH_V6, NULL); @@ -1532,27 +1531,10 @@ static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - unsigned long flags; - - spin_lock_irqsave(&dev->irqlock, flags); - - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers.\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer_v6(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0); - spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame_v6(ctx, 1); + s5p_mfc_decode_one_frame_v6(ctx, MFC_DEC_LAST_FRAME); } static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) @@ -1588,7 +1570,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); if (temp_vb->b->v4l2_planes[0].bytesused == 0) { last_frame = 1; mfc_debug(2, "Setting ctx->state to FINISHING\n"); @@ -1645,7 +1626,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_encode_one_frame_v6(ctx); return 0; @@ -1667,7 +1647,6 @@ static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_init_decode_v6(ctx); } @@ -1687,7 +1666,6 @@ static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_init_encode_v6(ctx); } @@ -1707,7 +1685,6 @@ static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) } dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); if (ret) { mfc_err("Failed to alloc frame mem.\n"); @@ -1722,7 +1699,6 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) int ret; dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); if (ret) { mfc_err("Failed to alloc frame mem.\n"); @@ -1771,6 +1747,8 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) * Now obtaining frames from MFC buffer */ s5p_mfc_clock_on(); + s5p_mfc_clean_ctx_int_flags(ctx); + if (ctx->type == MFCINST_DECODER) { switch (ctx->state) { case MFCINST_FINISHING: @@ -1780,12 +1758,10 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) ret = s5p_mfc_run_dec_frame(ctx); break; case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, ctx); break; case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, ctx); break; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 826c48945bf5..5f97a3398c11 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -13,9 +13,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> -#ifdef CONFIG_PM_RUNTIME #include <linux/pm_runtime.h> -#endif #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" @@ -67,7 +65,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) } atomic_set(&pm->power, 0); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM pm->device = &dev->plat_dev->dev; pm_runtime_enable(pm->device); #endif @@ -93,7 +91,7 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) } clk_unprepare(pm->clock_gate); clk_put(pm->clock_gate); -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM pm_runtime_disable(pm->device); #endif } @@ -120,7 +118,7 @@ void s5p_mfc_clock_off(void) int s5p_mfc_power_on(void) { -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM return pm_runtime_get_sync(pm->device); #else atomic_set(&pm->power, 1); @@ -130,7 +128,7 @@ int s5p_mfc_power_on(void) int s5p_mfc_power_off(void) { -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM return pm_runtime_put_sync(pm->device); #else atomic_set(&pm->power, 0); |