clock.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. #include <common.h>
  29. #include <asm/errno.h>
  30. #include <asm/io.h>
  31. #include <asm/arch/clock.h>
  32. #include <asm/arch/imx-regs.h>
  33. /*
  34. * The PLL frequency is 480MHz and XTAL frequency is 24MHz
  35. * iMX23: datasheet section 4.2
  36. * iMX28: datasheet section 10.2
  37. */
  38. #define PLL_FREQ_KHZ 480000
  39. #define PLL_FREQ_COEF 18
  40. #define XTAL_FREQ_KHZ 24000
  41. #define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
  42. #define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
  43. #if defined(CONFIG_MX23)
  44. #define MXC_SSPCLK_MAX MXC_SSPCLK0
  45. #elif defined(CONFIG_MX28)
  46. #define MXC_SSPCLK_MAX MXC_SSPCLK3
  47. #endif
  48. static uint32_t mxs_get_pclk(void)
  49. {
  50. struct mxs_clkctrl_regs *clkctrl_regs =
  51. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  52. uint32_t clkctrl, clkseq, div;
  53. uint8_t clkfrac, frac;
  54. clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
  55. /* No support of fractional divider calculation */
  56. if (clkctrl &
  57. (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
  58. return 0;
  59. }
  60. clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  61. /* XTAL Path */
  62. if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
  63. div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
  64. CLKCTRL_CPU_DIV_XTAL_OFFSET;
  65. return XTAL_FREQ_MHZ / div;
  66. }
  67. /* REF Path */
  68. clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
  69. frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
  70. div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
  71. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  72. }
  73. static uint32_t mxs_get_hclk(void)
  74. {
  75. struct mxs_clkctrl_regs *clkctrl_regs =
  76. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  77. uint32_t div;
  78. uint32_t clkctrl;
  79. clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
  80. /* No support of fractional divider calculation */
  81. if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
  82. return 0;
  83. div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
  84. return mxs_get_pclk() / div;
  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. uint32_t clkctrl, clkseq, div;
  91. uint8_t clkfrac, frac;
  92. clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  93. clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
  94. /* XTAL Path */
  95. if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
  96. div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
  97. CLKCTRL_EMI_DIV_XTAL_OFFSET;
  98. return XTAL_FREQ_MHZ / div;
  99. }
  100. /* REF Path */
  101. clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
  102. frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
  103. div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
  104. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  105. }
  106. static uint32_t mxs_get_gpmiclk(void)
  107. {
  108. struct mxs_clkctrl_regs *clkctrl_regs =
  109. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  110. #if defined(CONFIG_MX23)
  111. uint8_t *reg =
  112. &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
  113. #elif defined(CONFIG_MX28)
  114. uint8_t *reg =
  115. &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
  116. #endif
  117. uint32_t clkctrl, clkseq, div;
  118. uint8_t clkfrac, frac;
  119. clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  120. clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
  121. /* XTAL Path */
  122. if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
  123. div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
  124. return XTAL_FREQ_MHZ / div;
  125. }
  126. /* REF Path */
  127. clkfrac = readb(reg);
  128. frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
  129. div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
  130. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  131. }
  132. /*
  133. * Set IO clock frequency, in kHz
  134. */
  135. void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
  136. {
  137. struct mxs_clkctrl_regs *clkctrl_regs =
  138. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  139. uint32_t div;
  140. int io_reg;
  141. if (freq == 0)
  142. return;
  143. if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
  144. return;
  145. div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
  146. if (div < 18)
  147. div = 18;
  148. if (div > 35)
  149. div = 35;
  150. io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
  151. writeb(CLKCTRL_FRAC_CLKGATE,
  152. &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
  153. writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
  154. &clkctrl_regs->hw_clkctrl_frac0[io_reg]);
  155. writeb(CLKCTRL_FRAC_CLKGATE,
  156. &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
  157. }
  158. /*
  159. * Get IO clock, returns IO clock in kHz
  160. */
  161. static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
  162. {
  163. struct mxs_clkctrl_regs *clkctrl_regs =
  164. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  165. uint8_t ret;
  166. int io_reg;
  167. if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
  168. return 0;
  169. io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
  170. ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
  171. CLKCTRL_FRAC_FRAC_MASK;
  172. return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
  173. }
  174. /*
  175. * Configure SSP clock frequency, in kHz
  176. */
  177. void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
  178. {
  179. struct mxs_clkctrl_regs *clkctrl_regs =
  180. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  181. uint32_t clk, clkreg;
  182. if (ssp > MXC_SSPCLK_MAX)
  183. return;
  184. clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
  185. (ssp * sizeof(struct mxs_register_32));
  186. clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
  187. while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
  188. ;
  189. if (xtal)
  190. clk = XTAL_FREQ_KHZ;
  191. else
  192. clk = mxs_get_ioclk(ssp >> 1);
  193. if (freq > clk)
  194. return;
  195. /* Calculate the divider and cap it if necessary */
  196. clk /= freq;
  197. if (clk > CLKCTRL_SSP_DIV_MASK)
  198. clk = CLKCTRL_SSP_DIV_MASK;
  199. clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
  200. while (readl(clkreg) & CLKCTRL_SSP_BUSY)
  201. ;
  202. if (xtal)
  203. writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
  204. &clkctrl_regs->hw_clkctrl_clkseq_set);
  205. else
  206. writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
  207. &clkctrl_regs->hw_clkctrl_clkseq_clr);
  208. }
  209. /*
  210. * Return SSP frequency, in kHz
  211. */
  212. static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
  213. {
  214. struct mxs_clkctrl_regs *clkctrl_regs =
  215. (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  216. uint32_t clkreg;
  217. uint32_t clk, tmp;
  218. if (ssp > MXC_SSPCLK_MAX)
  219. return 0;
  220. tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  221. if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
  222. return XTAL_FREQ_KHZ;
  223. clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
  224. (ssp * sizeof(struct mxs_register_32));
  225. tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
  226. if (tmp == 0)
  227. return 0;
  228. clk = mxs_get_ioclk(ssp >> 1);
  229. return clk / tmp;
  230. }
  231. /*
  232. * Set SSP/MMC bus frequency, in kHz)
  233. */
  234. void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
  235. {
  236. struct mxs_ssp_regs *ssp_regs;
  237. const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
  238. const uint32_t sspclk = mxs_get_sspclk(clk);
  239. uint32_t reg;
  240. uint32_t divide, rate, tgtclk;
  241. ssp_regs = mxs_ssp_regs_by_bus(bus);
  242. /*
  243. * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
  244. * CLOCK_DIVIDE has to be an even value from 2 to 254, and
  245. * CLOCK_RATE could be any integer from 0 to 255.
  246. */
  247. for (divide = 2; divide < 254; divide += 2) {
  248. rate = sspclk / freq / divide;
  249. if (rate <= 256)
  250. break;
  251. }
  252. tgtclk = sspclk / divide / rate;
  253. while (tgtclk > freq) {
  254. rate++;
  255. tgtclk = sspclk / divide / rate;
  256. }
  257. if (rate > 256)
  258. rate = 256;
  259. /* Always set timeout the maximum */
  260. reg = SSP_TIMING_TIMEOUT_MASK |
  261. (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
  262. ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
  263. writel(reg, &ssp_regs->hw_ssp_timing);
  264. debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
  265. bus, tgtclk, freq);
  266. }
  267. uint32_t mxc_get_clock(enum mxc_clock clk)
  268. {
  269. switch (clk) {
  270. case MXC_ARM_CLK:
  271. return mxs_get_pclk() * 1000000;
  272. case MXC_GPMI_CLK:
  273. return mxs_get_gpmiclk() * 1000000;
  274. case MXC_AHB_CLK:
  275. case MXC_IPG_CLK:
  276. return mxs_get_hclk() * 1000000;
  277. case MXC_EMI_CLK:
  278. return mxs_get_emiclk();
  279. case MXC_IO0_CLK:
  280. return mxs_get_ioclk(MXC_IOCLK0);
  281. case MXC_IO1_CLK:
  282. return mxs_get_ioclk(MXC_IOCLK1);
  283. case MXC_XTAL_CLK:
  284. return XTAL_FREQ_KHZ * 1000;
  285. case MXC_SSP0_CLK:
  286. return mxs_get_sspclk(MXC_SSPCLK0);
  287. #ifdef CONFIG_MX28
  288. case MXC_SSP1_CLK:
  289. return mxs_get_sspclk(MXC_SSPCLK1);
  290. case MXC_SSP2_CLK:
  291. return mxs_get_sspclk(MXC_SSPCLK2);
  292. case MXC_SSP3_CLK:
  293. return mxs_get_sspclk(MXC_SSPCLK3);
  294. #endif
  295. }
  296. return 0;
  297. }