blob: 5c54762ecc7300ee486061a1ffa519ea4a1a3257 [file] [log] [blame]
Yann Gautierd0ca7f42018-07-13 21:33:09 +02001/*
Yann Gautier2b79c372021-06-11 10:54:56 +02002 * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
Yann Gautierd0ca7f42018-07-13 21:33:09 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Yann Gautier038bff22019-01-17 19:17:47 +01007#include <assert.h>
8#include <errno.h>
Yann Gautierd0ca7f42018-07-13 21:33:09 +02009#include <stdbool.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
Yann Gautier038bff22019-01-17 19:17:47 +010011#include <libfdt.h>
12
13#include <platform_def.h>
14
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000015#include <common/bl_common.h>
16#include <common/debug.h>
Yann Gautiera205a5c2021-08-30 15:06:54 +020017#include <drivers/clk.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000018#include <drivers/st/stm32_gpio.h>
Yann Gautier4d429472019-02-14 11:15:20 +010019#include <drivers/st/stm32mp_clkfunc.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000020#include <lib/mmio.h>
Yann Gautier038bff22019-01-17 19:17:47 +010021#include <lib/utils_def.h>
Yann Gautierd0ca7f42018-07-13 21:33:09 +020022
Yann Gautier038bff22019-01-17 19:17:47 +010023#define DT_GPIO_BANK_SHIFT 12
24#define DT_GPIO_BANK_MASK GENMASK(16, 12)
25#define DT_GPIO_PIN_SHIFT 8
26#define DT_GPIO_PIN_MASK GENMASK(11, 8)
27#define DT_GPIO_MODE_MASK GENMASK(7, 0)
28
29/*******************************************************************************
30 * This function gets GPIO bank node in DT.
31 * Returns node offset if status is okay in DT, else return 0
32 ******************************************************************************/
33static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
Yann Gautierd0ca7f42018-07-13 21:33:09 +020034{
Yann Gautier038bff22019-01-17 19:17:47 +010035 int pinctrl_subnode;
36 uint32_t bank_offset = stm32_get_gpio_bank_offset(bank);
Yann Gautierd0ca7f42018-07-13 21:33:09 +020037
Yann Gautier038bff22019-01-17 19:17:47 +010038 fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
39 const fdt32_t *cuint;
40
41 if (fdt_getprop(fdt, pinctrl_subnode,
42 "gpio-controller", NULL) == NULL) {
43 continue;
44 }
45
46 cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
47 if (cuint == NULL) {
48 continue;
49 }
50
51 if ((fdt32_to_cpu(*cuint) == bank_offset) &&
52 (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) {
53 return pinctrl_subnode;
54 }
Yann Gautierd0ca7f42018-07-13 21:33:09 +020055 }
56
Yann Gautier038bff22019-01-17 19:17:47 +010057 return 0;
Yann Gautierd0ca7f42018-07-13 21:33:09 +020058}
59
Yann Gautier038bff22019-01-17 19:17:47 +010060/*******************************************************************************
61 * This function gets the pin settings from DT information.
62 * When analyze and parsing is done, set the GPIO registers.
63 * Returns 0 on success and a negative FDT error code on failure.
64 ******************************************************************************/
65static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
Yann Gautierd0ca7f42018-07-13 21:33:09 +020066{
Yann Gautier038bff22019-01-17 19:17:47 +010067 const fdt32_t *cuint, *slewrate;
68 int len;
69 int pinctrl_node;
70 uint32_t i;
71 uint32_t speed = GPIO_SPEED_LOW;
72 uint32_t pull = GPIO_NO_PULL;
Yann Gautierd0ca7f42018-07-13 21:33:09 +020073
Yann Gautier038bff22019-01-17 19:17:47 +010074 cuint = fdt_getprop(fdt, node, "pinmux", &len);
75 if (cuint == NULL) {
76 return -FDT_ERR_NOTFOUND;
Yann Gautierd0ca7f42018-07-13 21:33:09 +020077 }
78
Yann Gautier038bff22019-01-17 19:17:47 +010079 pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
80 if (pinctrl_node < 0) {
81 return -FDT_ERR_NOTFOUND;
82 }
83
84 slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
85 if (slewrate != NULL) {
86 speed = fdt32_to_cpu(*slewrate);
87 }
88
89 if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
90 pull = GPIO_PULL_UP;
91 } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
92 pull = GPIO_PULL_DOWN;
Yann Gautierd0ca7f42018-07-13 21:33:09 +020093 } else {
Yann Gautier038bff22019-01-17 19:17:47 +010094 VERBOSE("No bias configured in node %d\n", node);
Yann Gautierd0ca7f42018-07-13 21:33:09 +020095 }
96
Yann Gautier038bff22019-01-17 19:17:47 +010097 for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
98 uint32_t pincfg;
99 uint32_t bank;
100 uint32_t pin;
101 uint32_t mode;
102 uint32_t alternate = GPIO_ALTERNATE_(0);
103 int bank_node;
104 int clk;
105
106 pincfg = fdt32_to_cpu(*cuint);
107 cuint++;
108
109 bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
110
111 pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
112
113 mode = pincfg & DT_GPIO_MODE_MASK;
114
115 switch (mode) {
116 case 0:
117 mode = GPIO_MODE_INPUT;
118 break;
119 case 1 ... 16:
120 alternate = mode - 1U;
121 mode = GPIO_MODE_ALTERNATE;
122 break;
123 case 17:
124 mode = GPIO_MODE_ANALOG;
125 break;
126 default:
127 mode = GPIO_MODE_OUTPUT;
128 break;
129 }
130
131 if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
132 mode |= GPIO_OPEN_DRAIN;
133 }
134
135 bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
136 if (bank_node == 0) {
137 ERROR("PINCTRL inconsistent in DT\n");
138 panic();
139 }
140
141 clk = fdt_get_clock_id(bank_node);
142 if (clk < 0) {
143 return -FDT_ERR_NOTFOUND;
144 }
145
146 /* Platform knows the clock: assert it is okay */
147 assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank));
148
149 set_gpio(bank, pin, mode, speed, pull, alternate, status);
150 }
151
152 return 0;
153}
154
155/*******************************************************************************
156 * This function gets the pin settings from DT information.
157 * When analyze and parsing is done, set the GPIO registers.
158 * Returns 0 on success and a negative FDT/ERRNO error code on failure.
159 ******************************************************************************/
160int dt_set_pinctrl_config(int node)
161{
162 const fdt32_t *cuint;
163 int lenp = 0;
164 uint32_t i;
Yann Gautier2e002b02020-09-04 13:25:27 +0200165 uint8_t status;
Yann Gautier038bff22019-01-17 19:17:47 +0100166 void *fdt;
167
168 if (fdt_get_address(&fdt) == 0) {
Nicolas Le Bayonc5c69452019-09-11 15:58:31 +0200169 return -FDT_ERR_NOTFOUND;
Yann Gautier038bff22019-01-17 19:17:47 +0100170 }
171
Yann Gautier2e002b02020-09-04 13:25:27 +0200172 status = fdt_get_status(node);
Yann Gautier038bff22019-01-17 19:17:47 +0100173 if (status == DT_DISABLED) {
174 return -FDT_ERR_NOTFOUND;
175 }
176
177 cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
178 if (cuint == NULL) {
179 return -FDT_ERR_NOTFOUND;
180 }
181
182 for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
183 int p_node, p_subnode;
184
185 p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
186 if (p_node < 0) {
187 return -FDT_ERR_NOTFOUND;
188 }
189
190 fdt_for_each_subnode(p_subnode, fdt, p_node) {
191 int ret = dt_set_gpio_config(fdt, p_subnode, status);
192
193 if (ret < 0) {
194 return ret;
195 }
196 }
197
198 cuint++;
199 }
200
201 return 0;
202}
203
204void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
205 uint32_t pull, uint32_t alternate, uint8_t status)
206{
207 uintptr_t base = stm32_get_gpio_bank_base(bank);
208 unsigned long clock = stm32_get_gpio_bank_clock(bank);
209
210 assert(pin <= GPIO_PIN_MAX);
211
Yann Gautiera205a5c2021-08-30 15:06:54 +0200212 clk_enable(clock);
Yann Gautier038bff22019-01-17 19:17:47 +0100213
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100214 mmio_clrbits_32(base + GPIO_MODE_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200215 ((uint32_t)GPIO_MODE_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100216 mmio_setbits_32(base + GPIO_MODE_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200217 (mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
218
219 if ((mode & GPIO_OPEN_DRAIN) != 0U) {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100220 mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
221 } else {
222 mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200223 }
224
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100225 mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200226 ((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100227 mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200228
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100229 mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200230 ((uint32_t)GPIO_PULL_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100231 mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200232
233 if (pin < GPIO_ALT_LOWER_LIMIT) {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100234 mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200235 ((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100236 mmio_setbits_32(base + GPIO_AFRL_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200237 alternate << (pin << 2));
238 } else {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100239 mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200240 ((uint32_t)GPIO_ALTERNATE_MASK <<
241 ((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100242 mmio_setbits_32(base + GPIO_AFRH_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200243 alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
244 2));
245 }
246
247 VERBOSE("GPIO %u mode set to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100248 mmio_read_32(base + GPIO_MODE_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200249 VERBOSE("GPIO %u speed set to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100250 mmio_read_32(base + GPIO_SPEED_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200251 VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100252 mmio_read_32(base + GPIO_PUPD_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200253 VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100254 mmio_read_32(base + GPIO_AFRL_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200255 VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100256 mmio_read_32(base + GPIO_AFRH_OFFSET));
Yann Gautier038bff22019-01-17 19:17:47 +0100257
Yann Gautiera205a5c2021-08-30 15:06:54 +0200258 clk_disable(clock);
Etienne Carriere30189212019-12-02 10:11:32 +0100259
260 if (status == DT_SECURE) {
261 stm32mp_register_secure_gpio(bank, pin);
262 set_gpio_secure_cfg(bank, pin, true);
263
264 } else {
265 stm32mp_register_non_secure_gpio(bank, pin);
266 set_gpio_secure_cfg(bank, pin, false);
267 }
Yann Gautier038bff22019-01-17 19:17:47 +0100268}
269
270void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
271{
272 uintptr_t base = stm32_get_gpio_bank_base(bank);
Yann Gautieree8f5422019-02-14 11:13:25 +0100273 unsigned long clock = stm32_get_gpio_bank_clock(bank);
Yann Gautier038bff22019-01-17 19:17:47 +0100274
275 assert(pin <= GPIO_PIN_MAX);
276
Yann Gautiera205a5c2021-08-30 15:06:54 +0200277 clk_enable(clock);
Yann Gautier038bff22019-01-17 19:17:47 +0100278
279 if (secure) {
280 mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
281 } else {
282 mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
283 }
284
Yann Gautiera205a5c2021-08-30 15:06:54 +0200285 clk_disable(clock);
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200286}
Yann Gautier2b79c372021-06-11 10:54:56 +0200287
288void set_gpio_reset_cfg(uint32_t bank, uint32_t pin)
289{
290 set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_SPEED_LOW,
291 GPIO_NO_PULL, GPIO_ALTERNATE_(0), DT_DISABLED);
292 set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank));
293}