Home | History | Annotate | Download | only in mxs
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Freescale i.MX23/i.MX28 clock setup code
      4  *
      5  * Copyright (C) 2011 Marek Vasut <marek.vasut (at) gmail.com>
      6  * on behalf of DENX Software Engineering GmbH
      7  *
      8  * Based on code from LTIB:
      9  * Copyright (C) 2010 Freescale Semiconductor, Inc.
     10  */
     11 
     12 #include <common.h>
     13 #include <linux/errno.h>
     14 #include <asm/io.h>
     15 #include <asm/arch/clock.h>
     16 #include <asm/arch/imx-regs.h>
     17 
     18 /*
     19  * The PLL frequency is 480MHz and XTAL frequency is 24MHz
     20  *   iMX23: datasheet section 4.2
     21  *   iMX28: datasheet section 10.2
     22  */
     23 #define	PLL_FREQ_KHZ	480000
     24 #define	PLL_FREQ_COEF	18
     25 #define	XTAL_FREQ_KHZ	24000
     26 
     27 #define	PLL_FREQ_MHZ	(PLL_FREQ_KHZ / 1000)
     28 #define	XTAL_FREQ_MHZ	(XTAL_FREQ_KHZ / 1000)
     29 
     30 #if defined(CONFIG_MX23)
     31 #define MXC_SSPCLK_MAX MXC_SSPCLK0
     32 #elif defined(CONFIG_MX28)
     33 #define MXC_SSPCLK_MAX MXC_SSPCLK3
     34 #endif
     35 
     36 static uint32_t mxs_get_pclk(void)
     37 {
     38 	struct mxs_clkctrl_regs *clkctrl_regs =
     39 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
     40 
     41 	uint32_t clkctrl, clkseq, div;
     42 	uint8_t clkfrac, frac;
     43 
     44 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
     45 
     46 	/* No support of fractional divider calculation */
     47 	if (clkctrl &
     48 		(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
     49 		return 0;
     50 	}
     51 
     52 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
     53 
     54 	/* XTAL Path */
     55 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
     56 		div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
     57 			CLKCTRL_CPU_DIV_XTAL_OFFSET;
     58 		return XTAL_FREQ_MHZ / div;
     59 	}
     60 
     61 	/* REF Path */
     62 	clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
     63 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
     64 	div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
     65 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
     66 }
     67 
     68 static uint32_t mxs_get_hclk(void)
     69 {
     70 	struct mxs_clkctrl_regs *clkctrl_regs =
     71 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
     72 
     73 	uint32_t div;
     74 	uint32_t clkctrl;
     75 
     76 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
     77 
     78 	/* No support of fractional divider calculation */
     79 	if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
     80 		return 0;
     81 
     82 	div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
     83 	return mxs_get_pclk() / div;
     84 }
     85 
     86 static uint32_t mxs_get_emiclk(void)
     87 {
     88 	struct mxs_clkctrl_regs *clkctrl_regs =
     89 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
     90 
     91 	uint32_t clkctrl, clkseq, div;
     92 	uint8_t clkfrac, frac;
     93 
     94 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
     95 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
     96 
     97 	/* XTAL Path */
     98 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
     99 		div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
    100 			CLKCTRL_EMI_DIV_XTAL_OFFSET;
    101 		return XTAL_FREQ_MHZ / div;
    102 	}
    103 
    104 	/* REF Path */
    105 	clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
    106 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
    107 	div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
    108 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
    109 }
    110 
    111 static uint32_t mxs_get_gpmiclk(void)
    112 {
    113 	struct mxs_clkctrl_regs *clkctrl_regs =
    114 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    115 #if defined(CONFIG_MX23)
    116 	uint8_t *reg =
    117 		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
    118 #elif defined(CONFIG_MX28)
    119 	uint8_t *reg =
    120 		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
    121 #endif
    122 	uint32_t clkctrl, clkseq, div;
    123 	uint8_t clkfrac, frac;
    124 
    125 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
    126 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
    127 
    128 	/* XTAL Path */
    129 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
    130 		div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
    131 		return XTAL_FREQ_MHZ / div;
    132 	}
    133 
    134 	/* REF Path */
    135 	clkfrac = readb(reg);
    136 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
    137 	div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
    138 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
    139 }
    140 
    141 /*
    142  * Set IO clock frequency, in kHz
    143  */
    144 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
    145 {
    146 	struct mxs_clkctrl_regs *clkctrl_regs =
    147 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    148 	uint32_t div;
    149 	int io_reg;
    150 
    151 	if (freq == 0)
    152 		return;
    153 
    154 	if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
    155 		return;
    156 
    157 	div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
    158 
    159 	if (div < 18)
    160 		div = 18;
    161 
    162 	if (div > 35)
    163 		div = 35;
    164 
    165 	io_reg = CLKCTRL_FRAC0_IO0 - io;	/* Register order is reversed */
    166 	writeb(CLKCTRL_FRAC_CLKGATE,
    167 		&clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
    168 	writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
    169 		&clkctrl_regs->hw_clkctrl_frac0[io_reg]);
    170 	writeb(CLKCTRL_FRAC_CLKGATE,
    171 		&clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
    172 }
    173 
    174 /*
    175  * Get IO clock, returns IO clock in kHz
    176  */
    177 static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
    178 {
    179 	struct mxs_clkctrl_regs *clkctrl_regs =
    180 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    181 	uint8_t ret;
    182 	int io_reg;
    183 
    184 	if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
    185 		return 0;
    186 
    187 	io_reg = CLKCTRL_FRAC0_IO0 - io;	/* Register order is reversed */
    188 
    189 	ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
    190 		CLKCTRL_FRAC_FRAC_MASK;
    191 
    192 	return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
    193 }
    194 
    195 /*
    196  * Configure SSP clock frequency, in kHz
    197  */
    198 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
    199 {
    200 	struct mxs_clkctrl_regs *clkctrl_regs =
    201 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    202 	uint32_t clk, clkreg;
    203 
    204 	if (ssp > MXC_SSPCLK_MAX)
    205 		return;
    206 
    207 	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
    208 			(ssp * sizeof(struct mxs_register_32));
    209 
    210 	clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
    211 	while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
    212 		;
    213 
    214 	if (xtal)
    215 		clk = XTAL_FREQ_KHZ;
    216 	else
    217 		clk = mxs_get_ioclk(ssp >> 1);
    218 
    219 	if (freq > clk)
    220 		return;
    221 
    222 	/* Calculate the divider and cap it if necessary */
    223 	clk /= freq;
    224 	if (clk > CLKCTRL_SSP_DIV_MASK)
    225 		clk = CLKCTRL_SSP_DIV_MASK;
    226 
    227 	clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
    228 	while (readl(clkreg) & CLKCTRL_SSP_BUSY)
    229 		;
    230 
    231 	if (xtal)
    232 		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
    233 			&clkctrl_regs->hw_clkctrl_clkseq_set);
    234 	else
    235 		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
    236 			&clkctrl_regs->hw_clkctrl_clkseq_clr);
    237 }
    238 
    239 /*
    240  * Return SSP frequency, in kHz
    241  */
    242 static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
    243 {
    244 	struct mxs_clkctrl_regs *clkctrl_regs =
    245 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    246 	uint32_t clkreg;
    247 	uint32_t clk, tmp;
    248 
    249 	if (ssp > MXC_SSPCLK_MAX)
    250 		return 0;
    251 
    252 	tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
    253 	if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
    254 		return XTAL_FREQ_KHZ;
    255 
    256 	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
    257 			(ssp * sizeof(struct mxs_register_32));
    258 
    259 	tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
    260 
    261 	if (tmp == 0)
    262 		return 0;
    263 
    264 	clk = mxs_get_ioclk(ssp >> 1);
    265 
    266 	return clk / tmp;
    267 }
    268 
    269 /*
    270  * Set SSP/MMC bus frequency, in kHz)
    271  */
    272 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
    273 {
    274 	struct mxs_ssp_regs *ssp_regs;
    275 	const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
    276 	const uint32_t sspclk = mxs_get_sspclk(clk);
    277 	uint32_t reg;
    278 	uint32_t divide, rate, tgtclk;
    279 
    280 	ssp_regs = mxs_ssp_regs_by_bus(bus);
    281 
    282 	/*
    283 	 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
    284 	 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
    285 	 * CLOCK_RATE could be any integer from 0 to 255.
    286 	 */
    287 	for (divide = 2; divide < 254; divide += 2) {
    288 		rate = sspclk / freq / divide;
    289 		if (rate <= 256)
    290 			break;
    291 	}
    292 
    293 	tgtclk = sspclk / divide / rate;
    294 	while (tgtclk > freq) {
    295 		rate++;
    296 		tgtclk = sspclk / divide / rate;
    297 	}
    298 	if (rate > 256)
    299 		rate = 256;
    300 
    301 	/* Always set timeout the maximum */
    302 	reg = SSP_TIMING_TIMEOUT_MASK |
    303 		(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
    304 		((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
    305 	writel(reg, &ssp_regs->hw_ssp_timing);
    306 
    307 	debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
    308 		bus, tgtclk, freq);
    309 }
    310 
    311 void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq)
    312 {
    313 	struct mxs_clkctrl_regs *clkctrl_regs =
    314 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
    315 	uint32_t fp, x, k_rest, k_best, x_best, tk;
    316 	int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
    317 
    318 	if (freq == 0)
    319 		return;
    320 
    321 #if defined(CONFIG_MX23)
    322 	writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
    323 #elif defined(CONFIG_MX28)
    324 	writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
    325 #endif
    326 
    327 	/*
    328 	 *             /               18 \     1       1
    329 	 * freq kHz = | 480000000 Hz * --  | * --- * ------
    330 	 *             \                x /     k     1000
    331 	 *
    332 	 *      480000000 Hz   18
    333 	 *      ------------ * --
    334 	 *        freq kHz      x
    335 	 * k = -------------------
    336 	 *             1000
    337 	 */
    338 
    339 	fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
    340 
    341 	for (x = 18; x <= 35; x++) {
    342 		tk = fp / x;
    343 		if ((tk / 1000 == 0) || (tk / 1000 > 255))
    344 			continue;
    345 
    346 		k_rest = tk % 1000;
    347 
    348 		if (k_rest < (k_best_l % 1000)) {
    349 			k_best_l = tk;
    350 			x_best_l = x;
    351 		}
    352 
    353 		if (k_rest > (k_best_t % 1000)) {
    354 			k_best_t = tk;
    355 			x_best_t = x;
    356 		}
    357 	}
    358 
    359 	if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
    360 		k_best = k_best_l;
    361 		x_best = x_best_l;
    362 	} else {
    363 		k_best = k_best_t;
    364 		x_best = x_best_t;
    365 	}
    366 
    367 	k_best /= 1000;
    368 
    369 #if defined(CONFIG_MX23)
    370 	writeb(CLKCTRL_FRAC_CLKGATE,
    371 		&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
    372 	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
    373 		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
    374 	writeb(CLKCTRL_FRAC_CLKGATE,
    375 		&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
    376 
    377 	writel(CLKCTRL_PIX_CLKGATE,
    378 		&clkctrl_regs->hw_clkctrl_pix_set);
    379 	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
    380 			CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
    381 			k_best << CLKCTRL_PIX_DIV_OFFSET);
    382 
    383 	while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
    384 		;
    385 #elif defined(CONFIG_MX28)
    386 	writeb(CLKCTRL_FRAC_CLKGATE,
    387 		&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
    388 	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
    389 		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
    390 	writeb(CLKCTRL_FRAC_CLKGATE,
    391 		&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
    392 
    393 	writel(CLKCTRL_DIS_LCDIF_CLKGATE,
    394 		&clkctrl_regs->hw_clkctrl_lcdif_set);
    395 	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
    396 			CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
    397 			k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
    398 
    399 	while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
    400 		;
    401 #endif
    402 }
    403 
    404 uint32_t mxc_get_clock(enum mxc_clock clk)
    405 {
    406 	switch (clk) {
    407 	case MXC_ARM_CLK:
    408 		return mxs_get_pclk() * 1000000;
    409 	case MXC_GPMI_CLK:
    410 		return mxs_get_gpmiclk() * 1000000;
    411 	case MXC_AHB_CLK:
    412 	case MXC_IPG_CLK:
    413 		return mxs_get_hclk() * 1000000;
    414 	case MXC_EMI_CLK:
    415 		return mxs_get_emiclk();
    416 	case MXC_IO0_CLK:
    417 		return mxs_get_ioclk(MXC_IOCLK0);
    418 	case MXC_IO1_CLK:
    419 		return mxs_get_ioclk(MXC_IOCLK1);
    420 	case MXC_XTAL_CLK:
    421 		return XTAL_FREQ_KHZ * 1000;
    422 	case MXC_SSP0_CLK:
    423 		return mxs_get_sspclk(MXC_SSPCLK0);
    424 #ifdef CONFIG_MX28
    425 	case MXC_SSP1_CLK:
    426 		return mxs_get_sspclk(MXC_SSPCLK1);
    427 	case MXC_SSP2_CLK:
    428 		return mxs_get_sspclk(MXC_SSPCLK2);
    429 	case MXC_SSP3_CLK:
    430 		return mxs_get_sspclk(MXC_SSPCLK3);
    431 #endif
    432 	}
    433 
    434 	return 0;
    435 }
    436