jz4760-cgu.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * JZ4760 SoC CGU driver
  4. * Copyright 2018, Paul Cercueil <[email protected]>
  5. */
  6. #include <linux/bitops.h>
  7. #include <linux/clk-provider.h>
  8. #include <linux/delay.h>
  9. #include <linux/io.h>
  10. #include <linux/of.h>
  11. #include <linux/clk.h>
  12. #include <dt-bindings/clock/ingenic,jz4760-cgu.h>
  13. #include "cgu.h"
  14. #include "pm.h"
  15. #define MHZ (1000 * 1000)
  16. /*
  17. * CPM registers offset address definition
  18. */
  19. #define CGU_REG_CPCCR 0x00
  20. #define CGU_REG_LCR 0x04
  21. #define CGU_REG_CPPCR0 0x10
  22. #define CGU_REG_CLKGR0 0x20
  23. #define CGU_REG_OPCR 0x24
  24. #define CGU_REG_CLKGR1 0x28
  25. #define CGU_REG_CPPCR1 0x30
  26. #define CGU_REG_USBPCR 0x3c
  27. #define CGU_REG_USBCDR 0x50
  28. #define CGU_REG_I2SCDR 0x60
  29. #define CGU_REG_LPCDR 0x64
  30. #define CGU_REG_MSCCDR 0x68
  31. #define CGU_REG_UHCCDR 0x6c
  32. #define CGU_REG_SSICDR 0x74
  33. #define CGU_REG_CIMCDR 0x7c
  34. #define CGU_REG_GPSCDR 0x80
  35. #define CGU_REG_PCMCDR 0x84
  36. #define CGU_REG_GPUCDR 0x88
  37. static const s8 pll_od_encoding[8] = {
  38. 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
  39. };
  40. static const u8 jz4760_cgu_cpccr_div_table[] = {
  41. 1, 2, 3, 4, 6, 8,
  42. };
  43. static const u8 jz4760_cgu_pll_half_div_table[] = {
  44. 2, 1,
  45. };
  46. static void
  47. jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
  48. unsigned long rate, unsigned long parent_rate,
  49. unsigned int *pm, unsigned int *pn, unsigned int *pod)
  50. {
  51. unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1;
  52. /* The frequency after the N divider must be between 1 and 50 MHz. */
  53. n = parent_rate / (1 * MHZ);
  54. /* The N divider must be >= 2. */
  55. n = clamp_val(n, 2, 1 << pll_info->n_bits);
  56. rate /= MHZ;
  57. parent_rate /= MHZ;
  58. for (m = m_max; m >= m_max && n >= 2; n--) {
  59. m = rate * n / parent_rate;
  60. od = m & 1;
  61. m <<= od;
  62. }
  63. *pm = m;
  64. *pn = n + 1;
  65. *pod = 1 << od;
  66. }
  67. static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
  68. /* External clocks */
  69. [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
  70. [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
  71. /* PLLs */
  72. [JZ4760_CLK_PLL0] = {
  73. "pll0", CGU_CLK_PLL,
  74. .parents = { JZ4760_CLK_EXT },
  75. .pll = {
  76. .reg = CGU_REG_CPPCR0,
  77. .rate_multiplier = 1,
  78. .m_shift = 23,
  79. .m_bits = 8,
  80. .m_offset = 0,
  81. .n_shift = 18,
  82. .n_bits = 4,
  83. .n_offset = 0,
  84. .od_shift = 16,
  85. .od_bits = 2,
  86. .od_max = 8,
  87. .od_encoding = pll_od_encoding,
  88. .bypass_reg = CGU_REG_CPPCR0,
  89. .bypass_bit = 9,
  90. .enable_bit = 8,
  91. .stable_bit = 10,
  92. .calc_m_n_od = jz4760_cgu_calc_m_n_od,
  93. },
  94. },
  95. [JZ4760_CLK_PLL1] = {
  96. /* TODO: PLL1 can depend on PLL0 */
  97. "pll1", CGU_CLK_PLL,
  98. .parents = { JZ4760_CLK_EXT },
  99. .pll = {
  100. .reg = CGU_REG_CPPCR1,
  101. .rate_multiplier = 1,
  102. .m_shift = 23,
  103. .m_bits = 8,
  104. .m_offset = 0,
  105. .n_shift = 18,
  106. .n_bits = 4,
  107. .n_offset = 0,
  108. .od_shift = 16,
  109. .od_bits = 2,
  110. .od_max = 8,
  111. .od_encoding = pll_od_encoding,
  112. .bypass_bit = -1,
  113. .enable_bit = 7,
  114. .stable_bit = 6,
  115. .calc_m_n_od = jz4760_cgu_calc_m_n_od,
  116. },
  117. },
  118. /* Main clocks */
  119. [JZ4760_CLK_CCLK] = {
  120. "cclk", CGU_CLK_DIV,
  121. /*
  122. * Disabling the CPU clock or any parent clocks will hang the
  123. * system; mark it critical.
  124. */
  125. .flags = CLK_IS_CRITICAL,
  126. .parents = { JZ4760_CLK_PLL0, },
  127. .div = {
  128. CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
  129. jz4760_cgu_cpccr_div_table,
  130. },
  131. },
  132. [JZ4760_CLK_HCLK] = {
  133. "hclk", CGU_CLK_DIV,
  134. .parents = { JZ4760_CLK_PLL0, },
  135. .div = {
  136. CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
  137. jz4760_cgu_cpccr_div_table,
  138. },
  139. },
  140. [JZ4760_CLK_SCLK] = {
  141. "sclk", CGU_CLK_DIV,
  142. .parents = { JZ4760_CLK_PLL0, },
  143. .div = {
  144. CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
  145. jz4760_cgu_cpccr_div_table,
  146. },
  147. },
  148. [JZ4760_CLK_H2CLK] = {
  149. "h2clk", CGU_CLK_DIV,
  150. .parents = { JZ4760_CLK_PLL0, },
  151. .div = {
  152. CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
  153. jz4760_cgu_cpccr_div_table,
  154. },
  155. },
  156. [JZ4760_CLK_MCLK] = {
  157. "mclk", CGU_CLK_DIV,
  158. /*
  159. * Disabling MCLK or its parents will render DRAM
  160. * inaccessible; mark it critical.
  161. */
  162. .flags = CLK_IS_CRITICAL,
  163. .parents = { JZ4760_CLK_PLL0, },
  164. .div = {
  165. CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
  166. jz4760_cgu_cpccr_div_table,
  167. },
  168. },
  169. [JZ4760_CLK_PCLK] = {
  170. "pclk", CGU_CLK_DIV,
  171. .parents = { JZ4760_CLK_PLL0, },
  172. .div = {
  173. CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
  174. jz4760_cgu_cpccr_div_table,
  175. },
  176. },
  177. /* Divided clocks */
  178. [JZ4760_CLK_PLL0_HALF] = {
  179. "pll0_half", CGU_CLK_DIV,
  180. .parents = { JZ4760_CLK_PLL0 },
  181. .div = {
  182. CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
  183. jz4760_cgu_pll_half_div_table,
  184. },
  185. },
  186. /* Those divided clocks can connect to PLL0 or PLL1 */
  187. [JZ4760_CLK_UHC] = {
  188. "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
  189. .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
  190. .mux = { CGU_REG_UHCCDR, 31, 1 },
  191. .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
  192. .gate = { CGU_REG_CLKGR0, 24 },
  193. },
  194. [JZ4760_CLK_GPU] = {
  195. "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
  196. .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
  197. .mux = { CGU_REG_GPUCDR, 31, 1 },
  198. .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
  199. .gate = { CGU_REG_CLKGR1, 9 },
  200. },
  201. [JZ4760_CLK_LPCLK_DIV] = {
  202. "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
  203. .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
  204. .mux = { CGU_REG_LPCDR, 29, 1 },
  205. .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
  206. },
  207. [JZ4760_CLK_TVE] = {
  208. "tve", CGU_CLK_GATE | CGU_CLK_MUX,
  209. .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
  210. .mux = { CGU_REG_LPCDR, 31, 1 },
  211. .gate = { CGU_REG_CLKGR0, 27 },
  212. },
  213. [JZ4760_CLK_LPCLK] = {
  214. "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
  215. .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
  216. .mux = { CGU_REG_LPCDR, 30, 1 },
  217. .gate = { CGU_REG_CLKGR0, 28 },
  218. },
  219. [JZ4760_CLK_GPS] = {
  220. "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
  221. .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
  222. .mux = { CGU_REG_GPSCDR, 31, 1 },
  223. .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
  224. .gate = { CGU_REG_CLKGR0, 22 },
  225. },
  226. /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
  227. [JZ4760_CLK_PCM] = {
  228. "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
  229. .parents = { JZ4760_CLK_EXT, -1,
  230. JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
  231. .mux = { CGU_REG_PCMCDR, 30, 2 },
  232. .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
  233. .gate = { CGU_REG_CLKGR1, 8 },
  234. },
  235. [JZ4760_CLK_I2S] = {
  236. "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
  237. .parents = { JZ4760_CLK_EXT, -1,
  238. JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
  239. .mux = { CGU_REG_I2SCDR, 30, 2 },
  240. .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
  241. },
  242. [JZ4760_CLK_OTG] = {
  243. "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
  244. .parents = { JZ4760_CLK_EXT, -1,
  245. JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
  246. .mux = { CGU_REG_USBCDR, 30, 2 },
  247. .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
  248. .gate = { CGU_REG_CLKGR0, 2 },
  249. },
  250. /* Those divided clocks can connect to EXT or PLL0 */
  251. [JZ4760_CLK_MMC_MUX] = {
  252. "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
  253. .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
  254. .mux = { CGU_REG_MSCCDR, 31, 1 },
  255. .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
  256. },
  257. [JZ4760_CLK_SSI_MUX] = {
  258. "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
  259. .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
  260. .mux = { CGU_REG_SSICDR, 31, 1 },
  261. .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
  262. },
  263. /* These divided clock can connect to PLL0 only */
  264. [JZ4760_CLK_CIM] = {
  265. "cim", CGU_CLK_DIV | CGU_CLK_GATE,
  266. .parents = { JZ4760_CLK_PLL0_HALF },
  267. .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
  268. .gate = { CGU_REG_CLKGR0, 26 },
  269. },
  270. /* Gate-only clocks */
  271. [JZ4760_CLK_SSI0] = {
  272. "ssi0", CGU_CLK_GATE,
  273. .parents = { JZ4760_CLK_SSI_MUX, },
  274. .gate = { CGU_REG_CLKGR0, 4 },
  275. },
  276. [JZ4760_CLK_SSI1] = {
  277. "ssi1", CGU_CLK_GATE,
  278. .parents = { JZ4760_CLK_SSI_MUX, },
  279. .gate = { CGU_REG_CLKGR0, 19 },
  280. },
  281. [JZ4760_CLK_SSI2] = {
  282. "ssi2", CGU_CLK_GATE,
  283. .parents = { JZ4760_CLK_SSI_MUX, },
  284. .gate = { CGU_REG_CLKGR0, 20 },
  285. },
  286. [JZ4760_CLK_DMA] = {
  287. "dma", CGU_CLK_GATE,
  288. .parents = { JZ4760_CLK_H2CLK, },
  289. .gate = { CGU_REG_CLKGR0, 21 },
  290. },
  291. [JZ4760_CLK_MDMA] = {
  292. "mdma", CGU_CLK_GATE,
  293. .parents = { JZ4760_CLK_HCLK, },
  294. .gate = { CGU_REG_CLKGR0, 25 },
  295. },
  296. [JZ4760_CLK_BDMA] = {
  297. "bdma", CGU_CLK_GATE,
  298. .parents = { JZ4760_CLK_HCLK, },
  299. .gate = { CGU_REG_CLKGR1, 0 },
  300. },
  301. [JZ4760_CLK_I2C0] = {
  302. "i2c0", CGU_CLK_GATE,
  303. .parents = { JZ4760_CLK_EXT, },
  304. .gate = { CGU_REG_CLKGR0, 5 },
  305. },
  306. [JZ4760_CLK_I2C1] = {
  307. "i2c1", CGU_CLK_GATE,
  308. .parents = { JZ4760_CLK_EXT, },
  309. .gate = { CGU_REG_CLKGR0, 6 },
  310. },
  311. [JZ4760_CLK_UART0] = {
  312. "uart0", CGU_CLK_GATE,
  313. .parents = { JZ4760_CLK_EXT, },
  314. .gate = { CGU_REG_CLKGR0, 15 },
  315. },
  316. [JZ4760_CLK_UART1] = {
  317. "uart1", CGU_CLK_GATE,
  318. .parents = { JZ4760_CLK_EXT, },
  319. .gate = { CGU_REG_CLKGR0, 16 },
  320. },
  321. [JZ4760_CLK_UART2] = {
  322. "uart2", CGU_CLK_GATE,
  323. .parents = { JZ4760_CLK_EXT, },
  324. .gate = { CGU_REG_CLKGR0, 17 },
  325. },
  326. [JZ4760_CLK_UART3] = {
  327. "uart3", CGU_CLK_GATE,
  328. .parents = { JZ4760_CLK_EXT, },
  329. .gate = { CGU_REG_CLKGR0, 18 },
  330. },
  331. [JZ4760_CLK_IPU] = {
  332. "ipu", CGU_CLK_GATE,
  333. .parents = { JZ4760_CLK_HCLK, },
  334. .gate = { CGU_REG_CLKGR0, 29 },
  335. },
  336. [JZ4760_CLK_ADC] = {
  337. "adc", CGU_CLK_GATE,
  338. .parents = { JZ4760_CLK_EXT, },
  339. .gate = { CGU_REG_CLKGR0, 14 },
  340. },
  341. [JZ4760_CLK_AIC] = {
  342. "aic", CGU_CLK_GATE,
  343. .parents = { JZ4760_CLK_EXT, },
  344. .gate = { CGU_REG_CLKGR0, 8 },
  345. },
  346. [JZ4760_CLK_VPU] = {
  347. "vpu", CGU_CLK_GATE,
  348. .parents = { JZ4760_CLK_HCLK, },
  349. .gate = { CGU_REG_LCR, 30, false, 150 },
  350. },
  351. [JZ4760_CLK_MMC0] = {
  352. "mmc0", CGU_CLK_GATE,
  353. .parents = { JZ4760_CLK_MMC_MUX, },
  354. .gate = { CGU_REG_CLKGR0, 3 },
  355. },
  356. [JZ4760_CLK_MMC1] = {
  357. "mmc1", CGU_CLK_GATE,
  358. .parents = { JZ4760_CLK_MMC_MUX, },
  359. .gate = { CGU_REG_CLKGR0, 11 },
  360. },
  361. [JZ4760_CLK_MMC2] = {
  362. "mmc2", CGU_CLK_GATE,
  363. .parents = { JZ4760_CLK_MMC_MUX, },
  364. .gate = { CGU_REG_CLKGR0, 12 },
  365. },
  366. [JZ4760_CLK_UHC_PHY] = {
  367. "uhc_phy", CGU_CLK_GATE,
  368. .parents = { JZ4760_CLK_UHC, },
  369. .gate = { CGU_REG_OPCR, 5 },
  370. },
  371. [JZ4760_CLK_OTG_PHY] = {
  372. "usb_phy", CGU_CLK_GATE,
  373. .parents = { JZ4760_CLK_OTG },
  374. .gate = { CGU_REG_OPCR, 7, true, 50 },
  375. },
  376. /* Custom clocks */
  377. [JZ4760_CLK_EXT512] = {
  378. "ext/512", CGU_CLK_FIXDIV,
  379. .parents = { JZ4760_CLK_EXT },
  380. .fixdiv = { 512 },
  381. },
  382. [JZ4760_CLK_RTC] = {
  383. "rtc", CGU_CLK_MUX,
  384. .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
  385. .mux = { CGU_REG_OPCR, 2, 1},
  386. },
  387. };
  388. static void __init jz4760_cgu_init(struct device_node *np)
  389. {
  390. struct ingenic_cgu *cgu;
  391. int retval;
  392. cgu = ingenic_cgu_new(jz4760_cgu_clocks,
  393. ARRAY_SIZE(jz4760_cgu_clocks), np);
  394. if (!cgu) {
  395. pr_err("%s: failed to initialise CGU\n", __func__);
  396. return;
  397. }
  398. retval = ingenic_cgu_register_clocks(cgu);
  399. if (retval)
  400. pr_err("%s: failed to register CGU Clocks\n", __func__);
  401. ingenic_cgu_register_syscore_ops(cgu);
  402. }
  403. /* We only probe via devicetree, no need for a platform driver */
  404. CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
  405. /* JZ4760B has some small differences, but we don't implement them. */
  406. CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);