blob: 4f130ce20ca5b044dc04647593c4840674e33c52 [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
Yann Gautier1c959332021-03-10 14:07:34 +01002 * Copyright (c) 2017-2021, 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
Yann Gautier9aea69e2018-07-24 17:13:36 +020010#include <libfdt.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011
Yann Gautier9aea69e2018-07-24 17:13:36 +020012#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000013
14#include <common/debug.h>
Andre Przywaracc99f3f2020-03-26 12:51:21 +000015#include <common/fdt_wrappers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000016#include <drivers/st/stm32_gpio.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000017#include <drivers/st/stm32mp1_ddr.h>
18#include <drivers/st/stm32mp1_ram.h>
19
Yann Gautieree8f5422019-02-14 11:13:25 +010020#include <stm32mp_dt.h>
21
Yann Gautier9aea69e2018-07-24 17:13:36 +020022static int fdt_checked;
23
Yann Gautiera2e2a302019-02-14 11:13:39 +010024static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020025
26/*******************************************************************************
27 * This function checks device tree file with its header.
Yann Gautier038bff22019-01-17 19:17:47 +010028 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier9aea69e2018-07-24 17:13:36 +020029 ******************************************************************************/
30int dt_open_and_check(void)
31{
32 int ret = fdt_check_header(fdt);
33
34 if (ret == 0) {
35 fdt_checked = 1;
36 }
37
38 return ret;
39}
40
41/*******************************************************************************
42 * This function gets the address of the DT.
43 * If DT is OK, fdt_addr is filled with DT address.
44 * Returns 1 if success, 0 otherwise.
45 ******************************************************************************/
46int fdt_get_address(void **fdt_addr)
47{
48 if (fdt_checked == 1) {
49 *fdt_addr = fdt;
50 }
51
52 return fdt_checked;
53}
54
55/*******************************************************************************
56 * This function check the presence of a node (generic use of fdt library).
Yann Gautier038bff22019-01-17 19:17:47 +010057 * Returns true if present, else return false.
Yann Gautier9aea69e2018-07-24 17:13:36 +020058 ******************************************************************************/
59bool fdt_check_node(int node)
60{
61 int len;
62 const char *cchar;
63
64 cchar = fdt_get_name(fdt, node, &len);
65
66 return (cchar != NULL) && (len >= 0);
67}
68
69/*******************************************************************************
Yann Gautier038bff22019-01-17 19:17:47 +010070 * This function return global node status (generic use of fdt library).
Yann Gautier9aea69e2018-07-24 17:13:36 +020071 ******************************************************************************/
Yann Gautieree8f5422019-02-14 11:13:25 +010072uint8_t fdt_get_status(int node)
Yann Gautier9aea69e2018-07-24 17:13:36 +020073{
Yann Gautieree8f5422019-02-14 11:13:25 +010074 uint8_t status = DT_DISABLED;
Yann Gautier9aea69e2018-07-24 17:13:36 +020075 const char *cchar;
76
Yann Gautier1c959332021-03-10 14:07:34 +010077 cchar = fdt_getprop(fdt, node, "status", NULL);
Yann Gautier038bff22019-01-17 19:17:47 +010078 if ((cchar == NULL) ||
Yann Gautier1c959332021-03-10 14:07:34 +010079 (strncmp(cchar, "okay", strlen("okay")) == 0)) {
Yann Gautier038bff22019-01-17 19:17:47 +010080 status |= DT_NON_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020081 }
82
Yann Gautier1c959332021-03-10 14:07:34 +010083 cchar = fdt_getprop(fdt, node, "secure-status", NULL);
Yann Gautier9aea69e2018-07-24 17:13:36 +020084 if (cchar == NULL) {
Yann Gautier038bff22019-01-17 19:17:47 +010085 if (status == DT_NON_SECURE) {
86 status |= DT_SECURE;
87 }
Yann Gautier1c959332021-03-10 14:07:34 +010088 } else if (strncmp(cchar, "okay", strlen("okay")) == 0) {
Yann Gautier038bff22019-01-17 19:17:47 +010089 status |= DT_SECURE;
Yann Gautier9aea69e2018-07-24 17:13:36 +020090 }
91
Yann Gautier038bff22019-01-17 19:17:47 +010092 return status;
Yann Gautier9aea69e2018-07-24 17:13:36 +020093}
94
Yann Gautier2260b842020-03-11 17:17:51 +010095#if ENABLE_ASSERTIONS
Yann Gautier9aea69e2018-07-24 17:13:36 +020096/*******************************************************************************
Lionel Debieveb0899eb2019-09-24 17:41:11 +020097 * This function returns the address cells from the node parent.
98 * Returns:
99 * - #address-cells value if success.
100 * - invalid value if error.
101 * - a default value if undefined #address-cells property as per libfdt
102 * implementation.
103 ******************************************************************************/
Yann Gautier2260b842020-03-11 17:17:51 +0100104static int fdt_get_node_parent_address_cells(int node)
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200105{
106 int parent;
107
108 parent = fdt_parent_offset(fdt, node);
109 if (parent < 0) {
110 return -FDT_ERR_NOTFOUND;
111 }
112
113 return fdt_address_cells(fdt, parent);
114}
Yann Gautier2260b842020-03-11 17:17:51 +0100115#endif
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200116
117/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200118 * This function gets the stdout pin configuration information from the DT.
119 * And then calls the sub-function to treat it and set GPIO registers.
Yann Gautier038bff22019-01-17 19:17:47 +0100120 * Returns 0 on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200121 ******************************************************************************/
122int dt_set_stdout_pinctrl(void)
123{
124 int node;
125
Andre Przywaraeec91922020-04-09 11:27:21 +0100126 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200127 if (node < 0) {
128 return -FDT_ERR_NOTFOUND;
129 }
130
131 return dt_set_pinctrl_config(node);
132}
133
134/*******************************************************************************
135 * This function fills the generic information from a given node.
136 ******************************************************************************/
137void dt_fill_device_info(struct dt_node_info *info, int node)
138{
139 const fdt32_t *cuint;
140
Lionel Debieveb0899eb2019-09-24 17:41:11 +0200141 assert(fdt_get_node_parent_address_cells(node) == 1);
142
Yann Gautier69035a82018-07-05 16:48:16 +0200143 cuint = fdt_getprop(fdt, node, "reg", NULL);
144 if (cuint != NULL) {
145 info->base = fdt32_to_cpu(*cuint);
146 } else {
147 info->base = 0;
148 }
149
150 cuint = fdt_getprop(fdt, node, "clocks", NULL);
151 if (cuint != NULL) {
152 cuint++;
153 info->clock = (int)fdt32_to_cpu(*cuint);
154 } else {
155 info->clock = -1;
156 }
157
158 cuint = fdt_getprop(fdt, node, "resets", NULL);
159 if (cuint != NULL) {
160 cuint++;
161 info->reset = (int)fdt32_to_cpu(*cuint);
162 } else {
163 info->reset = -1;
164 }
165
Yann Gautier038bff22019-01-17 19:17:47 +0100166 info->status = fdt_get_status(node);
Yann Gautier69035a82018-07-05 16:48:16 +0200167}
168
169/*******************************************************************************
170 * This function retrieve the generic information from DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100171 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200172 ******************************************************************************/
173int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
174{
175 int node;
176
177 node = fdt_node_offset_by_compatible(fdt, offset, compat);
178 if (node < 0) {
179 return -FDT_ERR_NOTFOUND;
180 }
181
182 dt_fill_device_info(info, node);
183
184 return node;
185}
186
187/*******************************************************************************
188 * This function gets the UART instance info of stdout from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100189 * Returns node on success and a negative FDT error code on failure.
Yann Gautier69035a82018-07-05 16:48:16 +0200190 ******************************************************************************/
191int dt_get_stdout_uart_info(struct dt_node_info *info)
192{
193 int node;
194
Andre Przywaraeec91922020-04-09 11:27:21 +0100195 node = fdt_get_stdout_node_offset(fdt);
Yann Gautier69035a82018-07-05 16:48:16 +0200196 if (node < 0) {
197 return -FDT_ERR_NOTFOUND;
198 }
199
200 dt_fill_device_info(info, node);
201
202 return node;
203}
204
205/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200206 * This function gets DDR size information from the DT.
Yann Gautier038bff22019-01-17 19:17:47 +0100207 * Returns value in bytes on success, and 0 on failure.
Yann Gautiercaf575b2018-07-24 17:18:19 +0200208 ******************************************************************************/
209uint32_t dt_get_ddr_size(void)
210{
211 int node;
212
213 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
214 if (node < 0) {
215 INFO("%s: Cannot read DDR node in DT\n", __func__);
Yann Gautier038bff22019-01-17 19:17:47 +0100216 return 0;
Yann Gautiercaf575b2018-07-24 17:18:19 +0200217 }
218
Andre Przywara2d5690c2020-03-26 11:50:33 +0000219 return fdt_read_uint32_default(fdt, node, "st,mem-size", 0);
Yann Gautiercaf575b2018-07-24 17:18:19 +0200220}
221
222/*******************************************************************************
Yann Gautier3edc7c32019-05-20 19:17:08 +0200223 * This function gets PWR VDD regulator voltage information from the DT.
224 * Returns value in microvolts on success, and 0 on failure.
225 ******************************************************************************/
226uint32_t dt_get_pwr_vdd_voltage(void)
227{
228 int node, pwr_regulators_node;
229 const fdt32_t *cuint;
230
231 node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
232 if (node < 0) {
233 INFO("%s: Cannot read PWR node in DT\n", __func__);
234 return 0;
235 }
236
237 pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
Yann Gautierdf473922020-03-18 14:35:27 +0100238 if (pwr_regulators_node < 0) {
Yann Gautier3edc7c32019-05-20 19:17:08 +0200239 INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
240 return 0;
241 }
242
243 cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
244 if (cuint == NULL) {
245 return 0;
246 }
247
248 node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
249 if (node < 0) {
250 return 0;
251 }
252
253 cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
254 if (cuint == NULL) {
255 return 0;
256 }
257
258 return fdt32_to_cpu(*cuint);
259}
260
261/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200262 * This function retrieves board model from DT
263 * Returns string taken from model node, NULL otherwise
264 ******************************************************************************/
265const char *dt_get_board_model(void)
266{
267 int node = fdt_path_offset(fdt, "/");
268
269 if (node < 0) {
270 return NULL;
271 }
272
273 return (const char *)fdt_getprop(fdt, node, "model", NULL);
274}
Etienne Carriered81dadf2020-04-25 11:14:45 +0200275
276/*******************************************************************************
277 * This function gets the pin count for a GPIO bank based from the FDT.
278 * It also checks node consistency.
279 ******************************************************************************/
280int fdt_get_gpio_bank_pin_count(unsigned int bank)
281{
282 int pinctrl_node;
283 int node;
284 uint32_t bank_offset;
285
286 pinctrl_node = stm32_get_gpio_bank_pinctrl_node(fdt, bank);
287 if (pinctrl_node < 0) {
288 return -FDT_ERR_NOTFOUND;
289 }
290
291 bank_offset = stm32_get_gpio_bank_offset(bank);
292
293 fdt_for_each_subnode(node, fdt, pinctrl_node) {
294 const fdt32_t *cuint;
295
296 if (fdt_getprop(fdt, node, "gpio-controller", NULL) == NULL) {
297 continue;
298 }
299
300 cuint = fdt_getprop(fdt, node, "reg", NULL);
301 if (cuint == NULL) {
302 continue;
303 }
304
305 if (fdt32_to_cpu(*cuint) != bank_offset) {
306 continue;
307 }
308
309 if (fdt_get_status(node) == DT_DISABLED) {
310 return 0;
311 }
312
313 cuint = fdt_getprop(fdt, node, "ngpios", NULL);
314 if (cuint == NULL) {
315 return -FDT_ERR_NOTFOUND;
316 }
317
318 return (int)fdt32_to_cpu(*cuint);
319 }
320
321 return 0;
322}