Commit | Line | Data |
---|---|---|
3fde0e16 JS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Zynq UltraScale+ MPSoC clock controller | |
4 | * | |
c1e846b8 | 5 | * Copyright (C) 2016-2019 Xilinx |
3fde0e16 JS |
6 | * |
7 | * Based on drivers/clk/zynq/clkc.c | |
8 | */ | |
9 | ||
10 | #include <linux/bitfield.h> | |
11 | #include <linux/clk.h> | |
12 | #include <linux/clk-provider.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/of_platform.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/string.h> | |
17 | ||
18 | #include "clk-zynqmp.h" | |
19 | ||
20 | #define MAX_PARENT 100 | |
21 | #define MAX_NODES 6 | |
22 | #define MAX_NAME_LEN 50 | |
23 | ||
3fde0e16 JS |
24 | /* Flags for parents */ |
25 | #define PARENT_CLK_SELF 0 | |
26 | #define PARENT_CLK_NODE1 1 | |
27 | #define PARENT_CLK_NODE2 2 | |
28 | #define PARENT_CLK_NODE3 3 | |
29 | #define PARENT_CLK_NODE4 4 | |
30 | #define PARENT_CLK_EXTERNAL 5 | |
31 | ||
32 | #define END_OF_CLK_NAME "END_OF_CLK" | |
33 | #define END_OF_TOPOLOGY_NODE 1 | |
34 | #define END_OF_PARENTS 1 | |
35 | #define RESERVED_CLK_NAME "" | |
36 | ||
5852b136 MT |
37 | #define CLK_GET_NAME_RESP_LEN 16 |
38 | #define CLK_GET_TOPOLOGY_RESP_WORDS 3 | |
39 | #define CLK_GET_PARENTS_RESP_WORDS 3 | |
40 | #define CLK_GET_ATTR_RESP_WORDS 1 | |
3fde0e16 JS |
41 | |
42 | enum clk_type { | |
43 | CLK_TYPE_OUTPUT, | |
44 | CLK_TYPE_EXTERNAL, | |
45 | }; | |
46 | ||
47 | /** | |
48 | * struct clock_parent - Clock parent | |
49 | * @name: Parent name | |
50 | * @id: Parent clock ID | |
51 | * @flag: Parent flags | |
52 | */ | |
53 | struct clock_parent { | |
54 | char name[MAX_NAME_LEN]; | |
55 | int id; | |
56 | u32 flag; | |
57 | }; | |
58 | ||
59 | /** | |
60 | * struct zynqmp_clock - Clock | |
61 | * @clk_name: Clock name | |
62 | * @valid: Validity flag of clock | |
63 | * @type: Clock type (Output/External) | |
64 | * @node: Clock topology nodes | |
65 | * @num_nodes: Number of nodes present in topology | |
66 | * @parent: Parent of clock | |
67 | * @num_parents: Number of parents of clock | |
d3e4ebc1 | 68 | * @clk_id: Clock id |
3fde0e16 JS |
69 | */ |
70 | struct zynqmp_clock { | |
71 | char clk_name[MAX_NAME_LEN]; | |
72 | u32 valid; | |
73 | enum clk_type type; | |
74 | struct clock_topology node[MAX_NODES]; | |
75 | u32 num_nodes; | |
76 | struct clock_parent parent[MAX_PARENT]; | |
77 | u32 num_parents; | |
d3e4ebc1 | 78 | u32 clk_id; |
3fde0e16 JS |
79 | }; |
80 | ||
5852b136 MT |
81 | struct name_resp { |
82 | char name[CLK_GET_NAME_RESP_LEN]; | |
83 | }; | |
84 | ||
85 | struct topology_resp { | |
86 | #define CLK_TOPOLOGY_TYPE GENMASK(3, 0) | |
e605fa9c | 87 | #define CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS GENMASK(7, 4) |
5852b136 MT |
88 | #define CLK_TOPOLOGY_FLAGS GENMASK(23, 8) |
89 | #define CLK_TOPOLOGY_TYPE_FLAGS GENMASK(31, 24) | |
90 | u32 topology[CLK_GET_TOPOLOGY_RESP_WORDS]; | |
91 | }; | |
92 | ||
93 | struct parents_resp { | |
94 | #define NA_PARENT 0xFFFFFFFF | |
95 | #define DUMMY_PARENT 0xFFFFFFFE | |
96 | #define CLK_PARENTS_ID GENMASK(15, 0) | |
97 | #define CLK_PARENTS_FLAGS GENMASK(31, 16) | |
98 | u32 parents[CLK_GET_PARENTS_RESP_WORDS]; | |
99 | }; | |
100 | ||
101 | struct attr_resp { | |
102 | #define CLK_ATTR_VALID BIT(0) | |
103 | #define CLK_ATTR_TYPE BIT(2) | |
104 | #define CLK_ATTR_NODE_INDEX GENMASK(13, 0) | |
105 | #define CLK_ATTR_NODE_TYPE GENMASK(19, 14) | |
106 | #define CLK_ATTR_NODE_SUBCLASS GENMASK(25, 20) | |
107 | #define CLK_ATTR_NODE_CLASS GENMASK(31, 26) | |
108 | u32 attr[CLK_GET_ATTR_RESP_WORDS]; | |
109 | }; | |
110 | ||
3fde0e16 JS |
111 | static const char clk_type_postfix[][10] = { |
112 | [TYPE_INVALID] = "", | |
113 | [TYPE_MUX] = "_mux", | |
114 | [TYPE_GATE] = "", | |
115 | [TYPE_DIV1] = "_div1", | |
116 | [TYPE_DIV2] = "_div2", | |
117 | [TYPE_FIXEDFACTOR] = "_ff", | |
118 | [TYPE_PLL] = "" | |
119 | }; | |
120 | ||
121 | static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id, | |
122 | const char * const *parents, | |
123 | u8 num_parents, | |
124 | const struct clock_topology *nodes) | |
125 | = { | |
126 | [TYPE_INVALID] = NULL, | |
127 | [TYPE_MUX] = zynqmp_clk_register_mux, | |
128 | [TYPE_PLL] = zynqmp_clk_register_pll, | |
129 | [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor, | |
130 | [TYPE_DIV1] = zynqmp_clk_register_divider, | |
131 | [TYPE_DIV2] = zynqmp_clk_register_divider, | |
132 | [TYPE_GATE] = zynqmp_clk_register_gate | |
133 | }; | |
134 | ||
135 | static struct zynqmp_clock *clock; | |
136 | static struct clk_hw_onecell_data *zynqmp_data; | |
137 | static unsigned int clock_max_idx; | |
3fde0e16 JS |
138 | |
139 | /** | |
140 | * zynqmp_is_valid_clock() - Check whether clock is valid or not | |
141 | * @clk_id: Clock index | |
142 | * | |
143 | * Return: 1 if clock is valid, 0 if clock is invalid else error code | |
144 | */ | |
145 | static inline int zynqmp_is_valid_clock(u32 clk_id) | |
146 | { | |
9a43be9c | 147 | if (clk_id >= clock_max_idx) |
3fde0e16 JS |
148 | return -ENODEV; |
149 | ||
150 | return clock[clk_id].valid; | |
151 | } | |
152 | ||
153 | /** | |
154 | * zynqmp_get_clock_name() - Get name of clock from Clock index | |
155 | * @clk_id: Clock index | |
156 | * @clk_name: Name of clock | |
157 | * | |
158 | * Return: 0 on success else error code | |
159 | */ | |
160 | static int zynqmp_get_clock_name(u32 clk_id, char *clk_name) | |
161 | { | |
162 | int ret; | |
163 | ||
164 | ret = zynqmp_is_valid_clock(clk_id); | |
165 | if (ret == 1) { | |
acc1c732 | 166 | strscpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN); |
3fde0e16 JS |
167 | return 0; |
168 | } | |
169 | ||
170 | return ret == 0 ? -EINVAL : ret; | |
171 | } | |
172 | ||
173 | /** | |
174 | * zynqmp_get_clock_type() - Get type of clock | |
175 | * @clk_id: Clock index | |
176 | * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL | |
177 | * | |
178 | * Return: 0 on success else error code | |
179 | */ | |
180 | static int zynqmp_get_clock_type(u32 clk_id, u32 *type) | |
181 | { | |
182 | int ret; | |
183 | ||
184 | ret = zynqmp_is_valid_clock(clk_id); | |
185 | if (ret == 1) { | |
186 | *type = clock[clk_id].type; | |
187 | return 0; | |
188 | } | |
189 | ||
190 | return ret == 0 ? -EINVAL : ret; | |
191 | } | |
192 | ||
193 | /** | |
194 | * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system | |
195 | * @nclocks: Number of clocks in system/board. | |
196 | * | |
197 | * Call firmware API to get number of clocks. | |
198 | * | |
199 | * Return: 0 on success else error code. | |
200 | */ | |
201 | static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks) | |
202 | { | |
203 | struct zynqmp_pm_query_data qdata = {0}; | |
204 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
205 | int ret; | |
206 | ||
207 | qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS; | |
208 | ||
6366c1ba | 209 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
3fde0e16 JS |
210 | *nclocks = ret_payload[1]; |
211 | ||
212 | return ret; | |
213 | } | |
214 | ||
215 | /** | |
216 | * zynqmp_pm_clock_get_name() - Get the name of clock for given id | |
217 | * @clock_id: ID of the clock to be queried | |
5852b136 | 218 | * @response: Name of the clock with the given id |
3fde0e16 JS |
219 | * |
220 | * This function is used to get name of clock specified by given | |
221 | * clock ID. | |
222 | * | |
8bdb15cd | 223 | * Return: 0 on success else error+reason |
3fde0e16 | 224 | */ |
5852b136 MT |
225 | static int zynqmp_pm_clock_get_name(u32 clock_id, |
226 | struct name_resp *response) | |
3fde0e16 JS |
227 | { |
228 | struct zynqmp_pm_query_data qdata = {0}; | |
229 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
8bdb15cd | 230 | int ret; |
3fde0e16 JS |
231 | |
232 | qdata.qid = PM_QID_CLOCK_GET_NAME; | |
233 | qdata.arg1 = clock_id; | |
234 | ||
8bdb15cd SD |
235 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
236 | if (ret) | |
237 | return ret; | |
238 | ||
5852b136 | 239 | memcpy(response, ret_payload, sizeof(*response)); |
3fde0e16 JS |
240 | |
241 | return 0; | |
242 | } | |
243 | ||
244 | /** | |
245 | * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id | |
246 | * @clock_id: ID of the clock to be queried | |
247 | * @index: Node index of clock topology | |
5852b136 | 248 | * @response: Buffer used for the topology response |
3fde0e16 JS |
249 | * |
250 | * This function is used to get topology information for the clock | |
251 | * specified by given clock ID. | |
252 | * | |
253 | * This API will return 3 node of topology with a single response. To get | |
254 | * other nodes, master should call same API in loop with new | |
255 | * index till error is returned. E.g First call should have | |
256 | * index 0 which will return nodes 0,1 and 2. Next call, index | |
257 | * should be 3 which will return nodes 3,4 and 5 and so on. | |
258 | * | |
259 | * Return: 0 on success else error+reason | |
260 | */ | |
5852b136 MT |
261 | static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, |
262 | struct topology_resp *response) | |
3fde0e16 JS |
263 | { |
264 | struct zynqmp_pm_query_data qdata = {0}; | |
265 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
266 | int ret; | |
267 | ||
268 | qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY; | |
269 | qdata.arg1 = clock_id; | |
270 | qdata.arg2 = index; | |
271 | ||
6366c1ba | 272 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
5852b136 | 273 | memcpy(response, &ret_payload[1], sizeof(*response)); |
3fde0e16 JS |
274 | |
275 | return ret; | |
276 | } | |
277 | ||
610a5d83 RV |
278 | unsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag) |
279 | { | |
280 | unsigned long ccf_flag = 0; | |
281 | ||
282 | if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_GATE) | |
283 | ccf_flag |= CLK_SET_RATE_GATE; | |
284 | if (zynqmp_flag & ZYNQMP_CLK_SET_PARENT_GATE) | |
285 | ccf_flag |= CLK_SET_PARENT_GATE; | |
286 | if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_PARENT) | |
287 | ccf_flag |= CLK_SET_RATE_PARENT; | |
288 | if (zynqmp_flag & ZYNQMP_CLK_IGNORE_UNUSED) | |
289 | ccf_flag |= CLK_IGNORE_UNUSED; | |
290 | if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_NO_REPARENT) | |
291 | ccf_flag |= CLK_SET_RATE_NO_REPARENT; | |
292 | if (zynqmp_flag & ZYNQMP_CLK_IS_CRITICAL) | |
293 | ccf_flag |= CLK_IS_CRITICAL; | |
294 | ||
295 | return ccf_flag; | |
296 | } | |
297 | ||
3fde0e16 JS |
298 | /** |
299 | * zynqmp_clk_register_fixed_factor() - Register fixed factor with the | |
300 | * clock framework | |
301 | * @name: Name of this clock | |
302 | * @clk_id: Clock ID | |
303 | * @parents: Name of this clock's parents | |
304 | * @num_parents: Number of parents | |
305 | * @nodes: Clock topology node | |
306 | * | |
307 | * Return: clock hardware to the registered clock | |
308 | */ | |
309 | struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id, | |
310 | const char * const *parents, | |
311 | u8 num_parents, | |
312 | const struct clock_topology *nodes) | |
313 | { | |
314 | u32 mult, div; | |
315 | struct clk_hw *hw; | |
316 | struct zynqmp_pm_query_data qdata = {0}; | |
317 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
318 | int ret; | |
610a5d83 | 319 | unsigned long flag; |
3fde0e16 JS |
320 | |
321 | qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS; | |
322 | qdata.arg1 = clk_id; | |
323 | ||
6366c1ba | 324 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
27c0f2b0 RV |
325 | if (ret) |
326 | return ERR_PTR(ret); | |
327 | ||
3fde0e16 JS |
328 | mult = ret_payload[1]; |
329 | div = ret_payload[2]; | |
330 | ||
610a5d83 RV |
331 | flag = zynqmp_clk_map_common_ccf_flags(nodes->flag); |
332 | ||
3fde0e16 JS |
333 | hw = clk_hw_register_fixed_factor(NULL, name, |
334 | parents[0], | |
610a5d83 | 335 | flag, mult, |
3fde0e16 JS |
336 | div); |
337 | ||
338 | return hw; | |
339 | } | |
340 | ||
341 | /** | |
342 | * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id | |
343 | * @clock_id: Clock ID | |
344 | * @index: Parent index | |
5852b136 | 345 | * @response: Parents of the given clock |
3fde0e16 JS |
346 | * |
347 | * This function is used to get 3 parents for the clock specified by | |
348 | * given clock ID. | |
349 | * | |
350 | * This API will return 3 parents with a single response. To get | |
351 | * other parents, master should call same API in loop with new | |
352 | * parent index till error is returned. E.g First call should have | |
353 | * index 0 which will return parents 0,1 and 2. Next call, index | |
354 | * should be 3 which will return parent 3,4 and 5 and so on. | |
355 | * | |
356 | * Return: 0 on success else error+reason | |
357 | */ | |
5852b136 MT |
358 | static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, |
359 | struct parents_resp *response) | |
3fde0e16 JS |
360 | { |
361 | struct zynqmp_pm_query_data qdata = {0}; | |
362 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
363 | int ret; | |
364 | ||
365 | qdata.qid = PM_QID_CLOCK_GET_PARENTS; | |
366 | qdata.arg1 = clock_id; | |
367 | qdata.arg2 = index; | |
368 | ||
6366c1ba | 369 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
5852b136 | 370 | memcpy(response, &ret_payload[1], sizeof(*response)); |
3fde0e16 JS |
371 | |
372 | return ret; | |
373 | } | |
374 | ||
375 | /** | |
376 | * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id | |
377 | * @clock_id: Clock ID | |
5852b136 | 378 | * @response: Clock attributes response |
3fde0e16 JS |
379 | * |
380 | * This function is used to get clock's attributes(e.g. valid, clock type, etc). | |
381 | * | |
382 | * Return: 0 on success else error+reason | |
383 | */ | |
5852b136 MT |
384 | static int zynqmp_pm_clock_get_attributes(u32 clock_id, |
385 | struct attr_resp *response) | |
3fde0e16 JS |
386 | { |
387 | struct zynqmp_pm_query_data qdata = {0}; | |
388 | u32 ret_payload[PAYLOAD_ARG_CNT]; | |
389 | int ret; | |
390 | ||
391 | qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES; | |
392 | qdata.arg1 = clock_id; | |
393 | ||
6366c1ba | 394 | ret = zynqmp_pm_query_data(qdata, ret_payload); |
5852b136 | 395 | memcpy(response, &ret_payload[1], sizeof(*response)); |
3fde0e16 JS |
396 | |
397 | return ret; | |
398 | } | |
399 | ||
400 | /** | |
401 | * __zynqmp_clock_get_topology() - Get topology data of clock from firmware | |
402 | * response data | |
403 | * @topology: Clock topology | |
5852b136 | 404 | * @response: Clock topology data received from firmware |
3fde0e16 JS |
405 | * @nnodes: Number of nodes |
406 | * | |
407 | * Return: 0 on success else error+reason | |
408 | */ | |
409 | static int __zynqmp_clock_get_topology(struct clock_topology *topology, | |
5852b136 MT |
410 | struct topology_resp *response, |
411 | u32 *nnodes) | |
3fde0e16 JS |
412 | { |
413 | int i; | |
5852b136 | 414 | u32 type; |
3fde0e16 | 415 | |
5852b136 MT |
416 | for (i = 0; i < ARRAY_SIZE(response->topology); i++) { |
417 | type = FIELD_GET(CLK_TOPOLOGY_TYPE, response->topology[i]); | |
418 | if (type == TYPE_INVALID) | |
3fde0e16 | 419 | return END_OF_TOPOLOGY_NODE; |
5852b136 MT |
420 | topology[*nnodes].type = type; |
421 | topology[*nnodes].flag = FIELD_GET(CLK_TOPOLOGY_FLAGS, | |
422 | response->topology[i]); | |
3fde0e16 | 423 | topology[*nnodes].type_flag = |
5852b136 MT |
424 | FIELD_GET(CLK_TOPOLOGY_TYPE_FLAGS, |
425 | response->topology[i]); | |
e605fa9c RV |
426 | topology[*nnodes].custom_type_flag = |
427 | FIELD_GET(CLK_TOPOLOGY_CUSTOM_TYPE_FLAGS, | |
428 | response->topology[i]); | |
3fde0e16 JS |
429 | (*nnodes)++; |
430 | } | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
435 | /** | |
436 | * zynqmp_clock_get_topology() - Get topology of clock from firmware using | |
437 | * PM_API | |
438 | * @clk_id: Clock index | |
439 | * @topology: Clock topology | |
440 | * @num_nodes: Number of nodes | |
441 | * | |
442 | * Return: 0 on success else error+reason | |
443 | */ | |
444 | static int zynqmp_clock_get_topology(u32 clk_id, | |
445 | struct clock_topology *topology, | |
446 | u32 *num_nodes) | |
447 | { | |
448 | int j, ret; | |
5852b136 | 449 | struct topology_resp response = { }; |
3fde0e16 JS |
450 | |
451 | *num_nodes = 0; | |
5852b136 | 452 | for (j = 0; j <= MAX_NODES; j += ARRAY_SIZE(response.topology)) { |
d3e4ebc1 | 453 | ret = zynqmp_pm_clock_get_topology(clock[clk_id].clk_id, j, |
5852b136 | 454 | &response); |
3fde0e16 JS |
455 | if (ret) |
456 | return ret; | |
5852b136 MT |
457 | ret = __zynqmp_clock_get_topology(topology, &response, |
458 | num_nodes); | |
3fde0e16 JS |
459 | if (ret == END_OF_TOPOLOGY_NODE) |
460 | return 0; | |
461 | } | |
462 | ||
463 | return 0; | |
464 | } | |
465 | ||
466 | /** | |
5e088fae | 467 | * __zynqmp_clock_get_parents() - Get parents info of clock from firmware |
3fde0e16 JS |
468 | * response data |
469 | * @parents: Clock parents | |
5852b136 | 470 | * @response: Clock parents data received from firmware |
3fde0e16 JS |
471 | * @nparent: Number of parent |
472 | * | |
473 | * Return: 0 on success else error+reason | |
474 | */ | |
5852b136 MT |
475 | static int __zynqmp_clock_get_parents(struct clock_parent *parents, |
476 | struct parents_resp *response, | |
3fde0e16 JS |
477 | u32 *nparent) |
478 | { | |
479 | int i; | |
480 | struct clock_parent *parent; | |
481 | ||
5852b136 MT |
482 | for (i = 0; i < ARRAY_SIZE(response->parents); i++) { |
483 | if (response->parents[i] == NA_PARENT) | |
3fde0e16 JS |
484 | return END_OF_PARENTS; |
485 | ||
486 | parent = &parents[i]; | |
5852b136 MT |
487 | parent->id = FIELD_GET(CLK_PARENTS_ID, response->parents[i]); |
488 | if (response->parents[i] == DUMMY_PARENT) { | |
3fde0e16 JS |
489 | strcpy(parent->name, "dummy_name"); |
490 | parent->flag = 0; | |
491 | } else { | |
5852b136 MT |
492 | parent->flag = FIELD_GET(CLK_PARENTS_FLAGS, |
493 | response->parents[i]); | |
3fde0e16 JS |
494 | if (zynqmp_get_clock_name(parent->id, parent->name)) |
495 | continue; | |
496 | } | |
497 | *nparent += 1; | |
498 | } | |
499 | ||
500 | return 0; | |
501 | } | |
502 | ||
503 | /** | |
504 | * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API | |
505 | * @clk_id: Clock index | |
506 | * @parents: Clock parents | |
507 | * @num_parents: Total number of parents | |
508 | * | |
509 | * Return: 0 on success else error+reason | |
510 | */ | |
511 | static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents, | |
512 | u32 *num_parents) | |
513 | { | |
514 | int j = 0, ret; | |
5852b136 | 515 | struct parents_resp response = { }; |
3fde0e16 JS |
516 | |
517 | *num_parents = 0; | |
518 | do { | |
519 | /* Get parents from firmware */ | |
d3e4ebc1 | 520 | ret = zynqmp_pm_clock_get_parents(clock[clk_id].clk_id, j, |
5852b136 | 521 | &response); |
3fde0e16 JS |
522 | if (ret) |
523 | return ret; | |
524 | ||
5852b136 | 525 | ret = __zynqmp_clock_get_parents(&parents[j], &response, |
3fde0e16 JS |
526 | num_parents); |
527 | if (ret == END_OF_PARENTS) | |
528 | return 0; | |
5852b136 | 529 | j += ARRAY_SIZE(response.parents); |
3fde0e16 JS |
530 | } while (*num_parents <= MAX_PARENT); |
531 | ||
532 | return 0; | |
533 | } | |
534 | ||
535 | /** | |
536 | * zynqmp_get_parent_list() - Create list of parents name | |
537 | * @np: Device node | |
538 | * @clk_id: Clock index | |
539 | * @parent_list: List of parent's name | |
540 | * @num_parents: Total number of parents | |
541 | * | |
542 | * Return: 0 on success else error+reason | |
543 | */ | |
544 | static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id, | |
545 | const char **parent_list, u32 *num_parents) | |
546 | { | |
547 | int i = 0, ret; | |
548 | u32 total_parents = clock[clk_id].num_parents; | |
549 | struct clock_topology *clk_nodes; | |
550 | struct clock_parent *parents; | |
551 | ||
552 | clk_nodes = clock[clk_id].node; | |
553 | parents = clock[clk_id].parent; | |
554 | ||
555 | for (i = 0; i < total_parents; i++) { | |
556 | if (!parents[i].flag) { | |
557 | parent_list[i] = parents[i].name; | |
558 | } else if (parents[i].flag == PARENT_CLK_EXTERNAL) { | |
559 | ret = of_property_match_string(np, "clock-names", | |
560 | parents[i].name); | |
561 | if (ret < 0) | |
562 | strcpy(parents[i].name, "dummy_name"); | |
563 | parent_list[i] = parents[i].name; | |
564 | } else { | |
565 | strcat(parents[i].name, | |
566 | clk_type_postfix[clk_nodes[parents[i].flag - 1]. | |
567 | type]); | |
568 | parent_list[i] = parents[i].name; | |
569 | } | |
570 | } | |
571 | ||
572 | *num_parents = total_parents; | |
573 | return 0; | |
574 | } | |
575 | ||
576 | /** | |
577 | * zynqmp_register_clk_topology() - Register clock topology | |
578 | * @clk_id: Clock index | |
579 | * @clk_name: Clock Name | |
580 | * @num_parents: Total number of parents | |
581 | * @parent_names: List of parents name | |
582 | * | |
583 | * Return: Returns either clock hardware or error+reason | |
584 | */ | |
585 | static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name, | |
586 | int num_parents, | |
587 | const char **parent_names) | |
588 | { | |
589 | int j; | |
d3e4ebc1 | 590 | u32 num_nodes, clk_dev_id; |
58b0fb86 | 591 | char *clk_out[MAX_NODES]; |
3fde0e16 JS |
592 | struct clock_topology *nodes; |
593 | struct clk_hw *hw = NULL; | |
594 | ||
595 | nodes = clock[clk_id].node; | |
596 | num_nodes = clock[clk_id].num_nodes; | |
d3e4ebc1 | 597 | clk_dev_id = clock[clk_id].clk_id; |
3fde0e16 JS |
598 | |
599 | for (j = 0; j < num_nodes; j++) { | |
600 | /* | |
601 | * Clock name received from firmware is output clock name. | |
602 | * Intermediate clock names are postfixed with type of clock. | |
603 | */ | |
604 | if (j != (num_nodes - 1)) { | |
58b0fb86 | 605 | clk_out[j] = kasprintf(GFP_KERNEL, "%s%s", clk_name, |
3fde0e16 JS |
606 | clk_type_postfix[nodes[j].type]); |
607 | } else { | |
58b0fb86 | 608 | clk_out[j] = kasprintf(GFP_KERNEL, "%s", clk_name); |
3fde0e16 JS |
609 | } |
610 | ||
611 | if (!clk_topology[nodes[j].type]) | |
612 | continue; | |
613 | ||
58b0fb86 | 614 | hw = (*clk_topology[nodes[j].type])(clk_out[j], clk_dev_id, |
3fde0e16 JS |
615 | parent_names, |
616 | num_parents, | |
617 | &nodes[j]); | |
618 | if (IS_ERR(hw)) | |
d3e4ebc1 RV |
619 | pr_warn_once("%s() 0x%x: %s register fail with %ld\n", |
620 | __func__, clk_dev_id, clk_name, | |
621 | PTR_ERR(hw)); | |
3fde0e16 | 622 | |
58b0fb86 | 623 | parent_names[0] = clk_out[j]; |
3fde0e16 | 624 | } |
58b0fb86 QW |
625 | |
626 | for (j = 0; j < num_nodes; j++) | |
627 | kfree(clk_out[j]); | |
628 | ||
3fde0e16 JS |
629 | return hw; |
630 | } | |
631 | ||
632 | /** | |
633 | * zynqmp_register_clocks() - Register clocks | |
634 | * @np: Device node | |
635 | * | |
636 | * Return: 0 on success else error code | |
637 | */ | |
638 | static int zynqmp_register_clocks(struct device_node *np) | |
639 | { | |
640 | int ret; | |
641 | u32 i, total_parents = 0, type = 0; | |
642 | const char *parent_names[MAX_PARENT]; | |
643 | ||
644 | for (i = 0; i < clock_max_idx; i++) { | |
645 | char clk_name[MAX_NAME_LEN]; | |
646 | ||
647 | /* get clock name, continue to next clock if name not found */ | |
648 | if (zynqmp_get_clock_name(i, clk_name)) | |
649 | continue; | |
650 | ||
651 | /* Check if clock is valid and output clock. | |
652 | * Do not register invalid or external clock. | |
653 | */ | |
654 | ret = zynqmp_get_clock_type(i, &type); | |
655 | if (ret || type != CLK_TYPE_OUTPUT) | |
656 | continue; | |
657 | ||
658 | /* Get parents of clock*/ | |
659 | if (zynqmp_get_parent_list(np, i, parent_names, | |
660 | &total_parents)) { | |
661 | WARN_ONCE(1, "No parents found for %s\n", | |
662 | clock[i].clk_name); | |
663 | continue; | |
664 | } | |
665 | ||
666 | zynqmp_data->hws[i] = | |
667 | zynqmp_register_clk_topology(i, clk_name, | |
668 | total_parents, | |
669 | parent_names); | |
670 | } | |
671 | ||
672 | for (i = 0; i < clock_max_idx; i++) { | |
673 | if (IS_ERR(zynqmp_data->hws[i])) { | |
674 | pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n", | |
675 | clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i])); | |
676 | WARN_ON(1); | |
677 | } | |
678 | } | |
679 | return 0; | |
680 | } | |
681 | ||
682 | /** | |
683 | * zynqmp_get_clock_info() - Get clock information from firmware using PM_API | |
684 | */ | |
685 | static void zynqmp_get_clock_info(void) | |
686 | { | |
687 | int i, ret; | |
5852b136 MT |
688 | u32 type = 0; |
689 | u32 nodetype, subclass, class; | |
690 | struct attr_resp attr; | |
691 | struct name_resp name; | |
3fde0e16 JS |
692 | |
693 | for (i = 0; i < clock_max_idx; i++) { | |
3fde0e16 JS |
694 | ret = zynqmp_pm_clock_get_attributes(i, &attr); |
695 | if (ret) | |
696 | continue; | |
697 | ||
5852b136 | 698 | clock[i].valid = FIELD_GET(CLK_ATTR_VALID, attr.attr[0]); |
5268aa1c RV |
699 | /* skip query for Invalid clock */ |
700 | ret = zynqmp_is_valid_clock(i); | |
701 | if (ret != CLK_ATTR_VALID) | |
702 | continue; | |
703 | ||
5852b136 MT |
704 | clock[i].type = FIELD_GET(CLK_ATTR_TYPE, attr.attr[0]) ? |
705 | CLK_TYPE_EXTERNAL : CLK_TYPE_OUTPUT; | |
d3e4ebc1 | 706 | |
5852b136 MT |
707 | nodetype = FIELD_GET(CLK_ATTR_NODE_TYPE, attr.attr[0]); |
708 | subclass = FIELD_GET(CLK_ATTR_NODE_SUBCLASS, attr.attr[0]); | |
709 | class = FIELD_GET(CLK_ATTR_NODE_CLASS, attr.attr[0]); | |
d3e4ebc1 | 710 | |
5852b136 MT |
711 | clock[i].clk_id = FIELD_PREP(CLK_ATTR_NODE_CLASS, class) | |
712 | FIELD_PREP(CLK_ATTR_NODE_SUBCLASS, subclass) | | |
713 | FIELD_PREP(CLK_ATTR_NODE_TYPE, nodetype) | | |
714 | FIELD_PREP(CLK_ATTR_NODE_INDEX, i); | |
715 | ||
716 | zynqmp_pm_clock_get_name(clock[i].clk_id, &name); | |
dd80fb2d IN |
717 | |
718 | /* | |
719 | * Terminate with NULL character in case name provided by firmware | |
720 | * is longer and truncated due to size limit. | |
721 | */ | |
722 | name.name[sizeof(name.name) - 1] = '\0'; | |
723 | ||
5852b136 MT |
724 | if (!strcmp(name.name, RESERVED_CLK_NAME)) |
725 | continue; | |
acc1c732 | 726 | strscpy(clock[i].clk_name, name.name, MAX_NAME_LEN); |
3fde0e16 JS |
727 | } |
728 | ||
729 | /* Get topology of all clock */ | |
730 | for (i = 0; i < clock_max_idx; i++) { | |
731 | ret = zynqmp_get_clock_type(i, &type); | |
732 | if (ret || type != CLK_TYPE_OUTPUT) | |
733 | continue; | |
734 | ||
735 | ret = zynqmp_clock_get_topology(i, clock[i].node, | |
736 | &clock[i].num_nodes); | |
737 | if (ret) | |
738 | continue; | |
739 | ||
740 | ret = zynqmp_clock_get_parents(i, clock[i].parent, | |
741 | &clock[i].num_parents); | |
742 | if (ret) | |
743 | continue; | |
744 | } | |
745 | } | |
746 | ||
747 | /** | |
748 | * zynqmp_clk_setup() - Setup the clock framework and register clocks | |
749 | * @np: Device node | |
750 | * | |
751 | * Return: 0 on success else error code | |
752 | */ | |
753 | static int zynqmp_clk_setup(struct device_node *np) | |
754 | { | |
755 | int ret; | |
756 | ||
757 | ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx); | |
758 | if (ret) | |
759 | return ret; | |
760 | ||
4f340efc GS |
761 | zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx), |
762 | GFP_KERNEL); | |
3fde0e16 JS |
763 | if (!zynqmp_data) |
764 | return -ENOMEM; | |
765 | ||
766 | clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL); | |
767 | if (!clock) { | |
768 | kfree(zynqmp_data); | |
769 | return -ENOMEM; | |
770 | } | |
771 | ||
772 | zynqmp_get_clock_info(); | |
773 | zynqmp_register_clocks(np); | |
774 | ||
775 | zynqmp_data->num = clock_max_idx; | |
47d0fbd1 | 776 | return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data); |
3fde0e16 JS |
777 | } |
778 | ||
779 | static int zynqmp_clock_probe(struct platform_device *pdev) | |
780 | { | |
781 | int ret; | |
782 | struct device *dev = &pdev->dev; | |
783 | ||
3fde0e16 JS |
784 | ret = zynqmp_clk_setup(dev->of_node); |
785 | ||
786 | return ret; | |
787 | } | |
788 | ||
789 | static const struct of_device_id zynqmp_clock_of_match[] = { | |
790 | {.compatible = "xlnx,zynqmp-clk"}, | |
c1e846b8 | 791 | {.compatible = "xlnx,versal-clk"}, |
3fde0e16 JS |
792 | {}, |
793 | }; | |
794 | MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match); | |
795 | ||
796 | static struct platform_driver zynqmp_clock_driver = { | |
797 | .driver = { | |
798 | .name = "zynqmp_clock", | |
799 | .of_match_table = zynqmp_clock_of_match, | |
800 | }, | |
801 | .probe = zynqmp_clock_probe, | |
802 | }; | |
803 | module_platform_driver(zynqmp_clock_driver); |