Patchwork [U-Boot,1/4] arm: mxs: Add LCDIF clock configuration function

login
register
mail settings
Submitter Marek Vasut
Date April 28, 2013, 7:20 p.m.
Message ID <1367176804-13526-1-git-send-email-marex@denx.de>
Download mbox | patch
Permalink /patch/240273/
State Awaiting Upstream
Delegated to: Stefano Babic
Headers show

Comments

Marek Vasut - April 28, 2013, 7:20 p.m.
This function turns on the LCDIF clock and configures it's frequency. The
dividers settings are calculated within the function and the current
implementation should be fast and accurate.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Otavio Salvador <otavio@ossystems.com.br>
Cc: Stefano Babic <sbabic@denx.de>
---
 arch/arm/cpu/arm926ejs/mxs/clock.c    |   93 +++++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-mxs/clock.h |    1 +
 2 files changed, 94 insertions(+)
Marek Vasut - May 5, 2013, 9:26 p.m.
Hi Stefano,

you missed these.

> This function turns on the LCDIF clock and configures it's frequency. The
> dividers settings are calculated within the function and the current
> implementation should be fast and accurate.
> 
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Fabio Estevam <fabio.estevam@freescale.com>
> Cc: Otavio Salvador <otavio@ossystems.com.br>
> Cc: Stefano Babic <sbabic@denx.de>
> ---
>  arch/arm/cpu/arm926ejs/mxs/clock.c    |   93
> +++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mxs/clock.h | 
>   1 +
>  2 files changed, 94 insertions(+)
> 
> diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c
> b/arch/arm/cpu/arm926ejs/mxs/clock.c index 43e7663..f94107f 100644
> --- a/arch/arm/cpu/arm926ejs/mxs/clock.c
> +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c
> @@ -325,6 +325,99 @@ void mxs_set_ssp_busclock(unsigned int bus, uint32_t
> freq) bus, tgtclk, freq);
>  }
> 
> +void mxs_set_lcdclk(uint32_t freq)
> +{
> +	struct mxs_clkctrl_regs *clkctrl_regs =
> +		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +	uint32_t fp, x, k_rest, k_best, x_best, tk;
> +	int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
> +
> +	if (freq == 0)
> +		return;
> +
> +#if defined(CONFIG_MX23)
> +	writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
> +#elif defined(CONFIG_MX28)
> +	writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF,
> &clkctrl_regs->hw_clkctrl_clkseq_clr); +#endif
> +
> +	/*
> +	 *             /               18 \     1       1
> +	 * freq kHz = | 480000000 Hz * --  | * --- * ------
> +	 *             \                x /     k     1000
> +	 *
> +	 *      480000000 Hz   18
> +	 *      ------------ * --
> +	 *        freq kHz      x
> +	 * k = -------------------
> +	 *             1000
> +	 */
> +
> +	fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
> +
> +	for (x = 18; x <= 35; x++) {
> +		tk = fp / x;
> +		if ((tk / 1000 == 0) || (tk / 1000 > 255))
> +			continue;
> +
> +		k_rest = tk % 1000;
> +
> +		if (k_rest < (k_best_l % 1000)) {
> +			k_best_l = tk;
> +			x_best_l = x;
> +		}
> +
> +		if (k_rest > (k_best_t % 1000)) {
> +			k_best_t = tk;
> +			x_best_t = x;
> +		}
> +	}
> +
> +	if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
> +		k_best = k_best_l;
> +		x_best = x_best_l;
> +	} else {
> +		k_best = k_best_t;
> +		x_best = x_best_t;
> +	}
> +
> +	k_best /= 1000;
> +
> +#if defined(CONFIG_MX23)
> +	writeb(CLKCTRL_FRAC_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
> +	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
> +		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
> +	writeb(CLKCTRL_FRAC_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
> +
> +	writel(CLKCTRL_PIX_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_pix_set);
> +	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
> +			CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
> +			k_best << CLKCTRL_PIX_DIV_OFFSET);
> +
> +	while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
> +		;
> +#elif defined(CONFIG_MX28)
> +	writeb(CLKCTRL_FRAC_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
> +	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
> +		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
> +	writeb(CLKCTRL_FRAC_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
> +
> +	writel(CLKCTRL_DIS_LCDIF_CLKGATE,
> +		&clkctrl_regs->hw_clkctrl_lcdif_set);
> +	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
> +			CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
> +			k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
> +
> +	while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
> +		;
> +#endif
> +}
> +
>  uint32_t mxc_get_clock(enum mxc_clock clk)
>  {
>  	switch (clk) {
> diff --git a/arch/arm/include/asm/arch-mxs/clock.h
> b/arch/arm/include/asm/arch-mxs/clock.h index 3f7d3f0..9be53f0 100644
> --- a/arch/arm/include/asm/arch-mxs/clock.h
> +++ b/arch/arm/include/asm/arch-mxs/clock.h
> @@ -59,6 +59,7 @@ uint32_t mxc_get_clock(enum mxc_clock clk);
>  void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq);
>  void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal);
>  void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq);
> +void mxs_set_lcdclk(uint32_t freq);
> 
>  /* Compatibility with the FEC Ethernet driver */
>  #define	imx_get_fecclk()	mxc_get_clock(MXC_AHB_CLK)

Best regards,
Marek Vasut
Stefano Babic - May 6, 2013, 3:42 p.m.
On 28/04/2013 21:20, Marek Vasut wrote:
> This function turns on the LCDIF clock and configures it's frequency. The
> dividers settings are calculated within the function and the current
> implementation should be fast and accurate.
> 
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Fabio Estevam <fabio.estevam@freescale.com>
> Cc: Otavio Salvador <otavio@ossystems.com.br>
> Cc: Stefano Babic <sbabic@denx.de>
> ---

Applied to u-boot-imx, thanks.
Best regards,
Stefano Babic

Patch

diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c
index 43e7663..f94107f 100644
--- a/arch/arm/cpu/arm926ejs/mxs/clock.c
+++ b/arch/arm/cpu/arm926ejs/mxs/clock.c
@@ -325,6 +325,99 @@  void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
 		bus, tgtclk, freq);
 }
 
