blob: 29e936aff8d71cb1f39dbcc0e976e2a0f65d544b [file] [log] [blame]
Yann Gautier9aea69e2018-07-24 17:13:36 +02001/*
2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Yann Gautier9aea69e2018-07-24 17:13:36 +02009#include <libfdt.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
Yann Gautier9aea69e2018-07-24 17:13:36 +020011#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000012
13#include <common/debug.h>
14#include <drivers/st/stm32_gpio.h>
15#include <drivers/st/stm32mp1_clk.h>
16#include <drivers/st/stm32mp1_clkfunc.h>
17#include <drivers/st/stm32mp1_ddr.h>
18#include <drivers/st/stm32mp1_ram.h>
19
Yann Gautier9aea69e2018-07-24 17:13:36 +020020#include <stm32mp1_dt.h>
21
22#define DT_GPIO_BANK_SHIFT 12
23#define DT_GPIO_BANK_MASK 0x1F000U
24#define DT_GPIO_PIN_SHIFT 8
25#define DT_GPIO_PIN_MASK 0xF00U
26#define DT_GPIO_MODE_MASK 0xFFU
27
28static int fdt_checked;
29
30static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE;
31
32/*******************************************************************************
Yann Gautierd0ca7f42018-07-13 21:33:09 +020033 * This function gets the pin settings from DT information.
34 * When analyze and parsing is done, set the GPIO registers.
35 * Return 0 on success, else return a negative FDT_ERR_xxx error code.
36 ******************************************************************************/
37static int dt_set_gpio_config(int node)
38{
39 const fdt32_t *cuint, *slewrate;
40 int len, pinctrl_node, pinctrl_subnode;
41 uint32_t i;
42 uint32_t speed = GPIO_SPEED_LOW;
43 uint32_t pull = GPIO_NO_PULL;
44
45 cuint = fdt_getprop(fdt, node, "pinmux", &len);
46 if (cuint == NULL) {
47 return -FDT_ERR_NOTFOUND;
48 }
49
50 pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
51 if (pinctrl_node < 0) {
52 return -FDT_ERR_NOTFOUND;
53 }
54
55 slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
56 if (slewrate != NULL) {
57 speed = fdt32_to_cpu(*slewrate);
58 }
59
60 if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
61 pull = GPIO_PULL_UP;
62 } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
63 pull = GPIO_PULL_DOWN;
64 } else {
65 VERBOSE("No bias configured in node %d\n", node);
66 }
67
68 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
69 uint32_t pincfg;
70 uint32_t bank;
71 uint32_t pin;
72 uint32_t mode;
73 uint32_t alternate = GPIO_ALTERNATE_0;
74
75 pincfg = fdt32_to_cpu(*cuint);
76 cuint++;
77
78 bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
79
80 pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
81
82 mode = pincfg & DT_GPIO_MODE_MASK;
83
84 switch (mode) {
85 case 0:
86 mode = GPIO_MODE_INPUT;
87 break;
88 case 1 ... 16:
89 alternate = mode - 1U;
90 mode = GPIO_MODE_ALTERNATE;
91 break;
92 case 17:
93 mode = GPIO_MODE_ANALOG;
94 break;
95 default:
96 mode = GPIO_MODE_OUTPUT;
97 break;
98 }
99
100 if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
101 mode |= GPIO_OPEN_DRAIN;
102 }
103
104 fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
105 uint32_t bank_offset;
106 const fdt32_t *cuint2;
107
108 if (fdt_getprop(fdt, pinctrl_subnode,
109 "gpio-controller", NULL) == NULL) {
110 continue;
111 }
112
113 cuint2 = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
114 if (cuint2 == NULL) {
115 continue;
116 }
117
118 if (bank == GPIO_BANK_Z) {
119 bank_offset = 0;
120 } else {
121 bank_offset = bank * STM32_GPIO_BANK_OFFSET;
122 }
123
124 if (fdt32_to_cpu(*cuint2) == bank_offset) {
125 int clk_id = fdt_get_clock_id(pinctrl_subnode);
126
127 if (clk_id < 0) {
128 return -FDT_ERR_NOTFOUND;
129 }
130
131 if (stm32mp1_clk_enable((unsigned long)clk_id) <
132 0) {
133 return -FDT_ERR_BADVALUE;
134 }
135
136 break;
137 }
138 }
139
140 set_gpio(bank, pin, mode, speed, pull, alternate);
141 }
142
143 return 0;
144}
145
146/*******************************************************************************
Yann Gautier9aea69e2018-07-24 17:13:36 +0200147 * This function checks device tree file with its header.
148 * Returns 0 if success, and a negative value else.
149 ******************************************************************************/
150int dt_open_and_check(void)
151{
152 int ret = fdt_check_header(fdt);
153
154 if (ret == 0) {
155 fdt_checked = 1;
156 }
157
158 return ret;
159}
160
161/*******************************************************************************
162 * This function gets the address of the DT.
163 * If DT is OK, fdt_addr is filled with DT address.
164 * Returns 1 if success, 0 otherwise.
165 ******************************************************************************/
166int fdt_get_address(void **fdt_addr)
167{
168 if (fdt_checked == 1) {
169 *fdt_addr = fdt;
170 }
171
172 return fdt_checked;
173}
174
175/*******************************************************************************
176 * This function check the presence of a node (generic use of fdt library).
177 * Returns true if present, false else.
178 ******************************************************************************/
179bool fdt_check_node(int node)
180{
181 int len;
182 const char *cchar;
183
184 cchar = fdt_get_name(fdt, node, &len);
185
186 return (cchar != NULL) && (len >= 0);
187}
188
189/*******************************************************************************
190 * This function check the status of a node (generic use of fdt library).
191 * Returns true if "okay" or missing, false else.
192 ******************************************************************************/
193bool fdt_check_status(int node)
194{
195 int len;
196 const char *cchar;
197
198 cchar = fdt_getprop(fdt, node, "status", &len);
199 if (cchar == NULL) {
200 return true;
201 }
202
203 return strncmp(cchar, "okay", (size_t)len) == 0;
204}
205
206/*******************************************************************************
207 * This function check the secure-status of a node (generic use of fdt library).
208 * Returns true if "okay" or missing, false else.
209 ******************************************************************************/
210bool fdt_check_secure_status(int node)
211{
212 int len;
213 const char *cchar;
214
215 cchar = fdt_getprop(fdt, node, "secure-status", &len);
216 if (cchar == NULL) {
217 return true;
218 }
219
220 return strncmp(cchar, "okay", (size_t)len) == 0;
221}
222
223/*******************************************************************************
224 * This function reads a value of a node property (generic use of fdt
225 * library).
226 * Returns value if success, and a default value if property not found.
227 * Default value is passed as parameter.
228 ******************************************************************************/
229uint32_t fdt_read_uint32_default(int node, const char *prop_name,
230 uint32_t dflt_value)
231{
232 const fdt32_t *cuint;
233 int lenp;
234
235 cuint = fdt_getprop(fdt, node, prop_name, &lenp);
236 if (cuint == NULL) {
237 return dflt_value;
238 }
239
240 return fdt32_to_cpu(*cuint);
241}
242
243/*******************************************************************************
244 * This function reads a series of parameters in a node property
245 * (generic use of fdt library).
246 * It reads the values inside the device tree, from property name and node.
247 * The number of parameters is also indicated as entry parameter.
248 * Returns 0 if success, and a negative value else.
249 * If success, values are stored at the third parameter address.
250 ******************************************************************************/
251int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
252 uint32_t count)
253{
254 const fdt32_t *cuint;
255 int len;
256 uint32_t i;
257
258 cuint = fdt_getprop(fdt, node, prop_name, &len);
259 if (cuint == NULL) {
260 return -FDT_ERR_NOTFOUND;
261 }
262
263 if ((uint32_t)len != (count * sizeof(uint32_t))) {
264 return -FDT_ERR_BADLAYOUT;
265 }
266
267 for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
268 *array = fdt32_to_cpu(*cuint);
269 array++;
270 cuint++;
271 }
272
273 return 0;
274}
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200275
276/*******************************************************************************
277 * This function gets the pin settings from DT information.
278 * When analyze and parsing is done, set the GPIO registers.
279 * Returns 0 if success, and a negative value else.
280 ******************************************************************************/
281int dt_set_pinctrl_config(int node)
282{
283 const fdt32_t *cuint;
284 int lenp = 0;
285 uint32_t i;
286
287 if (!fdt_check_status(node)) {
288 return -FDT_ERR_NOTFOUND;
289 }
290
291 cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
292 if (cuint == NULL) {
293 return -FDT_ERR_NOTFOUND;
294 }
295
296 for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
297 int phandle_node, phandle_subnode;
298
299 phandle_node =
300 fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
301 if (phandle_node < 0) {
302 return -FDT_ERR_NOTFOUND;
303 }
304
305 fdt_for_each_subnode(phandle_subnode, fdt, phandle_node) {
306 int ret = dt_set_gpio_config(phandle_subnode);
307
308 if (ret < 0) {
309 return ret;
310 }
311 }
312
313 cuint++;
314 }
315
316 return 0;
317}
Yann Gautier69035a82018-07-05 16:48:16 +0200318
319/*******************************************************************************
320 * This function gets the stdout pin configuration information from the DT.
321 * And then calls the sub-function to treat it and set GPIO registers.
322 * Returns 0 if success, and a negative value else.
323 ******************************************************************************/
324int dt_set_stdout_pinctrl(void)
325{
326 int node;
327
328 node = dt_get_stdout_node_offset();
329 if (node < 0) {
330 return -FDT_ERR_NOTFOUND;
331 }
332
333 return dt_set_pinctrl_config(node);
334}
335
336/*******************************************************************************
337 * This function fills the generic information from a given node.
338 ******************************************************************************/
339void dt_fill_device_info(struct dt_node_info *info, int node)
340{
341 const fdt32_t *cuint;
342
343 cuint = fdt_getprop(fdt, node, "reg", NULL);
344 if (cuint != NULL) {
345 info->base = fdt32_to_cpu(*cuint);
346 } else {
347 info->base = 0;
348 }
349
350 cuint = fdt_getprop(fdt, node, "clocks", NULL);
351 if (cuint != NULL) {
352 cuint++;
353 info->clock = (int)fdt32_to_cpu(*cuint);
354 } else {
355 info->clock = -1;
356 }
357
358 cuint = fdt_getprop(fdt, node, "resets", NULL);
359 if (cuint != NULL) {
360 cuint++;
361 info->reset = (int)fdt32_to_cpu(*cuint);
362 } else {
363 info->reset = -1;
364 }
365
366 info->status = fdt_check_status(node);
367 info->sec_status = fdt_check_secure_status(node);
368}
369
370/*******************************************************************************
371 * This function retrieve the generic information from DT.
372 * Returns node if success, and a negative value else.
373 ******************************************************************************/
374int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
375{
376 int node;
377
378 node = fdt_node_offset_by_compatible(fdt, offset, compat);
379 if (node < 0) {
380 return -FDT_ERR_NOTFOUND;
381 }
382
383 dt_fill_device_info(info, node);
384
385 return node;
386}
387
388/*******************************************************************************
389 * This function gets the UART instance info of stdout from the DT.
390 * Returns node if success, and a negative value else.
391 ******************************************************************************/
392int dt_get_stdout_uart_info(struct dt_node_info *info)
393{
394 int node;
395
396 node = dt_get_stdout_node_offset();
397 if (node < 0) {
398 return -FDT_ERR_NOTFOUND;
399 }
400
401 dt_fill_device_info(info, node);
402
403 return node;
404}
405
406/*******************************************************************************
407 * This function gets the stdout path node.
408 * It reads the value indicated inside the device tree.
409 * Returns node if success, and a negative value else.
410 ******************************************************************************/
411int dt_get_stdout_node_offset(void)
412{
413 int node;
414 const char *cchar;
415
416 node = fdt_path_offset(fdt, "/chosen");
417 if (node < 0) {
418 return -FDT_ERR_NOTFOUND;
419 }
420
421 cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
422 if (cchar == NULL) {
423 return -FDT_ERR_NOTFOUND;
424 }
425
426 node = -FDT_ERR_NOTFOUND;
427 if (strchr(cchar, (int)':') != NULL) {
428 const char *name;
429 char *str = (char *)cchar;
430 int len = 0;
431
432 while (strncmp(":", str, 1)) {
433 len++;
434 str++;
435 }
436
437 name = fdt_get_alias_namelen(fdt, cchar, len);
438
439 if (name != NULL) {
440 node = fdt_path_offset(fdt, name);
441 }
442 } else {
443 node = fdt_path_offset(fdt, cchar);
444 }
445
446 return node;
447}
448
449/*******************************************************************************
Yann Gautiercaf575b2018-07-24 17:18:19 +0200450 * This function gets DDR size information from the DT.
451 * Returns value in bytes if success, and STM32MP1_DDR_SIZE_DFLT else.
452 ******************************************************************************/
453uint32_t dt_get_ddr_size(void)
454{
455 int node;
456
457 node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
458 if (node < 0) {
459 INFO("%s: Cannot read DDR node in DT\n", __func__);
460 return STM32MP1_DDR_SIZE_DFLT;
461 }
462
463 return fdt_read_uint32_default(node, "st,mem-size",
464 STM32MP1_DDR_SIZE_DFLT);
465}
466
467/*******************************************************************************
Yann Gautier69035a82018-07-05 16:48:16 +0200468 * This function retrieves board model from DT
469 * Returns string taken from model node, NULL otherwise
470 ******************************************************************************/
471const char *dt_get_board_model(void)
472{
473 int node = fdt_path_offset(fdt, "/");
474
475 if (node < 0) {
476 return NULL;
477 }
478
479 return (const char *)fdt_getprop(fdt, node, "model", NULL);
480}