From: Stefano Babic <sbabic@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH V2 07/14] imx: mx6: add clock api for lcdif
Date: Tue, 20 Oct 2015 15:39:32 +0200 [thread overview]
Message-ID: <56264414.6050604@denx.de> (raw)
In-Reply-To: <1445341184-22272-8-git-send-email-Peng.Fan@freescale.com>
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".
> + 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
=====================================================================
next prev parent reply other threads:[~2015-10-20 13:39 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 [this message]
2015-10-26 3:13 ` Peng Fan
2015-10-27 7:36 ` Peng Fan
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=56264414.6050604@denx.de \
--to=sbabic@denx.de \
--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