+void mxs_set_lcdclk(uint32_t freq)
+{
+	struct mxs_clkctrl_regs *clkctrl_regs =
+		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
+	uint32_t fp, x, k_rest, k_best, x_best, tk;
+	int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
+
+	if (freq == 0)
+		return;
+
+#if defined(CONFIG_MX23)
+	writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
+#elif defined(CONFIG_MX28)
+	writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
+#endif
+
+	/*
+	 *             /               18 \     1       1
+	 * freq kHz = | 480000000 Hz * --  | * --- * ------
+	 *             \                x /     k     1000
+	 *
+	 *      480000000 Hz   18
+	 *      ------------ * --
+	 *        freq kHz      x
+	 * k = -------------------
+	 *             1000
+	 */
+
+	fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
+
+	for (x = 18; x <= 35; x++) {
+		tk = fp / x;
+		if ((tk / 1000 == 0) || (tk / 1000 > 255))
+			continue;
+
+		k_rest = tk % 1000;
+
+		if (k_rest < (k_best_l % 1000)) {
+			k_best_l = tk;
+			x_best_l = x;
+		}
+
+		if (k_rest > (k_best_t % 1000)) {
+			k_best_t = tk;
+			x_best_t = x;
+		}
+	}
+
+	if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
+		k_best = k_best_l;
+		x_best = x_best_l;
+	} else {
+		k_best = k_best_t;
+		x_best = x_best_t;
+	}
+
+	k_best /= 1000;
+
+#if defined(CONFIG_MX23)
+	writeb(CLKCTRL_FRAC_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
+	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
+		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
+	writeb(CLKCTRL_FRAC_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
+
+	writel(CLKCTRL_PIX_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_pix_set);
+	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
+			CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
+			k_best << CLKCTRL_PIX_DIV_OFFSET);
+
+	while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
+		;
+#elif defined(CONFIG_MX28)
+	writeb(CLKCTRL_FRAC_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
+	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
+		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
+	writeb(CLKCTRL_FRAC_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
+
+	writel(CLKCTRL_DIS_LCDIF_CLKGATE,
+		&clkctrl_regs->hw_clkctrl_lcdif_set);
+	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
+			CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
+			k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
+
+	while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
+		;
+#endif
+}
+
 uint32_t mxc_get_clock(enum mxc_clock clk)
 {
 	switch (clk) {
diff --git a/arch/arm/include/asm/arch-mxs/clock.h b/arch/arm/include/asm/arch-mxs/clock.h
index 3f7d3f0..9be53f0 100644
--- a/arch/arm/include/asm/arch-mxs/clock.h
+++ b/arch/arm/include/asm/arch-mxs/clock.h
@@ -59,6 +59,7 @@  uint32_t mxc_get_clock(enum mxc_clock clk);
 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq);
 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal);
 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq);
+void mxs_set_lcdclk(uint32_t freq);
 
 /* Compatibility with the FEC Ethernet driver */
 #define	imx_get_fecclk()	mxc_get_clock(MXC_AHB_CLK)