X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=arch%2Farm%2Fcpu%2Farm926ejs%2Fmxs%2Fclock.c;h=e9d8800f8c1b30f26d3598bdbb18d14732949638;hb=7c604e98c2213619af6a8c3064418af9b689cf56;hp=4ff19c37efe91ac7247f2b48c0d78097de9fd9e1;hpb=a098cf41fdb2a6607c675f7fe4f3164617c9367e;p=oweals%2Fu-boot.git diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c index 4ff19c37ef..e9d8800f8c 100644 --- a/arch/arm/cpu/arm926ejs/mxs/clock.c +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -1,5 +1,5 @@ /* - * Freescale i.MX28 clock setup code + * Freescale i.MX23/i.MX28 clock setup code * * Copyright (C) 2011 Marek Vasut * on behalf of DENX Software Engineering GmbH @@ -7,23 +7,7 @@ * Based on code from LTIB: * Copyright (C) 2010 Freescale Semiconductor, Inc. * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -32,16 +16,25 @@ #include #include -/* The PLL frequency is always 480MHz, see section 10.2 in iMX28 datasheet. */ +/* + * The PLL frequency is 480MHz and XTAL frequency is 24MHz + * iMX23: datasheet section 4.2 + * iMX28: datasheet section 10.2 + */ #define PLL_FREQ_KHZ 480000 #define PLL_FREQ_COEF 18 -/* The XTAL frequency is always 24MHz, see section 10.2 in iMX28 datasheet. */ #define XTAL_FREQ_KHZ 24000 #define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000) #define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000) -static uint32_t mx28_get_pclk(void) +#if defined(CONFIG_MX23) +#define MXC_SSPCLK_MAX MXC_SSPCLK0 +#elif defined(CONFIG_MX28) +#define MXC_SSPCLK_MAX MXC_SSPCLK3 +#endif + +static uint32_t mxs_get_pclk(void) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; @@ -73,7 +66,7 @@ static uint32_t mx28_get_pclk(void) return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; } -static uint32_t mx28_get_hclk(void) +static uint32_t mxs_get_hclk(void) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; @@ -88,10 +81,10 @@ static uint32_t mx28_get_hclk(void) return 0; div = clkctrl & CLKCTRL_HBUS_DIV_MASK; - return mx28_get_pclk() / div; + return mxs_get_pclk() / div; } -static uint32_t mx28_get_emiclk(void) +static uint32_t mxs_get_emiclk(void) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; @@ -116,11 +109,17 @@ static uint32_t mx28_get_emiclk(void) return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; } -static uint32_t mx28_get_gpmiclk(void) +static uint32_t mxs_get_gpmiclk(void) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; - +#if defined(CONFIG_MX23) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]; +#elif defined(CONFIG_MX28) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]; +#endif uint32_t clkctrl, clkseq, div; uint8_t clkfrac, frac; @@ -134,7 +133,7 @@ static uint32_t mx28_get_gpmiclk(void) } /* REF Path */ - clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]); + clkfrac = readb(reg); frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; div = clkctrl & CLKCTRL_GPMI_DIV_MASK; return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; @@ -143,7 +142,7 @@ static uint32_t mx28_get_gpmiclk(void) /* * Set IO clock frequency, in kHz */ -void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq) +void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; @@ -176,7 +175,7 @@ void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq) /* * Get IO clock, returns IO clock in kHz */ -static uint32_t mx28_get_ioclk(enum mxs_ioclock io) +static uint32_t mxs_get_ioclk(enum mxs_ioclock io) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; @@ -197,13 +196,13 @@ static uint32_t mx28_get_ioclk(enum mxs_ioclock io) /* * Configure SSP clock frequency, in kHz */ -void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) +void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; uint32_t clk, clkreg; - if (ssp > MXC_SSPCLK3) + if (ssp > MXC_SSPCLK_MAX) return; clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + @@ -216,7 +215,7 @@ void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) if (xtal) clk = XTAL_FREQ_KHZ; else - clk = mx28_get_ioclk(ssp >> 1); + clk = mxs_get_ioclk(ssp >> 1); if (freq > clk) return; @@ -241,14 +240,14 @@ void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) /* * Return SSP frequency, in kHz */ -static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp) +static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp) { struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; uint32_t clkreg; uint32_t clk, tmp; - if (ssp > MXC_SSPCLK3) + if (ssp > MXC_SSPCLK_MAX) return 0; tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq); @@ -263,7 +262,7 @@ static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp) if (tmp == 0) return 0; - clk = mx28_get_ioclk(ssp >> 1); + clk = mxs_get_ioclk(ssp >> 1); return clk / tmp; } @@ -271,14 +270,15 @@ static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp) /* * Set SSP/MMC bus frequency, in kHz) */ -void mx28_set_ssp_busclock(unsigned int bus, uint32_t freq) +void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq) { struct mxs_ssp_regs *ssp_regs; - const uint32_t sspclk = mx28_get_sspclk(bus); + const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus); + const uint32_t sspclk = mxs_get_sspclk(clk); uint32_t reg; uint32_t divide, rate, tgtclk; - ssp_regs = (struct mxs_ssp_regs *)(MXS_SSP0_BASE + (bus * 0x2000)); + ssp_regs = mxs_ssp_regs_by_bus(bus); /* * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), @@ -309,32 +309,127 @@ void mx28_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) { case MXC_ARM_CLK: - return mx28_get_pclk() * 1000000; + return mxs_get_pclk() * 1000000; case MXC_GPMI_CLK: - return mx28_get_gpmiclk() * 1000000; + return mxs_get_gpmiclk() * 1000000; case MXC_AHB_CLK: case MXC_IPG_CLK: - return mx28_get_hclk() * 1000000; + return mxs_get_hclk() * 1000000; case MXC_EMI_CLK: - return mx28_get_emiclk(); + return mxs_get_emiclk(); case MXC_IO0_CLK: - return mx28_get_ioclk(MXC_IOCLK0); + return mxs_get_ioclk(MXC_IOCLK0); case MXC_IO1_CLK: - return mx28_get_ioclk(MXC_IOCLK1); + return mxs_get_ioclk(MXC_IOCLK1); + case MXC_XTAL_CLK: + return XTAL_FREQ_KHZ * 1000; case MXC_SSP0_CLK: - return mx28_get_sspclk(MXC_SSPCLK0); + return mxs_get_sspclk(MXC_SSPCLK0); +#ifdef CONFIG_MX28 case MXC_SSP1_CLK: - return mx28_get_sspclk(MXC_SSPCLK1); + return mxs_get_sspclk(MXC_SSPCLK1); case MXC_SSP2_CLK: - return mx28_get_sspclk(MXC_SSPCLK2); + return mxs_get_sspclk(MXC_SSPCLK2); case MXC_SSP3_CLK: - return mx28_get_sspclk(MXC_SSPCLK3); - case MXC_XTAL_CLK: - return XTAL_FREQ_KHZ * 1000; + return mxs_get_sspclk(MXC_SSPCLK3); +#endif } return 0;