13a0398d7SOtavio Salvador /*
200239977SOtavio Salvador * Freescale i.MX23/i.MX28 clock setup code
33a0398d7SOtavio Salvador *
43a0398d7SOtavio Salvador * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
53a0398d7SOtavio Salvador * on behalf of DENX Software Engineering GmbH
63a0398d7SOtavio Salvador *
73a0398d7SOtavio Salvador * Based on code from LTIB:
83a0398d7SOtavio Salvador * Copyright (C) 2010 Freescale Semiconductor, Inc.
93a0398d7SOtavio Salvador *
101a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
113a0398d7SOtavio Salvador */
123a0398d7SOtavio Salvador
133a0398d7SOtavio Salvador #include <common.h>
14*1221ce45SMasahiro Yamada #include <linux/errno.h>
153a0398d7SOtavio Salvador #include <asm/io.h>
163a0398d7SOtavio Salvador #include <asm/arch/clock.h>
173a0398d7SOtavio Salvador #include <asm/arch/imx-regs.h>
183a0398d7SOtavio Salvador
1900239977SOtavio Salvador /*
2000239977SOtavio Salvador * The PLL frequency is 480MHz and XTAL frequency is 24MHz
2100239977SOtavio Salvador * iMX23: datasheet section 4.2
2200239977SOtavio Salvador * iMX28: datasheet section 10.2
2300239977SOtavio Salvador */
243a0398d7SOtavio Salvador #define PLL_FREQ_KHZ 480000
253a0398d7SOtavio Salvador #define PLL_FREQ_COEF 18
263a0398d7SOtavio Salvador #define XTAL_FREQ_KHZ 24000
273a0398d7SOtavio Salvador
283a0398d7SOtavio Salvador #define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
293a0398d7SOtavio Salvador #define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
303a0398d7SOtavio Salvador
3100239977SOtavio Salvador #if defined(CONFIG_MX23)
3200239977SOtavio Salvador #define MXC_SSPCLK_MAX MXC_SSPCLK0
3300239977SOtavio Salvador #elif defined(CONFIG_MX28)
3400239977SOtavio Salvador #define MXC_SSPCLK_MAX MXC_SSPCLK3
3500239977SOtavio Salvador #endif
3600239977SOtavio Salvador
mxs_get_pclk(void)37bf48fcb6SOtavio Salvador static uint32_t mxs_get_pclk(void)
383a0398d7SOtavio Salvador {
399c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
409c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
413a0398d7SOtavio Salvador
423a0398d7SOtavio Salvador uint32_t clkctrl, clkseq, div;
433a0398d7SOtavio Salvador uint8_t clkfrac, frac;
443a0398d7SOtavio Salvador
453a0398d7SOtavio Salvador clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
463a0398d7SOtavio Salvador
473a0398d7SOtavio Salvador /* No support of fractional divider calculation */
483a0398d7SOtavio Salvador if (clkctrl &
493a0398d7SOtavio Salvador (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
503a0398d7SOtavio Salvador return 0;
513a0398d7SOtavio Salvador }
523a0398d7SOtavio Salvador
533a0398d7SOtavio Salvador clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
543a0398d7SOtavio Salvador
553a0398d7SOtavio Salvador /* XTAL Path */
563a0398d7SOtavio Salvador if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
573a0398d7SOtavio Salvador div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
583a0398d7SOtavio Salvador CLKCTRL_CPU_DIV_XTAL_OFFSET;
593a0398d7SOtavio Salvador return XTAL_FREQ_MHZ / div;
603a0398d7SOtavio Salvador }
613a0398d7SOtavio Salvador
623a0398d7SOtavio Salvador /* REF Path */
633a0398d7SOtavio Salvador clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
643a0398d7SOtavio Salvador frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
653a0398d7SOtavio Salvador div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
663a0398d7SOtavio Salvador return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
673a0398d7SOtavio Salvador }
683a0398d7SOtavio Salvador
mxs_get_hclk(void)69bf48fcb6SOtavio Salvador static uint32_t mxs_get_hclk(void)
703a0398d7SOtavio Salvador {
719c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
729c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
733a0398d7SOtavio Salvador
743a0398d7SOtavio Salvador uint32_t div;
753a0398d7SOtavio Salvador uint32_t clkctrl;
763a0398d7SOtavio Salvador
773a0398d7SOtavio Salvador clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
783a0398d7SOtavio Salvador
793a0398d7SOtavio Salvador /* No support of fractional divider calculation */
803a0398d7SOtavio Salvador if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
813a0398d7SOtavio Salvador return 0;
823a0398d7SOtavio Salvador
833a0398d7SOtavio Salvador div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
84bf48fcb6SOtavio Salvador return mxs_get_pclk() / div;
853a0398d7SOtavio Salvador }
863a0398d7SOtavio Salvador
mxs_get_emiclk(void)87bf48fcb6SOtavio Salvador static uint32_t mxs_get_emiclk(void)
883a0398d7SOtavio Salvador {
899c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
909c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
913a0398d7SOtavio Salvador
923a0398d7SOtavio Salvador uint32_t clkctrl, clkseq, div;
933a0398d7SOtavio Salvador uint8_t clkfrac, frac;
943a0398d7SOtavio Salvador
953a0398d7SOtavio Salvador clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
963a0398d7SOtavio Salvador clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
973a0398d7SOtavio Salvador
983a0398d7SOtavio Salvador /* XTAL Path */
993a0398d7SOtavio Salvador if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
1003a0398d7SOtavio Salvador div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
1013a0398d7SOtavio Salvador CLKCTRL_EMI_DIV_XTAL_OFFSET;
1023a0398d7SOtavio Salvador return XTAL_FREQ_MHZ / div;
1033a0398d7SOtavio Salvador }
1043a0398d7SOtavio Salvador
1053a0398d7SOtavio Salvador /* REF Path */
1063a0398d7SOtavio Salvador clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
1073a0398d7SOtavio Salvador frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
1083a0398d7SOtavio Salvador div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
1093a0398d7SOtavio Salvador return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
1103a0398d7SOtavio Salvador }
1113a0398d7SOtavio Salvador
mxs_get_gpmiclk(void)112bf48fcb6SOtavio Salvador static uint32_t mxs_get_gpmiclk(void)
1133a0398d7SOtavio Salvador {
1149c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
1159c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
11600239977SOtavio Salvador #if defined(CONFIG_MX23)
11700239977SOtavio Salvador uint8_t *reg =
11800239977SOtavio Salvador &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
11900239977SOtavio Salvador #elif defined(CONFIG_MX28)
12000239977SOtavio Salvador uint8_t *reg =
12100239977SOtavio Salvador &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
12200239977SOtavio Salvador #endif
1233a0398d7SOtavio Salvador uint32_t clkctrl, clkseq, div;
1243a0398d7SOtavio Salvador uint8_t clkfrac, frac;
1253a0398d7SOtavio Salvador
1263a0398d7SOtavio Salvador clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
1273a0398d7SOtavio Salvador clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
1283a0398d7SOtavio Salvador
1293a0398d7SOtavio Salvador /* XTAL Path */
1303a0398d7SOtavio Salvador if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
1313a0398d7SOtavio Salvador div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
1323a0398d7SOtavio Salvador return XTAL_FREQ_MHZ / div;
1333a0398d7SOtavio Salvador }
1343a0398d7SOtavio Salvador
1353a0398d7SOtavio Salvador /* REF Path */
13600239977SOtavio Salvador clkfrac = readb(reg);
1373a0398d7SOtavio Salvador frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
1383a0398d7SOtavio Salvador div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
1393a0398d7SOtavio Salvador return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
1403a0398d7SOtavio Salvador }
1413a0398d7SOtavio Salvador
1423a0398d7SOtavio Salvador /*
1433a0398d7SOtavio Salvador * Set IO clock frequency, in kHz
1443a0398d7SOtavio Salvador */
mxs_set_ioclk(enum mxs_ioclock io,uint32_t freq)145bf48fcb6SOtavio Salvador void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
1463a0398d7SOtavio Salvador {
1479c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
1489c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
1493a0398d7SOtavio Salvador uint32_t div;
1503a0398d7SOtavio Salvador int io_reg;
1513a0398d7SOtavio Salvador
1523a0398d7SOtavio Salvador if (freq == 0)
1533a0398d7SOtavio Salvador return;
1543a0398d7SOtavio Salvador
1553a0398d7SOtavio Salvador if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
1563a0398d7SOtavio Salvador return;
1573a0398d7SOtavio Salvador
1583a0398d7SOtavio Salvador div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
1593a0398d7SOtavio Salvador
1603a0398d7SOtavio Salvador if (div < 18)
1613a0398d7SOtavio Salvador div = 18;
1623a0398d7SOtavio Salvador
1633a0398d7SOtavio Salvador if (div > 35)
1643a0398d7SOtavio Salvador div = 35;
1653a0398d7SOtavio Salvador
1663a0398d7SOtavio Salvador io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
1673a0398d7SOtavio Salvador writeb(CLKCTRL_FRAC_CLKGATE,
1683a0398d7SOtavio Salvador &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
1693a0398d7SOtavio Salvador writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
1703a0398d7SOtavio Salvador &clkctrl_regs->hw_clkctrl_frac0[io_reg]);
1713a0398d7SOtavio Salvador writeb(CLKCTRL_FRAC_CLKGATE,
1723a0398d7SOtavio Salvador &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
1733a0398d7SOtavio Salvador }
1743a0398d7SOtavio Salvador
1753a0398d7SOtavio Salvador /*
1763a0398d7SOtavio Salvador * Get IO clock, returns IO clock in kHz
1773a0398d7SOtavio Salvador */
mxs_get_ioclk(enum mxs_ioclock io)178bf48fcb6SOtavio Salvador static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
1793a0398d7SOtavio Salvador {
1809c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
1819c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
1823a0398d7SOtavio Salvador uint8_t ret;
1833a0398d7SOtavio Salvador int io_reg;
1843a0398d7SOtavio Salvador
1853a0398d7SOtavio Salvador if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
1863a0398d7SOtavio Salvador return 0;
1873a0398d7SOtavio Salvador
1883a0398d7SOtavio Salvador io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
1893a0398d7SOtavio Salvador
1903a0398d7SOtavio Salvador ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
1913a0398d7SOtavio Salvador CLKCTRL_FRAC_FRAC_MASK;
1923a0398d7SOtavio Salvador
1933a0398d7SOtavio Salvador return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
1943a0398d7SOtavio Salvador }
1953a0398d7SOtavio Salvador
1963a0398d7SOtavio Salvador /*
1973a0398d7SOtavio Salvador * Configure SSP clock frequency, in kHz
1983a0398d7SOtavio Salvador */
mxs_set_sspclk(enum mxs_sspclock ssp,uint32_t freq,int xtal)199bf48fcb6SOtavio Salvador void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
2003a0398d7SOtavio Salvador {
2019c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
2029c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
2033a0398d7SOtavio Salvador uint32_t clk, clkreg;
2043a0398d7SOtavio Salvador
20500239977SOtavio Salvador if (ssp > MXC_SSPCLK_MAX)
2063a0398d7SOtavio Salvador return;
2073a0398d7SOtavio Salvador
2083a0398d7SOtavio Salvador clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
209ddcf13b1SOtavio Salvador (ssp * sizeof(struct mxs_register_32));
2103a0398d7SOtavio Salvador
2113a0398d7SOtavio Salvador clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
2123a0398d7SOtavio Salvador while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
2133a0398d7SOtavio Salvador ;
2143a0398d7SOtavio Salvador
2153a0398d7SOtavio Salvador if (xtal)
2163a0398d7SOtavio Salvador clk = XTAL_FREQ_KHZ;
2173a0398d7SOtavio Salvador else
218bf48fcb6SOtavio Salvador clk = mxs_get_ioclk(ssp >> 1);
2193a0398d7SOtavio Salvador
2203a0398d7SOtavio Salvador if (freq > clk)
2213a0398d7SOtavio Salvador return;
2223a0398d7SOtavio Salvador
2233a0398d7SOtavio Salvador /* Calculate the divider and cap it if necessary */
2243a0398d7SOtavio Salvador clk /= freq;
2253a0398d7SOtavio Salvador if (clk > CLKCTRL_SSP_DIV_MASK)
2263a0398d7SOtavio Salvador clk = CLKCTRL_SSP_DIV_MASK;
2273a0398d7SOtavio Salvador
2283a0398d7SOtavio Salvador clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
2293a0398d7SOtavio Salvador while (readl(clkreg) & CLKCTRL_SSP_BUSY)
2303a0398d7SOtavio Salvador ;
2313a0398d7SOtavio Salvador
2323a0398d7SOtavio Salvador if (xtal)
2333a0398d7SOtavio Salvador writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
2343a0398d7SOtavio Salvador &clkctrl_regs->hw_clkctrl_clkseq_set);
2353a0398d7SOtavio Salvador else
2363a0398d7SOtavio Salvador writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
2373a0398d7SOtavio Salvador &clkctrl_regs->hw_clkctrl_clkseq_clr);
2383a0398d7SOtavio Salvador }
2393a0398d7SOtavio Salvador
2403a0398d7SOtavio Salvador /*
2413a0398d7SOtavio Salvador * Return SSP frequency, in kHz
2423a0398d7SOtavio Salvador */
mxs_get_sspclk(enum mxs_sspclock ssp)243bf48fcb6SOtavio Salvador static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
2443a0398d7SOtavio Salvador {
2459c471142SOtavio Salvador struct mxs_clkctrl_regs *clkctrl_regs =
2469c471142SOtavio Salvador (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
2473a0398d7SOtavio Salvador uint32_t clkreg;
2483a0398d7SOtavio Salvador uint32_t clk, tmp;
2493a0398d7SOtavio Salvador
25000239977SOtavio Salvador if (ssp > MXC_SSPCLK_MAX)
2513a0398d7SOtavio Salvador return 0;
2523a0398d7SOtavio Salvador
2533a0398d7SOtavio Salvador tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
2543a0398d7SOtavio Salvador if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
2553a0398d7SOtavio Salvador return XTAL_FREQ_KHZ;
2563a0398d7SOtavio Salvador
2573a0398d7SOtavio Salvador clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
258ddcf13b1SOtavio Salvador (ssp * sizeof(struct mxs_register_32));
2593a0398d7SOtavio Salvador
2603a0398d7SOtavio Salvador tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
2613a0398d7SOtavio Salvador
2623a0398d7SOtavio Salvador if (tmp == 0)
2633a0398d7SOtavio Salvador return 0;
2643a0398d7SOtavio Salvador
265bf48fcb6SOtavio Salvador clk = mxs_get_ioclk(ssp >> 1);
2663a0398d7SOtavio Salvador
2673a0398d7SOtavio Salvador return clk / tmp;
2683a0398d7SOtavio Salvador }
2693a0398d7SOtavio Salvador
2703a0398d7SOtavio Salvador /*
2713a0398d7SOtavio Salvador * Set SSP/MMC bus frequency, in kHz)
2723a0398d7SOtavio Salvador */
mxs_set_ssp_busclock(unsigned int bus,uint32_t freq)273bf48fcb6SOtavio Salvador void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
2743a0398d7SOtavio Salvador {
2759c471142SOtavio Salvador struct mxs_ssp_regs *ssp_regs;
2763430e0bdSMarek Vasut const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
2773430e0bdSMarek Vasut const uint32_t sspclk = mxs_get_sspclk(clk);
2783a0398d7SOtavio Salvador uint32_t reg;
2793a0398d7SOtavio Salvador uint32_t divide, rate, tgtclk;
2803a0398d7SOtavio Salvador
28114e26bcfSMarek Vasut ssp_regs = mxs_ssp_regs_by_bus(bus);
2823a0398d7SOtavio Salvador
2833a0398d7SOtavio Salvador /*
2843a0398d7SOtavio Salvador * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
2853a0398d7SOtavio Salvador * CLOCK_DIVIDE has to be an even value from 2 to 254, and
2863a0398d7SOtavio Salvador * CLOCK_RATE could be any integer from 0 to 255.
2873a0398d7SOtavio Salvador */
2883a0398d7SOtavio Salvador for (divide = 2; divide < 254; divide += 2) {
2893a0398d7SOtavio Salvador rate = sspclk / freq / divide;
2903a0398d7SOtavio Salvador if (rate <= 256)
2913a0398d7SOtavio Salvador break;
2923a0398d7SOtavio Salvador }
2933a0398d7SOtavio Salvador
2943a0398d7SOtavio Salvador tgtclk = sspclk / divide / rate;
2953a0398d7SOtavio Salvador while (tgtclk > freq) {
2963a0398d7SOtavio Salvador rate++;
2973a0398d7SOtavio Salvador tgtclk = sspclk / divide / rate;
2983a0398d7SOtavio Salvador }
2993a0398d7SOtavio Salvador if (rate > 256)
3003a0398d7SOtavio Salvador rate = 256;
3013a0398d7SOtavio Salvador
3023a0398d7SOtavio Salvador /* Always set timeout the maximum */
3033a0398d7SOtavio Salvador reg = SSP_TIMING_TIMEOUT_MASK |
3043a0398d7SOtavio Salvador (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
3053a0398d7SOtavio Salvador ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
3063a0398d7SOtavio Salvador writel(reg, &ssp_regs->hw_ssp_timing);
3073a0398d7SOtavio Salvador
3083a0398d7SOtavio Salvador debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
3093a0398d7SOtavio Salvador bus, tgtclk, freq);
3103a0398d7SOtavio Salvador }
3113a0398d7SOtavio Salvador
mxs_set_lcdclk(uint32_t __maybe_unused lcd_base,uint32_t freq)31295ae7000SPeng Fan void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq)
3137411cdf0SMarek Vasut {
3147411cdf0SMarek Vasut struct mxs_clkctrl_regs *clkctrl_regs =
3157411cdf0SMarek Vasut (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
3167411cdf0SMarek Vasut uint32_t fp, x, k_rest, k_best, x_best, tk;
3177411cdf0SMarek Vasut int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
3187411cdf0SMarek Vasut
3197411cdf0SMarek Vasut if (freq == 0)
3207411cdf0SMarek Vasut return;
3217411cdf0SMarek Vasut
3227411cdf0SMarek Vasut #if defined(CONFIG_MX23)
3237411cdf0SMarek Vasut writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
3247411cdf0SMarek Vasut #elif defined(CONFIG_MX28)
3257411cdf0SMarek Vasut writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
3267411cdf0SMarek Vasut #endif
3277411cdf0SMarek Vasut
3287411cdf0SMarek Vasut /*
3297411cdf0SMarek Vasut * / 18 \ 1 1
3307411cdf0SMarek Vasut * freq kHz = | 480000000 Hz * -- | * --- * ------
3317411cdf0SMarek Vasut * \ x / k 1000
3327411cdf0SMarek Vasut *
3337411cdf0SMarek Vasut * 480000000 Hz 18
3347411cdf0SMarek Vasut * ------------ * --
3357411cdf0SMarek Vasut * freq kHz x
3367411cdf0SMarek Vasut * k = -------------------
3377411cdf0SMarek Vasut * 1000
3387411cdf0SMarek Vasut */
3397411cdf0SMarek Vasut
3407411cdf0SMarek Vasut fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
3417411cdf0SMarek Vasut
3427411cdf0SMarek Vasut for (x = 18; x <= 35; x++) {
3437411cdf0SMarek Vasut tk = fp / x;
3447411cdf0SMarek Vasut if ((tk / 1000 == 0) || (tk / 1000 > 255))
3457411cdf0SMarek Vasut continue;
3467411cdf0SMarek Vasut
3477411cdf0SMarek Vasut k_rest = tk % 1000;
3487411cdf0SMarek Vasut
3497411cdf0SMarek Vasut if (k_rest < (k_best_l % 1000)) {
3507411cdf0SMarek Vasut k_best_l = tk;
3517411cdf0SMarek Vasut x_best_l = x;
3527411cdf0SMarek Vasut }
3537411cdf0SMarek Vasut
3547411cdf0SMarek Vasut if (k_rest > (k_best_t % 1000)) {
3557411cdf0SMarek Vasut k_best_t = tk;
3567411cdf0SMarek Vasut x_best_t = x;
3577411cdf0SMarek Vasut }
3587411cdf0SMarek Vasut }
3597411cdf0SMarek Vasut
3607411cdf0SMarek Vasut if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
3617411cdf0SMarek Vasut k_best = k_best_l;
3627411cdf0SMarek Vasut x_best = x_best_l;
3637411cdf0SMarek Vasut } else {
3647411cdf0SMarek Vasut k_best = k_best_t;
3657411cdf0SMarek Vasut x_best = x_best_t;
3667411cdf0SMarek Vasut }
3677411cdf0SMarek Vasut
3687411cdf0SMarek Vasut k_best /= 1000;
3697411cdf0SMarek Vasut
3707411cdf0SMarek Vasut #if defined(CONFIG_MX23)
3717411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE,
3727411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
3737411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
3747411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
3757411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE,
3767411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
3777411cdf0SMarek Vasut
3787411cdf0SMarek Vasut writel(CLKCTRL_PIX_CLKGATE,
3797411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_pix_set);
3807411cdf0SMarek Vasut clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
3817411cdf0SMarek Vasut CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
3827411cdf0SMarek Vasut k_best << CLKCTRL_PIX_DIV_OFFSET);
3837411cdf0SMarek Vasut
3847411cdf0SMarek Vasut while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
3857411cdf0SMarek Vasut ;
3867411cdf0SMarek Vasut #elif defined(CONFIG_MX28)
3877411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE,
3887411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
3897411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
3907411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
3917411cdf0SMarek Vasut writeb(CLKCTRL_FRAC_CLKGATE,
3927411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
3937411cdf0SMarek Vasut
3947411cdf0SMarek Vasut writel(CLKCTRL_DIS_LCDIF_CLKGATE,
3957411cdf0SMarek Vasut &clkctrl_regs->hw_clkctrl_lcdif_set);
3967411cdf0SMarek Vasut clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
3977411cdf0SMarek Vasut CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
3987411cdf0SMarek Vasut k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
3997411cdf0SMarek Vasut
4007411cdf0SMarek Vasut while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
4017411cdf0SMarek Vasut ;
4027411cdf0SMarek Vasut #endif
4037411cdf0SMarek Vasut }
4047411cdf0SMarek Vasut
mxc_get_clock(enum mxc_clock clk)4053a0398d7SOtavio Salvador uint32_t mxc_get_clock(enum mxc_clock clk)
4063a0398d7SOtavio Salvador {
4073a0398d7SOtavio Salvador switch (clk) {
4083a0398d7SOtavio Salvador case MXC_ARM_CLK:
409bf48fcb6SOtavio Salvador return mxs_get_pclk() * 1000000;
4103a0398d7SOtavio Salvador case MXC_GPMI_CLK:
411bf48fcb6SOtavio Salvador return mxs_get_gpmiclk() * 1000000;
4123a0398d7SOtavio Salvador case MXC_AHB_CLK:
4133a0398d7SOtavio Salvador case MXC_IPG_CLK:
414bf48fcb6SOtavio Salvador return mxs_get_hclk() * 1000000;
4153a0398d7SOtavio Salvador case MXC_EMI_CLK:
416bf48fcb6SOtavio Salvador return mxs_get_emiclk();
4173a0398d7SOtavio Salvador case MXC_IO0_CLK:
418bf48fcb6SOtavio Salvador return mxs_get_ioclk(MXC_IOCLK0);
4193a0398d7SOtavio Salvador case MXC_IO1_CLK:
420bf48fcb6SOtavio Salvador return mxs_get_ioclk(MXC_IOCLK1);
42100239977SOtavio Salvador case MXC_XTAL_CLK:
42200239977SOtavio Salvador return XTAL_FREQ_KHZ * 1000;
4233a0398d7SOtavio Salvador case MXC_SSP0_CLK:
424bf48fcb6SOtavio Salvador return mxs_get_sspclk(MXC_SSPCLK0);
42500239977SOtavio Salvador #ifdef CONFIG_MX28
4263a0398d7SOtavio Salvador case MXC_SSP1_CLK:
427bf48fcb6SOtavio Salvador return mxs_get_sspclk(MXC_SSPCLK1);
4283a0398d7SOtavio Salvador case MXC_SSP2_CLK:
429bf48fcb6SOtavio Salvador return mxs_get_sspclk(MXC_SSPCLK2);
4303a0398d7SOtavio Salvador case MXC_SSP3_CLK:
431bf48fcb6SOtavio Salvador return mxs_get_sspclk(MXC_SSPCLK3);
43200239977SOtavio Salvador #endif
4333a0398d7SOtavio Salvador }
4343a0398d7SOtavio Salvador
4353a0398d7SOtavio Salvador return 0;
4363a0398d7SOtavio Salvador }
437