clk_pic32.c 9.0 KB

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