1 /*
2 * Copyright (c) 2023 Chen Xingyu <hi@xingrz.me>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT brcm_bcm2711_gpio
7
8 #include <zephyr/arch/cpu.h>
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/gpio/gpio_utils.h>
12 #include <zephyr/irq.h>
13
14 #define GPIO_REG_GROUP(n, cnt) (n / cnt)
15 #define GPIO_REG_SHIFT(n, cnt, bits) ((n % cnt) * bits)
16
17 #define GPFSEL(base, n) (base + 0x00 + 0x04 * n)
18 #define GPSET(base, n) (base + 0x1C + 0x04 * n)
19 #define GPCLR(base, n) (base + 0x28 + 0x04 * n)
20 #define GPLEV(base, n) (base + 0x34 + 0x04 * n)
21 #define GPEDS(base, n) (base + 0x40 + 0x04 * n)
22 #define GPREN(base, n) (base + 0x4C + 0x04 * n)
23 #define GPFEN(base, n) (base + 0x58 + 0x04 * n)
24 #define GPHEN(base, n) (base + 0x64 + 0x04 * n)
25 #define GPLEN(base, n) (base + 0x70 + 0x04 * n)
26 #define GPAREN(base, n) (base + 0x7C + 0x04 * n)
27 #define GPAFEN(base, n) (base + 0x88 + 0x04 * n)
28 #define GPPULL(base, n) (base + 0xE4 + 0x04 * n)
29
30 #define FSEL_GROUPS (10)
31 #define FSEL_BITS (3)
32 #define FSEL_OUTPUT (0x1)
33
34 #define IO_GROUPS (32)
35 #define IO_BITS (1)
36
37 #define PULL_GROUPS (16)
38 #define PULL_BITS (2)
39 #define PULL_UP (0x1)
40 #define PULL_DOWN (0x2)
41
42 #define DEV_CFG(dev) ((const struct gpio_bcm2711_config *const)(dev)->config)
43 #define DEV_DATA(dev) ((struct gpio_bcm2711_data *const)(dev)->data)
44
45 #define RPI_PIN_NUM(dev, n) (DEV_CFG(dev)->offset + n)
46
47 #define FROM_U64(val, idx) ((uint32_t)((val >> (idx * 32)) & UINT32_MAX))
48
49 struct gpio_bcm2711_config {
50 struct gpio_driver_config common;
51
52 DEVICE_MMIO_NAMED_ROM(reg_base);
53
54 void (*irq_config_func)(void);
55
56 uint8_t offset;
57 uint8_t ngpios;
58 };
59
60 struct gpio_bcm2711_data {
61 struct gpio_driver_data common;
62
63 DEVICE_MMIO_NAMED_RAM(reg_base);
64 mem_addr_t base;
65
66 sys_slist_t cb;
67 };
68
gpio_bcm2711_pin_configure(const struct device * port,gpio_pin_t pin,gpio_flags_t flags)69 static int gpio_bcm2711_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags)
70 {
71 struct gpio_bcm2711_data *data = DEV_DATA(port);
72 uint32_t group;
73 uint32_t shift;
74 uint32_t regval;
75
76 if (flags & GPIO_OPEN_DRAIN) {
77 return -ENOTSUP;
78 }
79
80 /* Set direction */
81 {
82 group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), FSEL_GROUPS);
83 shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), FSEL_GROUPS, FSEL_BITS);
84
85 regval = sys_read32(GPFSEL(data->base, group));
86 regval &= ~(BIT_MASK(FSEL_BITS) << shift);
87 if (flags & GPIO_OUTPUT) {
88 regval |= (FSEL_OUTPUT << shift);
89 }
90 sys_write32(regval, GPFSEL(data->base, group));
91 }
92
93 /* Set output level */
94 if (flags & GPIO_OUTPUT) {
95 group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), IO_GROUPS);
96 shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), IO_GROUPS, IO_BITS);
97
98 if (flags & GPIO_OUTPUT_INIT_HIGH) {
99 regval = sys_read32(GPSET(data->base, group));
100 regval |= BIT(shift);
101 sys_write32(regval, GPSET(data->base, group));
102 } else if (flags & GPIO_OUTPUT_INIT_LOW) {
103 regval = sys_read32(GPCLR(data->base, group));
104 regval |= BIT(shift);
105 sys_write32(regval, GPCLR(data->base, group));
106 }
107 }
108
109 /* Set pull */
110 {
111 group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), PULL_GROUPS);
112 shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), PULL_GROUPS, PULL_BITS);
113
114 regval = sys_read32(GPPULL(data->base, group));
115 regval &= ~(BIT_MASK(PULL_BITS) << shift);
116 if (flags & GPIO_PULL_UP) {
117 regval |= (PULL_UP << shift);
118 } else if (flags & GPIO_PULL_DOWN) {
119 regval |= (PULL_DOWN << shift);
120 }
121 sys_write32(regval, GPPULL(data->base, group));
122 }
123
124 return 0;
125 }
126
gpio_bcm2711_port_get_raw(const struct device * port,gpio_port_value_t * value)127 static int gpio_bcm2711_port_get_raw(const struct device *port, gpio_port_value_t *value)
128 {
129 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
130 struct gpio_bcm2711_data *data = DEV_DATA(port);
131 uint64_t regval;
132
133 regval = ((uint64_t)sys_read32(GPLEV(data->base, 0))) |
134 ((uint64_t)sys_read32(GPLEV(data->base, 1)) << 32);
135
136 *value = (regval >> cfg->offset) & BIT_MASK(cfg->ngpios);
137
138 return 0;
139 }
140
gpio_bcm2711_port_set_masked_raw(const struct device * port,gpio_port_pins_t mask,gpio_port_value_t value)141 static int gpio_bcm2711_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask,
142 gpio_port_value_t value)
143 {
144 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
145 struct gpio_bcm2711_data *data = DEV_DATA(port);
146 uint64_t regval, regmask;
147 uint64_t set, clr;
148
149 value &= BIT_MASK(cfg->ngpios);
150 mask &= BIT_MASK(cfg->ngpios);
151
152 regval = (uint64_t)value << cfg->offset;
153 regmask = (uint64_t)mask << cfg->offset;
154
155 set = regval & regmask;
156 clr = regval ^ regmask;
157
158 sys_write32(FROM_U64(set, 0), GPSET(data->base, 0));
159 sys_write32(FROM_U64(clr, 0), GPCLR(data->base, 0));
160 sys_write32(FROM_U64(set, 1), GPSET(data->base, 1));
161 sys_write32(FROM_U64(clr, 1), GPCLR(data->base, 1));
162
163 return 0;
164 }
165
gpio_bcm2711_port_set_bits_raw(const struct device * port,gpio_port_pins_t pins)166 static int gpio_bcm2711_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins)
167 {
168 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
169 struct gpio_bcm2711_data *data = DEV_DATA(port);
170 uint64_t regval;
171
172 regval = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset;
173
174 sys_write32(FROM_U64(regval, 0), GPSET(data->base, 0));
175 sys_write32(FROM_U64(regval, 1), GPSET(data->base, 1));
176
177 return 0;
178 }
179
gpio_bcm2711_port_clear_bits_raw(const struct device * port,gpio_port_pins_t pins)180 static int gpio_bcm2711_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins)
181 {
182 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
183 struct gpio_bcm2711_data *data = DEV_DATA(port);
184 uint64_t regval;
185
186 regval = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset;
187
188 sys_write32(FROM_U64(regval, 0), GPCLR(data->base, 0));
189 sys_write32(FROM_U64(regval, 1), GPCLR(data->base, 1));
190
191 return 0;
192 }
193
gpio_bcm2711_port_toggle_bits(const struct device * port,gpio_port_pins_t pins)194 static int gpio_bcm2711_port_toggle_bits(const struct device *port, gpio_port_pins_t pins)
195 {
196 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
197 struct gpio_bcm2711_data *data = DEV_DATA(port);
198 uint64_t regval, regmask;
199 uint64_t set, clr;
200
201 regval = ((uint64_t)sys_read32(GPLEV(data->base, 0))) |
202 ((uint64_t)sys_read32(GPLEV(data->base, 1)) << 32);
203
204 regmask = ((uint64_t)pins & BIT_MASK(cfg->ngpios)) << cfg->offset;
205
206 set = regval ^ regmask;
207 clr = regval & regmask;
208
209 sys_write32(FROM_U64(set, 0), GPSET(data->base, 0));
210 sys_write32(FROM_U64(clr, 0), GPCLR(data->base, 0));
211 sys_write32(FROM_U64(set, 1), GPSET(data->base, 1));
212 sys_write32(FROM_U64(clr, 1), GPCLR(data->base, 1));
213
214 return 0;
215 }
216
gpio_bcm2711_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)217 static int gpio_bcm2711_pin_interrupt_configure(const struct device *port, gpio_pin_t pin,
218 enum gpio_int_mode mode, enum gpio_int_trig trig)
219 {
220 struct gpio_bcm2711_data *data = DEV_DATA(port);
221 uint32_t group;
222 uint32_t shift;
223 uint32_t regval;
224
225 group = GPIO_REG_GROUP(RPI_PIN_NUM(port, pin), IO_GROUPS);
226 shift = GPIO_REG_SHIFT(RPI_PIN_NUM(port, pin), IO_GROUPS, IO_BITS);
227
228 /* Clear all detections first */
229
230 regval = sys_read32(GPREN(data->base, group));
231 regval &= ~BIT(shift);
232 sys_write32(regval, GPREN(data->base, group));
233
234 regval = sys_read32(GPFEN(data->base, group));
235 regval &= ~BIT(shift);
236 sys_write32(regval, GPFEN(data->base, group));
237
238 regval = sys_read32(GPHEN(data->base, group));
239 regval &= ~BIT(shift);
240 sys_write32(regval, GPHEN(data->base, group));
241
242 regval = sys_read32(GPLEN(data->base, group));
243 regval &= ~BIT(shift);
244 sys_write32(regval, GPLEN(data->base, group));
245
246 regval = sys_read32(GPAREN(data->base, group));
247 regval &= ~BIT(shift);
248 sys_write32(regval, GPAREN(data->base, group));
249
250 regval = sys_read32(GPAFEN(data->base, group));
251 regval &= ~BIT(shift);
252 sys_write32(regval, GPAFEN(data->base, group));
253
254 if (mode == GPIO_INT_MODE_LEVEL) {
255 if (trig & GPIO_INT_LOW_0) {
256 regval = sys_read32(GPLEN(data->base, group));
257 regval |= BIT(shift);
258 sys_write32(regval, GPLEN(data->base, group));
259 }
260 if (trig & GPIO_INT_HIGH_1) {
261 regval = sys_read32(GPHEN(data->base, group));
262 regval |= BIT(shift);
263 sys_write32(regval, GPHEN(data->base, group));
264 }
265 } else if (mode == GPIO_INT_MODE_EDGE) {
266 if (trig & GPIO_INT_LOW_0) {
267 regval = sys_read32(GPAFEN(data->base, group));
268 regval |= BIT(shift);
269 sys_write32(regval, GPAFEN(data->base, group));
270 }
271 if (trig & GPIO_INT_HIGH_1) {
272 regval = sys_read32(GPAREN(data->base, group));
273 regval |= BIT(shift);
274 sys_write32(regval, GPAREN(data->base, group));
275 }
276 }
277
278 return 0;
279 }
280
gpio_bcm2711_manage_callback(const struct device * port,struct gpio_callback * cb,bool set)281 static int gpio_bcm2711_manage_callback(const struct device *port, struct gpio_callback *cb,
282 bool set)
283 {
284 struct gpio_bcm2711_data *data = DEV_DATA(port);
285
286 return gpio_manage_callback(&data->cb, cb, set);
287 }
288
gpio_bcm2711_isr(const struct device * port)289 static void gpio_bcm2711_isr(const struct device *port)
290 {
291 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
292 struct gpio_bcm2711_data *data = DEV_DATA(port);
293 uint64_t regval;
294 uint32_t pins;
295
296 regval = ((uint64_t)sys_read32(GPEDS(data->base, 0))) |
297 ((uint64_t)sys_read32(GPEDS(data->base, 1)) << 32);
298
299 regval &= BIT_MASK(cfg->ngpios) << cfg->offset;
300
301 pins = (uint32_t)(regval >> cfg->offset);
302 gpio_fire_callbacks(&data->cb, port, pins);
303
304 /* Write to clear */
305 sys_write32(FROM_U64(regval, 0), GPEDS(data->base, 0));
306 sys_write32(FROM_U64(regval, 1), GPEDS(data->base, 1));
307 }
308
gpio_bcm2711_init(const struct device * port)309 int gpio_bcm2711_init(const struct device *port)
310 {
311 const struct gpio_bcm2711_config *cfg = DEV_CFG(port);
312 struct gpio_bcm2711_data *data = DEV_DATA(port);
313
314 DEVICE_MMIO_NAMED_MAP(port, reg_base, K_MEM_CACHE_NONE);
315 data->base = DEVICE_MMIO_NAMED_GET(port, reg_base);
316
317 cfg->irq_config_func();
318
319 return 0;
320 }
321
322 static const struct gpio_driver_api gpio_bcm2711_api = {
323 .pin_configure = gpio_bcm2711_pin_configure,
324 .port_get_raw = gpio_bcm2711_port_get_raw,
325 .port_set_masked_raw = gpio_bcm2711_port_set_masked_raw,
326 .port_set_bits_raw = gpio_bcm2711_port_set_bits_raw,
327 .port_clear_bits_raw = gpio_bcm2711_port_clear_bits_raw,
328 .port_toggle_bits = gpio_bcm2711_port_toggle_bits,
329 .pin_interrupt_configure = gpio_bcm2711_pin_interrupt_configure,
330 .manage_callback = gpio_bcm2711_manage_callback,
331 };
332
333 #define GPIO_BCM2711_INST(n) \
334 static struct gpio_bcm2711_data gpio_bcm2711_data_##n; \
335 \
336 static void gpio_bcm2711_irq_config_func_##n(void) \
337 { \
338 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_bcm2711_isr, \
339 DEVICE_DT_INST_GET(n), 0); \
340 irq_enable(DT_INST_IRQN(n)); \
341 } \
342 \
343 static const struct gpio_bcm2711_config gpio_bcm2711_cfg_##n = { \
344 .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}, \
345 DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_INST_PARENT(n)), \
346 .irq_config_func = gpio_bcm2711_irq_config_func_##n, \
347 .offset = DT_INST_REG_ADDR(n), \
348 .ngpios = DT_INST_PROP(n, ngpios), \
349 }; \
350 \
351 DEVICE_DT_INST_DEFINE(n, gpio_bcm2711_init, NULL, &gpio_bcm2711_data_##n, \
352 &gpio_bcm2711_cfg_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
353 &gpio_bcm2711_api);
354
355 DT_INST_FOREACH_STATUS_OKAY(GPIO_BCM2711_INST)
356