xref: /rk3399_rockchip-uboot/arch/arm/cpu/arm926ejs/mxs/clock.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
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