From: Liu Ying Date: Wed, 25 Apr 2012 06:34:31 +0000 (+0800) Subject: ENGR00180775 IPUv3:Change pixel clock disabling sequence X-Git-Tag: v3.0.35-fsl_4.1.0~1302 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=02e53d3f1989084a6ffeeac2b5b5cc07e5bacd3f;p=karo-tx-linux.git ENGR00180775 IPUv3:Change pixel clock disabling sequence This patch postpones pixel clock and its parent clock(if the parent clock usecount is 1) disabling time point until DC/DP/DI enable bits are cleared in IPU_CONF register to prevent LVDS display channel starvation for some special LVDS display video mode. Signed-off-by: Liu Ying --- diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index f03980bdc819..61687ad1411c 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -97,6 +97,18 @@ static inline int _ipu_is_trb_chan(uint32_t dma_chan) (g_ipu_hw_rev >= 2)); } +/* + * We usually use IDMAC 23 as full plane and IDMAC 27 as partial + * plane. + * IDMAC 23/24/28/41 can drive a display respectively - primary + * IDMAC 27 depends on IDMAC 23 - nonprimary + */ +static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan) +{ + return ((dma_chan == 23) || (dma_chan == 24) || + (dma_chan == 28) || (dma_chan == 41)); +} + #define idma_is_valid(ch) (ch != NO_DMA) #define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0) #define idma_is_set(ipu, reg, dma) (ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma)) @@ -952,6 +964,7 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel) uint32_t reg; uint32_t in_dma, out_dma = 0; uint32_t ipu_conf; + uint32_t dc_chan = 0; _ipu_lock(ipu); @@ -1084,12 +1097,14 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel) _ipu_ic_uninit_rotate_pp(ipu); break; case MEM_DC_SYNC: + dc_chan = 1; _ipu_dc_uninit(ipu, 1); ipu->di_use_count[ipu->dc_di_assignment[1]]--; ipu->dc_use_count--; ipu->dmfc_use_count--; break; case MEM_BG_SYNC: + dc_chan = 5; _ipu_dp_uninit(ipu, channel); _ipu_dc_uninit(ipu, 5); ipu->di_use_count[ipu->dc_di_assignment[5]]--; @@ -1104,11 +1119,13 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel) ipu->dmfc_use_count--; break; case DIRECT_ASYNC0: + dc_chan = 8; _ipu_dc_uninit(ipu, 8); ipu->di_use_count[ipu->dc_di_assignment[8]]--; ipu->dc_use_count--; break; case DIRECT_ASYNC1: + dc_chan = 9; _ipu_dc_uninit(ipu, 9); ipu->di_use_count[ipu->dc_di_assignment[9]]--; ipu->dc_use_count--; @@ -1145,6 +1162,14 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel) ipu->channel_init_mask &= ~(1L << IPU_CHAN_ID(channel)); + /* + * Disable pixel clk and its parent clock(if the parent clock + * usecount is 1) after clearing DC/DP/DI bits in IPU_CONF + * register to prevent LVDS display channel starvation. + */ + if (_ipu_is_primary_disp_chan(in_dma)) + clk_disable(&ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]); + _ipu_unlock(ipu); _ipu_put(ipu); diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index 229545c9cb34..d2fa65dd774e 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -997,10 +997,7 @@ void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap) reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; reg ^= DC_WR_CH_CONF_PROG_DI_ID; ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan)); - } else - /* Clock is already off because it must be done quickly, but - we need to fix the ref count */ - clk_disable(&ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]); + } } void _ipu_init_dc_mappings(struct ipu_soc *ipu)