blob: d900d4cd528642f1508050bb7d0deb27a3a82987 [file] [log] [blame]
Peng Fan6a8e5f92019-03-05 02:32:33 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 NXP
4 * Peng Fan <peng.fan@nxp.com>
5 */
6
7#include <common.h>
8#include <clk-uclass.h>
9#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Peng Fan2e0644a2023-04-28 12:08:09 +080011#include <firmware/imx/sci/sci.h>
Peng Fan6a8e5f92019-03-05 02:32:33 +000012#include <asm/arch/clock.h>
13#include <dt-bindings/clock/imx8qxp-clock.h>
14#include <dt-bindings/soc/imx_rsrc.h>
15#include <misc.h>
16
17#include "clk-imx8.h"
18
Simon Glass495e80f2023-02-05 15:36:26 -070019#if IS_ENABLED(CONFIG_CMD_CLK)
Peng Fan6a8e5f92019-03-05 02:32:33 +000020struct imx8_clks imx8_clk_names[] = {
21 { IMX8QXP_A35_DIV, "A35_DIV" },
22 { IMX8QXP_I2C0_CLK, "I2C0" },
23 { IMX8QXP_I2C1_CLK, "I2C1" },
24 { IMX8QXP_I2C2_CLK, "I2C2" },
25 { IMX8QXP_I2C3_CLK, "I2C3" },
26 { IMX8QXP_UART0_CLK, "UART0" },
27 { IMX8QXP_UART1_CLK, "UART1" },
28 { IMX8QXP_UART2_CLK, "UART2" },
29 { IMX8QXP_UART3_CLK, "UART3" },
30 { IMX8QXP_SDHC0_CLK, "SDHC0" },
31 { IMX8QXP_SDHC1_CLK, "SDHC1" },
32 { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
33 { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
34 { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
35 { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
36 { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
37 { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
38 { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
39 { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
40};
41
42int num_clks = ARRAY_SIZE(imx8_clk_names);
43#endif
44
45ulong imx8_clk_get_rate(struct clk *clk)
46{
47 sc_pm_clk_t pm_clk;
48 ulong rate;
49 u16 resource;
50 int ret;
51
52 debug("%s(#%lu)\n", __func__, clk->id);
53
54 switch (clk->id) {
55 case IMX8QXP_A35_DIV:
56 resource = SC_R_A35;
57 pm_clk = SC_PM_CLK_CPU;
58 break;
59 case IMX8QXP_I2C0_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +010060 case IMX8QXP_I2C0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000061 resource = SC_R_I2C_0;
62 pm_clk = SC_PM_CLK_PER;
63 break;
64 case IMX8QXP_I2C1_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +010065 case IMX8QXP_I2C1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000066 resource = SC_R_I2C_1;
67 pm_clk = SC_PM_CLK_PER;
68 break;
69 case IMX8QXP_I2C2_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +010070 case IMX8QXP_I2C2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000071 resource = SC_R_I2C_2;
72 pm_clk = SC_PM_CLK_PER;
73 break;
74 case IMX8QXP_I2C3_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +010075 case IMX8QXP_I2C3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000076 resource = SC_R_I2C_3;
77 pm_clk = SC_PM_CLK_PER;
78 break;
79 case IMX8QXP_SDHC0_IPG_CLK:
80 case IMX8QXP_SDHC0_CLK:
81 case IMX8QXP_SDHC0_DIV:
82 resource = SC_R_SDHC_0;
83 pm_clk = SC_PM_CLK_PER;
84 break;
85 case IMX8QXP_SDHC1_IPG_CLK:
86 case IMX8QXP_SDHC1_CLK:
87 case IMX8QXP_SDHC1_DIV:
88 resource = SC_R_SDHC_1;
89 pm_clk = SC_PM_CLK_PER;
90 break;
Peng Fan6a8e5f92019-03-05 02:32:33 +000091 case IMX8QXP_UART0_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -030092 case IMX8QXP_UART0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000093 resource = SC_R_UART_0;
94 pm_clk = SC_PM_CLK_PER;
95 break;
96 case IMX8QXP_UART1_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -030097 case IMX8QXP_UART1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +000098 resource = SC_R_UART_1;
99 pm_clk = SC_PM_CLK_PER;
100 break;
101 case IMX8QXP_UART2_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300102 case IMX8QXP_UART2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000103 resource = SC_R_UART_2;
104 pm_clk = SC_PM_CLK_PER;
105 break;
106 case IMX8QXP_UART3_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300107 case IMX8QXP_UART3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000108 resource = SC_R_UART_3;
109 pm_clk = SC_PM_CLK_PER;
110 break;
111 case IMX8QXP_ENET0_IPG_CLK:
112 case IMX8QXP_ENET0_AHB_CLK:
113 case IMX8QXP_ENET0_REF_DIV:
114 case IMX8QXP_ENET0_PTP_CLK:
115 resource = SC_R_ENET_0;
116 pm_clk = SC_PM_CLK_PER;
117 break;
118 case IMX8QXP_ENET1_IPG_CLK:
119 case IMX8QXP_ENET1_AHB_CLK:
120 case IMX8QXP_ENET1_REF_DIV:
121 case IMX8QXP_ENET1_PTP_CLK:
122 resource = SC_R_ENET_1;
123 pm_clk = SC_PM_CLK_PER;
124 break;
125 default:
126 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
127 clk->id >= IMX8QXP_CLK_END) {
128 printf("%s(Invalid clk ID #%lu)\n",
129 __func__, clk->id);
130 return -EINVAL;
131 }
Simon Glass29ff16a2021-03-25 10:26:08 +1300132 return -EINVAL;
Peng Fan6a8e5f92019-03-05 02:32:33 +0000133 };
134
135 ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
136 (sc_pm_clock_rate_t *)&rate);
137 if (ret) {
138 printf("%s err %d\n", __func__, ret);
139 return ret;
140 }
141
142 return rate;
143}
144
145ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
146{
147 sc_pm_clk_t pm_clk;
148 u32 new_rate = rate;
149 u16 resource;
150 int ret;
151
152 debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
153
154 switch (clk->id) {
155 case IMX8QXP_I2C0_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100156 case IMX8QXP_I2C0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000157 resource = SC_R_I2C_0;
158 pm_clk = SC_PM_CLK_PER;
159 break;
160 case IMX8QXP_I2C1_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100161 case IMX8QXP_I2C1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000162 resource = SC_R_I2C_1;
163 pm_clk = SC_PM_CLK_PER;
164 break;
165 case IMX8QXP_I2C2_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100166 case IMX8QXP_I2C2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000167 resource = SC_R_I2C_2;
168 pm_clk = SC_PM_CLK_PER;
169 break;
170 case IMX8QXP_I2C3_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100171 case IMX8QXP_I2C3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000172 resource = SC_R_I2C_3;
173 pm_clk = SC_PM_CLK_PER;
174 break;
175 case IMX8QXP_UART0_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300176 case IMX8QXP_UART0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000177 resource = SC_R_UART_0;
178 pm_clk = SC_PM_CLK_PER;
179 break;
180 case IMX8QXP_UART1_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300181 case IMX8QXP_UART1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000182 resource = SC_R_UART_1;
183 pm_clk = SC_PM_CLK_PER;
184 break;
185 case IMX8QXP_UART2_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300186 case IMX8QXP_UART2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000187 resource = SC_R_UART_2;
188 pm_clk = SC_PM_CLK_PER;
189 break;
190 case IMX8QXP_UART3_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300191 case IMX8QXP_UART3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000192 resource = SC_R_UART_3;
193 pm_clk = SC_PM_CLK_PER;
194 break;
195 case IMX8QXP_SDHC0_IPG_CLK:
196 case IMX8QXP_SDHC0_CLK:
197 case IMX8QXP_SDHC0_DIV:
198 resource = SC_R_SDHC_0;
199 pm_clk = SC_PM_CLK_PER;
200 break;
201 case IMX8QXP_SDHC1_SEL:
202 case IMX8QXP_SDHC0_SEL:
203 return 0;
204 case IMX8QXP_SDHC1_IPG_CLK:
205 case IMX8QXP_SDHC1_CLK:
206 case IMX8QXP_SDHC1_DIV:
207 resource = SC_R_SDHC_1;
208 pm_clk = SC_PM_CLK_PER;
209 break;
210 case IMX8QXP_ENET0_IPG_CLK:
211 case IMX8QXP_ENET0_AHB_CLK:
212 case IMX8QXP_ENET0_REF_DIV:
213 case IMX8QXP_ENET0_PTP_CLK:
214 resource = SC_R_ENET_0;
215 pm_clk = SC_PM_CLK_PER;
216 break;
217 case IMX8QXP_ENET1_IPG_CLK:
218 case IMX8QXP_ENET1_AHB_CLK:
219 case IMX8QXP_ENET1_REF_DIV:
220 case IMX8QXP_ENET1_PTP_CLK:
221 resource = SC_R_ENET_1;
222 pm_clk = SC_PM_CLK_PER;
223 break;
224 default:
225 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
226 clk->id >= IMX8QXP_CLK_END) {
227 printf("%s(Invalid clk ID #%lu)\n",
228 __func__, clk->id);
229 return -EINVAL;
230 }
Simon Glass29ff16a2021-03-25 10:26:08 +1300231 return -EINVAL;
Peng Fan6a8e5f92019-03-05 02:32:33 +0000232 };
233
234 ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
235 if (ret) {
236 printf("%s err %d\n", __func__, ret);
237 return ret;
238 }
239
240 return new_rate;
241}
242
243int __imx8_clk_enable(struct clk *clk, bool enable)
244{
245 sc_pm_clk_t pm_clk;
246 u16 resource;
247 int ret;
248
249 debug("%s(#%lu)\n", __func__, clk->id);
250
251 switch (clk->id) {
252 case IMX8QXP_I2C0_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100253 case IMX8QXP_I2C0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000254 resource = SC_R_I2C_0;
255 pm_clk = SC_PM_CLK_PER;
256 break;
257 case IMX8QXP_I2C1_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100258 case IMX8QXP_I2C1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000259 resource = SC_R_I2C_1;
260 pm_clk = SC_PM_CLK_PER;
261 break;
262 case IMX8QXP_I2C2_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100263 case IMX8QXP_I2C2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000264 resource = SC_R_I2C_2;
265 pm_clk = SC_PM_CLK_PER;
266 break;
267 case IMX8QXP_I2C3_CLK:
Anatolij Gustschinb9a1e512020-01-07 14:03:03 +0100268 case IMX8QXP_I2C3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000269 resource = SC_R_I2C_3;
270 pm_clk = SC_PM_CLK_PER;
271 break;
272 case IMX8QXP_UART0_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300273 case IMX8QXP_UART0_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000274 resource = SC_R_UART_0;
275 pm_clk = SC_PM_CLK_PER;
276 break;
277 case IMX8QXP_UART1_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300278 case IMX8QXP_UART1_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000279 resource = SC_R_UART_1;
280 pm_clk = SC_PM_CLK_PER;
281 break;
282 case IMX8QXP_UART2_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300283 case IMX8QXP_UART2_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000284 resource = SC_R_UART_2;
285 pm_clk = SC_PM_CLK_PER;
286 break;
287 case IMX8QXP_UART3_CLK:
Fabio Estevamb08666d2024-03-08 17:13:15 -0300288 case IMX8QXP_UART3_IPG_CLK:
Peng Fan6a8e5f92019-03-05 02:32:33 +0000289 resource = SC_R_UART_3;
290 pm_clk = SC_PM_CLK_PER;
291 break;
292 case IMX8QXP_SDHC0_IPG_CLK:
293 case IMX8QXP_SDHC0_CLK:
294 case IMX8QXP_SDHC0_DIV:
295 resource = SC_R_SDHC_0;
296 pm_clk = SC_PM_CLK_PER;
297 break;
298 case IMX8QXP_SDHC1_IPG_CLK:
299 case IMX8QXP_SDHC1_CLK:
300 case IMX8QXP_SDHC1_DIV:
301 resource = SC_R_SDHC_1;
302 pm_clk = SC_PM_CLK_PER;
303 break;
304 case IMX8QXP_ENET0_IPG_CLK:
305 case IMX8QXP_ENET0_AHB_CLK:
306 case IMX8QXP_ENET0_REF_DIV:
307 case IMX8QXP_ENET0_PTP_CLK:
308 resource = SC_R_ENET_0;
309 pm_clk = SC_PM_CLK_PER;
310 break;
311 case IMX8QXP_ENET1_IPG_CLK:
312 case IMX8QXP_ENET1_AHB_CLK:
313 case IMX8QXP_ENET1_REF_DIV:
314 case IMX8QXP_ENET1_PTP_CLK:
315 resource = SC_R_ENET_1;
316 pm_clk = SC_PM_CLK_PER;
317 break;
318 default:
319 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
320 clk->id >= IMX8QXP_CLK_END) {
321 printf("%s(Invalid clk ID #%lu)\n",
322 __func__, clk->id);
323 return -EINVAL;
324 }
Simon Glass29ff16a2021-03-25 10:26:08 +1300325 return -EINVAL;
Peng Fan6a8e5f92019-03-05 02:32:33 +0000326 }
327
328 ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
329 if (ret) {
330 printf("%s err %d\n", __func__, ret);
331 return ret;
332 }
333
334 return 0;
335}