summaryrefslogtreecommitdiff
path: root/drivers/mxc/ipu3/ipu_common.c
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2016-01-04 10:49:17 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit2511df5d3ab8e85b3dfdfa2962e805398d5e64b3 (patch)
tree6ef3f3e9d73548dc70a2f4e8a11732f37be691e0 /drivers/mxc/ipu3/ipu_common.c
parent4ce34256a3f2e0f4dad0ab7bd34db1d6486ef31a (diff)
MLK-11759 mxc IPUv3: common: Config IPU_CONF correctly in ipu_enable_channel()
The register IPU_CONF contains several dedicated enable bits for IPU internal modules. When we enable an IPU logic channel, e.g., MEM_BG_SYNC, by calling the function ipu_enable_channel(), we should enable the necessary IPU internal modules for that logic channel instead of touching other irrelevant modules. This may most definitely keep the steps for enabling a logic channel steady if no IPU internal module is shared by different logic channels. An known issue is caused by breaking this rule: we are likely to switch the display pixel clock source from IPU internal HSP clock to external clock when enabling a display which is driven by MEM_BG_SYNC. This operation is safe if the relevant DI enable bit in IPU_CONF is zero. In case another task, e.g., MEM_PP_MEM, is being enabled in parallel, it may accidently set the DI enable bit to one before the pixel clock source is switched, which may cause the display engine malfunction. To fix this issue, this patch configures the register IPU_CONF correctly in the function ipu_enable_channel() according to specific IPU logic channels. Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
Diffstat (limited to 'drivers/mxc/ipu3/ipu_common.c')
-rw-r--r--drivers/mxc/ipu3/ipu_common.c99
1 files changed, 75 insertions, 24 deletions
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index d472ad442dc1..c38f882be0a7 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
@@ -2315,6 +2315,7 @@ int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
uint32_t out_dma;
uint32_t sec_dma;
uint32_t thrd_dma;
+ uint32_t di = 0;
mutex_lock(&ipu->mutex_lock);
@@ -2330,29 +2331,79 @@ int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
ipu_conf = ipu_cm_read(ipu, IPU_CONF);
- if (ipu->di_use_count[0] > 0) {
- ipu_conf |= IPU_CONF_DI0_EN;
- }
- if (ipu->di_use_count[1] > 0) {
- ipu_conf |= IPU_CONF_DI1_EN;
- }
- if (ipu->dp_use_count > 0)
- ipu_conf |= IPU_CONF_DP_EN;
- if (ipu->dc_use_count > 0)
- ipu_conf |= IPU_CONF_DC_EN;
- if (ipu->dmfc_use_count > 0)
- ipu_conf |= IPU_CONF_DMFC_EN;
- if (ipu->ic_use_count > 0)
- ipu_conf |= IPU_CONF_IC_EN;
- if (ipu->vdi_use_count > 0) {
- ipu_conf |= IPU_CONF_ISP_EN;
- ipu_conf |= IPU_CONF_VDI_EN;
- ipu_conf |= IPU_CONF_IC_INPUT;
- }
- if (ipu->rot_use_count > 0)
- ipu_conf |= IPU_CONF_ROT_EN;
- if (ipu->smfc_use_count > 0)
- ipu_conf |= IPU_CONF_SMFC_EN;
+ switch (channel) {
+ case MEM_BG_SYNC:
+ di = ipu->dc_di_assignment[5];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dp_use_count > 0)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case MEM_DC_SYNC:
+ di = ipu->dc_di_assignment[1];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case MEM_FG_SYNC:
+ if (ipu->dp_use_count > 0)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case DIRECT_ASYNC0:
+ di = ipu->dc_di_assignment[8];
+ /* fall through */
+ case DIRECT_ASYNC1:
+ di = ipu->dc_di_assignment[9];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ break;
+ case MEM_ROT_PP_MEM:
+ case MEM_ROT_ENC_MEM:
+ case MEM_ROT_VF_MEM:
+ if (ipu->rot_use_count > 0)
+ ipu_conf |= IPU_CONF_ROT_EN;
+ /* fall through */
+ case MEM_PP_MEM:
+ case MEM_PRP_ENC_MEM:
+ case MEM_PRP_VF_MEM:
+ case CSI_PRP_ENC_MEM:
+ case CSI_PRP_VF_MEM:
+ if (ipu->ic_use_count > 0)
+ ipu_conf |= IPU_CONF_IC_EN;
+ break;
+ case CSI_MEM0:
+ case CSI_MEM1:
+ case CSI_MEM2:
+ case CSI_MEM3:
+ if (ipu->smfc_use_count > 0)
+ ipu_conf |= IPU_CONF_SMFC_EN;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ case MEM_VDI_MEM:
+ if (ipu->vdi_use_count > 0) {
+ ipu_conf |= IPU_CONF_ISP_EN;
+ ipu_conf |= IPU_CONF_VDI_EN;
+ ipu_conf |= IPU_CONF_IC_INPUT;
+ }
+ if (ipu->ic_use_count > 0)
+ ipu_conf |= IPU_CONF_IC_EN;
+ break;
+ default:
+ break;
+ }
ipu_cm_write(ipu, ipu_conf, IPU_CONF);
if (idma_is_valid(in_dma)) {