blob: fe46ffac984073d30e26b377a5d310d0e9523f4f [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}