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