blob: d217c4501b6f8ca8d0b041211726440aff959b77 [file] [log] [blame]
Yann Gautierd0ca7f42018-07-13 21:33:09 +02001/*
Yann Gautier1a3fc9f2019-01-17 14:35:22 +01002 * Copyright (c) 2016-2019, 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>
17#include <drivers/st/stm32_gpio.h>
Yann Gautier038bff22019-01-17 19:17:47 +010018#include <drivers/st/stm32mp1_clk.h>
19#include <drivers/st/stm32mp1_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;
165 uint8_t status = fdt_get_status(node);
166 void *fdt;
167
168 if (fdt_get_address(&fdt) == 0) {
169 return -ENOENT;
170 }
171
172 if (status == DT_DISABLED) {
173 return -FDT_ERR_NOTFOUND;
174 }
175
176 cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
177 if (cuint == NULL) {
178 return -FDT_ERR_NOTFOUND;
179 }
180
181 for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
182 int p_node, p_subnode;
183
184 p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
185 if (p_node < 0) {
186 return -FDT_ERR_NOTFOUND;
187 }
188
189 fdt_for_each_subnode(p_subnode, fdt, p_node) {
190 int ret = dt_set_gpio_config(fdt, p_subnode, status);
191
192 if (ret < 0) {
193 return ret;
194 }
195 }
196
197 cuint++;
198 }
199
200 return 0;
201}
202
203void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
204 uint32_t pull, uint32_t alternate, uint8_t status)
205{
206 uintptr_t base = stm32_get_gpio_bank_base(bank);
207 unsigned long clock = stm32_get_gpio_bank_clock(bank);
208
209 assert(pin <= GPIO_PIN_MAX);
210
211 stm32mp1_clk_enable(clock);
212
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100213 mmio_clrbits_32(base + GPIO_MODE_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200214 ((uint32_t)GPIO_MODE_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100215 mmio_setbits_32(base + GPIO_MODE_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200216 (mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
217
218 if ((mode & GPIO_OPEN_DRAIN) != 0U) {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100219 mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
220 } else {
221 mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200222 }
223
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100224 mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200225 ((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100226 mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200227
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100228 mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200229 ((uint32_t)GPIO_PULL_MASK << (pin << 1)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100230 mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200231
232 if (pin < GPIO_ALT_LOWER_LIMIT) {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100233 mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200234 ((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100235 mmio_setbits_32(base + GPIO_AFRL_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200236 alternate << (pin << 2));
237 } else {
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100238 mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200239 ((uint32_t)GPIO_ALTERNATE_MASK <<
240 ((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100241 mmio_setbits_32(base + GPIO_AFRH_OFFSET,
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200242 alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
243 2));
244 }
245
246 VERBOSE("GPIO %u mode set to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100247 mmio_read_32(base + GPIO_MODE_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200248 VERBOSE("GPIO %u speed set to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100249 mmio_read_32(base + GPIO_SPEED_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200250 VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100251 mmio_read_32(base + GPIO_PUPD_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200252 VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100253 mmio_read_32(base + GPIO_AFRL_OFFSET));
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200254 VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
Yann Gautier1a3fc9f2019-01-17 14:35:22 +0100255 mmio_read_32(base + GPIO_AFRH_OFFSET));
Yann Gautier038bff22019-01-17 19:17:47 +0100256
257 stm32mp1_clk_disable((unsigned long)clock);
258}
259
260void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
261{
262 uintptr_t base = stm32_get_gpio_bank_base(bank);
263 int clock = stm32_get_gpio_bank_clock(bank);
264
265 assert(pin <= GPIO_PIN_MAX);
266
267 stm32mp1_clk_enable((unsigned long)clock);
268
269 if (secure) {
270 mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
271 } else {
272 mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
273 }
274
275 stm32mp1_clk_disable((unsigned long)clock);
Yann Gautierd0ca7f42018-07-13 21:33:09 +0200276}