1fca36ac9142527817ee6967a6cc9213a5fb8034
[oweals/u-boot.git] / drivers / clk / imx / clk-imx8qxp.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/imx8qxp-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         { IMX8QXP_A35_DIV, "A35_DIV" },
21         { IMX8QXP_I2C0_CLK, "I2C0" },
22         { IMX8QXP_I2C1_CLK, "I2C1" },
23         { IMX8QXP_I2C2_CLK, "I2C2" },
24         { IMX8QXP_I2C3_CLK, "I2C3" },
25         { IMX8QXP_UART0_CLK, "UART0" },
26         { IMX8QXP_UART1_CLK, "UART1" },
27         { IMX8QXP_UART2_CLK, "UART2" },
28         { IMX8QXP_UART3_CLK, "UART3" },
29         { IMX8QXP_SDHC0_CLK, "SDHC0" },
30         { IMX8QXP_SDHC1_CLK, "SDHC1" },
31         { IMX8QXP_ENET0_AHB_CLK, "ENET0_AHB" },
32         { IMX8QXP_ENET0_IPG_CLK, "ENET0_IPG" },
33         { IMX8QXP_ENET0_REF_DIV, "ENET0_REF" },
34         { IMX8QXP_ENET0_PTP_CLK, "ENET0_PTP" },
35         { IMX8QXP_ENET1_AHB_CLK, "ENET1_AHB" },
36         { IMX8QXP_ENET1_IPG_CLK, "ENET1_IPG" },
37         { IMX8QXP_ENET1_REF_DIV, "ENET1_REF" },
38         { IMX8QXP_ENET1_PTP_CLK, "ENET1_PTP" },
39 };
40
41 int num_clks = ARRAY_SIZE(imx8_clk_names);
42 #endif
43
44 ulong imx8_clk_get_rate(struct clk *clk)
45 {
46         sc_pm_clk_t pm_clk;
47         ulong rate;
48         u16 resource;
49         int ret;
50
51         debug("%s(#%lu)\n", __func__, clk->id);
52
53         switch (clk->id) {
54         case IMX8QXP_A35_DIV:
55                 resource = SC_R_A35;
56                 pm_clk = SC_PM_CLK_CPU;
57                 break;
58         case IMX8QXP_I2C0_CLK:
59                 resource = SC_R_I2C_0;
60                 pm_clk = SC_PM_CLK_PER;
61                 break;
62         case IMX8QXP_I2C1_CLK:
63                 resource = SC_R_I2C_1;
64                 pm_clk = SC_PM_CLK_PER;
65                 break;
66         case IMX8QXP_I2C2_CLK:
67                 resource = SC_R_I2C_2;
68                 pm_clk = SC_PM_CLK_PER;
69                 break;
70         case IMX8QXP_I2C3_CLK:
71                 resource = SC_R_I2C_3;
72                 pm_clk = SC_PM_CLK_PER;
73                 break;
74         case IMX8QXP_SDHC0_IPG_CLK:
75         case IMX8QXP_SDHC0_CLK:
76         case IMX8QXP_SDHC0_DIV:
77                 resource = SC_R_SDHC_0;
78                 pm_clk = SC_PM_CLK_PER;
79                 break;
80         case IMX8QXP_SDHC1_IPG_CLK:
81         case IMX8QXP_SDHC1_CLK:
82         case IMX8QXP_SDHC1_DIV:
83                 resource = SC_R_SDHC_1;
84                 pm_clk = SC_PM_CLK_PER;
85                 break;
86         case IMX8QXP_UART0_IPG_CLK:
87         case IMX8QXP_UART0_CLK:
88                 resource = SC_R_UART_0;
89                 pm_clk = SC_PM_CLK_PER;
90                 break;
91         case IMX8QXP_UART1_CLK:
92                 resource = SC_R_UART_1;
93                 pm_clk = SC_PM_CLK_PER;
94                 break;
95         case IMX8QXP_UART2_CLK:
96                 resource = SC_R_UART_2;
97                 pm_clk = SC_PM_CLK_PER;
98                 break;
99         case IMX8QXP_UART3_CLK:
100                 resource = SC_R_UART_3;
101                 pm_clk = SC_PM_CLK_PER;
102                 break;
103         case IMX8QXP_ENET0_IPG_CLK:
104         case IMX8QXP_ENET0_AHB_CLK:
105         case IMX8QXP_ENET0_REF_DIV:
106         case IMX8QXP_ENET0_PTP_CLK:
107                 resource = SC_R_ENET_0;
108                 pm_clk = SC_PM_CLK_PER;
109                 break;
110         case IMX8QXP_ENET1_IPG_CLK:
111         case IMX8QXP_ENET1_AHB_CLK:
112         case IMX8QXP_ENET1_REF_DIV:
113         case IMX8QXP_ENET1_PTP_CLK:
114                 resource = SC_R_ENET_1;
115                 pm_clk = SC_PM_CLK_PER;
116                 break;
117         default:
118                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
119                     clk->id >= IMX8QXP_CLK_END) {
120                         printf("%s(Invalid clk ID #%lu)\n",
121                                __func__, clk->id);
122                         return -EINVAL;
123                 }
124                 return -ENOTSUPP;
125         };
126
127         ret = sc_pm_get_clock_rate(-1, resource, pm_clk,
128                                    (sc_pm_clock_rate_t *)&rate);
129         if (ret) {
130                 printf("%s err %d\n", __func__, ret);
131                 return ret;
132         }
133
134         return rate;
135 }
136
137 ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate)
138 {
139         sc_pm_clk_t pm_clk;
140         u32 new_rate = rate;
141         u16 resource;
142         int ret;
143
144         debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
145
146         switch (clk->id) {
147         case IMX8QXP_I2C0_CLK:
148                 resource = SC_R_I2C_0;
149                 pm_clk = SC_PM_CLK_PER;
150                 break;
151         case IMX8QXP_I2C1_CLK:
152                 resource = SC_R_I2C_1;
153                 pm_clk = SC_PM_CLK_PER;
154                 break;
155         case IMX8QXP_I2C2_CLK:
156                 resource = SC_R_I2C_2;
157                 pm_clk = SC_PM_CLK_PER;
158                 break;
159         case IMX8QXP_I2C3_CLK:
160                 resource = SC_R_I2C_3;
161                 pm_clk = SC_PM_CLK_PER;
162                 break;
163         case IMX8QXP_UART0_CLK:
164                 resource = SC_R_UART_0;
165                 pm_clk = SC_PM_CLK_PER;
166                 break;
167         case IMX8QXP_UART1_CLK:
168                 resource = SC_R_UART_1;
169                 pm_clk = SC_PM_CLK_PER;
170                 break;
171         case IMX8QXP_UART2_CLK:
172                 resource = SC_R_UART_2;
173                 pm_clk = SC_PM_CLK_PER;
174                 break;
175         case IMX8QXP_UART3_CLK:
176                 resource = SC_R_UART_3;
177                 pm_clk = SC_PM_CLK_PER;
178                 break;
179         case IMX8QXP_SDHC0_IPG_CLK:
180         case IMX8QXP_SDHC0_CLK:
181         case IMX8QXP_SDHC0_DIV:
182                 resource = SC_R_SDHC_0;
183                 pm_clk = SC_PM_CLK_PER;
184                 break;
185         case IMX8QXP_SDHC1_SEL:
186         case IMX8QXP_SDHC0_SEL:
187                 return 0;
188         case IMX8QXP_SDHC1_IPG_CLK:
189         case IMX8QXP_SDHC1_CLK:
190         case IMX8QXP_SDHC1_DIV:
191                 resource = SC_R_SDHC_1;
192                 pm_clk = SC_PM_CLK_PER;
193                 break;
194         case IMX8QXP_ENET0_IPG_CLK:
195         case IMX8QXP_ENET0_AHB_CLK:
196         case IMX8QXP_ENET0_REF_DIV:
197         case IMX8QXP_ENET0_PTP_CLK:
198                 resource = SC_R_ENET_0;
199                 pm_clk = SC_PM_CLK_PER;
200                 break;
201         case IMX8QXP_ENET1_IPG_CLK:
202         case IMX8QXP_ENET1_AHB_CLK:
203         case IMX8QXP_ENET1_REF_DIV:
204         case IMX8QXP_ENET1_PTP_CLK:
205                 resource = SC_R_ENET_1;
206                 pm_clk = SC_PM_CLK_PER;
207                 break;
208         default:
209                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
210                     clk->id >= IMX8QXP_CLK_END) {
211                         printf("%s(Invalid clk ID #%lu)\n",
212                                __func__, clk->id);
213                         return -EINVAL;
214                 }
215                 return -ENOTSUPP;
216         };
217
218         ret = sc_pm_set_clock_rate(-1, resource, pm_clk, &new_rate);
219         if (ret) {
220                 printf("%s err %d\n", __func__, ret);
221                 return ret;
222         }
223
224         return new_rate;
225 }
226
227 int __imx8_clk_enable(struct clk *clk, bool enable)
228 {
229         sc_pm_clk_t pm_clk;
230         u16 resource;
231         int ret;
232
233         debug("%s(#%lu)\n", __func__, clk->id);
234
235         switch (clk->id) {
236         case IMX8QXP_I2C0_CLK:
237                 resource = SC_R_I2C_0;
238                 pm_clk = SC_PM_CLK_PER;
239                 break;
240         case IMX8QXP_I2C1_CLK:
241                 resource = SC_R_I2C_1;
242                 pm_clk = SC_PM_CLK_PER;
243                 break;
244         case IMX8QXP_I2C2_CLK:
245                 resource = SC_R_I2C_2;
246                 pm_clk = SC_PM_CLK_PER;
247                 break;
248         case IMX8QXP_I2C3_CLK:
249                 resource = SC_R_I2C_3;
250                 pm_clk = SC_PM_CLK_PER;
251                 break;
252         case IMX8QXP_UART0_CLK:
253                 resource = SC_R_UART_0;
254                 pm_clk = SC_PM_CLK_PER;
255                 break;
256         case IMX8QXP_UART1_CLK:
257                 resource = SC_R_UART_1;
258                 pm_clk = SC_PM_CLK_PER;
259                 break;
260         case IMX8QXP_UART2_CLK:
261                 resource = SC_R_UART_2;
262                 pm_clk = SC_PM_CLK_PER;
263                 break;
264         case IMX8QXP_UART3_CLK:
265                 resource = SC_R_UART_3;
266                 pm_clk = SC_PM_CLK_PER;
267                 break;
268         case IMX8QXP_SDHC0_IPG_CLK:
269         case IMX8QXP_SDHC0_CLK:
270         case IMX8QXP_SDHC0_DIV:
271                 resource = SC_R_SDHC_0;
272                 pm_clk = SC_PM_CLK_PER;
273                 break;
274         case IMX8QXP_SDHC1_IPG_CLK:
275         case IMX8QXP_SDHC1_CLK:
276         case IMX8QXP_SDHC1_DIV:
277                 resource = SC_R_SDHC_1;
278                 pm_clk = SC_PM_CLK_PER;
279                 break;
280         case IMX8QXP_ENET0_IPG_CLK:
281         case IMX8QXP_ENET0_AHB_CLK:
282         case IMX8QXP_ENET0_REF_DIV:
283         case IMX8QXP_ENET0_PTP_CLK:
284                 resource = SC_R_ENET_0;
285                 pm_clk = SC_PM_CLK_PER;
286                 break;
287         case IMX8QXP_ENET1_IPG_CLK:
288         case IMX8QXP_ENET1_AHB_CLK:
289         case IMX8QXP_ENET1_REF_DIV:
290         case IMX8QXP_ENET1_PTP_CLK:
291                 resource = SC_R_ENET_1;
292                 pm_clk = SC_PM_CLK_PER;
293                 break;
294         default:
295                 if (clk->id < IMX8QXP_UART0_IPG_CLK ||
296                     clk->id >= IMX8QXP_CLK_END) {
297                         printf("%s(Invalid clk ID #%lu)\n",
298                                __func__, clk->id);
299                         return -EINVAL;
300                 }
301                 return -ENOTSUPP;
302         }
303
304         ret = sc_pm_clock_enable(-1, resource, pm_clk, enable, 0);
305         if (ret) {
306                 printf("%s err %d\n", __func__, ret);
307                 return ret;
308         }
309
310         return 0;
311 }