clock.c 8.3 KB

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