public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Peng Fan <b51431@freescale.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH V2 07/14] imx: mx6: add clock api for lcdif
Date: Tue, 27 Oct 2015 15:36:13 +0800	[thread overview]
Message-ID: <20151027073610.GA24904@shlinux2> (raw)
In-Reply-To: <56264414.6050604@denx.de>

Hi Stefano,

On Tue, Oct 20, 2015 at 03:39:32PM +0200, Stefano Babic wrote:
>Hi Peng,
>
>On 20/10/2015 13:39, Peng Fan wrote:
>> Implement mxs_set_lcdclk, enable_lcdif_clock and enable_pll_video.
>> The three API can be used to configure lcdif related clock when
>> CONFIG_VIDEO_MXS enabled.
>> 
>> Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
>> Cc: Stefano Babic <sbabic@denx.de>
>> ---
>> 
>> V2:
>>  none
>> 
>>  arch/arm/cpu/armv7/mx6/clock.c        | 239 ++++++++++++++++++++++++++++++++++
>>  arch/arm/include/asm/arch-mx6/clock.h |   2 +
>>  2 files changed, 241 insertions(+)
>> 
>> diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
>> index 11efd12..8a88378 100644
>> --- a/arch/arm/cpu/armv7/mx6/clock.c
>> +++ b/arch/arm/cpu/armv7/mx6/clock.c
>> @@ -473,6 +473,245 @@ static u32 get_mmdc_ch0_clk(void)
>>  	}
>>  }
>>  
>> +#if defined(CONFIG_VIDEO_MXS)
>> +static int enable_pll_video(u32 pll_div, u32 pll_num, u32 pll_denom,
>> +			    u32 post_div)
>> +{
>> +	u32 reg = 0;
>> +	ulong start;
>> +
>> +	debug("pll5 div = %d, num = %d, denom = %d\n",
>> +	      pll_div, pll_num, pll_denom);
>> +
>> +	/* Power up PLL5 video */
>> +	writel(BM_ANADIG_PLL_VIDEO_POWERDOWN |
>> +	       BM_ANADIG_PLL_VIDEO_BYPASS |
>> +	       BM_ANADIG_PLL_VIDEO_DIV_SELECT |
>> +	       BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT,
>> +	       &imx_ccm->analog_pll_video_clr);
>> +
>> +	/* Set div, num and denom */
>> +	switch (post_div) {
>> +	case 1:
>> +		writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
>> +		       BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x2),
>> +		       &imx_ccm->analog_pll_video_set);
>> +		break;
>> +	case 2:
>> +		writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
>> +		       BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x1),
>> +		       &imx_ccm->analog_pll_video_set);
>> +		break;
>> +	case 4:
>> +		writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
>> +		       BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x0),
>> +		       &imx_ccm->analog_pll_video_set);
>> +		break;
>> +	default:
>> +		puts("Wrong test_div!\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	writel(BF_ANADIG_PLL_VIDEO_NUM_A(pll_num),
>> +	       &imx_ccm->analog_pll_video_num);
>> +	writel(BF_ANADIG_PLL_VIDEO_DENOM_B(pll_denom),
>> +	       &imx_ccm->analog_pll_video_denom);
>> +
>> +	/* Wait PLL5 lock */
>> +	start = get_timer(0);	/* Get current timestamp */
>> +
>> +	do {
>> +		reg = readl(&imx_ccm->analog_pll_video);
>> +		if (reg & BM_ANADIG_PLL_VIDEO_LOCK) {
>> +			/* Enable PLL out */
>> +			writel(BM_ANADIG_PLL_VIDEO_ENABLE,
>> +			       &imx_ccm->analog_pll_video_set);
>> +			return 0;
>> +		}
>> +	} while (get_timer(0) < (start + 10)); /* Wait 10ms */
>> +
>> +	printf("Lock PLL5 timeout\n");
>
>Maybe puts() is better here
>
>> +
>> +	return -ETIME;
>> +}
>> +
>> +/*
>> + * 24M--> PLL_VIDEO -> LCDIFx_PRED -> LCDIFx_PODF -> LCD
>> + *
>> + * 'freq' using KHz as unit, see driver/video/mxsfb.c.
>> + */
>> +void mxs_set_lcdclk(u32 base_addr, u32 freq)
>> +{
>> +	u32 reg = 0;
>> +	u32 hck = MXC_HCLK / 1000;
>> +	/* DIV_SELECT ranges from 27 to 54 */
>> +	u32 min = hck * 27;
>> +	u32 max = hck * 54;
>> +	u32 temp, best = 0;
>> +	u32 i, j, max_pred = 8, max_postd = 8, pred = 1, postd = 1;
>> +	u32 pll_div, pll_num, pll_denom, post_div = 1;
>> +
>> +	debug("mxs_set_lcdclk, freq = %dKHz\n", freq);
>> +
>> +	if ((!is_cpu_type(MXC_CPU_MX6SX)) && !is_cpu_type(MXC_CPU_MX6UL))
>> +		return;
>> +
>> +	if (base_addr == LCDIF1_BASE_ADDR) {
>
>As mentioned before: base_addr is really an index, it is not used as
>address. The interface is then confusing.
>
>> +		reg = readl(&imx_ccm->cscdr2);
>> +		/* Can't change clocks when clock not from pre-mux */
>> +		if ((reg & MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK) != 0)
>> +			return;
>> +	}
>> +
>> +	if (is_cpu_type(MXC_CPU_MX6SX)) {
>> +		reg = readl(&imx_ccm->cscdr2);
>> +		/* Can't change clocks when clock not from pre-mux */
>> +		if ((reg & MXC_CCM_CSCDR2_LCDIF2_CLK_SEL_MASK) != 0)
>> +			return;
>> +	}
>> +
>> +	temp = freq * max_pred * max_postd;
>> +	if (temp > max) {
>> +		puts("Please decrease freq, too large!\n");
>> +		return;
>> +	}
>> +	if (temp < min) {
>> +		/*
>> +		 * Register: PLL_VIDEO
>> +		 * Bit Field: POST_DIV_SELECT
>> +		 * 00 ? Divide by 4.
>> +		 * 01 ? Divide by 2.
>> +		 * 10 ? Divide by 1.
>> +		 * 11 ? Reserved
>> +		 * No need to check post_div(1)
>> +		 */
>> +		for (post_div = 2; post_div <= 4; post_div <<= 1) {
>> +			if ((temp * post_div) > min) {
>> +				freq *= post_div;
>> +				break;
>> +			}
>> +		}
>> +
>> +		if (post_div > 4) {
>> +			printf("Fail to set rate to %dkhz", freq);
>> +			return;
>> +		}
>> +	}
>
>It is not clear what happens in the calling function in error case. The
>error is not propagate to the caller. Of course, we see the error on the
>console. Is it enough ? The caller will tzry to go on setting the LCD
>controller even in case this function fails.
>
>
>> +
>> +	/* Choose the best pred and postd to match freq for lcd */
>> +	for (i = 1; i <= max_pred; i++) {
>> +		for (j = 1; j <= max_postd; j++) {
>> +			temp = freq * i * j;
>> +			if (temp > max || temp < min)
>> +				continue;
>> +			if (best == 0 || temp < best) {
>> +				best = temp;
>> +				pred = i;
>> +				postd = j;
>> +			}
>> +		}
>> +	}
>> +
>> +	if (best == 0) {
>> +		printf("Fail to set rate to %dKHz", freq);
>> +		return;
>> +	}
>> +
>> +	debug("best %d, pred = %d, postd = %d\n", best, pred, postd);
>> +
>> +	pll_div = best / hck;
>> +	pll_denom = 1000000;
>> +	pll_num = (best - hck * pll_div) * pll_denom / hck;
>> +
>> +	/*
>> +	 *                                  pll_num
>> +	 *             (24MHz * (pll_div + --------- ))
>> +	 *                                 pll_denom
>> +	 *freq KHz =  --------------------------------
>> +	 *             post_div * pred * postd * 1000
>> +	 */
>> +
>> +	if (base_addr == LCDIF1_BASE_ADDR) {
>> +		if (enable_pll_video(pll_div, pll_num, pll_denom, post_div))
>> +			return;
>> +
>> +		/* Select pre-lcd clock to PLL5 and set pre divider */
>> +		clrsetbits_le32(&imx_ccm->cscdr2,
>> +				MXC_CCM_CSCDR2_LCDIF1_PRED_SEL_MASK |
>> +				MXC_CCM_CSCDR2_LCDIF1_PRE_DIV_MASK,
>> +				(0x2 << MXC_CCM_CSCDR2_LCDIF1_PRED_SEL_OFFSET) |
>> +				((pred - 1) <<
>> +				 MXC_CCM_CSCDR2_LCDIF1_PRE_DIV_OFFSET));
>> +
>> +		/* Set the post divider */
>> +		clrsetbits_le32(&imx_ccm->cbcmr,
>> +				MXC_CCM_CBCMR_LCDIF1_PODF_MASK,
>> +				((postd - 1) <<
>> +				 MXC_CCM_CBCMR_LCDIF1_PODF_OFFSET));
>> +	}
>> +
>> +	if (is_cpu_type(MXC_CPU_MX6SX)) {
>> +		if (enable_pll_video(pll_div, pll_num, pll_denom, post_div))
>> +			return;
>
>This is not very good readable. If the cpu is i.MX6SX and LCD is LCDIF1,
>is enable_pll_video called twice ? Why ?
>
>Should we not use something like:
>
>	if (lcd == LCDIF1 || is_cpu_type(MXC_CPU_MX6SX)) {
>		if (enable_pll_video(pll_div, pll_num, pll_denom, post_div))
>		return;
>
>	}
>
>> +
>> +		/* Select pre-lcd clock to PLL5 and set pre divider */
>> +		clrsetbits_le32(&imx_ccm->cscdr2,
>> +				MXC_CCM_CSCDR2_LCDIF2_PRED_SEL_MASK |
>> +				MXC_CCM_CSCDR2_LCDIF2_PRE_DIV_MASK,
>> +				(0x2 << MXC_CCM_CSCDR2_LCDIF2_PRED_SEL_OFFSET) |
>> +				((pred - 1) <<
>> +				 MXC_CCM_CSCDR2_LCDIF2_PRE_DIV_OFFSET));
>> +
>> +		/* Set the post divider */
>> +		clrsetbits_le32(&imx_ccm->cscmr1,
>> +				MXC_CCM_CSCMR1_LCDIF2_PODF_MASK,
>> +				((postd - 1) <<
>> +				 MXC_CCM_CSCMR1_LCDIF2_PODF_OFFSET));
>> +	}
>> +}
>> +
>> +void enable_lcdif_clock(u32 index)
>> +{
>
>You see, you are already using an index. Now you have a mix sometimes
>with an enumeration (this index), sometimes with "base_addr".

After a thought, I think use base_addr is better. In drivers/video/mxs_fb.c,
MXS_LCDIF_BASE is used, I do not want to introduce another macro such as
MXS_LCDIF_INDEX. So choose base_addr can avoid add more macro definitions
in board header files. I'll switch to use base_addr in the patch set.

Regards,
Peng.
>
>> +	u32 reg = 0;
>> +	u32 lcdif_clk_sel_mask, lcdif_ccgr3_mask;
>> +
>> +	if (is_cpu_type(MXC_CPU_MX6SX)) {
>> +		if (index > 1)
>> +			return;
>> +		/* Set to pre-mux clock at default */
>> +		lcdif_clk_sel_mask = (index == 1) ?
>> +			MXC_CCM_CSCDR2_LCDIF2_CLK_SEL_MASK :
>> +			MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK;
>> +		lcdif_ccgr3_mask = (index == 1) ?
>> +			(MXC_CCM_CCGR3_LCDIF2_PIX_MASK |
>> +			 MXC_CCM_CCGR3_DISP_AXI_MASK) :
>> +			(MXC_CCM_CCGR3_LCDIF1_PIX_MASK |
>> +			 MXC_CCM_CCGR3_DISP_AXI_MASK);
>> +	} else if (is_cpu_type(MXC_CPU_MX6UL)) {
>> +		if (index > 0)
>> +			return;
>> +		/* Set to pre-mux clock at default */
>> +		lcdif_clk_sel_mask = MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK;
>> +		lcdif_ccgr3_mask =  MXC_CCM_CCGR3_LCDIF1_PIX_MASK;
>> +	} else {
>> +		return;
>> +	}
>> +
>> +	reg = readl(&imx_ccm->cscdr2);
>> +	reg &= ~lcdif_clk_sel_mask;
>> +	writel(reg, &imx_ccm->cscdr2);
>> +
>> +	/* Enable the LCDIF pix clock */
>> +	reg = readl(&imx_ccm->CCGR3);
>> +	reg |= lcdif_ccgr3_mask;
>> +	writel(reg, &imx_ccm->CCGR3);
>> +
>> +	reg = readl(&imx_ccm->CCGR2);
>> +	reg |= MXC_CCM_CCGR2_LCD_MASK;
>> +	writel(reg, &imx_ccm->CCGR2);
>> +}
>> +#endif
>> +
>>  #ifdef CONFIG_FSL_QSPI
>>  /* qspi_num can be from 0 - 1 */
>>  void enable_qspi_clk(int qspi_num)
>> diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h
>> index 2b220d6..15d14f0 100644
>> --- a/arch/arm/include/asm/arch-mx6/clock.h
>> +++ b/arch/arm/include/asm/arch-mx6/clock.h
>> @@ -66,6 +66,8 @@ int enable_spi_clk(unsigned char enable, unsigned spi_num);
>>  void enable_ipu_clock(void);
>>  int enable_fec_anatop_clock(int fec_id, enum enet_freq freq);
>>  void enable_enet_clk(unsigned char enable);
>> +void enable_lcdif_clock(unsigned int index);
>>  void enable_qspi_clk(int qspi_num);
>>  void enable_thermal_clk(void);
>> +void mxs_set_lcdclk(u32 base_addr, u32 freq);
>>  #endif /* __ASM_ARCH_CLOCK_H */
>> 
>
>Best regards,
>Stefano Babic
>
>-- 
>=====================================================================
>DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
>HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic at denx.de
>=====================================================================

