clock.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 mx28_get_pclk(void)
  41. {
  42. struct mx28_clkctrl_regs *clkctrl_regs =
  43. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  44. uint32_t clkctrl, clkseq, clkfrac;
  45. uint32_t frac, div;
  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 = readl(&clkctrl_regs->hw_clkctrl_frac0);
  61. frac = clkfrac & CLKCTRL_FRAC0_CPUFRAC_MASK;
  62. div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
  63. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  64. }
  65. static uint32_t mx28_get_hclk(void)
  66. {
  67. struct mx28_clkctrl_regs *clkctrl_regs =
  68. (struct mx28_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 mx28_get_pclk() / div;
  77. }
  78. static uint32_t mx28_get_emiclk(void)
  79. {
  80. struct mx28_clkctrl_regs *clkctrl_regs =
  81. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  82. uint32_t frac, div;
  83. uint32_t clkctrl, clkseq, clkfrac;
  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. clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac0);
  93. /* REF Path */
  94. frac = (clkfrac & CLKCTRL_FRAC0_EMIFRAC_MASK) >>
  95. CLKCTRL_FRAC0_EMIFRAC_OFFSET;
  96. div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
  97. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  98. }
  99. static uint32_t mx28_get_gpmiclk(void)
  100. {
  101. struct mx28_clkctrl_regs *clkctrl_regs =
  102. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  103. uint32_t frac, div;
  104. uint32_t clkctrl, clkseq, clkfrac;
  105. clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  106. clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
  107. /* XTAL Path */
  108. if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
  109. div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
  110. return XTAL_FREQ_MHZ / div;
  111. }
  112. clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac1);
  113. /* REF Path */
  114. frac = (clkfrac & CLKCTRL_FRAC1_GPMIFRAC_MASK) >>
  115. CLKCTRL_FRAC1_GPMIFRAC_OFFSET;
  116. div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
  117. return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
  118. }
  119. /*
  120. * Set IO clock frequency, in kHz
  121. */
  122. void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq)
  123. {
  124. struct mx28_clkctrl_regs *clkctrl_regs =
  125. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  126. uint32_t div;
  127. if (freq == 0)
  128. return;
  129. if (io > MXC_IOCLK1)
  130. return;
  131. div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
  132. if (div < 18)
  133. div = 18;
  134. if (div > 35)
  135. div = 35;
  136. if (io == MXC_IOCLK0) {
  137. writel(CLKCTRL_FRAC0_CLKGATEIO0,
  138. &clkctrl_regs->hw_clkctrl_frac0_set);
  139. clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
  140. CLKCTRL_FRAC0_IO0FRAC_MASK,
  141. div << CLKCTRL_FRAC0_IO0FRAC_OFFSET);
  142. writel(CLKCTRL_FRAC0_CLKGATEIO0,
  143. &clkctrl_regs->hw_clkctrl_frac0_clr);
  144. } else {
  145. writel(CLKCTRL_FRAC0_CLKGATEIO1,
  146. &clkctrl_regs->hw_clkctrl_frac0_set);
  147. clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
  148. CLKCTRL_FRAC0_IO1FRAC_MASK,
  149. div << CLKCTRL_FRAC0_IO1FRAC_OFFSET);
  150. writel(CLKCTRL_FRAC0_CLKGATEIO1,
  151. &clkctrl_regs->hw_clkctrl_frac0_clr);
  152. }
  153. }
  154. /*
  155. * Get IO clock, returns IO clock in kHz
  156. */
  157. static uint32_t mx28_get_ioclk(enum mxs_ioclock io)
  158. {
  159. struct mx28_clkctrl_regs *clkctrl_regs =
  160. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  161. uint32_t tmp, ret;
  162. if (io > MXC_IOCLK1)
  163. return 0;
  164. tmp = readl(&clkctrl_regs->hw_clkctrl_frac0);
  165. if (io == MXC_IOCLK0)
  166. ret = (tmp & CLKCTRL_FRAC0_IO0FRAC_MASK) >>
  167. CLKCTRL_FRAC0_IO0FRAC_OFFSET;
  168. else
  169. ret = (tmp & CLKCTRL_FRAC0_IO1FRAC_MASK) >>
  170. CLKCTRL_FRAC0_IO1FRAC_OFFSET;
  171. return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
  172. }
  173. /*
  174. * Configure SSP clock frequency, in kHz
  175. */
  176. void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
  177. {
  178. struct mx28_clkctrl_regs *clkctrl_regs =
  179. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  180. uint32_t clk, clkreg;
  181. if (ssp > MXC_SSPCLK3)
  182. return;
  183. clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
  184. (ssp * sizeof(struct mx28_register_32));
  185. clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
  186. while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
  187. ;
  188. if (xtal)
  189. clk = XTAL_FREQ_KHZ;
  190. else
  191. clk = mx28_get_ioclk(ssp >> 1);
  192. if (freq > clk)
  193. return;
  194. /* Calculate the divider and cap it if necessary */
  195. clk /= freq;
  196. if (clk > CLKCTRL_SSP_DIV_MASK)
  197. clk = CLKCTRL_SSP_DIV_MASK;
  198. clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
  199. while (readl(clkreg) & CLKCTRL_SSP_BUSY)
  200. ;
  201. if (xtal)
  202. writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
  203. &clkctrl_regs->hw_clkctrl_clkseq_set);
  204. else
  205. writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
  206. &clkctrl_regs->hw_clkctrl_clkseq_clr);
  207. }
  208. /*
  209. * Return SSP frequency, in kHz
  210. */
  211. static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp)
  212. {
  213. struct mx28_clkctrl_regs *clkctrl_regs =
  214. (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
  215. uint32_t clkreg;
  216. uint32_t clk, tmp;
  217. if (ssp > MXC_SSPCLK3)
  218. return 0;
  219. tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
  220. if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
  221. return XTAL_FREQ_KHZ;
  222. clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
  223. (ssp * sizeof(struct mx28_register_32));
  224. tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
  225. if (tmp == 0)
  226. return 0;
  227. clk = mx28_get_ioclk(ssp >> 1);
  228. return clk / tmp;
  229. }
  230. /*
  231. * Set SSP/MMC bus frequency, in kHz)
  232. */
  233. void mx28_set_ssp_busclock(unsigned int bus, uint32_t freq)
  234. {
  235. struct mx28_ssp_regs *ssp_regs;
  236. const uint32_t sspclk = mx28_get_sspclk(bus);
  237. uint32_t reg;
  238. uint32_t divide, rate, tgtclk;
  239. ssp_regs = (struct mx28_ssp_regs *)(MXS_SSP0_BASE + (bus * 0x2000));
  240. /*
  241. * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
  242. * CLOCK_DIVIDE has to be an even value from 2 to 254, and
  243. * CLOCK_RATE could be any integer from 0 to 255.
  244. */
  245. for (divide = 2; divide < 254; divide += 2) {
  246. rate = sspclk / freq / divide;
  247. if (rate <= 256)
  248. break;
  249. }
  250. tgtclk = sspclk / divide / rate;
  251. while (tgtclk > freq) {
  252. rate++;
  253. tgtclk = sspclk / divide / rate;
  254. }
  255. if (rate > 256)
  256. rate = 256;
  257. /* Always set timeout the maximum */
  258. reg = SSP_TIMING_TIMEOUT_MASK |
  259. (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
  260. ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
  261. writel(reg, &ssp_regs->hw_ssp_timing);
  262. debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
  263. bus, tgtclk, freq);
  264. }
  265. uint32_t mxc_get_clock(enum mxc_clock clk)
  266. {
  267. switch (clk) {
  268. case MXC_ARM_CLK:
  269. return mx28_get_pclk() * 1000000;
  270. case MXC_GPMI_CLK:
  271. return mx28_get_gpmiclk() * 1000000;
  272. case MXC_AHB_CLK:
  273. case MXC_IPG_CLK:
  274. return mx28_get_hclk() * 1000000;
  275. case MXC_EMI_CLK:
  276. return mx28_get_emiclk();
  277. case MXC_IO0_CLK:
  278. return mx28_get_ioclk(MXC_IOCLK0);
  279. case MXC_IO1_CLK:
  280. return mx28_get_ioclk(MXC_IOCLK1);
  281. case MXC_SSP0_CLK:
  282. return mx28_get_sspclk(MXC_SSPCLK0);
  283. case MXC_SSP1_CLK:
  284. return mx28_get_sspclk(MXC_SSPCLK1);
  285. case MXC_SSP2_CLK:
  286. return mx28_get_sspclk(MXC_SSPCLK2);
  287. case MXC_SSP3_CLK:
  288. return mx28_get_sspclk(MXC_SSPCLK3);
  289. }
  290. return 0;
  291. }