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