clk-imx8.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2018 NXP
  4. * Peng Fan <peng.fan@nxp.com>
  5. */
  6. #include <common.h>
  7. #include <clk-uclass.h>
  8. #include <dm.h>
  9. #include <asm/arch/sci/sci.h>
  10. #include <asm/arch/clock.h>
  11. #include <dt-bindings/clock/imx8qxp-clock.h>
  12. #include <dt-bindings/soc/imx_rsrc.h>
  13. #include <misc.h>
  14. struct imx8_clks {
  15. ulong id;
  16. const char *name;
  17. };
  18. static struct imx8_clks imx8_clk_names[] = {
  19. { IMX8QXP_A35_DIV, "A35_DIV" },
  20. { IMX8QXP_I2C0_CLK, "I2C0" },
  21. { IMX8QXP_I2C1_CLK, "I2C1" },
  22. { IMX8QXP_I2C2_CLK, "I2C2" },
  23. { IMX8QXP_I2C3_CLK, "I2C3" },
  24. { IMX8QXP_UART0_CLK, "UART0" },
  25. { IMX8QXP_UART1_CLK, "UART1" },
  26. { IMX8QXP_UART2_CLK, "UART2" },
  27. { IMX8QXP_UART3_CLK, "UART3" },
  28. { IMX8QXP_SDHC0_CLK, "SDHC0" },
  29. { IMX8QXP_SDHC1_CLK, "SDHC1" },
  30. { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
  31. { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
  32. { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
  33. { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
  34. { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
  35. { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
  36. { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
  37. { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
  38. };
  39. static ulong imx8_clk_get_rate(struct clk *clk)
  40. {
  41. sc_pm_clk_t pm_clk;
  42. ulong rate;
  43. u16 resource;
  44. int ret;
  45. debug("%s(#%lu)\n", __func__, clk->id);
  46. switch (clk->id) {
  47. case IMX8QXP_A35_DIV:
  48. resource = SC_R_A35;
  49. pm_clk = SC_PM_CLK_CPU;
  50. break;
  51. case IMX8QXP_I2C0_CLK:
  52. resource = SC_R_I2C_0;
  53. pm_clk = SC_PM_CLK_PER;
  54. break;
  55. case IMX8QXP_I2C1_CLK:
  56. resource = SC_R_I2C_1;
  57. pm_clk = SC_PM_CLK_PER;
  58. break;
  59. case IMX8QXP_I2C2_CLK:
  60. resource = SC_R_I2C_2;
  61. pm_clk = SC_PM_CLK_PER;
  62. break;
  63. case IMX8QXP_I2C3_CLK:
  64. resource = SC_R_I2C_3;
  65. pm_clk = SC_PM_CLK_PER;
  66. break;
  67. case IMX8QXP_SDHC0_IPG_CLK:
  68. case IMX8QXP_SDHC0_CLK:
  69. case IMX8QXP_SDHC0_DIV:
  70. resource = SC_R_SDHC_0;
  71. pm_clk = SC_PM_CLK_PER;
  72. break;
  73. case IMX8QXP_SDHC1_IPG_CLK:
  74. case IMX8QXP_SDHC1_CLK:
  75. case IMX8QXP_SDHC1_DIV:
  76. resource = SC_R_SDHC_1;
  77. pm_clk = SC_PM_CLK_PER;
  78. break;
  79. case IMX8QXP_UART0_IPG_CLK:
  80. case IMX8QXP_UART0_CLK:
  81. resource = SC_R_UART_0;
  82. pm_clk = SC_PM_CLK_PER;
  83. break;
  84. case IMX8QXP_UART1_CLK:
  85. resource = SC_R_UART_1;
  86. pm_clk = SC_PM_CLK_PER;
  87. break;
  88. case IMX8QXP_UART2_CLK:
  89. resource = SC_R_UART_2;
  90. pm_clk = SC_PM_CLK_PER;
  91. break;
  92. case IMX8QXP_UART3_CLK:
  93. resource = SC_R_UART_3;
  94. pm_clk = SC_PM_CLK_PER;
  95. break;
  96. case IMX8QXP_ENET0_IPG_CLK:
  97. case IMX8QXP_ENET0_AHB_CLK:
  98. case IMX8QXP_ENET0_REF_DIV:
  99. case IMX8QXP_ENET0_PTP_CLK:
  100. resource = SC_R_ENET_0;
  101. pm_clk = SC_PM_CLK_PER;
  102. break;
  103. case IMX8QXP_ENET1_IPG_CLK:
  104. case IMX8QXP_ENET1_AHB_CLK:
  105. case IMX8QXP_ENET1_REF_DIV:
  106. case IMX8QXP_ENET1_PTP_CLK:
  107. resource = SC_R_ENET_1;
  108. pm_clk = SC_PM_CLK_PER;
  109. break;
  110. default:
  111. if (clk->id < IMX8QXP_UART0_IPG_CLK ||
  112. clk->id >= IMX8QXP_CLK_END) {
  113. printf("%s(Invalid clk ID #%lu)\n",
  114. __func__, clk->id);
  115. return -EINVAL;
  116. }
  117. return -ENOTSUPP;
  118. };
  119. ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
  120. (sc_pm_clock_rate_t *)&rate);
  121. if (ret) {
  122. printf("%s err %d\n", __func__, ret);
  123. return ret;
  124. }
  125. return rate;
  126. }
  127. static ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
  128. {
  129. sc_pm_clk_t pm_clk;
  130. u32 new_rate = rate;
  131. u16 resource;
  132. int ret;
  133. debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
  134. switch (clk->id) {
  135. case IMX8QXP_I2C0_CLK:
  136. resource = SC_R_I2C_0;
  137. pm_clk = SC_PM_CLK_PER;
  138. break;
  139. case IMX8QXP_I2C1_CLK:
  140. resource = SC_R_I2C_1;
  141. pm_clk = SC_PM_CLK_PER;
  142. break;
  143. case IMX8QXP_I2C2_CLK:
  144. resource = SC_R_I2C_2;
  145. pm_clk = SC_PM_CLK_PER;
  146. break;
  147. case IMX8QXP_I2C3_CLK:
  148. resource = SC_R_I2C_3;
  149. pm_clk = SC_PM_CLK_PER;
  150. break;
  151. case IMX8QXP_UART0_CLK:
  152. resource = SC_R_UART_0;
  153. pm_clk = SC_PM_CLK_PER;
  154. break;
  155. case IMX8QXP_UART1_CLK:
  156. resource = SC_R_UART_1;
  157. pm_clk = SC_PM_CLK_PER;
  158. break;
  159. case IMX8QXP_UART2_CLK:
  160. resource = SC_R_UART_2;
  161. pm_clk = SC_PM_CLK_PER;
  162. break;
  163. case IMX8QXP_UART3_CLK:
  164. resource = SC_R_UART_3;
  165. pm_clk = SC_PM_CLK_PER;
  166. break;
  167. case IMX8QXP_SDHC0_IPG_CLK:
  168. case IMX8QXP_SDHC0_CLK:
  169. case IMX8QXP_SDHC0_DIV:
  170. resource = SC_R_SDHC_0;
  171. pm_clk = SC_PM_CLK_PER;
  172. break;
  173. case IMX8QXP_SDHC1_SEL:
  174. case IMX8QXP_SDHC0_SEL:
  175. return 0;
  176. case IMX8QXP_SDHC1_IPG_CLK:
  177. case IMX8QXP_SDHC1_CLK:
  178. case IMX8QXP_SDHC1_DIV:
  179. resource = SC_R_SDHC_1;
  180. pm_clk = SC_PM_CLK_PER;
  181. break;
  182. case IMX8QXP_ENET0_IPG_CLK:
  183. case IMX8QXP_ENET0_AHB_CLK:
  184. case IMX8QXP_ENET0_REF_DIV:
  185. case IMX8QXP_ENET0_PTP_CLK:
  186. resource = SC_R_ENET_0;
  187. pm_clk = SC_PM_CLK_PER;
  188. break;
  189. case IMX8QXP_ENET1_IPG_CLK:
  190. case IMX8QXP_ENET1_AHB_CLK:
  191. case IMX8QXP_ENET1_REF_DIV:
  192. case IMX8QXP_ENET1_PTP_CLK:
  193. resource = SC_R_ENET_1;
  194. pm_clk = SC_PM_CLK_PER;
  195. break;
  196. default:
  197. if (clk->id < IMX8QXP_UART0_IPG_CLK ||
  198. clk->id >= IMX8QXP_CLK_END) {
  199. printf("%s(Invalid clk ID #%lu)\n",
  200. __func__, clk->id);
  201. return -EINVAL;
  202. }
  203. return -ENOTSUPP;
  204. };
  205. ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
  206. if (ret) {
  207. printf("%s err %d\n", __func__, ret);
  208. return ret;
  209. }
  210. return new_rate;
  211. }
  212. static int __imx8_clk_enable(struct clk *clk, bool enable)
  213. {
  214. sc_pm_clk_t pm_clk;
  215. u16 resource;
  216. int ret;
  217. debug("%s(#%lu)\n", __func__, clk->id);
  218. switch (clk->id) {
  219. case IMX8QXP_I2C0_CLK:
  220. resource = SC_R_I2C_0;
  221. pm_clk = SC_PM_CLK_PER;
  222. break;
  223. case IMX8QXP_I2C1_CLK:
  224. resource = SC_R_I2C_1;
  225. pm_clk = SC_PM_CLK_PER;
  226. break;
  227. case IMX8QXP_I2C2_CLK:
  228. resource = SC_R_I2C_2;
  229. pm_clk = SC_PM_CLK_PER;
  230. break;
  231. case IMX8QXP_I2C3_CLK:
  232. resource = SC_R_I2C_3;
  233. pm_clk = SC_PM_CLK_PER;
  234. break;
  235. case IMX8QXP_UART0_CLK:
  236. resource = SC_R_UART_0;
  237. pm_clk = SC_PM_CLK_PER;
  238. break;
  239. case IMX8QXP_UART1_CLK:
  240. resource = SC_R_UART_1;
  241. pm_clk = SC_PM_CLK_PER;
  242. break;
  243. case IMX8QXP_UART2_CLK:
  244. resource = SC_R_UART_2;
  245. pm_clk = SC_PM_CLK_PER;
  246. break;
  247. case IMX8QXP_UART3_CLK:
  248. resource = SC_R_UART_3;
  249. pm_clk = SC_PM_CLK_PER;
  250. break;
  251. case IMX8QXP_SDHC0_IPG_CLK:
  252. case IMX8QXP_SDHC0_CLK:
  253. case IMX8QXP_SDHC0_DIV:
  254. resource = SC_R_SDHC_0;
  255. pm_clk = SC_PM_CLK_PER;
  256. break;
  257. case IMX8QXP_SDHC1_IPG_CLK:
  258. case IMX8QXP_SDHC1_CLK:
  259. case IMX8QXP_SDHC1_DIV:
  260. resource = SC_R_SDHC_1;
  261. pm_clk = SC_PM_CLK_PER;
  262. break;
  263. case IMX8QXP_ENET0_IPG_CLK:
  264. case IMX8QXP_ENET0_AHB_CLK:
  265. case IMX8QXP_ENET0_REF_DIV:
  266. case IMX8QXP_ENET0_PTP_CLK:
  267. resource = SC_R_ENET_0;
  268. pm_clk = SC_PM_CLK_PER;
  269. break;
  270. case IMX8QXP_ENET1_IPG_CLK:
  271. case IMX8QXP_ENET1_AHB_CLK:
  272. case IMX8QXP_ENET1_REF_DIV:
  273. case IMX8QXP_ENET1_PTP_CLK:
  274. resource = SC_R_ENET_1;
  275. pm_clk = SC_PM_CLK_PER;
  276. break;
  277. default:
  278. if (clk->id < IMX8QXP_UART0_IPG_CLK ||
  279. clk->id >= IMX8QXP_CLK_END) {
  280. printf("%s(Invalid clk ID #%lu)\n",
  281. __func__, clk->id);
  282. return -EINVAL;
  283. }
  284. return -ENOTSUPP;
  285. }
  286. ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
  287. if (ret) {
  288. printf("%s err %d\n", __func__, ret);
  289. return ret;
  290. }
  291. return 0;
  292. }
  293. static int imx8_clk_disable(struct clk *clk)
  294. {
  295. return __imx8_clk_enable(clk, 0);
  296. }
  297. static int imx8_clk_enable(struct clk *clk)
  298. {
  299. return __imx8_clk_enable(clk, 1);
  300. }
  301. #if CONFIG_IS_ENABLED(CMD_CLK)
  302. int soc_clk_dump(void)
  303. {
  304. struct udevice *dev;
  305. struct clk clk;
  306. unsigned long rate;
  307. int i, ret;
  308. ret = uclass_get_device_by_driver(UCLASS_CLK,
  309. DM_GET_DRIVER(imx8_clk), &dev);
  310. if (ret)
  311. return ret;
  312. printf("Clk\t\tHz\n");
  313. for (i = 0; i < ARRAY_SIZE(imx8_clk_names); i++) {
  314. clk.id = imx8_clk_names[i].id;
  315. ret = clk_request(dev, &clk);
  316. if (ret < 0) {
  317. debug("%s clk_request() failed: %d\n", __func__, ret);
  318. continue;
  319. }
  320. ret = clk_get_rate(&clk);
  321. rate = ret;
  322. clk_free(&clk);
  323. if (ret == -ENOTSUPP) {
  324. printf("clk ID %lu not supported yet\n",
  325. imx8_clk_names[i].id);
  326. continue;
  327. }
  328. if (ret < 0) {
  329. printf("%s %lu: get_rate err: %d\n",
  330. __func__, imx8_clk_names[i].id, ret);
  331. continue;
  332. }
  333. printf("%s(%3lu):\t%lu\n",
  334. imx8_clk_names[i].name, imx8_clk_names[i].id, rate);
  335. }
  336. return 0;
  337. }
  338. #endif
  339. static struct clk_ops imx8_clk_ops = {
  340. .set_rate = imx8_clk_set_rate,
  341. .get_rate = imx8_clk_get_rate,
  342. .enable = imx8_clk_enable,
  343. .disable = imx8_clk_disable,
  344. };
  345. static int imx8_clk_probe(struct udevice *dev)
  346. {
  347. return 0;
  348. }
  349. static const struct udevice_id imx8_clk_ids[] = {
  350. { .compatible = "fsl,imx8qxp-clk" },
  351. { },
  352. };
  353. U_BOOT_DRIVER(imx8_clk) = {
  354. .name = "clk_imx8",
  355. .id = UCLASS_CLK,
  356. .of_match = imx8_clk_ids,
  357. .ops = &imx8_clk_ops,
  358. .probe = imx8_clk_probe,
  359. .flags = DM_FLAG_PRE_RELOC,
  360. };