1 /*
2 * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9
10 #include <common/debug.h>
11 #include <common/fdt_wrappers.h>
12 #include <drivers/st/regulator.h>
13 #include <drivers/st/stm32_gpio.h>
14 #include <libfdt.h>
15
16 #include <platform_def.h>
17 #include <stm32mp_dt.h>
18
19 static void *fdt;
20
21 /*******************************************************************************
22 * This function checks device tree file with its header.
23 * Returns 0 on success and a negative FDT error code on failure.
24 ******************************************************************************/
dt_open_and_check(uintptr_t dt_addr)25 int dt_open_and_check(uintptr_t dt_addr)
26 {
27 int ret;
28
29 ret = fdt_check_header((void *)dt_addr);
30 if (ret == 0) {
31 fdt = (void *)dt_addr;
32 }
33
34 return ret;
35 }
36
37 /*******************************************************************************
38 * This function gets the address of the DT.
39 * If DT is OK, fdt_addr is filled with DT address.
40 * Returns 1 if success, 0 otherwise.
41 ******************************************************************************/
fdt_get_address(void ** fdt_addr)42 int fdt_get_address(void **fdt_addr)
43 {
44 if (fdt == NULL) {
45 return 0;
46 }
47
48 *fdt_addr = fdt;
49
50 return 1;
51 }
52
53 /*******************************************************************************
54 * This function check the presence of a node (generic use of fdt library).
55 * Returns true if present, else return false.
56 ******************************************************************************/
fdt_check_node(int node)57 bool fdt_check_node(int node)
58 {
59 int len;
60 const char *cchar;
61
62 cchar = fdt_get_name(fdt, node, &len);
63
64 return (cchar != NULL) && (len >= 0);
65 }
66
67 /*******************************************************************************
68 * This function return global node status (generic use of fdt library).
69 ******************************************************************************/
fdt_get_status(int node)70 uint8_t fdt_get_status(int node)
71 {
72 uint8_t status = DT_DISABLED;
73 const char *cchar;
74
75 cchar = fdt_getprop(fdt, node, "status", NULL);
76 if ((cchar == NULL) ||
77 (strncmp(cchar, "okay", strlen("okay")) == 0)) {
78 status |= DT_NON_SECURE;
79 }
80
81 cchar = fdt_getprop(fdt, node, "secure-status", NULL);
82 if (((cchar == NULL) && (status == DT_NON_SECURE)) ||
83 ((cchar != NULL) && (strncmp(cchar, "okay", strlen("okay")) == 0))) {
84 status |= DT_SECURE;
85 }
86
87 return status;
88 }
89
90 #if ENABLE_ASSERTIONS
91 /*******************************************************************************
92 * This function returns the address cells from the node parent.
93 * Returns:
94 * - #address-cells value if success.
95 * - invalid value if error.
96 * - a default value if undefined #address-cells property as per libfdt
97 * implementation.
98 ******************************************************************************/
fdt_get_node_parent_address_cells(int node)99 static int fdt_get_node_parent_address_cells(int node)
100 {
101 int parent;
102
103 parent = fdt_parent_offset(fdt, node);
104 if (parent < 0) {
105 return -FDT_ERR_NOTFOUND;
106 }
107
108 return fdt_address_cells(fdt, parent);
109 }
110 #endif
111
112 /*******************************************************************************
113 * This function gets the stdout pin configuration information from the DT.
114 * And then calls the sub-function to treat it and set GPIO registers.
115 * Returns 0 on success and a negative FDT error code on failure.
116 ******************************************************************************/
dt_set_stdout_pinctrl(void)117 int dt_set_stdout_pinctrl(void)
118 {
119 int node;
120
121 node = fdt_get_stdout_node_offset(fdt);
122 if (node < 0) {
123 return -FDT_ERR_NOTFOUND;
124 }
125
126 return dt_set_pinctrl_config(node);
127 }
128
129 /*******************************************************************************
130 * This function fills the generic information from a given node.
131 ******************************************************************************/
dt_fill_device_info(struct dt_node_info * info,int node)132 void dt_fill_device_info(struct dt_node_info *info, int node)
133 {
134 const fdt32_t *cuint;
135
136 assert(fdt_get_node_parent_address_cells(node) == 1);
137
138 cuint = fdt_getprop(fdt, node, "reg", NULL);
139 if (cuint != NULL) {
140 info->base = fdt32_to_cpu(*cuint);
141 } else {
142 info->base = 0;
143 }
144
145 cuint = fdt_getprop(fdt, node, "clocks", NULL);
146 if (cuint != NULL) {
147 cuint++;
148 info->clock = (int)fdt32_to_cpu(*cuint);
149 } else {
150 info->clock = -1;
151 }
152
153 cuint = fdt_getprop(fdt, node, "resets", NULL);
154 if (cuint != NULL) {
155 cuint++;
156 info->reset = (int)fdt32_to_cpu(*cuint);
157 } else {
158 info->reset = -1;
159 }
160
161 info->status = fdt_get_status(node);
162 }
163
164 /*******************************************************************************
165 * This function retrieve the generic information from DT.
166 * Returns node on success and a negative FDT error code on failure.
167 ******************************************************************************/
dt_get_node(struct dt_node_info * info,int offset,const char * compat)168 int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
169 {
170 int node;
171
172 node = fdt_node_offset_by_compatible(fdt, offset, compat);
173 if (node < 0) {
174 return -FDT_ERR_NOTFOUND;
175 }
176
177 dt_fill_device_info(info, node);
178
179 return node;
180 }
181
182 /*******************************************************************************
183 * This function gets the UART instance info of stdout from the DT.
184 * Returns node on success and a negative FDT error code on failure.
185 ******************************************************************************/
dt_get_stdout_uart_info(struct dt_node_info * info)186 int dt_get_stdout_uart_info(struct dt_node_info *info)
187 {
188 int node;
189
190 node = fdt_get_stdout_node_offset(fdt);
191 if (node < 0) {
192 return -FDT_ERR_NOTFOUND;
193 }
194
195 dt_fill_device_info(info, node);
196
197 return node;
198 }
199
200 /*******************************************************************************
201 * This function returns the node offset matching compatible string in the DT,
202 * and also matching the reg property with the given address.
203 * Returns value on success, and error value on failure.
204 ******************************************************************************/
dt_match_instance_by_compatible(const char * compatible,uintptr_t address)205 int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
206 {
207 int node;
208
209 fdt_for_each_compatible_node(fdt, node, compatible) {
210 const fdt32_t *cuint;
211
212 assert(fdt_get_node_parent_address_cells(node) == 1);
213
214 cuint = fdt_getprop(fdt, node, "reg", NULL);
215 if (cuint == NULL) {
216 continue;
217 }
218
219 if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
220 return node;
221 }
222 }
223
224 return -FDT_ERR_NOTFOUND;
225 }
226
227 /*******************************************************************************
228 * This function gets DDR size information from the DT.
229 * Returns value in bytes on success, and 0 on failure.
230 ******************************************************************************/
dt_get_ddr_size(void)231 size_t dt_get_ddr_size(void)
232 {
233 static size_t size;
234 int node;
235
236 if (size != 0U) {
237 return size;
238 }
239
240 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
241 if (node < 0) {
242 INFO("%s: Cannot read DDR node in DT\n", __func__);
243 return 0U;
244 }
245
246 size = (size_t)fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
247
248 flush_dcache_range((uintptr_t)&size, sizeof(size_t));
249
250 return size;
251 }
252
253 /*******************************************************************************
254 * This function gets PWR VDD regulator voltage information from the DT.
255 * Returns value in microvolts on success, and 0 on failure.
256 ******************************************************************************/
dt_get_pwr_vdd_voltage(void)257 uint32_t dt_get_pwr_vdd_voltage(void)
258 {
259 struct rdev *regul = dt_get_vdd_regulator();
260 uint16_t min;
261
262 if (regul == NULL) {
263 return 0;
264 }
265
266 regulator_get_range(regul, &min, NULL);
267
268 return (uint32_t)min * 1000U;
269 }
270
271 /*******************************************************************************
272 * This function retrieves VDD supply regulator from DT.
273 * Returns an rdev taken from supply node, NULL otherwise.
274 ******************************************************************************/
dt_get_vdd_regulator(void)275 struct rdev *dt_get_vdd_regulator(void)
276 {
277 int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
278
279 if (node < 0) {
280 return NULL;
281 }
282
283 return regulator_get_by_supply_name(fdt, node, "vdd");
284 }
285
286 /*******************************************************************************
287 * This function retrieves CPU supply regulator from DT.
288 * Returns an rdev taken from supply node, NULL otherwise.
289 ******************************************************************************/
dt_get_cpu_regulator(void)290 struct rdev *dt_get_cpu_regulator(void)
291 {
292 int node = fdt_path_offset(fdt, "/cpus/cpu@0");
293
294 if (node < 0) {
295 return NULL;
296 }
297
298 return regulator_get_by_supply_name(fdt, node, "cpu");
299 }
300
301 /*******************************************************************************
302 * This function retrieves board model from DT
303 * Returns string taken from model node, NULL otherwise
304 ******************************************************************************/
dt_get_board_model(void)305 const char *dt_get_board_model(void)
306 {
307 int node = fdt_path_offset(fdt, "/");
308
309 if (node < 0) {
310 return NULL;
311 }
312
313 return (const char *)fdt_getprop(fdt, node, "model", NULL);
314 }
315
316 /*******************************************************************************
317 * dt_find_otp_name: get OTP ID and length in DT.
318 * name: sub-node name to look up.
319 * otp: pointer to read OTP number or NULL.
320 * otp_len: pointer to read OTP length in bits or NULL.
321 * return value: 0 if no error, an FDT error value otherwise.
322 ******************************************************************************/
dt_find_otp_name(const char * name,uint32_t * otp,uint32_t * otp_len)323 int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
324 {
325 int node;
326 int len;
327 const fdt32_t *cuint;
328
329 if ((name == NULL) || (otp == NULL)) {
330 return -FDT_ERR_BADVALUE;
331 }
332
333 node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
334 if (node < 0) {
335 return node;
336 }
337
338 node = fdt_subnode_offset(fdt, node, name);
339 if (node < 0) {
340 ERROR("nvmem node %s not found\n", name);
341 return node;
342 }
343
344 cuint = fdt_getprop(fdt, node, "reg", &len);
345 if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
346 ERROR("Malformed nvmem node %s: ignored\n", name);
347 return -FDT_ERR_BADVALUE;
348 }
349
350 if ((fdt32_to_cpu(*cuint) % sizeof(uint32_t)) != 0U) {
351 ERROR("Misaligned nvmem %s element: ignored\n", name);
352 return -FDT_ERR_BADVALUE;
353 }
354
355 if (otp != NULL) {
356 *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
357 }
358
359 if (otp_len != NULL) {
360 cuint++;
361 *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
362 }
363
364 return 0;
365 }
366
367 /*******************************************************************************
368 * This function gets the pin count for a GPIO bank based from the FDT.
369 * It also checks node consistency.
370 ******************************************************************************/
fdt_get_gpio_bank_pin_count(unsigned int bank)371 int fdt_get_gpio_bank_pin_count(unsigned int bank)
372 {
373 int pinctrl_node;
374 int node;
375 uint32_t bank_offset;
376
377 pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
378 if (pinctrl_node < 0) {
379 return -FDT_ERR_NOTFOUND;
380 }
381
382 bank_offset = stm32_get_gpio_bank_offset(bank);
383
384 fdt_for_each_subnode(node, fdt, pinctrl_node) {
385 const fdt32_t *cuint;
386 int pin_count = 0;
387 int len;
388 int i;
389
390 if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
391 continue;
392 }
393
394 cuint = fdt_getprop(fdt, node, "reg", NULL);
395 if (cuint == NULL) {
396 continue;
397 }
398
399 if (fdt32_to_cpu(*cuint) != bank_offset) {
400 continue;
401 }
402
403 if (fdt_get_status(node) == DT_DISABLED) {
404 return 0;
405 }
406
407 /* Parse gpio-ranges with its 4 parameters */
408 cuint = fdt_getprop(fdt, node, "gpio-ranges", &len);
409 len /= sizeof(*cuint);
410 if ((len % 4) != 0) {
411 return -FDT_ERR_BADVALUE;
412 }
413
414 /* Get the last defined gpio line (offset + nb of pins) */
415 for (i = 0; i < len; i += 4) {
416 pin_count = MAX(pin_count, (int)(fdt32_to_cpu(cuint[i + 1]) +
417 fdt32_to_cpu(cuint[i + 3])));
418 }
419
420 return pin_count;
421 }
422
423 return 0;
424 }
425