diff options
Diffstat (limited to 'drivers/media/platform/s5p-mfc')
-rw-r--r-- | drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 3 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/regs-mfc.h | 3 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc.c | 73 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 12 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_debug.h | 6 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 15 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 7 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 132 |
11 files changed, 133 insertions, 128 deletions
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index 83e01f3466e9..d2cd35916dc5 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -386,7 +386,8 @@ ((w) * 144 + 8192 * (h) + 49216 + 1048576) #define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ (2096 * ((w) + (h) + 1)) -#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) \ + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) #define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) #define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index cc7cbec51b5e..4d1c3750eb5e 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -90,7 +90,7 @@ #define S5P_FIMV_E_H264_OPTIONS_V8 0xfb54 /* MFCv8 Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V8 (30 * SZ_1K) /* 30KB */ +#define MFC_CTX_BUF_SIZE_V8 (36 * SZ_1K) /* 36KB */ #define MFC_H264_DEC_CTX_BUF_SIZE_V8 (2 * SZ_1M) /* 2MB */ #define MFC_OTHER_DEC_CTX_BUF_SIZE_V8 (20 * SZ_1K) /* 20KB */ #define MFC_H264_ENC_CTX_BUF_SIZE_V8 (100 * SZ_1K) /* 100KB */ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index 6ccc3f8c122a..57b7e0be0596 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -393,6 +393,9 @@ #define S5P_FIMV_REG_CLEAR_COUNT 0 /* Error handling defines */ +#define S5P_FIMV_ERR_NO_VALID_SEQ_HDR 67 +#define S5P_FIMV_ERR_INCOMPLETE_FRAME 124 +#define S5P_FIMV_ERR_TIMEOUT 140 #define S5P_FIMV_ERR_WARNINGS_START 145 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF #define S5P_FIMV_ERR_DEC_SHIFT 0 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0a5b8f5e011e..bb0a5887c9a9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -641,8 +641,11 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occurred */ if (ctx->state == MFCINST_RUNNING && - s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= - dev->warn_start) + (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start || + err == S5P_FIMV_ERR_NO_VALID_SEQ_HDR || + err == S5P_FIMV_ERR_INCOMPLETE_FRAME || + err == S5P_FIMV_ERR_TIMEOUT)) s5p_mfc_handle_frame(ctx, reason, err); else s5p_mfc_handle_error(dev, ctx, reason, err); @@ -848,6 +851,11 @@ static int s5p_mfc_open(struct file *file) ret = -ENOENT; goto err_queue_init; } + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); @@ -878,6 +886,12 @@ static int s5p_mfc_open(struct file *file) * will keep the value of bytesused intact. */ q->allow_zero_bytesused = 1; + + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); @@ -926,10 +940,11 @@ static int s5p_mfc_release(struct file *file) mfc_debug_enter(); if (dev) mutex_lock(&dev->mfc_mutex); - s5p_mfc_clock_on(); vb2_queue_release(&ctx->vq_src); vb2_queue_release(&ctx->vq_dst); if (dev) { + s5p_mfc_clock_on(); + /* Mark context as idle */ clear_work_bit_irqsave(ctx); /* @@ -948,12 +963,14 @@ static int s5p_mfc_release(struct file *file) 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) mfc_err("Power off failed\n"); + } else { + mfc_debug(2, "Shutting down clock\n"); + s5p_mfc_clock_off(); } } - mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); if (dev) dev->ctx[ctx->num] = NULL; s5p_mfc_dec_ctrls_delete(ctx); @@ -1082,6 +1099,7 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, idx); if (ret == 0) return child; + device_del(child); } put_device(child); @@ -1387,31 +1405,9 @@ static int s5p_mfc_resume(struct device *dev) } #endif -#ifdef CONFIG_PM -static int s5p_mfc_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - - atomic_set(&m_dev->pm.power, 0); - return 0; -} - -static int s5p_mfc_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - - atomic_set(&m_dev->pm.power, 1); - return 0; -} -#endif - /* Power management */ static const struct dev_pm_ops s5p_mfc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) - SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume, - NULL) }; static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { @@ -1438,6 +1434,9 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, .fw_name[0] = "s5p-mfc.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, + .use_clock_gating = true, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { @@ -1470,6 +1469,8 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { * for init buffer command */ .fw_name[1] = "s5p-mfc-v6-v2.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { @@ -1497,6 +1498,8 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = { .buf_size = &buf_size_v7, .buf_align = &mfc_buf_align_v7, .fw_name[0] = "s5p-mfc-v7.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { @@ -1524,6 +1527,19 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .buf_size = &buf_size_v8, .buf_align = &mfc_buf_align_v8, .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, +}; + +static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { + .version = MFC_VERSION_V8, + .version_bit = MFC_V8_BIT, + .port_num = MFC_NUM_PORTS_V8, + .buf_size = &buf_size_v8, + .buf_align = &mfc_buf_align_v8, + .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"pclk", "aclk", "aclk_xiu"}, + .num_clocks = 3, }; static const struct of_device_id exynos_mfc_match[] = { @@ -1539,6 +1555,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,mfc-v8", .data = &mfc_drvdata_v8, + }, { + .compatible = "samsung,exynos5433-mfc", + .data = &mfc_drvdata_v8_5433, }, {}, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 46b99f28cbd7..ab23236aa942 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -104,6 +104,8 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 #define S5P_MFC_R2H_CMD_ERR_RET 32 +#define MFC_MAX_CLOCKS 4 + #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ (offset)) @@ -197,9 +199,12 @@ struct s5p_mfc_buf { * struct s5p_mfc_pm - power management data structure */ struct s5p_mfc_pm { - struct clk *clock; struct clk *clock_gate; - atomic_t power; + const char **clk_names; + struct clk *clocks[MFC_MAX_CLOCKS]; + int num_clocks; + bool use_clock_gating; + struct device *device; }; @@ -235,6 +240,9 @@ struct s5p_mfc_variant { struct s5p_mfc_buf_size *buf_size; struct s5p_mfc_buf_align *buf_align; char *fw_name[MFC_FW_MAX_VERSIONS]; + const char *clk_names[MFC_MAX_CLOCKS]; + int num_clocks; + bool use_clock_gating; }; /** diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index 5936923c631c..1936a5b868f5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -39,6 +39,12 @@ extern int mfc_debug_level; __func__, __LINE__, ##args); \ } while (0) +#define mfc_err_limited(fmt, args...) \ + do { \ + printk_ratelimited(KERN_ERR "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + #define mfc_info(fmt, args...) \ do { \ printk(KERN_INFO "%s:%d: " fmt, \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 52081ddc9bf2..367ef8e8dbf0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -642,7 +642,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) int ret; if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on DQBUF after unrecoverable error\n"); + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); return -EIO; } @@ -793,18 +793,17 @@ static int vidioc_g_crop(struct file *file, void *priv, cr->c.top = top; cr->c.width = ctx->img_width - left - right; cr->c.height = ctx->img_height - top - bottom; - mfc_debug(2, "Cropping info [h264]: l=%d t=%d " - "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, - cr->c.width, cr->c.height, right, bottom, - ctx->buf_width, ctx->buf_height); + mfc_debug(2, "Cropping info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", + left, top, cr->c.width, cr->c.height, right, bottom, + ctx->buf_width, ctx->buf_height); } else { cr->c.left = 0; cr->c.top = 0; cr->c.width = ctx->img_width; cr->c.height = ctx->img_height; - mfc_debug(2, "Cropping info: w=%d h=%d fw=%d " - "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width, - ctx->buf_height); + mfc_debug(2, "Cropping info: w=%d h=%d fw=%d fh=%d\n", + cr->c.width, cr->c.height, ctx->buf_width, + ctx->buf_height); } return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index fcc2e054c61f..e39d9e06e299 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1268,7 +1268,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) int ret; if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on DQBUF after unrecoverable error\n"); + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); return -EIO; } if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 1e7250260a9a..99f65a92a6be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -45,13 +45,13 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); if (!b->virt) { - mfc_err("Allocating private buffer failed\n"); + mfc_err("Allocating private buffer of size %zu failed\n", + b->size); return -ENOMEM; } if (b->dma < base) { - mfc_err("Invaling memory configuration!\n"); - mfc_err("Allocated buffer (%pad) is lower than memory base address (%pad)\n", + mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", &b->dma, &base); dma_free_coherent(dev, b->size, b->virt, b->dma); return -ENOMEM; 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 81e1e4ce6c24..f4301d5bbd32 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1293,14 +1293,11 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) * First set the output frame buffers */ if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destionation buffers were " - "mmaped\nMFC requires that all destination are mmaped " - "before starting processing\n"); + mfc_err("It seems that not all destionation buffers were mmaped\nMFC requires that all destination are mmaped before starting processing\n"); return -EAGAIN; } if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of" - " initialization\n"); + mfc_err("Header has been deallocated in the middle of initialization\n"); return -EIO; } temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 930dc2dddae6..eb85cedc5ef3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -18,129 +18,101 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -#define MFC_GATE_CLK_NAME "mfc" -#define MFC_SCLK_NAME "sclk_mfc" -#define MFC_SCLK_RATE (200 * 1000000) - -#define CLK_DEBUG - static struct s5p_mfc_pm *pm; static struct s5p_mfc_dev *p_dev; - -#ifdef CLK_DEBUG static atomic_t clk_ref; -#endif int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) { - int ret = 0; + int i; pm = &dev->pm; p_dev = dev; - pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); - if (IS_ERR(pm->clock_gate)) { - mfc_err("Failed to get clock-gating control\n"); - ret = PTR_ERR(pm->clock_gate); - goto err_g_ip_clk; - } - ret = clk_prepare(pm->clock_gate); - if (ret) { - mfc_err("Failed to prepare clock-gating control\n"); - goto err_p_ip_clk; - } + pm->num_clocks = dev->variant->num_clocks; + pm->clk_names = dev->variant->clk_names; + pm->device = &dev->plat_dev->dev; + pm->clock_gate = NULL; - if (dev->variant->version != MFC_VERSION_V6) { - pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME); - if (IS_ERR(pm->clock)) { - mfc_info("Failed to get MFC special clock control\n"); - pm->clock = NULL; - } else { - clk_set_rate(pm->clock, MFC_SCLK_RATE); - ret = clk_prepare_enable(pm->clock); - if (ret) { - mfc_err("Failed to enable MFC special clock\n"); - goto err_s_clk; - } + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); + if (IS_ERR(pm->clocks[i])) { + mfc_err("Failed to get clock: %s\n", + pm->clk_names[i]); + return PTR_ERR(pm->clocks[i]); } } - atomic_set(&pm->power, 0); -#ifdef CONFIG_PM - pm->device = &dev->plat_dev->dev; + if (dev->variant->use_clock_gating) + pm->clock_gate = pm->clocks[0]; + pm_runtime_enable(pm->device); -#endif -#ifdef CLK_DEBUG atomic_set(&clk_ref, 0); -#endif return 0; - -err_s_clk: - clk_put(pm->clock); - pm->clock = NULL; -err_p_ip_clk: - clk_put(pm->clock_gate); - pm->clock_gate = NULL; -err_g_ip_clk: - return ret; } void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) { - if (dev->variant->version != MFC_VERSION_V6 && - pm->clock) { - clk_disable_unprepare(pm->clock); - clk_put(pm->clock); - pm->clock = NULL; - } - clk_unprepare(pm->clock_gate); - clk_put(pm->clock_gate); - pm->clock_gate = NULL; -#ifdef CONFIG_PM pm_runtime_disable(pm->device); -#endif } int s5p_mfc_clock_on(void) { - int ret = 0; -#ifdef CLK_DEBUG atomic_inc(&clk_ref); mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); -#endif - if (!IS_ERR_OR_NULL(pm->clock_gate)) - ret = clk_enable(pm->clock_gate); - return ret; + + return clk_enable(pm->clock_gate); } void s5p_mfc_clock_off(void) { -#ifdef CLK_DEBUG atomic_dec(&clk_ref); mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); -#endif - if (!IS_ERR_OR_NULL(pm->clock_gate)) - clk_disable(pm->clock_gate); + + clk_disable(pm->clock_gate); } int s5p_mfc_power_on(void) { -#ifdef CONFIG_PM - return pm_runtime_get_sync(pm->device); -#else - atomic_set(&pm->power, 1); + int i, ret = 0; + + ret = pm_runtime_get_sync(pm->device); + if (ret < 0) + return ret; + + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + ret = clk_prepare_enable(pm->clocks[i]); + if (ret < 0) { + mfc_err("clock prepare failed for clock: %s\n", + pm->clk_names[i]); + i++; + goto err; + } + } + + /* prepare for software clock gating */ + clk_disable(pm->clock_gate); + return 0; -#endif +err: + while (--i > 0) + clk_disable_unprepare(pm->clocks[i]); + pm_runtime_put(pm->device); + return ret; } int s5p_mfc_power_off(void) { -#ifdef CONFIG_PM + int i; + + /* finish software clock gating */ + clk_enable(pm->clock_gate); + + for (i = 0; i < pm->num_clocks; i++) + clk_disable_unprepare(pm->clocks[i]); + return pm_runtime_put_sync(pm->device); -#else - atomic_set(&pm->power, 0); - return 0; -#endif } - |