From dcc05d9c24bb299d7b15e3bc1e100d79e32fa627 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Fri, 11 Sep 2015 14:58:02 +0800 Subject: [PATCH] MLK-11316-1 mxc IPUv3: PRE: Export a function to set PRE_CTRL register In order to workaround the PRE SoC bug recorded by errata ERR009624, the software cannot write the PRE_CTRL register when the PRE writes the PRE_CTRL register automatically to set the ENABLE bit(bit0) to 1 in the PRE repeat mode. This patch exports a function to set the PRE_CTRL register so that it could be used by the software when the PRE automatic writing doesn't happen for sure. Signed-off-by: Liu Ying (cherry picked from commit e64bbcd9243a17f9eba9cb3abb6f2c1939eae110) --- drivers/mxc/ipu3/pre.c | 42 +++++++++++--------------- drivers/video/fbdev/mxc/mxc_ipuv3_fb.c | 4 +++ include/linux/ipu-v3-pre.h | 6 ++++ 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/mxc/ipu3/pre.c b/drivers/mxc/ipu3/pre.c index a15a60bac52d..edac7e9f9c21 100644 --- a/drivers/mxc/ipu3/pre.c +++ b/drivers/mxc/ipu3/pre.c @@ -168,16 +168,7 @@ void ipu_pre_free_double_buffer(unsigned int id) EXPORT_SYMBOL(ipu_pre_free_double_buffer); /* PRE register configurations */ -static int ipu_pre_set_ctrl(unsigned int id, - bool repeat, - bool vflip, - bool handshake_en, - bool hsk_abort_en, - unsigned int hsk_line_num, - bool sdw_update, - unsigned int block_size, - unsigned int interlaced, - unsigned int prefetch_mode) +int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config) { struct ipu_pre_data *pre = get_pre(id); unsigned long lock_flags; @@ -186,29 +177,32 @@ static int ipu_pre_set_ctrl(unsigned int id, if (!pre) return -EINVAL; + if (!pre->enabled) + clk_prepare_enable(pre->clk); + spin_lock_irqsave(&pre->lock, lock_flags); pre_write(pre, BF_PRE_CTRL_TPR_RESET_SEL(1), HW_PRE_CTRL_SET); - if (repeat) + if (config->repeat) pre_write(pre, BF_PRE_CTRL_EN_REPEAT(1), HW_PRE_CTRL_SET); else pre_write(pre, BM_PRE_CTRL_EN_REPEAT, HW_PRE_CTRL_CLR); - if (vflip) + if (config->vflip) pre_write(pre, BF_PRE_CTRL_VFLIP(1), HW_PRE_CTRL_SET); else pre_write(pre, BM_PRE_CTRL_VFLIP, HW_PRE_CTRL_CLR); - if (handshake_en) { + if (config->handshake_en) { pre_write(pre, BF_PRE_CTRL_HANDSHAKE_EN(1), HW_PRE_CTRL_SET); - if (hsk_abort_en) + if (config->hsk_abort_en) pre_write(pre, BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(1), HW_PRE_CTRL_SET); else pre_write(pre, BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN, HW_PRE_CTRL_CLR); - switch (hsk_line_num) { + switch (config->hsk_line_num) { case 0 /* 4 lines */: pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM, HW_PRE_CTRL_CLR); @@ -234,13 +228,13 @@ static int ipu_pre_set_ctrl(unsigned int id, pre_write(pre, BM_PRE_CTRL_HANDSHAKE_EN, HW_PRE_CTRL_CLR); - switch (prefetch_mode) { + switch (config->prefetch_mode) { case 0: pre_write(pre, BM_PRE_CTRL_BLOCK_EN, HW_PRE_CTRL_CLR); break; case 1: pre_write(pre, BF_PRE_CTRL_BLOCK_EN(1), HW_PRE_CTRL_SET); - switch (block_size) { + switch (config->block_size) { case 0: pre_write(pre, BM_PRE_CTRL_BLOCK_16, HW_PRE_CTRL_CLR); break; @@ -259,7 +253,7 @@ static int ipu_pre_set_ctrl(unsigned int id, goto err; } - switch (interlaced) { + switch (config->interlaced) { case 0: /* progressive mode */ pre_write(pre, BM_PRE_CTRL_SO, HW_PRE_CTRL_CLR); break; @@ -277,7 +271,7 @@ static int ipu_pre_set_ctrl(unsigned int id, goto err; } - if (sdw_update) + if (config->sdw_update) pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET); else pre_write(pre, BM_PRE_CTRL_SDW_UPDATE, HW_PRE_CTRL_CLR); @@ -285,8 +279,12 @@ static int ipu_pre_set_ctrl(unsigned int id, err: spin_unlock_irqrestore(&pre->lock, lock_flags); + if (!pre->enabled) + clk_disable_unprepare(pre->clk); + return ret; } +EXPORT_SYMBOL(ipu_pre_set_ctrl); static void ipu_pre_irq_mask(struct ipu_pre_data *pre, unsigned long mask, bool clear) @@ -741,12 +739,6 @@ int ipu_pre_config(int id, struct ipu_pre_context *config) if (ret < 0) goto out; - ret = ipu_pre_set_ctrl(id, config->repeat, - config->vflip, config->handshake_en, - config->hsk_abort_en, config->hsk_line_num, - config->sdw_update, config->block_size, - config->interlaced, config->prefetch_mode); - ipu_pre_irq_mask(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ | BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ | BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, false); diff --git a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c index d45b414126a6..355b4778e1d8 100644 --- a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c @@ -704,6 +704,10 @@ static int _setup_disp_channel2(struct fb_info *fbi) ipu_base = pre.store_addr; mxc_fbi->store_addr = ipu_base; + retval = ipu_pre_set_ctrl(mxc_fbi->pre_num, &pre); + if (retval < 0) + return retval; + retval = ipu_pre_sdw_update(mxc_fbi->pre_num); if (retval < 0) { dev_err(fbi->device, diff --git a/include/linux/ipu-v3-pre.h b/include/linux/ipu-v3-pre.h index 4447c4084592..2b36d34d25fc 100644 --- a/include/linux/ipu-v3-pre.h +++ b/include/linux/ipu-v3-pre.h @@ -72,6 +72,7 @@ void ipu_pre_free(unsigned int *id); unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size); void ipu_pre_free_double_buffer(unsigned int id); int ipu_pre_config(int id, struct ipu_pre_context *config); +int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config); int ipu_pre_enable(int id); void ipu_pre_disable(int id); int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr, @@ -104,6 +105,11 @@ int ipu_pre_config(int id, struct ipu_pre_context *config) return -ENODEV; } +int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config) +{ + return -ENODEV; +} + int ipu_pre_enable(int id) { return -ENODEV; -- 2.17.1