blob: 1cbf51bacb2a59628c0d8873587483e26e26a2c5 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +02002 * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
Yann Gautier9aea69e2018-07-24 17:13:36 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Yann Gautier038bff22019-01-17 19:17:47 +01008#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <common/debug.h>
Andre Przywaracc99f3f2020-03-26 12:51:21 +000011#include <common/fdt_wrappers.h>
Yann Gautier296e1ab2021-09-17 16:08:12 +020012#include <drivers/st/regulator.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000013#include <drivers/st/stm32_gpio.h>
Yann Gautier296e1ab2021-09-17 16:08:12 +020014#include <libfdt.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015
Yann Gautier296e1ab2021-09-17 16:08:12 +020016#include <platform_def.h>
Yann Gautieree8f5422019-02-14 11:13:25 +010017#include <stm32mp_dt.h>
18
Yann Gautier05773eb2020-08-24 11:51:50 +020019static void *fdt;
Yann Gautier9aea69e2018-07-24 17:13:36 +020020
21/*******************************************************************************
22 * This function checks device tree file with its header.
Yann Gautier038bff22019-01-17 19:17:47 +010023 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +020024 ******************************************************************************/
Yann Gautier05773eb2020-08-24 11:51:50 +020025int dt_open_and_check(uintptr_t dt_addr)
Yann Gautier9aea69e2018-07-24 17:13:36 +020026{
Yann Gautier05773eb2020-08-24 11:51:50 +020027 int ret;
Yann Gautier9aea69e2018-07-24 17:13:36 +020028
Yann Gautier05773eb2020-08-24 11:51:50 +020029 ret = fdt_check_header((void *)dt_addr);
Yann Gautier9aea69e2018-07-24 17:13:36 +020030 if (ret == 0) {
Yann Gautier05773eb2020-08-24 11:51:50 +020031 fdt = (void *)dt_addr;
Yann Gautier9aea69e2018-07-24 17:13:36 +020032 }
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 ******************************************************************************/
42int fdt_get_address(void **fdt_addr)
43{
Yann Gautier05773eb2020-08-24 11:51:50 +020044 if (fdt == NULL) {
45 return 0;
Yann Gautier9aea69e2018-07-24 17:13:36 +020046 }
47
Yann Gautier05773eb2020-08-24 11:51:50 +020048 *fdt_addr = fdt;
49
50 return 1;
Yann Gautier9aea69e2018-07-24 17:13:36 +020051}
52
53/*******************************************************************************
54 * This function check the presence of a node (generic use of fdt library).
Yann Gautier038bff22019-01-17 19:17:47 +010055 * Returns true if present, else return false.
Yann Gautier9aea69e2018-07-24 17:13:36 +020056 ******************************************************************************/
57bool 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/*******************************************************************************
Yann Gautier038bff22019-01-17 19:17:47 +010068 * This function return global node status (generic use of fdt library).
Yann Gautier9aea69e2018-07-24 17:13:36 +020069 ******************************************************************************/
Yann Gautieree8f5422019-02-14 11:13:25 +010070uint8_t fdt_get_status(int node)
Yann Gautier9aea69e2018-07-24 17:13:36 +020071{
Yann Gautieree8f5422019-02-14 11:13:25 +010072 uint8_t status = DT_DISABLED;
Yann Gautier9aea69e2018-07-24 17:13:36 +020073 const char *cchar;
74
Yann Gautier1c959332021-03-10 14:07:34 +010075 cchar = fdt_getprop(fdt, node, "status", NULL);
Yann Gautier038bff22019-01-17 19:17:47 +010076 if ((cchar == NULL) ||
Yann Gautier1c959332021-03-10 14:07:34 +010077 (strncmp(cchar, "okay", strlen("okay")) == 0)) {
Yann Gautier038bff22019-01-17 19:17:47 +010078 status |= DT_NON_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020079 }
80
Yann Gautier1c959332021-03-10 14:07:34 +010081 cchar = fdt_getprop(fdt, node, "secure-status", NULL);
Yann Gautier6768c072022-11-24 19:16:46 +010082 if (((cchar == NULL) && (status == DT_NON_SECURE)) ||
83 ((cchar != NULL) && (strncmp(cchar, "okay", strlen("okay")) == 0))) {
Yann Gautier038bff22019-01-17 19:17:47 +010084 status |= DT_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020085 }
86
Yann Gautier038bff22019-01-17 19:17:47 +010087 return status;
Yann Gautier9aea69e2018-07-24 17:13:36 +020088}
89
Yann Gautier2260b842020-03-11 17:17:51 +010090#if ENABLE_ASSERTIONS
Yann Gautier9aea69e2018-07-24 17:13:36 +020091/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +020092 * 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 ******************************************************************************/
Yann Gautier2260b842020-03-11 17:17:51 +010099static int fdt_get_node_parent_address_cells(int node)
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200100{
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}
Yann Gautier2260b842020-03-11 17:17:51 +0100110#endif
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200111
112/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200113 * 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.
Yann Gautier038bff22019-01-17 19:17:47 +0100115 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200116 ******************************************************************************/
117int dt_set_stdout_pinctrl(void)
118{
119 int node;
120
Andre Przywaraeec91922020-04-09 11:27:21 +0100121 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200122 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 ******************************************************************************/
132void dt_fill_device_info(struct dt_node_info *info, int node)
133{
134 const fdt32_t *cuint;
135
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200136 assert(fdt_get_node_parent_address_cells(node) == 1);
137
Yann Gautier69035a82018-07-05 16:48:16 +0200138 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
Yann Gautier038bff22019-01-17 19:17:47 +0100161 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200162}
163
164/*******************************************************************************
165 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100166 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200167 ******************************************************************************/
168int 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.
Yann Gautier038bff22019-01-17 19:17:47 +0100184 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200185 ******************************************************************************/
186int dt_get_stdout_uart_info(struct dt_node_info *info)
187{
188 int node;
189
Andre Przywaraeec91922020-04-09 11:27:21 +0100190 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200191 if (node < 0) {
192 return -FDT_ERR_NOTFOUND;
193 }
194
195 dt_fill_device_info(info, node);
196
197 return node;
198}
199
200/*******************************************************************************
Yann Gautier4e267842021-09-29 11:31:09 +0200201 * 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 ******************************************************************************/
205int 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/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200228 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100229 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200230 ******************************************************************************/
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +0200231size_t dt_get_ddr_size(void)
Yann Gautiercaf575b2018-07-24 17:18:19 +0200232{
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +0200233 static size_t size;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200234 int node;
235
Lionel Debieve003972c2020-09-24 16:01:12 +0200236 if (size != 0U) {
237 return size;
238 }
239
Yann Gautiercaf575b2018-07-24 17:18:19 +0200240 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__);
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +0200243 return 0U;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200244 }
245
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +0200246 size = (size_t)fdt_read_uint32_default(fdt, node, "st,mem-size", 0U);
Lionel Debieve003972c2020-09-24 16:01:12 +0200247
Sebastien PASDELOUP1c2d89b2023-06-05 09:56:49 +0200248 flush_dcache_range((uintptr_t)&size, sizeof(size_t));
Lionel Debieve003972c2020-09-24 16:01:12 +0200249
250 return size;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200251}
252
253/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200254 * This function gets PWR VDD regulator voltage information from the DT.
255 * Returns value in microvolts on success, and 0 on failure.
256 ******************************************************************************/
257uint32_t dt_get_pwr_vdd_voltage(void)
258{
Yann Gautier296e1ab2021-09-17 16:08:12 +0200259 struct rdev *regul = dt_get_vdd_regulator();
260 uint16_t min;
Yann Gautier3edc7c32019-05-20 19:17:08 +0200261
Yann Gautier296e1ab2021-09-17 16:08:12 +0200262 if (regul == NULL) {
Yann Gautier3edc7c32019-05-20 19:17:08 +0200263 return 0;
264 }
265
Yann Gautier296e1ab2021-09-17 16:08:12 +0200266 regulator_get_range(regul, &min, NULL);
Yann Gautier3edc7c32019-05-20 19:17:08 +0200267
Yann Gautier296e1ab2021-09-17 16:08:12 +0200268 return (uint32_t)min * 1000U;
269}
Yann Gautier3edc7c32019-05-20 19:17:08 +0200270
Yann Gautier296e1ab2021-09-17 16:08:12 +0200271/*******************************************************************************
272 * This function retrieves VDD supply regulator from DT.
273 * Returns an rdev taken from supply node, NULL otherwise.
274 ******************************************************************************/
275struct rdev *dt_get_vdd_regulator(void)
276{
277 int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
278
Yann Gautier3edc7c32019-05-20 19:17:08 +0200279 if (node < 0) {
Yann Gautier296e1ab2021-09-17 16:08:12 +0200280 return NULL;
Yann Gautier3edc7c32019-05-20 19:17:08 +0200281 }
282
Yann Gautier296e1ab2021-09-17 16:08:12 +0200283 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 ******************************************************************************/
290struct 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;
Yann Gautier3edc7c32019-05-20 19:17:08 +0200296 }
297
Yann Gautier296e1ab2021-09-17 16:08:12 +0200298 return regulator_get_by_supply_name(fdt, node, "cpu");
Yann Gautier3edc7c32019-05-20 19:17:08 +0200299}
300
301/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200302 * This function retrieves board model from DT
303 * Returns string taken from model node, NULL otherwise
304 ******************************************************************************/
305const 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}
Etienne Carriered81dadf2020-04-25 11:14:45 +0200315
316/*******************************************************************************
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100317 * 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 ******************************************************************************/
323int dt_find_otp_name(const char *name, uint32_t *otp, uint32_t *otp_len)
324{
325 int node;
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100326 int len;
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100327 const fdt32_t *cuint;
328
329 if ((name == NULL) || (otp == NULL)) {
330 return -FDT_ERR_BADVALUE;
331 }
332
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100333 node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100334 if (node < 0) {
335 return node;
336 }
337
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100338 node = fdt_subnode_offset(fdt, node, name);
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100339 if (node < 0) {
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100340 ERROR("nvmem node %s not found\n", name);
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100341 return node;
342 }
343
344 cuint = fdt_getprop(fdt, node, "reg", &len);
345 if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100346 ERROR("Malformed nvmem node %s: ignored\n", name);
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100347 return -FDT_ERR_BADVALUE;
348 }
349
Yann Gautier409b3822022-11-21 13:26:37 +0100350 if ((fdt32_to_cpu(*cuint) % sizeof(uint32_t)) != 0U) {
Patrick Delaunay82ece5c2022-03-01 09:56:03 +0100351 ERROR("Misaligned nvmem %s element: ignored\n", name);
Lionel Debievebc2d88d2019-11-04 14:31:38 +0100352 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/*******************************************************************************
Etienne Carriered81dadf2020-04-25 11:14:45 +0200368 * This function gets the pin count for a GPIO bank based from the FDT.
369 * It also checks node consistency.
370 ******************************************************************************/
371int 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;
Yann Gautier47516aa2022-11-21 11:45:04 +0100386 int pin_count = 0;
Fabien Dessenne41ab6522021-09-21 11:32:30 +0200387 int len;
388 int i;
Etienne Carriered81dadf2020-04-25 11:14:45 +0200389
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
Fabien Dessenne41ab6522021-09-21 11:32:30 +0200407 /* 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) */
Yann Gautier47516aa2022-11-21 11:45:04 +0100415 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])));
Etienne Carriered81dadf2020-04-25 11:14:45 +0200418 }
419
Fabien Dessenne41ab6522021-09-21 11:32:30 +0200420 return pin_count;
Etienne Carriered81dadf2020-04-25 11:14:45 +0200421 }
422
423 return 0;
424}