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