-- 

  parent reply	other threads:[~2015-10-27  7:36 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-20 11:39 [U-Boot] [PATCH V2 00/14] imx: mx6/7: support lcdif Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 01/14] mxs: add parameter base_addr for mxs_set_lcdclk Peng Fan
2015-10-20 13:05   ` Stefano Babic
2015-10-26  2:57     ` Peng Fan
2015-10-26 15:52       ` Stefano Babic
2015-10-27  5:28         ` Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 02/14] sandisk: sfp: correct function name Peng Fan
2015-10-20 13:09   ` Stefano Babic
2015-10-20 11:39 ` [U-Boot] [PATCH V2 03/14] xfi3: " Peng Fan
2015-10-20 13:10   ` Stefano Babic
2015-10-26  3:00     ` Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 04/14] imx: imx-common: move lcdif structure and macro definition to imx-common Peng Fan
2015-10-20 13:15   ` Stefano Babic
2015-10-26  3:06     ` Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 05/14] imx: mx6: fix register address Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 06/14] imx: mx6: crm_reg: add LCDIF related macros Peng Fan
2015-10-20 13:19   ` Stefano Babic
2015-10-20 11:39 ` [U-Boot] [PATCH V2 07/14] imx: mx6: add clock api for lcdif Peng Fan
2015-10-20 13:39   ` Stefano Babic
2015-10-26  3:13     ` Peng Fan
2015-10-27  7:36     ` Peng Fan [this message]
2015-10-20 11:39 ` [U-Boot] [PATCH V2 08/14] imx: mx6ul_14x14_evk: support lcdif display Peng Fan
2015-10-20 13:41   ` Stefano Babic
2015-10-26  3:18     ` Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 09/14] video: mxsfb: introduce lcdif_power_down Peng Fan
2015-10-20 13:59   ` Stefano Babic
2015-10-26  3:24     ` Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 10/14] imx: mx6: implement reset_misc Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 11/14] imx: imx-common: power down lcdif before boot os Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 12/14] imx: mx7: compile misc.c for mx7 Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 13/14] imx: mx7 use the common lcdif register structure Peng Fan
2015-10-20 11:39 ` [U-Boot] [PATCH V2 14/14] imx: mx7dsabresd: support lcdif Peng Fan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151027073610.GA24904@shlinux2 \
    --to=b51431@freescale.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox