clk_rk3188.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. /*
  2. * (C) Copyright 2015 Google, Inc
  3. * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0
  6. */
  7. #include <common.h>
  8. #include <clk-uclass.h>
  9. #include <dm.h>
  10. #include <dt-structs.h>
  11. #include <errno.h>
  12. #include <mapmem.h>
  13. #include <syscon.h>
  14. #include <asm/io.h>
  15. #include <asm/arch/clock.h>
  16. #include <asm/arch/cru_rk3188.h>
  17. #include <asm/arch/grf_rk3188.h>
  18. #include <asm/arch/hardware.h>
  19. #include <dt-bindings/clock/rk3188-cru.h>
  20. #include <dm/device-internal.h>
  21. #include <dm/lists.h>
  22. #include <dm/uclass-internal.h>
  23. #include <linux/log2.h>
  24. DECLARE_GLOBAL_DATA_PTR;
  25. enum rk3188_clk_type {
  26. RK3188_CRU,
  27. RK3188A_CRU,
  28. };
  29. struct rk3188_clk_plat {
  30. #if CONFIG_IS_ENABLED(OF_PLATDATA)
  31. struct dtd_rockchip_rk3188_cru dtd;
  32. #endif
  33. };
  34. struct pll_div {
  35. u32 nr;
  36. u32 nf;
  37. u32 no;
  38. };
  39. enum {
  40. VCO_MAX_HZ = 2200U * 1000000,
  41. VCO_MIN_HZ = 440 * 1000000,
  42. OUTPUT_MAX_HZ = 2200U * 1000000,
  43. OUTPUT_MIN_HZ = 30 * 1000000,
  44. FREF_MAX_HZ = 2200U * 1000000,
  45. FREF_MIN_HZ = 30 * 1000,
  46. };
  47. enum {
  48. /* PLL CON0 */
  49. PLL_OD_MASK = 0x0f,
  50. /* PLL CON1 */
  51. PLL_NF_MASK = 0x1fff,
  52. /* PLL CON2 */
  53. PLL_BWADJ_MASK = 0x0fff,
  54. /* PLL CON3 */
  55. PLL_RESET_SHIFT = 5,
  56. /* GRF_SOC_STATUS0 */
  57. SOCSTS_DPLL_LOCK = 1 << 5,
  58. SOCSTS_APLL_LOCK = 1 << 6,
  59. SOCSTS_CPLL_LOCK = 1 << 7,
  60. SOCSTS_GPLL_LOCK = 1 << 8,
  61. };
  62. #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
  63. #define PLL_DIVISORS(hz, _nr, _no) {\
  64. .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
  65. _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
  66. (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
  67. "divisors on line " __stringify(__LINE__));
  68. /* Keep divisors as low as possible to reduce jitter and power usage */
  69. #ifdef CONFIG_SPL_BUILD
  70. static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
  71. static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
  72. #endif
  73. static int rkclk_set_pll(struct rk3188_cru *cru, enum rk_clk_id clk_id,
  74. const struct pll_div *div, bool has_bwadj)
  75. {
  76. int pll_id = rk_pll_id(clk_id);
  77. struct rk3188_pll *pll = &cru->pll[pll_id];
  78. /* All PLLs have same VCO and output frequency range restrictions. */
  79. uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
  80. uint output_hz = vco_hz / div->no;
  81. debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
  82. (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz);
  83. assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
  84. output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
  85. (div->no == 1 || !(div->no % 2)));
  86. /* enter reset */
  87. rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
  88. rk_clrsetreg(&pll->con0,
  89. CLKR_MASK << CLKR_SHIFT | PLL_OD_MASK,
  90. ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
  91. rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
  92. if (has_bwadj)
  93. rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
  94. udelay(10);
  95. /* return from reset */
  96. rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
  97. return 0;
  98. }
  99. static int rkclk_configure_ddr(struct rk3188_cru *cru, struct rk3188_grf *grf,
  100. unsigned int hz, bool has_bwadj)
  101. {
  102. static const struct pll_div dpll_cfg[] = {
  103. {.nf = 25, .nr = 2, .no = 1},
  104. {.nf = 400, .nr = 9, .no = 2},
  105. {.nf = 500, .nr = 9, .no = 2},
  106. {.nf = 100, .nr = 3, .no = 1},
  107. };
  108. int cfg;
  109. switch (hz) {
  110. case 300000000:
  111. cfg = 0;
  112. break;
  113. case 533000000: /* actually 533.3P MHz */
  114. cfg = 1;
  115. break;
  116. case 666000000: /* actually 666.6P MHz */
  117. cfg = 2;
  118. break;
  119. case 800000000:
  120. cfg = 3;
  121. break;
  122. default:
  123. debug("Unsupported SDRAM frequency");
  124. return -EINVAL;
  125. }
  126. /* pll enter slow-mode */
  127. rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
  128. DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
  129. rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg], has_bwadj);
  130. /* wait for pll lock */
  131. while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
  132. udelay(1);
  133. /* PLL enter normal-mode */
  134. rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK << DPLL_MODE_SHIFT,
  135. DPLL_MODE_NORMAL << DPLL_MODE_SHIFT);
  136. return 0;
  137. }
  138. static int rkclk_configure_cpu(struct rk3188_cru *cru, struct rk3188_grf *grf,
  139. unsigned int hz, bool has_bwadj)
  140. {
  141. static const struct pll_div apll_cfg[] = {
  142. {.nf = 50, .nr = 1, .no = 2},
  143. {.nf = 67, .nr = 1, .no = 1},
  144. };
  145. int div_core_peri, div_aclk_core, cfg;
  146. /*
  147. * We support two possible frequencies, the safe 600MHz
  148. * which will work with default pmic settings and will
  149. * be set in SPL to get away from the 24MHz default and
  150. * the maximum of 1.6Ghz, which boards can set if they
  151. * were able to get pmic support for it.
  152. */
  153. switch (hz) {
  154. case APLL_SAFE_HZ:
  155. cfg = 0;
  156. div_core_peri = 1;
  157. div_aclk_core = 3;
  158. break;
  159. case APLL_HZ:
  160. cfg = 1;
  161. div_core_peri = 2;
  162. div_aclk_core = 3;
  163. break;
  164. default:
  165. debug("Unsupported ARMCLK frequency");
  166. return -EINVAL;
  167. }
  168. /* pll enter slow-mode */
  169. rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK << APLL_MODE_SHIFT,
  170. APLL_MODE_SLOW << APLL_MODE_SHIFT);
  171. rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj);
  172. /* waiting for pll lock */
  173. while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
  174. udelay(1);
  175. /* Set divider for peripherals attached to the cpu core. */
  176. rk_clrsetreg(&cru->cru_clksel_con[0],
  177. CORE_PERI_DIV_MASK << CORE_PERI_DIV_SHIFT,
  178. div_core_peri << CORE_PERI_DIV_SHIFT);
  179. /* set up dependent divisor for aclk_core */
  180. rk_clrsetreg(&cru->cru_clksel_con[1],
  181. CORE_ACLK_DIV_MASK << CORE_ACLK_DIV_SHIFT,
  182. div_aclk_core << CORE_ACLK_DIV_SHIFT);
  183. /* PLL enter normal-mode */
  184. rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK << APLL_MODE_SHIFT,
  185. APLL_MODE_NORMAL << APLL_MODE_SHIFT);
  186. return hz;
  187. }
  188. /* Get pll rate by id */
  189. static uint32_t rkclk_pll_get_rate(struct rk3188_cru *cru,
  190. enum rk_clk_id clk_id)
  191. {
  192. uint32_t nr, no, nf;
  193. uint32_t con;
  194. int pll_id = rk_pll_id(clk_id);
  195. struct rk3188_pll *pll = &cru->pll[pll_id];
  196. static u8 clk_shift[CLK_COUNT] = {
  197. 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
  198. GPLL_MODE_SHIFT
  199. };
  200. uint shift;
  201. con = readl(&cru->cru_mode_con);
  202. shift = clk_shift[clk_id];
  203. switch ((con >> shift) & APLL_MODE_MASK) {
  204. case APLL_MODE_SLOW:
  205. return OSC_HZ;
  206. case APLL_MODE_NORMAL:
  207. /* normal mode */
  208. con = readl(&pll->con0);
  209. no = ((con >> CLKOD_SHIFT) & CLKOD_MASK) + 1;
  210. nr = ((con >> CLKR_SHIFT) & CLKR_MASK) + 1;
  211. con = readl(&pll->con1);
  212. nf = ((con >> CLKF_SHIFT) & CLKF_MASK) + 1;
  213. return (24 * nf / (nr * no)) * 1000000;
  214. case APLL_MODE_DEEP:
  215. default:
  216. return 32768;
  217. }
  218. }
  219. static ulong rockchip_mmc_get_clk(struct rk3188_cru *cru, uint gclk_rate,
  220. int periph)
  221. {
  222. uint div;
  223. u32 con;
  224. switch (periph) {
  225. case HCLK_EMMC:
  226. case SCLK_EMMC:
  227. con = readl(&cru->cru_clksel_con[12]);
  228. div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
  229. break;
  230. case HCLK_SDMMC:
  231. case SCLK_SDMMC:
  232. con = readl(&cru->cru_clksel_con[11]);
  233. div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
  234. break;
  235. case HCLK_SDIO:
  236. case SCLK_SDIO:
  237. con = readl(&cru->cru_clksel_con[12]);
  238. div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK;
  239. break;
  240. default:
  241. return -EINVAL;
  242. }
  243. return DIV_TO_RATE(gclk_rate, div) / 2;
  244. }
  245. static ulong rockchip_mmc_set_clk(struct rk3188_cru *cru, uint gclk_rate,
  246. int periph, uint freq)
  247. {
  248. int src_clk_div;
  249. debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
  250. /* mmc clock defaulg div 2 internal, need provide double in cru */
  251. src_clk_div = DIV_ROUND_UP(gclk_rate / 2, freq) - 1;
  252. assert(src_clk_div <= 0x3f);
  253. switch (periph) {
  254. case HCLK_EMMC:
  255. case SCLK_EMMC:
  256. rk_clrsetreg(&cru->cru_clksel_con[12],
  257. EMMC_DIV_MASK << EMMC_DIV_SHIFT,
  258. src_clk_div << EMMC_DIV_SHIFT);
  259. break;
  260. case HCLK_SDMMC:
  261. case SCLK_SDMMC:
  262. rk_clrsetreg(&cru->cru_clksel_con[11],
  263. MMC0_DIV_MASK << MMC0_DIV_SHIFT,
  264. src_clk_div << MMC0_DIV_SHIFT);
  265. break;
  266. case HCLK_SDIO:
  267. case SCLK_SDIO:
  268. rk_clrsetreg(&cru->cru_clksel_con[12],
  269. SDIO_DIV_MASK << SDIO_DIV_SHIFT,
  270. src_clk_div << SDIO_DIV_SHIFT);
  271. break;
  272. default:
  273. return -EINVAL;
  274. }
  275. return rockchip_mmc_get_clk(cru, gclk_rate, periph);
  276. }
  277. static ulong rockchip_spi_get_clk(struct rk3188_cru *cru, uint gclk_rate,
  278. int periph)
  279. {
  280. uint div;
  281. u32 con;
  282. switch (periph) {
  283. case SCLK_SPI0:
  284. con = readl(&cru->cru_clksel_con[25]);
  285. div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK;
  286. break;
  287. case SCLK_SPI1:
  288. con = readl(&cru->cru_clksel_con[25]);
  289. div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK;
  290. break;
  291. default:
  292. return -EINVAL;
  293. }
  294. return DIV_TO_RATE(gclk_rate, div);
  295. }
  296. static ulong rockchip_spi_set_clk(struct rk3188_cru *cru, uint gclk_rate,
  297. int periph, uint freq)
  298. {
  299. int src_clk_div = DIV_ROUND_UP(gclk_rate, freq) - 1;
  300. assert(src_clk_div < 128);
  301. switch (periph) {
  302. case SCLK_SPI0:
  303. assert(src_clk_div <= SPI0_DIV_MASK);
  304. rk_clrsetreg(&cru->cru_clksel_con[25],
  305. SPI0_DIV_MASK << SPI0_DIV_SHIFT,
  306. src_clk_div << SPI0_DIV_SHIFT);
  307. break;
  308. case SCLK_SPI1:
  309. assert(src_clk_div <= SPI1_DIV_MASK);
  310. rk_clrsetreg(&cru->cru_clksel_con[25],
  311. SPI1_DIV_MASK << SPI1_DIV_SHIFT,
  312. src_clk_div << SPI1_DIV_SHIFT);
  313. break;
  314. default:
  315. return -EINVAL;
  316. }
  317. return rockchip_spi_get_clk(cru, gclk_rate, periph);
  318. }
  319. #ifdef CONFIG_SPL_BUILD
  320. static void rkclk_init(struct rk3188_cru *cru, struct rk3188_grf *grf,
  321. bool has_bwadj)
  322. {
  323. u32 aclk_div, hclk_div, pclk_div, h2p_div;
  324. /* pll enter slow-mode */
  325. rk_clrsetreg(&cru->cru_mode_con,
  326. GPLL_MODE_MASK << GPLL_MODE_SHIFT |
  327. CPLL_MODE_MASK << CPLL_MODE_SHIFT,
  328. GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
  329. CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
  330. /* init pll */
  331. rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj);
  332. rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj);
  333. /* waiting for pll lock */
  334. while ((readl(&grf->soc_status0) &
  335. (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
  336. (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
  337. udelay(1);
  338. /*
  339. * cpu clock pll source selection and
  340. * reparent aclk_cpu_pre from apll to gpll
  341. * set up dependent divisors for PCLK/HCLK and ACLK clocks.
  342. */
  343. aclk_div = DIV_ROUND_UP(GPLL_HZ, CPU_ACLK_HZ) - 1;
  344. assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f);
  345. rk_clrsetreg(&cru->cru_clksel_con[0],
  346. CPU_ACLK_PLL_MASK << CPU_ACLK_PLL_SHIFT |
  347. A9_CPU_DIV_MASK << A9_CPU_DIV_SHIFT,
  348. CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
  349. aclk_div << A9_CPU_DIV_SHIFT);
  350. hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ);
  351. assert((1 << hclk_div) * CPU_HCLK_HZ == CPU_ACLK_HZ && hclk_div < 0x3);
  352. pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ);
  353. assert((1 << pclk_div) * CPU_PCLK_HZ == CPU_ACLK_HZ && pclk_div < 0x4);
  354. h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ);
  355. assert((1 << h2p_div) * CPU_H2P_HZ == CPU_HCLK_HZ && pclk_div < 0x3);
  356. rk_clrsetreg(&cru->cru_clksel_con[1],
  357. AHB2APB_DIV_MASK << AHB2APB_DIV_SHIFT |
  358. CPU_PCLK_DIV_MASK << CPU_PCLK_DIV_SHIFT |
  359. CPU_HCLK_DIV_MASK << CPU_HCLK_DIV_SHIFT,
  360. h2p_div << AHB2APB_DIV_SHIFT |
  361. pclk_div << CPU_PCLK_DIV_SHIFT |
  362. hclk_div << CPU_HCLK_DIV_SHIFT);
  363. /*
  364. * peri clock pll source selection and
  365. * set up dependent divisors for PCLK/HCLK and ACLK clocks.
  366. */
  367. aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
  368. assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
  369. hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
  370. assert((1 << hclk_div) * PERI_HCLK_HZ ==
  371. PERI_ACLK_HZ && (hclk_div < 0x4));
  372. pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
  373. assert((1 << pclk_div) * PERI_PCLK_HZ ==
  374. PERI_ACLK_HZ && (pclk_div < 0x4));
  375. rk_clrsetreg(&cru->cru_clksel_con[10],
  376. PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT |
  377. PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT |
  378. PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT,
  379. PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT |
  380. pclk_div << PERI_PCLK_DIV_SHIFT |
  381. hclk_div << PERI_HCLK_DIV_SHIFT |
  382. aclk_div << PERI_ACLK_DIV_SHIFT);
  383. /* PLL enter normal-mode */
  384. rk_clrsetreg(&cru->cru_mode_con,
  385. GPLL_MODE_MASK << GPLL_MODE_SHIFT |
  386. CPLL_MODE_MASK << CPLL_MODE_SHIFT,
  387. GPLL_MODE_NORMAL << GPLL_MODE_SHIFT |
  388. CPLL_MODE_NORMAL << CPLL_MODE_SHIFT);
  389. rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
  390. }
  391. #endif
  392. static ulong rk3188_clk_get_rate(struct clk *clk)
  393. {
  394. struct rk3188_clk_priv *priv = dev_get_priv(clk->dev);
  395. ulong new_rate, gclk_rate;
  396. gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
  397. switch (clk->id) {
  398. case 1 ... 4:
  399. new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
  400. break;
  401. case HCLK_EMMC:
  402. case HCLK_SDMMC:
  403. case HCLK_SDIO:
  404. case SCLK_EMMC:
  405. case SCLK_SDMMC:
  406. case SCLK_SDIO:
  407. new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
  408. clk->id);
  409. break;
  410. case SCLK_SPI0:
  411. case SCLK_SPI1:
  412. new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ,
  413. clk->id);
  414. break;
  415. case PCLK_I2C0:
  416. case PCLK_I2C1:
  417. case PCLK_I2C2:
  418. case PCLK_I2C3:
  419. case PCLK_I2C4:
  420. return gclk_rate;
  421. default:
  422. return -ENOENT;
  423. }
  424. return new_rate;
  425. }
  426. static ulong rk3188_clk_set_rate(struct clk *clk, ulong rate)
  427. {
  428. struct rk3188_clk_priv *priv = dev_get_priv(clk->dev);
  429. struct rk3188_cru *cru = priv->cru;
  430. ulong new_rate;
  431. switch (clk->id) {
  432. case PLL_APLL:
  433. new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate,
  434. priv->has_bwadj);
  435. break;
  436. case CLK_DDR:
  437. new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate,
  438. priv->has_bwadj);
  439. break;
  440. case HCLK_EMMC:
  441. case HCLK_SDMMC:
  442. case HCLK_SDIO:
  443. case SCLK_EMMC:
  444. case SCLK_SDMMC:
  445. case SCLK_SDIO:
  446. new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
  447. clk->id, rate);
  448. break;
  449. case SCLK_SPI0:
  450. case SCLK_SPI1:
  451. new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ,
  452. clk->id, rate);
  453. break;
  454. default:
  455. return -ENOENT;
  456. }
  457. return new_rate;
  458. }
  459. static struct clk_ops rk3188_clk_ops = {
  460. .get_rate = rk3188_clk_get_rate,
  461. .set_rate = rk3188_clk_set_rate,
  462. };
  463. static int rk3188_clk_ofdata_to_platdata(struct udevice *dev)
  464. {
  465. #if !CONFIG_IS_ENABLED(OF_PLATDATA)
  466. struct rk3188_clk_priv *priv = dev_get_priv(dev);
  467. priv->cru = (struct rk3188_cru *)devfdt_get_addr(dev);
  468. #endif
  469. return 0;
  470. }
  471. static int rk3188_clk_probe(struct udevice *dev)
  472. {
  473. struct rk3188_clk_priv *priv = dev_get_priv(dev);
  474. enum rk3188_clk_type type = dev_get_driver_data(dev);
  475. priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
  476. if (IS_ERR(priv->grf))
  477. return PTR_ERR(priv->grf);
  478. priv->has_bwadj = (type == RK3188A_CRU) ? 1 : 0;
  479. #ifdef CONFIG_SPL_BUILD
  480. #if CONFIG_IS_ENABLED(OF_PLATDATA)
  481. struct rk3188_clk_plat *plat = dev_get_platdata(dev);
  482. priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
  483. #endif
  484. rkclk_init(priv->cru, priv->grf, priv->has_bwadj);
  485. #endif
  486. return 0;
  487. }
  488. static int rk3188_clk_bind(struct udevice *dev)
  489. {
  490. int ret;
  491. struct udevice *sys_child;
  492. struct sysreset_reg *priv;
  493. /* The reset driver does not have a device node, so bind it here */
  494. ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
  495. &sys_child);
  496. if (ret) {
  497. debug("Warning: No sysreset driver: ret=%d\n", ret);
  498. } else {
  499. priv = malloc(sizeof(struct sysreset_reg));
  500. priv->glb_srst_fst_value = offsetof(struct rk3188_cru,
  501. cru_glb_srst_fst_value);
  502. priv->glb_srst_snd_value = offsetof(struct rk3188_cru,
  503. cru_glb_srst_snd_value);
  504. sys_child->priv = priv;
  505. }
  506. return 0;
  507. }
  508. static const struct udevice_id rk3188_clk_ids[] = {
  509. { .compatible = "rockchip,rk3188-cru", .data = RK3188_CRU },
  510. { .compatible = "rockchip,rk3188a-cru", .data = RK3188A_CRU },
  511. { }
  512. };
  513. U_BOOT_DRIVER(rockchip_rk3188_cru) = {
  514. .name = "rockchip_rk3188_cru",
  515. .id = UCLASS_CLK,
  516. .of_match = rk3188_clk_ids,
  517. .priv_auto_alloc_size = sizeof(struct rk3188_clk_priv),
  518. .platdata_auto_alloc_size = sizeof(struct rk3188_clk_plat),
  519. .ops = &rk3188_clk_ops,
  520. .bind = rk3188_clk_bind,
  521. .ofdata_to_platdata = rk3188_clk_ofdata_to_platdata,
  522. .probe = rk3188_clk_probe,
  523. };