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