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