1 /* 2 * Freescale i.MX23/i.MX28 clock setup code 3 * 4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> 5 * on behalf of DENX Software Engineering GmbH 6 * 7 * Based on code from LTIB: 8 * Copyright (C) 2010 Freescale Semiconductor, Inc. 9 * 10 * See file CREDITS for list of people who contributed to this 11 * project. 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 26 * MA 02111-1307 USA 27 */ 28 29 #include <common.h> 30 #include <asm/errno.h> 31 #include <asm/io.h> 32 #include <asm/arch/clock.h> 33 #include <asm/arch/imx-regs.h> 34 35 /* 36 * The PLL frequency is 480MHz and XTAL frequency is 24MHz 37 * iMX23: datasheet section 4.2 38 * iMX28: datasheet section 10.2 39 */ 40 #define PLL_FREQ_KHZ 480000 41 #define PLL_FREQ_COEF 18 42 #define XTAL_FREQ_KHZ 24000 43 44 #define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000) 45 #define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000) 46 47 #if defined(CONFIG_MX23) 48 #define MXC_SSPCLK_MAX MXC_SSPCLK0 49 #elif defined(CONFIG_MX28) 50 #define MXC_SSPCLK_MAX MXC_SSPCLK3 51 #endif 52 53 static uint32_t mxs_get_pclk(void) 54 { 55 struct mxs_clkctrl_regs *clkctrl_regs = 56 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 57 58 uint32_t clkctrl, clkseq, div; 59 uint8_t clkfrac, frac; 60 61 clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu); 62 63 /* No support of fractional divider calculation */ 64 if (clkctrl & 65 (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) { 66 return 0; 67 } 68 69 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); 70 71 /* XTAL Path */ 72 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) { 73 div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >> 74 CLKCTRL_CPU_DIV_XTAL_OFFSET; 75 return XTAL_FREQ_MHZ / div; 76 } 77 78 /* REF Path */ 79 clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]); 80 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; 81 div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK; 82 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; 83 } 84 85 static uint32_t mxs_get_hclk(void) 86 { 87 struct mxs_clkctrl_regs *clkctrl_regs = 88 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 89 90 uint32_t div; 91 uint32_t clkctrl; 92 93 clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus); 94 95 /* No support of fractional divider calculation */ 96 if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN) 97 return 0; 98 99 div = clkctrl & CLKCTRL_HBUS_DIV_MASK; 100 return mxs_get_pclk() / div; 101 } 102 103 static uint32_t mxs_get_emiclk(void) 104 { 105 struct mxs_clkctrl_regs *clkctrl_regs = 106 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 107 108 uint32_t clkctrl, clkseq, div; 109 uint8_t clkfrac, frac; 110 111 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); 112 clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi); 113 114 /* XTAL Path */ 115 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) { 116 div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >> 117 CLKCTRL_EMI_DIV_XTAL_OFFSET; 118 return XTAL_FREQ_MHZ / div; 119 } 120 121 /* REF Path */ 122 clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]); 123 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; 124 div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK; 125 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; 126 } 127 128 static uint32_t mxs_get_gpmiclk(void) 129 { 130 struct mxs_clkctrl_regs *clkctrl_regs = 131 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 132 #if defined(CONFIG_MX23) 133 uint8_t *reg = 134 &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]; 135 #elif defined(CONFIG_MX28) 136 uint8_t *reg = 137 &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]; 138 #endif 139 uint32_t clkctrl, clkseq, div; 140 uint8_t clkfrac, frac; 141 142 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); 143 clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi); 144 145 /* XTAL Path */ 146 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) { 147 div = clkctrl & CLKCTRL_GPMI_DIV_MASK; 148 return XTAL_FREQ_MHZ / div; 149 } 150 151 /* REF Path */ 152 clkfrac = readb(reg); 153 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; 154 div = clkctrl & CLKCTRL_GPMI_DIV_MASK; 155 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; 156 } 157 158 /* 159 * Set IO clock frequency, in kHz 160 */ 161 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq) 162 { 163 struct mxs_clkctrl_regs *clkctrl_regs = 164 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 165 uint32_t div; 166 int io_reg; 167 168 if (freq == 0) 169 return; 170 171 if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) 172 return; 173 174 div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq; 175 176 if (div < 18) 177 div = 18; 178 179 if (div > 35) 180 div = 35; 181 182 io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ 183 writeb(CLKCTRL_FRAC_CLKGATE, 184 &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]); 185 writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK), 186 &clkctrl_regs->hw_clkctrl_frac0[io_reg]); 187 writeb(CLKCTRL_FRAC_CLKGATE, 188 &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]); 189 } 190 191 /* 192 * Get IO clock, returns IO clock in kHz 193 */ 194 static uint32_t mxs_get_ioclk(enum mxs_ioclock io) 195 { 196 struct mxs_clkctrl_regs *clkctrl_regs = 197 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 198 uint8_t ret; 199 int io_reg; 200 201 if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) 202 return 0; 203 204 io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ 205 206 ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) & 207 CLKCTRL_FRAC_FRAC_MASK; 208 209 return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret; 210 } 211 212 /* 213 * Configure SSP clock frequency, in kHz 214 */ 215 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) 216 { 217 struct mxs_clkctrl_regs *clkctrl_regs = 218 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 219 uint32_t clk, clkreg; 220 221 if (ssp > MXC_SSPCLK_MAX) 222 return; 223 224 clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + 225 (ssp * sizeof(struct mxs_register_32)); 226 227 clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE); 228 while (readl(clkreg) & CLKCTRL_SSP_CLKGATE) 229 ; 230 231 if (xtal) 232 clk = XTAL_FREQ_KHZ; 233 else 234 clk = mxs_get_ioclk(ssp >> 1); 235 236 if (freq > clk) 237 return; 238 239 /* Calculate the divider and cap it if necessary */ 240 clk /= freq; 241 if (clk > CLKCTRL_SSP_DIV_MASK) 242 clk = CLKCTRL_SSP_DIV_MASK; 243 244 clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk); 245 while (readl(clkreg) & CLKCTRL_SSP_BUSY) 246 ; 247 248 if (xtal) 249 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, 250 &clkctrl_regs->hw_clkctrl_clkseq_set); 251 else 252 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, 253 &clkctrl_regs->hw_clkctrl_clkseq_clr); 254 } 255 256 /* 257 * Return SSP frequency, in kHz 258 */ 259 static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp) 260 { 261 struct mxs_clkctrl_regs *clkctrl_regs = 262 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; 263 uint32_t clkreg; 264 uint32_t clk, tmp; 265 266 if (ssp > MXC_SSPCLK_MAX) 267 return 0; 268 269 tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq); 270 if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp)) 271 return XTAL_FREQ_KHZ; 272 273 clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + 274 (ssp * sizeof(struct mxs_register_32)); 275 276 tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK; 277 278 if (tmp == 0) 279 return 0; 280 281 clk = mxs_get_ioclk(ssp >> 1); 282 283 return clk / tmp; 284 } 285 286 /* 287 * Set SSP/MMC bus frequency, in kHz) 288 */ 289 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq) 290 { 291 struct mxs_ssp_regs *ssp_regs; 292 const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus); 293 const uint32_t sspclk = mxs_get_sspclk(clk); 294 uint32_t reg; 295 uint32_t divide, rate, tgtclk; 296 297 ssp_regs = mxs_ssp_regs_by_bus(bus); 298 299 /* 300 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), 301 * CLOCK_DIVIDE has to be an even value from 2 to 254, and 302 * CLOCK_RATE could be any integer from 0 to 255. 303 */ 304 for (divide = 2; divide < 254; divide += 2) { 305 rate = sspclk / freq / divide; 306 if (rate <= 256) 307 break; 308 } 309 310 tgtclk = sspclk / divide / rate; 311 while (tgtclk > freq) { 312 rate++; 313 tgtclk = sspclk / divide / rate; 314 } 315 if (rate > 256) 316 rate = 256; 317 318 /* Always set timeout the maximum */ 319 reg = SSP_TIMING_TIMEOUT_MASK | 320 (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) | 321 ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET); 322 writel(reg, &ssp_regs->hw_ssp_timing); 323 324 debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n", 325 bus, tgtclk, freq); 326 } 327 328 uint32_t mxc_get_clock(enum mxc_clock clk) 329 { 330 switch (clk) { 331 case MXC_ARM_CLK: 332 return mxs_get_pclk() * 1000000; 333 case MXC_GPMI_CLK: 334 return mxs_get_gpmiclk() * 1000000; 335 case MXC_AHB_CLK: 336 case MXC_IPG_CLK: 337 return mxs_get_hclk() * 1000000; 338 case MXC_EMI_CLK: 339 return mxs_get_emiclk(); 340 case MXC_IO0_CLK: 341 return mxs_get_ioclk(MXC_IOCLK0); 342 case MXC_IO1_CLK: 343 return mxs_get_ioclk(MXC_IOCLK1); 344 case MXC_XTAL_CLK: 345 return XTAL_FREQ_KHZ * 1000; 346 case MXC_SSP0_CLK: 347 return mxs_get_sspclk(MXC_SSPCLK0); 348 #ifdef CONFIG_MX28 349 case MXC_SSP1_CLK: 350 return mxs_get_sspclk(MXC_SSPCLK1); 351 case MXC_SSP2_CLK: 352 return mxs_get_sspclk(MXC_SSPCLK2); 353 case MXC_SSP3_CLK: 354 return mxs_get_sspclk(MXC_SSPCLK3); 355 #endif 356 } 357 358 return 0; 359 } 360