clk_pic32.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
  4. *
  5. */
  6. #include <common.h>
  7. #include <clk-uclass.h>
  8. #include <dm.h>
  9. #include <div64.h>
  10. #include <time.h>
  11. #include <wait_bit.h>
  12. #include <dm/lists.h>
  13. #include <asm/io.h>
  14. #include <mach/pic32.h>
  15. #include <dt-bindings/clock/microchip,clock.h>
  16. DECLARE_GLOBAL_DATA_PTR;
  17. /* Primary oscillator */
  18. #define SYS_POSC_CLK_HZ 24000000
  19. /* FRC clk rate */
  20. #define SYS_FRC_CLK_HZ 8000000
  21. /* Clock Registers */
  22. #define OSCCON 0x0000
  23. #define OSCTUNE 0x0010
  24. #define SPLLCON 0x0020
  25. #define REFO1CON 0x0080
  26. #define REFO1TRIM 0x0090
  27. #define PB1DIV 0x0140
  28. /* SPLL */
  29. #define ICLK_MASK 0x00000080
  30. #define PLLIDIV_MASK 0x00000007
  31. #define PLLODIV_MASK 0x00000007
  32. #define CUROSC_MASK 0x00000007
  33. #define PLLMUL_MASK 0x0000007F
  34. #define FRCDIV_MASK 0x00000007
  35. /* PBCLK */
  36. #define PBDIV_MASK 0x00000007
  37. /* SYSCLK MUX */
  38. #define SCLK_SRC_FRC1 0
  39. #define SCLK_SRC_SPLL 1
  40. #define SCLK_SRC_POSC 2
  41. #define SCLK_SRC_FRC2 7
  42. /* Reference Oscillator Control Reg fields */
  43. #define REFO_SEL_MASK 0x0f
  44. #define REFO_SEL_SHIFT 0
  45. #define REFO_ACTIVE BIT(8)
  46. #define REFO_DIVSW_EN BIT(9)
  47. #define REFO_OE BIT(12)
  48. #define REFO_ON BIT(15)
  49. #define REFO_DIV_SHIFT 16
  50. #define REFO_DIV_MASK 0x7fff
  51. /* Reference Oscillator Trim Register Fields */
  52. #define REFO_TRIM_REG 0x10
  53. #define REFO_TRIM_MASK 0x1ff
  54. #define REFO_TRIM_SHIFT 23
  55. #define REFO_TRIM_MAX 511
  56. #define ROCLK_SRC_SCLK 0x0
  57. #define ROCLK_SRC_SPLL 0x7
  58. #define ROCLK_SRC_ROCLKI 0x8
  59. /* Memory PLL */
  60. #define MPLL_IDIV 0x3f
  61. #define MPLL_MULT 0xff
  62. #define MPLL_ODIV1 0x7
  63. #define MPLL_ODIV2 0x7
  64. #define MPLL_VREG_RDY BIT(23)
  65. #define MPLL_RDY BIT(31)
  66. #define MPLL_IDIV_SHIFT 0
  67. #define MPLL_MULT_SHIFT 8
  68. #define MPLL_ODIV1_SHIFT 24
  69. #define MPLL_ODIV2_SHIFT 27
  70. #define MPLL_IDIV_INIT 0x03
  71. #define MPLL_MULT_INIT 0x32
  72. #define MPLL_ODIV1_INIT 0x02
  73. #define MPLL_ODIV2_INIT 0x01
  74. struct pic32_clk_priv {
  75. void __iomem *iobase;
  76. void __iomem *syscfg_base;
  77. };
  78. static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv)
  79. {
  80. u32 iclk, idiv, odiv, mult;
  81. ulong plliclk, v;
  82. v = readl(priv->iobase + SPLLCON);
  83. iclk = (v & ICLK_MASK);
  84. idiv = ((v >> 8) & PLLIDIV_MASK) + 1;
  85. odiv = ((v >> 24) & PLLODIV_MASK);
  86. mult = ((v >> 16) & PLLMUL_MASK) + 1;
  87. plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ;
  88. if (odiv < 2)
  89. odiv = 2;
  90. else if (odiv < 5)
  91. odiv = (1 << odiv);
  92. else
  93. odiv = 32;
  94. return ((plliclk / idiv) * mult) / odiv;
  95. }
  96. static ulong pic32_get_sysclk(struct pic32_clk_priv *priv)
  97. {
  98. ulong v;
  99. ulong hz;
  100. ulong div, frcdiv;
  101. ulong curr_osc;
  102. /* get clk source */
  103. v = readl(priv->iobase + OSCCON);
  104. curr_osc = (v >> 12) & CUROSC_MASK;
  105. switch (curr_osc) {
  106. case SCLK_SRC_FRC1:
  107. case SCLK_SRC_FRC2:
  108. frcdiv = ((v >> 24) & FRCDIV_MASK);
  109. div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
  110. hz = SYS_FRC_CLK_HZ / div;
  111. break;
  112. case SCLK_SRC_SPLL:
  113. hz = pic32_get_pll_rate(priv);
  114. break;
  115. case SCLK_SRC_POSC:
  116. hz = SYS_POSC_CLK_HZ;
  117. break;
  118. default:
  119. hz = 0;
  120. printf("clk: unknown sclk_src.\n");
  121. break;
  122. }
  123. return hz;
  124. }
  125. static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int periph)
  126. {
  127. void __iomem *reg;
  128. ulong div, clk_freq;
  129. WARN_ON((periph < PB1CLK) || (periph > PB7CLK));
  130. clk_freq = pic32_get_sysclk(priv);
  131. reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10;
  132. div = (readl(reg) & PBDIV_MASK) + 1;
  133. return clk_freq / div;
  134. }
  135. static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv)
  136. {
  137. return pic32_get_pbclk(priv, PB7CLK);
  138. }
  139. static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph,
  140. int parent_rate, int rate, int parent_id)
  141. {
  142. void __iomem *reg;
  143. u32 div, trim, v;
  144. u64 frac;
  145. WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
  146. /* calculate dividers,
  147. * rate = parent_rate / [2 * (div + (trim / 512))]
  148. */
  149. if (parent_rate <= rate) {
  150. div = 0;
  151. trim = 0;
  152. } else {
  153. div = parent_rate / (rate << 1);
  154. frac = parent_rate;
  155. frac <<= 8;
  156. do_div(frac, rate);
  157. frac -= (u64)(div << 9);
  158. trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : (u32)frac;
  159. }
  160. reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
  161. /* disable clk */
  162. writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET);
  163. /* wait till previous src change is active */
  164. wait_for_bit_le32(reg, REFO_DIVSW_EN | REFO_ACTIVE,
  165. false, CONFIG_SYS_HZ, false);
  166. /* parent_id */
  167. v = readl(reg);
  168. v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
  169. v |= (parent_id << REFO_SEL_SHIFT);
  170. /* apply rodiv */
  171. v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
  172. v |= (div << REFO_DIV_SHIFT);
  173. writel(v, reg);
  174. /* apply trim */
  175. v = readl(reg + REFO_TRIM_REG);
  176. v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
  177. v |= (trim << REFO_TRIM_SHIFT);
  178. writel(v, reg + REFO_TRIM_REG);
  179. /* enable clk */
  180. writel(REFO_ON | REFO_OE, reg + _SET_OFFSET);
  181. /* switch divider */
  182. writel(REFO_DIVSW_EN, reg + _SET_OFFSET);
  183. /* wait for divider switching to complete */
  184. return wait_for_bit_le32(reg, REFO_DIVSW_EN, false,
  185. CONFIG_SYS_HZ, false);
  186. }
  187. static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph)
  188. {
  189. u32 rodiv, rotrim, rosel, v, parent_rate;
  190. void __iomem *reg;
  191. u64 rate64;
  192. WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
  193. reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
  194. v = readl(reg);
  195. /* get rosel */
  196. rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
  197. /* get div */
  198. rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
  199. /* get trim */
  200. v = readl(reg + REFO_TRIM_REG);
  201. rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
  202. if (!rodiv)
  203. return 0;
  204. /* get parent rate */
  205. switch (rosel) {
  206. case ROCLK_SRC_SCLK:
  207. parent_rate = pic32_get_cpuclk(priv);
  208. break;
  209. case ROCLK_SRC_SPLL:
  210. parent_rate = pic32_get_pll_rate(priv);
  211. break;
  212. default:
  213. parent_rate = 0;
  214. break;
  215. }
  216. /* Calculation
  217. * rate = parent_rate / [2 * (div + (trim / 512))]
  218. */
  219. if (rotrim) {
  220. rodiv <<= 9;
  221. rodiv += rotrim;
  222. rate64 = parent_rate;
  223. rate64 <<= 8;
  224. do_div(rate64, rodiv);
  225. v = (u32)rate64;
  226. } else {
  227. v = parent_rate / (rodiv << 1);
  228. }
  229. return v;
  230. }
  231. static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv)
  232. {
  233. u32 v, idiv, mul;
  234. u32 odiv1, odiv2;
  235. u64 rate;
  236. v = readl(priv->syscfg_base + CFGMPLL);
  237. idiv = v & MPLL_IDIV;
  238. mul = (v >> MPLL_MULT_SHIFT) & MPLL_MULT;
  239. odiv1 = (v >> MPLL_ODIV1_SHIFT) & MPLL_ODIV1;
  240. odiv2 = (v >> MPLL_ODIV2_SHIFT) & MPLL_ODIV2;
  241. rate = (SYS_POSC_CLK_HZ / idiv) * mul;
  242. do_div(rate, odiv1);
  243. do_div(rate, odiv2);
  244. return (ulong)rate;
  245. }
  246. static int pic32_mpll_init(struct pic32_clk_priv *priv)
  247. {
  248. u32 v, mask;
  249. /* initialize */
  250. v = (MPLL_IDIV_INIT << MPLL_IDIV_SHIFT) |
  251. (MPLL_MULT_INIT << MPLL_MULT_SHIFT) |
  252. (MPLL_ODIV1_INIT << MPLL_ODIV1_SHIFT) |
  253. (MPLL_ODIV2_INIT << MPLL_ODIV2_SHIFT);
  254. writel(v, priv->syscfg_base + CFGMPLL);
  255. /* Wait for ready */
  256. mask = MPLL_RDY | MPLL_VREG_RDY;
  257. return wait_for_bit_le32(priv->syscfg_base + CFGMPLL, mask,
  258. true, get_tbclk(), false);
  259. }
  260. static void pic32_clk_init(struct udevice *dev)
  261. {
  262. const void *blob = gd->fdt_blob;
  263. struct pic32_clk_priv *priv;
  264. ulong rate, pll_hz;
  265. char propname[50];
  266. int i;
  267. priv = dev_get_priv(dev);
  268. pll_hz = pic32_get_pll_rate(priv);
  269. /* Initialize REFOs as not initialized and enabled on reset. */
  270. for (i = REF1CLK; i <= REF5CLK; i++) {
  271. snprintf(propname, sizeof(propname),
  272. "microchip,refo%d-frequency", i - REF1CLK + 1);
  273. rate = fdtdec_get_int(blob, dev_of_offset(dev), propname, 0);
  274. if (rate)
  275. pic32_set_refclk(priv, i, pll_hz, rate, ROCLK_SRC_SPLL);
  276. }
  277. /* Memory PLL */
  278. pic32_mpll_init(priv);
  279. }
  280. static ulong pic32_get_rate(struct clk *clk)
  281. {
  282. struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
  283. ulong rate;
  284. switch (clk->id) {
  285. case PB1CLK ... PB7CLK:
  286. rate = pic32_get_pbclk(priv, clk->id);
  287. break;
  288. case REF1CLK ... REF5CLK:
  289. rate = pic32_get_refclk(priv, clk->id);
  290. break;
  291. case PLLCLK:
  292. rate = pic32_get_pll_rate(priv);
  293. break;
  294. case MPLL:
  295. rate = pic32_get_mpll_rate(priv);
  296. break;
  297. default:
  298. rate = 0;
  299. break;
  300. }
  301. return rate;
  302. }
  303. static ulong pic32_set_rate(struct clk *clk, ulong rate)
  304. {
  305. struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
  306. ulong pll_hz;
  307. switch (clk->id) {
  308. case REF1CLK ... REF5CLK:
  309. pll_hz = pic32_get_pll_rate(priv);
  310. pic32_set_refclk(priv, clk->id, pll_hz, rate, ROCLK_SRC_SPLL);
  311. break;
  312. default:
  313. break;
  314. }
  315. return rate;
  316. }
  317. static struct clk_ops pic32_pic32_clk_ops = {
  318. .set_rate = pic32_set_rate,
  319. .get_rate = pic32_get_rate,
  320. };
  321. static int pic32_clk_probe(struct udevice *dev)
  322. {
  323. struct pic32_clk_priv *priv = dev_get_priv(dev);
  324. fdt_addr_t addr;
  325. fdt_size_t size;
  326. addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
  327. &size);
  328. if (addr == FDT_ADDR_T_NONE)
  329. return -EINVAL;
  330. priv->iobase = ioremap(addr, size);
  331. if (!priv->iobase)
  332. return -EINVAL;
  333. priv->syscfg_base = pic32_get_syscfg_base();
  334. /* initialize clocks */
  335. pic32_clk_init(dev);
  336. return 0;
  337. }
  338. static const struct udevice_id pic32_clk_ids[] = {
  339. { .compatible = "microchip,pic32mzda-clk"},
  340. {}
  341. };
  342. U_BOOT_DRIVER(pic32_clk) = {
  343. .name = "pic32_clk",
  344. .id = UCLASS_CLK,
  345. .of_match = pic32_clk_ids,
  346. .ops = &pic32_pic32_clk_ops,
  347. .probe = pic32_clk_probe,
  348. .priv_auto_alloc_size = sizeof(struct pic32_clk_priv),
  349. };