clk-cygnus.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright (C) 2014 Broadcom Corporation
  3. #include <linux/kernel.h>
  4. #include <linux/err.h>
  5. #include <linux/clk-provider.h>
  6. #include <linux/io.h>
  7. #include <linux/of.h>
  8. #include <linux/clkdev.h>
  9. #include <linux/of_address.h>
  10. #include <linux/delay.h>
  11. #include <dt-bindings/clock/bcm-cygnus.h>
  12. #include "clk-iproc.h"
  13. #define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, }
  14. #define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
  15. .pwr_shift = ps, .iso_shift = is }
  16. #define SW_CTRL_VAL(o, s) { .offset = o, .shift = s, }
  17. #define ASIU_DIV_VAL(o, es, hs, hw, ls, lw) \
  18. { .offset = o, .en_shift = es, .high_shift = hs, \
  19. .high_width = hw, .low_shift = ls, .low_width = lw }
  20. #define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \
  21. .p_reset_shift = prs }
  22. #define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\
  23. .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
  24. .ka_width = kaw }
  25. #define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo }
  26. #define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
  27. .hold_shift = hs, .bypass_shift = bs }
  28. #define ASIU_GATE_VAL(o, es) { .offset = o, .en_shift = es }
  29. static void __init cygnus_armpll_init(struct device_node *node)
  30. {
  31. iproc_armpll_setup(node);
  32. }
  33. CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init);
  34. static const struct iproc_pll_ctrl genpll = {
  35. .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
  36. IPROC_CLK_PLL_NEEDS_SW_CFG,
  37. .aon = AON_VAL(0x0, 2, 1, 0),
  38. .reset = RESET_VAL(0x0, 11, 10),
  39. .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
  40. .sw_ctrl = SW_CTRL_VAL(0x10, 31),
  41. .ndiv_int = REG_VAL(0x10, 20, 10),
  42. .ndiv_frac = REG_VAL(0x10, 0, 20),
  43. .pdiv = REG_VAL(0x14, 0, 4),
  44. .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
  45. .status = REG_VAL(0x28, 12, 1),
  46. };
  47. static const struct iproc_clk_ctrl genpll_clk[] = {
  48. [BCM_CYGNUS_GENPLL_AXI21_CLK] = {
  49. .channel = BCM_CYGNUS_GENPLL_AXI21_CLK,
  50. .flags = IPROC_CLK_AON,
  51. .enable = ENABLE_VAL(0x4, 6, 0, 12),
  52. .mdiv = REG_VAL(0x20, 0, 8),
  53. },
  54. [BCM_CYGNUS_GENPLL_250MHZ_CLK] = {
  55. .channel = BCM_CYGNUS_GENPLL_250MHZ_CLK,
  56. .flags = IPROC_CLK_AON,
  57. .enable = ENABLE_VAL(0x4, 7, 1, 13),
  58. .mdiv = REG_VAL(0x20, 10, 8),
  59. },
  60. [BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = {
  61. .channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK,
  62. .flags = IPROC_CLK_AON,
  63. .enable = ENABLE_VAL(0x4, 8, 2, 14),
  64. .mdiv = REG_VAL(0x20, 20, 8),
  65. },
  66. [BCM_CYGNUS_GENPLL_ENET_SW_CLK] = {
  67. .channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK,
  68. .flags = IPROC_CLK_AON,
  69. .enable = ENABLE_VAL(0x4, 9, 3, 15),
  70. .mdiv = REG_VAL(0x24, 0, 8),
  71. },
  72. [BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = {
  73. .channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK,
  74. .flags = IPROC_CLK_AON,
  75. .enable = ENABLE_VAL(0x4, 10, 4, 16),
  76. .mdiv = REG_VAL(0x24, 10, 8),
  77. },
  78. [BCM_CYGNUS_GENPLL_CAN_CLK] = {
  79. .channel = BCM_CYGNUS_GENPLL_CAN_CLK,
  80. .flags = IPROC_CLK_AON,
  81. .enable = ENABLE_VAL(0x4, 11, 5, 17),
  82. .mdiv = REG_VAL(0x24, 20, 8),
  83. },
  84. };
  85. static void __init cygnus_genpll_clk_init(struct device_node *node)
  86. {
  87. iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk,
  88. ARRAY_SIZE(genpll_clk));
  89. }
  90. CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init);
  91. static const struct iproc_pll_ctrl lcpll0 = {
  92. .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
  93. .aon = AON_VAL(0x0, 2, 5, 4),
  94. .reset = RESET_VAL(0x0, 31, 30),
  95. .dig_filter = DF_VAL(0x0, 27, 3, 23, 4, 19, 4),
  96. .sw_ctrl = SW_CTRL_VAL(0x4, 31),
  97. .ndiv_int = REG_VAL(0x4, 16, 10),
  98. .pdiv = REG_VAL(0x4, 26, 4),
  99. .vco_ctrl = VCO_CTRL_VAL(0x10, 0x14),
  100. .status = REG_VAL(0x18, 12, 1),
  101. };
  102. static const struct iproc_clk_ctrl lcpll0_clk[] = {
  103. [BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = {
  104. .channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK,
  105. .flags = IPROC_CLK_AON,
  106. .enable = ENABLE_VAL(0x0, 7, 1, 13),
  107. .mdiv = REG_VAL(0x8, 0, 8),
  108. },
  109. [BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = {
  110. .channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK,
  111. .flags = IPROC_CLK_AON,
  112. .enable = ENABLE_VAL(0x0, 8, 2, 14),
  113. .mdiv = REG_VAL(0x8, 10, 8),
  114. },
  115. [BCM_CYGNUS_LCPLL0_SDIO_CLK] = {
  116. .channel = BCM_CYGNUS_LCPLL0_SDIO_CLK,
  117. .flags = IPROC_CLK_AON,
  118. .enable = ENABLE_VAL(0x0, 9, 3, 15),
  119. .mdiv = REG_VAL(0x8, 20, 8),
  120. },
  121. [BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = {
  122. .channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK,
  123. .flags = IPROC_CLK_AON,
  124. .enable = ENABLE_VAL(0x0, 10, 4, 16),
  125. .mdiv = REG_VAL(0xc, 0, 8),
  126. },
  127. [BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = {
  128. .channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK,
  129. .flags = IPROC_CLK_AON,
  130. .enable = ENABLE_VAL(0x0, 11, 5, 17),
  131. .mdiv = REG_VAL(0xc, 10, 8),
  132. },
  133. [BCM_CYGNUS_LCPLL0_CH5_UNUSED] = {
  134. .channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED,
  135. .flags = IPROC_CLK_AON,
  136. .enable = ENABLE_VAL(0x0, 12, 6, 18),
  137. .mdiv = REG_VAL(0xc, 20, 8),
  138. },
  139. };
  140. static void __init cygnus_lcpll0_clk_init(struct device_node *node)
  141. {
  142. iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
  143. ARRAY_SIZE(lcpll0_clk));
  144. }
  145. CLK_OF_DECLARE(cygnus_lcpll0, "brcm,cygnus-lcpll0", cygnus_lcpll0_clk_init);
  146. /*
  147. * MIPI PLL VCO frequency parameter table
  148. */
  149. static const struct iproc_pll_vco_param mipipll_vco_params[] = {
  150. /* rate (Hz) ndiv_int ndiv_frac pdiv */
  151. { 750000000UL, 30, 0, 1 },
  152. { 1000000000UL, 40, 0, 1 },
  153. { 1350000000ul, 54, 0, 1 },
  154. { 2000000000UL, 80, 0, 1 },
  155. { 2100000000UL, 84, 0, 1 },
  156. { 2250000000UL, 90, 0, 1 },
  157. { 2500000000UL, 100, 0, 1 },
  158. { 2700000000UL, 54, 0, 0 },
  159. { 2975000000UL, 119, 0, 1 },
  160. { 3100000000UL, 124, 0, 1 },
  161. { 3150000000UL, 126, 0, 1 },
  162. };
  163. static const struct iproc_pll_ctrl mipipll = {
  164. .flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC |
  165. IPROC_CLK_NEEDS_READ_BACK,
  166. .aon = AON_VAL(0x0, 4, 17, 16),
  167. .asiu = ASIU_GATE_VAL(0x0, 3),
  168. .reset = RESET_VAL(0x0, 11, 10),
  169. .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 4),
  170. .ndiv_int = REG_VAL(0x10, 20, 10),
  171. .ndiv_frac = REG_VAL(0x10, 0, 20),
  172. .pdiv = REG_VAL(0x14, 0, 4),
  173. .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
  174. .status = REG_VAL(0x28, 12, 1),
  175. };
  176. static const struct iproc_clk_ctrl mipipll_clk[] = {
  177. [BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = {
  178. .channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED,
  179. .flags = IPROC_CLK_NEEDS_READ_BACK,
  180. .enable = ENABLE_VAL(0x4, 12, 6, 18),
  181. .mdiv = REG_VAL(0x20, 0, 8),
  182. },
  183. [BCM_CYGNUS_MIPIPLL_CH1_LCD] = {
  184. .channel = BCM_CYGNUS_MIPIPLL_CH1_LCD,
  185. .flags = IPROC_CLK_NEEDS_READ_BACK,
  186. .enable = ENABLE_VAL(0x4, 13, 7, 19),
  187. .mdiv = REG_VAL(0x20, 10, 8),
  188. },
  189. [BCM_CYGNUS_MIPIPLL_CH2_V3D] = {
  190. .channel = BCM_CYGNUS_MIPIPLL_CH2_V3D,
  191. .flags = IPROC_CLK_NEEDS_READ_BACK,
  192. .enable = ENABLE_VAL(0x4, 14, 8, 20),
  193. .mdiv = REG_VAL(0x20, 20, 8),
  194. },
  195. [BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = {
  196. .channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED,
  197. .flags = IPROC_CLK_NEEDS_READ_BACK,
  198. .enable = ENABLE_VAL(0x4, 15, 9, 21),
  199. .mdiv = REG_VAL(0x24, 0, 8),
  200. },
  201. [BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = {
  202. .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED,
  203. .flags = IPROC_CLK_NEEDS_READ_BACK,
  204. .enable = ENABLE_VAL(0x4, 16, 10, 22),
  205. .mdiv = REG_VAL(0x24, 10, 8),
  206. },
  207. [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = {
  208. .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED,
  209. .flags = IPROC_CLK_NEEDS_READ_BACK,
  210. .enable = ENABLE_VAL(0x4, 17, 11, 23),
  211. .mdiv = REG_VAL(0x24, 20, 8),
  212. },
  213. };
  214. static void __init cygnus_mipipll_clk_init(struct device_node *node)
  215. {
  216. iproc_pll_clk_setup(node, &mipipll, mipipll_vco_params,
  217. ARRAY_SIZE(mipipll_vco_params), mipipll_clk,
  218. ARRAY_SIZE(mipipll_clk));
  219. }
  220. CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init);
  221. static const struct iproc_asiu_div asiu_div[] = {
  222. [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_DIV_VAL(0x0, 31, 16, 10, 0, 10),
  223. [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_DIV_VAL(0x4, 31, 16, 10, 0, 10),
  224. [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_DIV_VAL(0x8, 31, 16, 10, 0, 10),
  225. };
  226. static const struct iproc_asiu_gate asiu_gate[] = {
  227. [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_GATE_VAL(0x0, 7),
  228. [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_GATE_VAL(0x0, 9),
  229. [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_GATE_VAL(IPROC_CLK_INVALID_OFFSET, 0),
  230. };
  231. static void __init cygnus_asiu_init(struct device_node *node)
  232. {
  233. iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div));
  234. }
  235. CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init);
  236. static const struct iproc_pll_ctrl audiopll = {
  237. .flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC |
  238. IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW |
  239. IPROC_CLK_PLL_CALC_PARAM,
  240. .reset = RESET_VAL(0x5c, 0, 1),
  241. .dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3),
  242. .sw_ctrl = SW_CTRL_VAL(0x4, 0),
  243. .ndiv_int = REG_VAL(0x8, 0, 10),
  244. .ndiv_frac = REG_VAL(0x8, 10, 20),
  245. .pdiv = REG_VAL(0x44, 0, 4),
  246. .vco_ctrl = VCO_CTRL_VAL(0x0c, 0x10),
  247. .status = REG_VAL(0x54, 0, 1),
  248. .macro_mode = REG_VAL(0x0, 0, 3),
  249. };
  250. static const struct iproc_clk_ctrl audiopll_clk[] = {
  251. [BCM_CYGNUS_AUDIOPLL_CH0] = {
  252. .channel = BCM_CYGNUS_AUDIOPLL_CH0,
  253. .flags = IPROC_CLK_AON | IPROC_CLK_MCLK_DIV_BY_2,
  254. .enable = ENABLE_VAL(0x14, 8, 10, 9),
  255. .mdiv = REG_VAL(0x14, 0, 8),
  256. },
  257. [BCM_CYGNUS_AUDIOPLL_CH1] = {
  258. .channel = BCM_CYGNUS_AUDIOPLL_CH1,
  259. .flags = IPROC_CLK_AON,
  260. .enable = ENABLE_VAL(0x18, 8, 10, 9),
  261. .mdiv = REG_VAL(0x18, 0, 8),
  262. },
  263. [BCM_CYGNUS_AUDIOPLL_CH2] = {
  264. .channel = BCM_CYGNUS_AUDIOPLL_CH2,
  265. .flags = IPROC_CLK_AON,
  266. .enable = ENABLE_VAL(0x1c, 8, 10, 9),
  267. .mdiv = REG_VAL(0x1c, 0, 8),
  268. },
  269. };
  270. static void __init cygnus_audiopll_clk_init(struct device_node *node)
  271. {
  272. iproc_pll_clk_setup(node, &audiopll, NULL, 0,
  273. audiopll_clk, ARRAY_SIZE(audiopll_clk));
  274. }
  275. CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll",
  276. cygnus_audiopll_clk_init);