diff options
Diffstat (limited to 'drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c')
| -rw-r--r-- | drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 160 |
1 files changed, 104 insertions, 56 deletions
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index e30e54935d79..4948d734eb02 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -143,7 +143,7 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) static void s5p_mfc_watchdog(struct timer_list *t) { - struct s5p_mfc_dev *dev = from_timer(dev, t, watchdog_timer); + struct s5p_mfc_dev *dev = timer_container_of(dev, t, watchdog_timer); if (test_bit(0, &dev->hw_lock)) atomic_inc(&dev->watchdog_cnt); @@ -183,7 +183,7 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) mfc_err("Error: some instance may be closing/opening\n"); spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); for (i = 0; i < MFC_NUM_CONTEXTS; i++) { ctx = dev->ctx[i]; @@ -211,9 +211,9 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) mfc_err("Failed to reload FW\n"); goto unlock; } - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) mfc_err("Failed to reinit FW\n"); } @@ -393,7 +393,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } @@ -465,7 +465,7 @@ leave_handle_frame: s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); /* if suspending, wake up device and do not try_run again*/ if (test_bit(0, &dev->enter_suspend)) wake_up_dev(dev, reason, err); @@ -509,7 +509,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, } WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up_dev(dev, reason, err); } @@ -565,7 +565,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -601,14 +601,16 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, } WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); + if (ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) + set_work_bit_irqsave(ctx); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); } @@ -636,7 +638,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } @@ -688,7 +690,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) } s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up_ctx(ctx, reason, err); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { @@ -737,6 +739,20 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) ctx->state = MFCINST_RUNNING; goto irq_cleanup_hw; + case S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET: + ctx->state = MFCINST_NAL_ABORT; + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + set_work_bit(ctx); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + break; + + case S5P_MFC_R2H_CMD_NAL_ABORT_RET: + ctx->state = MFCINST_ERROR; + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + goto irq_cleanup_hw; + default: mfc_debug(2, "Unknown int reason\n"); s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); @@ -752,7 +768,7 @@ irq_cleanup_hw: if (test_and_clear_bit(0, &dev->hw_lock) == 0) mfc_err("Failed to unlock hw\n"); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); clear_work_bit(ctx); wake_up(&ctx->queue); @@ -772,8 +788,10 @@ static int s5p_mfc_open(struct file *file) int ret = 0; mfc_debug_enter(); - if (mutex_lock_interruptible(&dev->mfc_mutex)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&dev->mfc_mutex)) { + ret = -ERESTARTSYS; + goto err_enter; + } dev->num_inst++; /* It is guarded by mfc_mutex in vfd */ /* Allocate memory for context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -783,13 +801,14 @@ static int s5p_mfc_open(struct file *file) } init_waitqueue_head(&ctx->queue); v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->dev = dev; INIT_LIST_HEAD(&ctx->src_queue); INIT_LIST_HEAD(&ctx->dst_queue); ctx->src_queue_cnt = 0; ctx->dst_queue_cnt = 0; + ctx->is_422 = 0; + ctx->is_10bit = 0; /* Get context number */ ctx->num = 0; while (dev->ctx[ctx->num]) { @@ -837,33 +856,33 @@ static int s5p_mfc_open(struct file *file) dev->watchdog_timer.expires = jiffies + msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); add_timer(&dev->watchdog_timer); - ret = s5p_mfc_power_on(); + ret = s5p_mfc_power_on(dev); if (ret < 0) { mfc_err("power on failed\n"); goto err_pwr_enable; } - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); ret = s5p_mfc_load_firmware(dev); if (ret) { - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); goto err_load_fw; } /* Init the FW */ ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) goto err_init_hw; } /* Init videobuf2 queue for CAPTURE */ q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; q->ops = get_enc_queue_ops(); } else { ret = -ENOENT; @@ -884,13 +903,13 @@ static int s5p_mfc_open(struct file *file) /* Init videobuf2 queue for OUTPUT */ q = &ctx->vq_src; q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; q->ops = get_enc_queue_ops(); } else { ret = -ENOENT; @@ -927,21 +946,22 @@ err_init_hw: err_load_fw: err_pwr_enable: if (dev->num_inst == 1) { - if (s5p_mfc_power_off() < 0) + if (s5p_mfc_power_off(dev) < 0) mfc_err("power off failed\n"); - del_timer_sync(&dev->watchdog_timer); + timer_delete_sync(&dev->watchdog_timer); } err_ctrls_setup: s5p_mfc_dec_ctrls_delete(ctx); err_bad_node: dev->ctx[ctx->num] = NULL; err_no_ctx: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); err_alloc: dev->num_inst--; mutex_unlock(&dev->mfc_mutex); +err_enter: mfc_debug_leave(); return ret; } @@ -949,7 +969,7 @@ err_alloc: /* Release MFC context */ static int s5p_mfc_release(struct file *file) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; /* if dev is null, do cleanup that doesn't need dev */ @@ -959,7 +979,7 @@ static int s5p_mfc_release(struct file *file) vb2_queue_release(&ctx->vq_src); vb2_queue_release(&ctx->vq_dst); if (dev) { - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); /* Mark context as idle */ clear_work_bit_irqsave(ctx); @@ -978,19 +998,19 @@ static int s5p_mfc_release(struct file *file) if (dev->num_inst == 0) { mfc_debug(2, "Last instance\n"); s5p_mfc_deinit_hw(dev); - del_timer_sync(&dev->watchdog_timer); - s5p_mfc_clock_off(); - if (s5p_mfc_power_off() < 0) + timer_delete_sync(&dev->watchdog_timer); + s5p_mfc_clock_off(dev); + if (s5p_mfc_power_off(dev) < 0) mfc_err("Power off failed\n"); } else { mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); } } if (dev) dev->ctx[ctx->num] = NULL; s5p_mfc_dec_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); /* vdev is gone if dev is null */ if (dev) v4l2_fh_exit(&ctx->fh); @@ -1006,7 +1026,7 @@ static int s5p_mfc_release(struct file *file) static __poll_t s5p_mfc_poll(struct file *file, struct poll_table_struct *wait) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct vb2_queue *src_q, *dst_q; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; @@ -1057,7 +1077,7 @@ end: /* Mmap */ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; @@ -1454,7 +1474,7 @@ static void s5p_mfc_remove(struct platform_device *pdev) } mutex_unlock(&dev->mfc_mutex); - del_timer_sync(&dev->watchdog_timer); + timer_delete_sync(&dev->watchdog_timer); flush_work(&dev->watchdog_work); video_unregister_device(dev->vfd_enc); @@ -1516,20 +1536,20 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) }; -static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { +static const struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { .h264_ctx = MFC_H264_CTX_BUF_SIZE, .non_h264_ctx = MFC_CTX_BUF_SIZE, .dsc = DESC_BUF_SIZE, .shm = SHARED_BUF_SIZE, }; -static struct s5p_mfc_buf_size buf_size_v5 = { +static const struct s5p_mfc_buf_size buf_size_v5 = { .fw = MAX_FW_SIZE, .cpb = MAX_CPB_SIZE, .priv = &mfc_buf_size_v5, }; -static struct s5p_mfc_variant mfc_drvdata_v5 = { +static const struct s5p_mfc_variant mfc_drvdata_v5 = { .version = MFC_VERSION, .version_bit = MFC_V5_BIT, .port_num = MFC_NUM_PORTS, @@ -1540,7 +1560,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .use_clock_gating = true, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .dev_ctx = MFC_CTX_BUF_SIZE_V6, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, @@ -1548,13 +1568,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, }; -static struct s5p_mfc_buf_size buf_size_v6 = { +static const struct s5p_mfc_buf_size buf_size_v6 = { .fw = MAX_FW_SIZE_V6, .cpb = MAX_CPB_SIZE_V6, .priv = &mfc_buf_size_v6, }; -static struct s5p_mfc_variant mfc_drvdata_v6 = { +static const struct s5p_mfc_variant mfc_drvdata_v6 = { .version = MFC_VERSION_V6, .version_bit = MFC_V6_BIT, .port_num = MFC_NUM_PORTS_V6, @@ -1569,7 +1589,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { .num_clocks = 1, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .dev_ctx = MFC_CTX_BUF_SIZE_V7, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7, @@ -1577,13 +1597,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7, }; -static struct s5p_mfc_buf_size buf_size_v7 = { +static const struct s5p_mfc_buf_size buf_size_v7 = { .fw = MAX_FW_SIZE_V7, .cpb = MAX_CPB_SIZE_V7, .priv = &mfc_buf_size_v7, }; -static struct s5p_mfc_variant mfc_drvdata_v7 = { +static const struct s5p_mfc_variant mfc_drvdata_v7 = { .version = MFC_VERSION_V7, .version_bit = MFC_V7_BIT, .port_num = MFC_NUM_PORTS_V7, @@ -1593,7 +1613,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = { .num_clocks = 1, }; -static struct s5p_mfc_variant mfc_drvdata_v7_3250 = { +static const struct s5p_mfc_variant mfc_drvdata_v7_3250 = { .version = MFC_VERSION_V7, .version_bit = MFC_V7_BIT, .port_num = MFC_NUM_PORTS_V7, @@ -1603,7 +1623,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7_3250 = { .num_clocks = 2, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .dev_ctx = MFC_CTX_BUF_SIZE_V8, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8, @@ -1611,13 +1631,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8, }; -static struct s5p_mfc_buf_size buf_size_v8 = { +static const struct s5p_mfc_buf_size buf_size_v8 = { .fw = MAX_FW_SIZE_V8, .cpb = MAX_CPB_SIZE_V8, .priv = &mfc_buf_size_v8, }; -static struct s5p_mfc_variant mfc_drvdata_v8 = { +static const struct s5p_mfc_variant mfc_drvdata_v8 = { .version = MFC_VERSION_V8, .version_bit = MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, @@ -1627,7 +1647,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .num_clocks = 1, }; -static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { +static const struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .version = MFC_VERSION_V8, .version_bit = MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, @@ -1637,7 +1657,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .num_clocks = 3, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { .dev_ctx = MFC_CTX_BUF_SIZE_V10, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, @@ -1646,13 +1666,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, }; -static struct s5p_mfc_buf_size buf_size_v10 = { +static const struct s5p_mfc_buf_size buf_size_v10 = { .fw = MAX_FW_SIZE_V10, .cpb = MAX_CPB_SIZE_V10, .priv = &mfc_buf_size_v10, }; -static struct s5p_mfc_variant mfc_drvdata_v10 = { +static const struct s5p_mfc_variant mfc_drvdata_v10 = { .version = MFC_VERSION_V10, .version_bit = MFC_V10_BIT, .port_num = MFC_NUM_PORTS_V10, @@ -1660,6 +1680,31 @@ static struct s5p_mfc_variant mfc_drvdata_v10 = { .fw_name[0] = "s5p-mfc-v10.fw", }; +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v12 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V12, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V12, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V12, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V12, + .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V12, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V12, +}; + +static struct s5p_mfc_buf_size buf_size_v12 = { + .fw = MAX_FW_SIZE_V12, + .cpb = MAX_CPB_SIZE_V12, + .priv = &mfc_buf_size_v12, +}; + +static struct s5p_mfc_variant mfc_drvdata_v12 = { + .version = MFC_VERSION_V12, + .version_bit = MFC_V12_BIT, + .port_num = MFC_NUM_PORTS_V12, + .buf_size = &buf_size_v12, + .fw_name[0] = "s5p-mfc-v12.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, +}; + static const struct of_device_id exynos_mfc_match[] = { { .compatible = "samsung,mfc-v5", @@ -1682,6 +1727,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,mfc-v10", .data = &mfc_drvdata_v10, + }, { + .compatible = "tesla,fsd-mfc", + .data = &mfc_drvdata_v12, }, {}, }; @@ -1689,7 +1737,7 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match); static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, - .remove_new = s5p_mfc_remove, + .remove = s5p_mfc_remove, .driver = { .name = S5P_MFC_NAME, .pm = &s5p_mfc_pm_ops, |
