1 // 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>
10 #include <log.h>
11 #include <asm/arch/sci/sci.h>
12 #include <asm/arch/clock.h>
13 #include <dt-bindings/clock/imx8qm-clock.h>
14 #include <dt-bindings/soc/imx_rsrc.h>
15 #include <misc.h>
16
17 #include "clk-imx8.h"
18
19 #if CONFIG_IS_ENABLED(CMD_CLK)
20 struct imx8_clks imx8_clk_names[] = {
21 { IMX8QM_A53_DIV, "A53_DIV" },
22 { IMX8QM_UART0_CLK, "UART0" },
23 { IMX8QM_UART1_CLK, "UART1" },
24 { IMX8QM_UART2_CLK, "UART2" },
25 { IMX8QM_UART3_CLK, "UART3" },
26 { IMX8QM_SDHC0_CLK, "SDHC0" },
27 { IMX8QM_SDHC1_CLK, "SDHC1" },
28 { IMX8QM_SDHC2_CLK, "SDHC2" },
29 { IMX8QM_ENET0_AHB_CLK, "ENET0_AHB" },
30 { IMX8QM_ENET0_IPG_CLK, "ENET0_IPG" },
31 { IMX8QM_ENET0_REF_DIV, "ENET0_REF" },
32 { IMX8QM_ENET0_PTP_CLK, "ENET0_PTP" },
33 { IMX8QM_ENET1_AHB_CLK, "ENET1_AHB" },
34 { IMX8QM_ENET1_IPG_CLK, "ENET1_IPG" },
35 { IMX8QM_ENET1_REF_DIV, "ENET1_REF" },
36 { IMX8QM_ENET1_PTP_CLK, "ENET1_PTP" },
37 };
38
39 int num_clks = ARRAY_SIZE(imx8_clk_names);
40 #endif
41
imx8_clk_get_rate(struct clk * clk)42 ulong imx8_clk_get_rate(struct clk *clk)
43 {
44 sc_pm_clk_t pm_clk;
45 ulong rate;
46 u16 resource;
47 int ret;
48
49 debug("%s(#%lu)\n", __func__, clk->id);
50
51 switch (clk->id) {
52 case IMX8QM_A53_DIV:
53 resource = SC_R_A53;
54 pm_clk = SC_PM_CLK_CPU;
55 break;
56 case IMX8QM_I2C0_IPG_CLK:
57 case IMX8QM_I2C0_CLK:
58 case IMX8QM_I2C0_DIV:
59 resource = SC_R_I2C_0;
60 pm_clk = SC_PM_CLK_PER;
61 break;
62 case IMX8QM_I2C1_IPG_CLK:
63 case IMX8QM_I2C1_CLK:
64 case IMX8QM_I2C1_DIV:
65 resource = SC_R_I2C_1;
66 pm_clk = SC_PM_CLK_PER;
67 break;
68 case IMX8QM_I2C2_IPG_CLK:
69 case IMX8QM_I2C2_CLK:
70 case IMX8QM_I2C2_DIV:
71 resource = SC_R_I2C_2;
72 pm_clk = SC_PM_CLK_PER;
73 break;
74 case IMX8QM_I2C3_IPG_CLK:
75 case IMX8QM_I2C3_CLK:
76 case IMX8QM_I2C3_DIV:
77 resource = SC_R_I2C_3;
78 pm_clk = SC_PM_CLK_PER;
79 break;
80 case IMX8QM_SDHC0_IPG_CLK:
81 case IMX8QM_SDHC0_CLK:
82 case IMX8QM_SDHC0_DIV:
83 resource = SC_R_SDHC_0;
84 pm_clk = SC_PM_CLK_PER;
85 break;
86 case IMX8QM_SDHC1_IPG_CLK:
87 case IMX8QM_SDHC1_CLK:
88 case IMX8QM_SDHC1_DIV:
89 resource = SC_R_SDHC_1;
90 pm_clk = SC_PM_CLK_PER;
91 break;
92 case IMX8QM_SDHC2_IPG_CLK:
93 case IMX8QM_SDHC2_CLK:
94 case IMX8QM_SDHC2_DIV:
95 resource = SC_R_SDHC_2;
96 pm_clk = SC_PM_CLK_PER;
97 break;
98 case IMX8QM_UART0_IPG_CLK:
99 case IMX8QM_UART0_CLK:
100 resource = SC_R_UART_0;
101 pm_clk = SC_PM_CLK_PER;
102 break;
103 case IMX8QM_UART1_CLK:
104 resource = SC_R_UART_1;
105 pm_clk = SC_PM_CLK_PER;
106 break;
107 case IMX8QM_UART2_CLK:
108 resource = SC_R_UART_2;
109 pm_clk = SC_PM_CLK_PER;
110 break;
111 case IMX8QM_UART3_CLK:
112 resource = SC_R_UART_3;
113 pm_clk = SC_PM_CLK_PER;
114 break;
115 case IMX8QM_ENET0_IPG_CLK:
116 case IMX8QM_ENET0_AHB_CLK:
117 case IMX8QM_ENET0_REF_DIV:
118 case IMX8QM_ENET0_PTP_CLK:
119 resource = SC_R_ENET_0;
120 pm_clk = SC_PM_CLK_PER;
121 break;
122 case IMX8QM_ENET1_IPG_CLK:
123 case IMX8QM_ENET1_AHB_CLK:
124 case IMX8QM_ENET1_REF_DIV:
125 case IMX8QM_ENET1_PTP_CLK:
126 resource = SC_R_ENET_1;
127 pm_clk = SC_PM_CLK_PER;
128 break;
129 default:
130 if (clk->id < IMX8QM_UART0_IPG_CLK ||
131 clk->id >= IMX8QM_CLK_END) {
132 printf("%s(Invalid clk ID #%lu)\n",
133 __func__, clk->id);
134 return -EINVAL;
135 }
136 return -ENOTSUPP;
137 };
138
139 ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
140 (sc_pm_clock_rate_t *)&rate);
141 if (ret) {
142 printf("%s err %d\n", __func__, ret);
143 return ret;
144 }
145
146 return rate;
147 }
148
imx8_clk_set_rate(struct clk * clk,unsigned long rate)149 ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
150 {
151 sc_pm_clk_t pm_clk;
152 u32 new_rate = rate;
153 u16 resource;
154 int ret;
155
156 debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
157
158 switch (clk->id) {
159 case IMX8QM_I2C0_IPG_CLK:
160 case IMX8QM_I2C0_CLK:
161 case IMX8QM_I2C0_DIV:
162 resource = SC_R_I2C_0;
163 pm_clk = SC_PM_CLK_PER;
164 break;
165 case IMX8QM_I2C1_IPG_CLK:
166 case IMX8QM_I2C1_CLK:
167 case IMX8QM_I2C1_DIV:
168 resource = SC_R_I2C_1;
169 pm_clk = SC_PM_CLK_PER;
170 break;
171 case IMX8QM_I2C2_IPG_CLK:
172 case IMX8QM_I2C2_CLK:
173 case IMX8QM_I2C2_DIV:
174 resource = SC_R_I2C_2;
175 pm_clk = SC_PM_CLK_PER;
176 break;
177 case IMX8QM_I2C3_IPG_CLK:
178 case IMX8QM_I2C3_CLK:
179 case IMX8QM_I2C3_DIV:
180 resource = SC_R_I2C_3;
181 pm_clk = SC_PM_CLK_PER;
182 break;
183 case IMX8QM_UART0_CLK:
184 resource = SC_R_UART_0;
185 pm_clk = SC_PM_CLK_PER;
186 break;
187 case IMX8QM_UART1_CLK:
188 resource = SC_R_UART_1;
189 pm_clk = SC_PM_CLK_PER;
190 break;
191 case IMX8QM_UART2_CLK:
192 resource = SC_R_UART_2;
193 pm_clk = SC_PM_CLK_PER;
194 break;
195 case IMX8QM_UART3_CLK:
196 resource = SC_R_UART_3;
197 pm_clk = SC_PM_CLK_PER;
198 break;
199 case IMX8QM_SDHC0_IPG_CLK:
200 case IMX8QM_SDHC0_CLK:
201 case IMX8QM_SDHC0_DIV:
202 resource = SC_R_SDHC_0;
203 pm_clk = SC_PM_CLK_PER;
204 break;
205 case IMX8QM_SDHC1_IPG_CLK:
206 case IMX8QM_SDHC1_CLK:
207 case IMX8QM_SDHC1_DIV:
208 resource = SC_R_SDHC_1;
209 pm_clk = SC_PM_CLK_PER;
210 break;
211 case IMX8QM_SDHC2_IPG_CLK:
212 case IMX8QM_SDHC2_CLK:
213 case IMX8QM_SDHC2_DIV:
214 resource = SC_R_SDHC_2;
215 pm_clk = SC_PM_CLK_PER;
216 break;
217 case IMX8QM_ENET0_IPG_CLK:
218 case IMX8QM_ENET0_AHB_CLK:
219 case IMX8QM_ENET0_REF_DIV:
220 case IMX8QM_ENET0_PTP_CLK:
221 case IMX8QM_ENET0_ROOT_DIV:
222 resource = SC_R_ENET_0;
223 pm_clk = SC_PM_CLK_PER;
224 break;
225 case IMX8QM_ENET1_IPG_CLK:
226 case IMX8QM_ENET1_AHB_CLK:
227 case IMX8QM_ENET1_REF_DIV:
228 case IMX8QM_ENET1_PTP_CLK:
229 case IMX8QM_ENET1_ROOT_DIV:
230 resource = SC_R_ENET_1;
231 pm_clk = SC_PM_CLK_PER;
232 break;
233 default:
234 if (clk->id < IMX8QM_UART0_IPG_CLK ||
235 clk->id >= IMX8QM_CLK_END) {
236 printf("%s(Invalid clk ID #%lu)\n",
237 __func__, clk->id);
238 return -EINVAL;
239 }
240 return -ENOTSUPP;
241 };
242
243 ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
244 if (ret) {
245 printf("%s err %d\n", __func__, ret);
246 return ret;
247 }
248
249 return new_rate;
250 }
251
__imx8_clk_enable(struct clk * clk,bool enable)252 int __imx8_clk_enable(struct clk *clk, bool enable)
253 {
254 sc_pm_clk_t pm_clk;
255 u16 resource;
256 int ret;
257
258 debug("%s(#%lu)\n", __func__, clk->id);
259
260 switch (clk->id) {
261 case IMX8QM_I2C0_IPG_CLK:
262 case IMX8QM_I2C0_CLK:
263 case IMX8QM_I2C0_DIV:
264 resource = SC_R_I2C_0;
265 pm_clk = SC_PM_CLK_PER;
266 break;
267 case IMX8QM_I2C1_IPG_CLK:
268 case IMX8QM_I2C1_CLK:
269 case IMX8QM_I2C1_DIV:
270 resource = SC_R_I2C_1;
271 pm_clk = SC_PM_CLK_PER;
272 break;
273 case IMX8QM_I2C2_IPG_CLK:
274 case IMX8QM_I2C2_CLK:
275 case IMX8QM_I2C2_DIV:
276 resource = SC_R_I2C_2;
277 pm_clk = SC_PM_CLK_PER;
278 break;
279 case IMX8QM_I2C3_IPG_CLK:
280 case IMX8QM_I2C3_CLK:
281 case IMX8QM_I2C3_DIV:
282 resource = SC_R_I2C_3;
283 pm_clk = SC_PM_CLK_PER;
284 break;
285 case IMX8QM_UART0_CLK:
286 resource = SC_R_UART_0;
287 pm_clk = SC_PM_CLK_PER;
288 break;
289 case IMX8QM_UART1_CLK:
290 resource = SC_R_UART_1;
291 pm_clk = SC_PM_CLK_PER;
292 break;
293 case IMX8QM_UART2_CLK:
294 resource = SC_R_UART_2;
295 pm_clk = SC_PM_CLK_PER;
296 break;
297 case IMX8QM_UART3_CLK:
298 resource = SC_R_UART_3;
299 pm_clk = SC_PM_CLK_PER;
300 break;
301 case IMX8QM_SDHC0_IPG_CLK:
302 case IMX8QM_SDHC0_CLK:
303 case IMX8QM_SDHC0_DIV:
304 resource = SC_R_SDHC_0;
305 pm_clk = SC_PM_CLK_PER;
306 break;
307 case IMX8QM_SDHC1_IPG_CLK:
308 case IMX8QM_SDHC1_CLK:
309 case IMX8QM_SDHC1_DIV:
310 resource = SC_R_SDHC_1;
311 pm_clk = SC_PM_CLK_PER;
312 break;
313 case IMX8QM_SDHC2_IPG_CLK:
314 case IMX8QM_SDHC2_CLK:
315 case IMX8QM_SDHC2_DIV:
316 resource = SC_R_SDHC_2;
317 pm_clk = SC_PM_CLK_PER;
318 break;
319 case IMX8QM_ENET0_IPG_CLK:
320 case IMX8QM_ENET0_AHB_CLK:
321 case IMX8QM_ENET0_REF_DIV:
322 case IMX8QM_ENET0_PTP_CLK:
323 resource = SC_R_ENET_0;
324 pm_clk = SC_PM_CLK_PER;
325 break;
326 case IMX8QM_ENET1_IPG_CLK:
327 case IMX8QM_ENET1_AHB_CLK:
328 case IMX8QM_ENET1_REF_DIV:
329 case IMX8QM_ENET1_PTP_CLK:
330 resource = SC_R_ENET_1;
331 pm_clk = SC_PM_CLK_PER;
332 break;
333 default:
334 if (clk->id < IMX8QM_UART0_IPG_CLK ||
335 clk->id >= IMX8QM_CLK_END) {
336 printf("%s(Invalid clk ID #%lu)\n",
337 __func__, clk->id);
338 return -EINVAL;
339 }
340 return -ENOTSUPP;
341 }
342
343 ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
344 if (ret) {
345 printf("%s err %d\n", __func__, ret);
346 return ret;
347 }
348
349 return 0;
350 }
351