clk_pll.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) Copyright 2018-2019 Rockchip Electronics Co., Ltd
  4. */
  5. #include <common.h>
  6. #include <bitfield.h>
  7. #include <clk-uclass.h>
  8. #include <dm.h>
  9. #include <errno.h>
  10. #include <log.h>
  11. #include <asm/io.h>
  12. #include <asm/arch-rockchip/clock.h>
  13. #include <asm/arch-rockchip/hardware.h>
  14. #include <div64.h>
  15. #include <linux/delay.h>
  16. static struct rockchip_pll_rate_table rockchip_auto_table;
  17. #define PLL_MODE_MASK 0x3
  18. #define PLL_RK3328_MODE_MASK 0x1
  19. #define RK3036_PLLCON0_FBDIV_MASK 0xfff
  20. #define RK3036_PLLCON0_FBDIV_SHIFT 0
  21. #define RK3036_PLLCON0_POSTDIV1_MASK 0x7 << 12
  22. #define RK3036_PLLCON0_POSTDIV1_SHIFT 12
  23. #define RK3036_PLLCON1_REFDIV_MASK 0x3f
  24. #define RK3036_PLLCON1_REFDIV_SHIFT 0
  25. #define RK3036_PLLCON1_POSTDIV2_MASK 0x7 << 6
  26. #define RK3036_PLLCON1_POSTDIV2_SHIFT 6
  27. #define RK3036_PLLCON1_DSMPD_MASK 0x1 << 12
  28. #define RK3036_PLLCON1_DSMPD_SHIFT 12
  29. #define RK3036_PLLCON2_FRAC_MASK 0xffffff
  30. #define RK3036_PLLCON2_FRAC_SHIFT 0
  31. #define RK3036_PLLCON1_PWRDOWN_SHIT 13
  32. #define MHZ 1000000
  33. #define KHZ 1000
  34. enum {
  35. OSC_HZ = 24 * 1000000,
  36. VCO_MAX_HZ = 3200U * 1000000,
  37. VCO_MIN_HZ = 800 * 1000000,
  38. OUTPUT_MAX_HZ = 3200U * 1000000,
  39. OUTPUT_MIN_HZ = 24 * 1000000,
  40. };
  41. #define MIN_FOUTVCO_FREQ (800 * MHZ)
  42. #define MAX_FOUTVCO_FREQ (2000 * MHZ)
  43. int gcd(int m, int n)
  44. {
  45. int t;
  46. while (m > 0) {
  47. if (n > m) {
  48. t = m;
  49. m = n;
  50. n = t;
  51. } /* swap */
  52. m -= n;
  53. }
  54. return n;
  55. }
  56. /*
  57. * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
  58. * Formulas also embedded within the Fractional PLL Verilog model:
  59. * If DSMPD = 1 (DSM is disabled, "integer mode")
  60. * FOUTVCO = FREF / REFDIV * FBDIV
  61. * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
  62. * Where:
  63. * FOUTVCO = Fractional PLL non-divided output frequency
  64. * FOUTPOSTDIV = Fractional PLL divided output frequency
  65. * (output of second post divider)
  66. * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
  67. * REFDIV = Fractional PLL input reference clock divider
  68. * FBDIV = Integer value programmed into feedback divide
  69. *
  70. */
  71. static int rockchip_pll_clk_set_postdiv(ulong fout_hz,
  72. u32 *postdiv1,
  73. u32 *postdiv2,
  74. u32 *foutvco)
  75. {
  76. ulong freq;
  77. if (fout_hz < MIN_FOUTVCO_FREQ) {
  78. for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++) {
  79. for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) {
  80. freq = fout_hz * (*postdiv1) * (*postdiv2);
  81. if (freq >= MIN_FOUTVCO_FREQ &&
  82. freq <= MAX_FOUTVCO_FREQ) {
  83. *foutvco = freq;
  84. return 0;
  85. }
  86. }
  87. }
  88. printf("Can't FIND postdiv1/2 to make fout=%lu in 800~2000M.\n",
  89. fout_hz);
  90. } else {
  91. *postdiv1 = 1;
  92. *postdiv2 = 1;
  93. }
  94. return 0;
  95. }
  96. static struct rockchip_pll_rate_table *
  97. rockchip_pll_clk_set_by_auto(ulong fin_hz,
  98. ulong fout_hz)
  99. {
  100. struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table;
  101. /* FIXME set postdiv1/2 always 1*/
  102. u32 foutvco = fout_hz;
  103. ulong fin_64, frac_64;
  104. u32 f_frac, postdiv1, postdiv2;
  105. ulong clk_gcd = 0;
  106. if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
  107. return NULL;
  108. rockchip_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco);
  109. rate_table->postdiv1 = postdiv1;
  110. rate_table->postdiv2 = postdiv2;
  111. rate_table->dsmpd = 1;
  112. if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
  113. fin_hz /= MHZ;
  114. foutvco /= MHZ;
  115. clk_gcd = gcd(fin_hz, foutvco);
  116. rate_table->refdiv = fin_hz / clk_gcd;
  117. rate_table->fbdiv = foutvco / clk_gcd;
  118. rate_table->frac = 0;
  119. debug("fin = %ld, fout = %ld, clk_gcd = %ld,\n",
  120. fin_hz, fout_hz, clk_gcd);
  121. debug("refdiv= %d,fbdiv= %d,postdiv1= %d,postdiv2= %d\n",
  122. rate_table->refdiv,
  123. rate_table->fbdiv, rate_table->postdiv1,
  124. rate_table->postdiv2);
  125. } else {
  126. debug("frac div,fin_hz = %ld,fout_hz = %ld\n",
  127. fin_hz, fout_hz);
  128. debug("frac get postdiv1 = %d, postdiv2 = %d, foutvco = %d\n",
  129. rate_table->postdiv1, rate_table->postdiv2, foutvco);
  130. clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ);
  131. rate_table->refdiv = fin_hz / MHZ / clk_gcd;
  132. rate_table->fbdiv = foutvco / MHZ / clk_gcd;
  133. debug("frac get refdiv = %d, fbdiv = %d\n",
  134. rate_table->refdiv, rate_table->fbdiv);
  135. rate_table->frac = 0;
  136. f_frac = (foutvco % MHZ);
  137. fin_64 = fin_hz;
  138. fin_64 = fin_64 / rate_table->refdiv;
  139. frac_64 = f_frac << 24;
  140. frac_64 = frac_64 / fin_64;
  141. rate_table->frac = frac_64;
  142. if (rate_table->frac > 0)
  143. rate_table->dsmpd = 0;
  144. debug("frac = %x\n", rate_table->frac);
  145. }
  146. return rate_table;
  147. }
  148. static const struct rockchip_pll_rate_table *
  149. rockchip_get_pll_settings(struct rockchip_pll_clock *pll, ulong rate)
  150. {
  151. struct rockchip_pll_rate_table *rate_table = pll->rate_table;
  152. while (rate_table->rate) {
  153. if (rate_table->rate == rate)
  154. break;
  155. rate_table++;
  156. }
  157. if (rate_table->rate != rate)
  158. return rockchip_pll_clk_set_by_auto(24 * MHZ, rate);
  159. else
  160. return rate_table;
  161. }
  162. static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll,
  163. void __iomem *base, ulong pll_id,
  164. ulong drate)
  165. {
  166. const struct rockchip_pll_rate_table *rate;
  167. rate = rockchip_get_pll_settings(pll, drate);
  168. if (!rate) {
  169. printf("%s unsupport rate\n", __func__);
  170. return -EINVAL;
  171. }
  172. debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d\n",
  173. __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv);
  174. debug("%s: rate settings for %lu postdiv2: %d, dsmpd: %d, frac: %d\n",
  175. __func__, rate->rate, rate->postdiv2, rate->dsmpd, rate->frac);
  176. /*
  177. * When power on or changing PLL setting,
  178. * we must force PLL into slow mode to ensure output stable clock.
  179. */
  180. rk_clrsetreg(base + pll->mode_offset,
  181. pll->mode_mask << pll->mode_shift,
  182. RKCLK_PLL_MODE_SLOW << pll->mode_shift);
  183. /* Power down */
  184. rk_setreg(base + pll->con_offset + 0x4,
  185. 1 << RK3036_PLLCON1_PWRDOWN_SHIT);
  186. rk_clrsetreg(base + pll->con_offset,
  187. (RK3036_PLLCON0_POSTDIV1_MASK |
  188. RK3036_PLLCON0_FBDIV_MASK),
  189. (rate->postdiv1 << RK3036_PLLCON0_POSTDIV1_SHIFT) |
  190. rate->fbdiv);
  191. rk_clrsetreg(base + pll->con_offset + 0x4,
  192. (RK3036_PLLCON1_POSTDIV2_MASK |
  193. RK3036_PLLCON1_REFDIV_MASK),
  194. (rate->postdiv2 << RK3036_PLLCON1_POSTDIV2_SHIFT |
  195. rate->refdiv << RK3036_PLLCON1_REFDIV_SHIFT));
  196. if (!rate->dsmpd) {
  197. rk_clrsetreg(base + pll->con_offset + 0x4,
  198. RK3036_PLLCON1_DSMPD_MASK,
  199. rate->dsmpd << RK3036_PLLCON1_DSMPD_SHIFT);
  200. writel((readl(base + pll->con_offset + 0x8) &
  201. (~RK3036_PLLCON2_FRAC_MASK)) |
  202. (rate->frac << RK3036_PLLCON2_FRAC_SHIFT),
  203. base + pll->con_offset + 0x8);
  204. }
  205. /* Power Up */
  206. rk_clrreg(base + pll->con_offset + 0x4,
  207. 1 << RK3036_PLLCON1_PWRDOWN_SHIT);
  208. /* waiting for pll lock */
  209. while (!(readl(base + pll->con_offset + 0x4) & (1 << pll->lock_shift)))
  210. udelay(1);
  211. rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift,
  212. RKCLK_PLL_MODE_NORMAL << pll->mode_shift);
  213. debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n",
  214. pll, readl(base + pll->con_offset),
  215. readl(base + pll->con_offset + 0x4),
  216. readl(base + pll->con_offset + 0x8),
  217. readl(base + pll->mode_offset));
  218. return 0;
  219. }
  220. static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll,
  221. void __iomem *base, ulong pll_id)
  222. {
  223. u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac;
  224. u32 con = 0, shift, mask;
  225. ulong rate;
  226. con = readl(base + pll->mode_offset);
  227. shift = pll->mode_shift;
  228. mask = pll->mode_mask << shift;
  229. switch ((con & mask) >> shift) {
  230. case RKCLK_PLL_MODE_SLOW:
  231. return OSC_HZ;
  232. case RKCLK_PLL_MODE_NORMAL:
  233. /* normal mode */
  234. con = readl(base + pll->con_offset);
  235. postdiv1 = (con & RK3036_PLLCON0_POSTDIV1_MASK) >>
  236. RK3036_PLLCON0_POSTDIV1_SHIFT;
  237. fbdiv = (con & RK3036_PLLCON0_FBDIV_MASK) >>
  238. RK3036_PLLCON0_FBDIV_SHIFT;
  239. con = readl(base + pll->con_offset + 0x4);
  240. postdiv2 = (con & RK3036_PLLCON1_POSTDIV2_MASK) >>
  241. RK3036_PLLCON1_POSTDIV2_SHIFT;
  242. refdiv = (con & RK3036_PLLCON1_REFDIV_MASK) >>
  243. RK3036_PLLCON1_REFDIV_SHIFT;
  244. dsmpd = (con & RK3036_PLLCON1_DSMPD_MASK) >>
  245. RK3036_PLLCON1_DSMPD_SHIFT;
  246. con = readl(base + pll->con_offset + 0x8);
  247. frac = (con & RK3036_PLLCON2_FRAC_MASK) >>
  248. RK3036_PLLCON2_FRAC_SHIFT;
  249. rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
  250. if (dsmpd == 0) {
  251. u64 frac_rate = OSC_HZ * (u64)frac;
  252. do_div(frac_rate, refdiv);
  253. frac_rate >>= 24;
  254. do_div(frac_rate, postdiv1);
  255. do_div(frac_rate, postdiv1);
  256. rate += frac_rate;
  257. }
  258. return rate;
  259. case RKCLK_PLL_MODE_DEEP:
  260. default:
  261. return 32768;
  262. }
  263. }
  264. ulong rockchip_pll_get_rate(struct rockchip_pll_clock *pll,
  265. void __iomem *base,
  266. ulong pll_id)
  267. {
  268. ulong rate = 0;
  269. switch (pll->type) {
  270. case pll_rk3036:
  271. pll->mode_mask = PLL_MODE_MASK;
  272. rate = rk3036_pll_get_rate(pll, base, pll_id);
  273. break;
  274. case pll_rk3328:
  275. pll->mode_mask = PLL_RK3328_MODE_MASK;
  276. rate = rk3036_pll_get_rate(pll, base, pll_id);
  277. break;
  278. default:
  279. printf("%s: Unknown pll type for pll clk %ld\n",
  280. __func__, pll_id);
  281. }
  282. return rate;
  283. }
  284. int rockchip_pll_set_rate(struct rockchip_pll_clock *pll,
  285. void __iomem *base, ulong pll_id,
  286. ulong drate)
  287. {
  288. int ret = 0;
  289. if (rockchip_pll_get_rate(pll, base, pll_id) == drate)
  290. return 0;
  291. switch (pll->type) {
  292. case pll_rk3036:
  293. pll->mode_mask = PLL_MODE_MASK;
  294. ret = rk3036_pll_set_rate(pll, base, pll_id, drate);
  295. break;
  296. case pll_rk3328:
  297. pll->mode_mask = PLL_RK3328_MODE_MASK;
  298. ret = rk3036_pll_set_rate(pll, base, pll_id, drate);
  299. break;
  300. default:
  301. printf("%s: Unknown pll type for pll clk %ld\n",
  302. __func__, pll_id);
  303. }
  304. return ret;
  305. }
  306. const struct rockchip_cpu_rate_table *
  307. rockchip_get_cpu_settings(struct rockchip_cpu_rate_table *cpu_table,
  308. ulong rate)
  309. {
  310. struct rockchip_cpu_rate_table *ps = cpu_table;
  311. while (ps->rate) {
  312. if (ps->rate == rate)
  313. break;
  314. ps++;
  315. }
  316. if (ps->rate != rate)
  317. return NULL;
  318. else
  319. return ps;
  320. }