clk_pic32.c 9.0 KB

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