xref: /optee_os/core/drivers/bcm_gpio.c (revision 9246c1f6ff295755b4141032eb81e88476ab0ffd)
1e61fc00fSSandeep Tripathy // SPDX-License-Identifier: BSD-2-Clause
2e61fc00fSSandeep Tripathy /*
3e61fc00fSSandeep Tripathy  * Copyright 2019 Broadcom.
4e61fc00fSSandeep Tripathy  */
5e61fc00fSSandeep Tripathy #include <assert.h>
6e61fc00fSSandeep Tripathy #include <drivers/bcm_gpio.h>
7e61fc00fSSandeep Tripathy #include <initcall.h>
8e61fc00fSSandeep Tripathy #include <io.h>
9e61fc00fSSandeep Tripathy #include <mm/core_memprot.h>
10e61fc00fSSandeep Tripathy #include <platform_config.h>
11e61fc00fSSandeep Tripathy #include <trace.h>
12e61fc00fSSandeep Tripathy 
13e61fc00fSSandeep Tripathy #define IPROC_GPIO_DATA_IN_OFFSET	0x00
14e61fc00fSSandeep Tripathy #define IPROC_GPIO_DATA_OUT_OFFSET	0x04
15e61fc00fSSandeep Tripathy #define IPROC_GPIO_OUT_EN_OFFSET	0x08
16e61fc00fSSandeep Tripathy #define IPROC_GPIO_INT_MSK_OFFSET	0x18
17e61fc00fSSandeep Tripathy 
18e61fc00fSSandeep Tripathy #define GPIO_BANK_SIZE			0x200
19e61fc00fSSandeep Tripathy #define NGPIOS_PER_BANK			32
20e61fc00fSSandeep Tripathy #define GPIO_BANK(pin)			((pin) / NGPIOS_PER_BANK)
21e61fc00fSSandeep Tripathy 
22e61fc00fSSandeep Tripathy #define IPROC_GPIO_REG(pin, reg)	((reg) + \
23e61fc00fSSandeep Tripathy 	GPIO_BANK(pin) * GPIO_BANK_SIZE)
24e61fc00fSSandeep Tripathy 
25e61fc00fSSandeep Tripathy #define IPROC_GPIO_SHIFT(pin)		((pin) % NGPIOS_PER_BANK)
26e61fc00fSSandeep Tripathy 
27*9246c1f6SSheetal Tigadoli #define GPIO_BANK_CNT			5
28*9246c1f6SSheetal Tigadoli #define SEC_GPIO_SIZE			0x4
29*9246c1f6SSheetal Tigadoli #define IPROC_GPIO_SEC_CFG_REG(pin) \
30*9246c1f6SSheetal Tigadoli 	(((GPIO_BANK_CNT - 1) - GPIO_BANK(pin)) * SEC_GPIO_SIZE)
31*9246c1f6SSheetal Tigadoli 
32e61fc00fSSandeep Tripathy static SLIST_HEAD(, bcm_gpio_chip) gclist = SLIST_HEAD_INITIALIZER(gclist);
33e61fc00fSSandeep Tripathy 
34e61fc00fSSandeep Tripathy struct bcm_gpio_chip *bcm_gpio_pin_to_chip(unsigned int pin)
35e61fc00fSSandeep Tripathy {
36e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = NULL;
37e61fc00fSSandeep Tripathy 
38e61fc00fSSandeep Tripathy 	SLIST_FOREACH(gc, &gclist, link)
39e61fc00fSSandeep Tripathy 		if ((pin >= gc->gpio_base) &&
40e61fc00fSSandeep Tripathy 		    (pin < (gc->gpio_base + gc->ngpios)))
41e61fc00fSSandeep Tripathy 			return gc;
42e61fc00fSSandeep Tripathy 	return NULL;
43e61fc00fSSandeep Tripathy }
44e61fc00fSSandeep Tripathy 
45e61fc00fSSandeep Tripathy static bool __maybe_unused gpio_is_range_overlap(unsigned int start,
46e61fc00fSSandeep Tripathy 						 unsigned int end)
47e61fc00fSSandeep Tripathy {
48e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = NULL;
49e61fc00fSSandeep Tripathy 
50e61fc00fSSandeep Tripathy 	SLIST_FOREACH(gc, &gclist, link)
51e61fc00fSSandeep Tripathy 		if ((start < (gc->gpio_base + gc->ngpios)) &&
52e61fc00fSSandeep Tripathy 		    (end > gc->gpio_base))
53e61fc00fSSandeep Tripathy 			return true;
54e61fc00fSSandeep Tripathy 	return false;
55e61fc00fSSandeep Tripathy }
56e61fc00fSSandeep Tripathy 
57e61fc00fSSandeep Tripathy static void iproc_set_bit(unsigned int reg, unsigned int gpio)
58e61fc00fSSandeep Tripathy {
59e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
60e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
61e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
62e61fc00fSSandeep Tripathy 
63e61fc00fSSandeep Tripathy 	assert(gc);
64e61fc00fSSandeep Tripathy 	io_setbits32(gc->base + offset, BIT(shift));
65e61fc00fSSandeep Tripathy }
66e61fc00fSSandeep Tripathy 
67e61fc00fSSandeep Tripathy static void iproc_clr_bit(unsigned int reg, unsigned int gpio)
68e61fc00fSSandeep Tripathy {
69e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
70e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
71e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
72e61fc00fSSandeep Tripathy 
73e61fc00fSSandeep Tripathy 	assert(gc);
74e61fc00fSSandeep Tripathy 	io_clrbits32(gc->base + offset, BIT(shift));
75e61fc00fSSandeep Tripathy }
76e61fc00fSSandeep Tripathy 
77e61fc00fSSandeep Tripathy static void iproc_gpio_set(unsigned int gpio, enum gpio_level val)
78e61fc00fSSandeep Tripathy {
79e61fc00fSSandeep Tripathy 	if (val == GPIO_LEVEL_HIGH)
80e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
81e61fc00fSSandeep Tripathy 	else
82e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
83e61fc00fSSandeep Tripathy }
84e61fc00fSSandeep Tripathy 
85e61fc00fSSandeep Tripathy static enum gpio_level iproc_gpio_get(unsigned int gpio)
86e61fc00fSSandeep Tripathy {
87e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_DATA_IN_OFFSET);
88e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
89e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
90e61fc00fSSandeep Tripathy 
91e61fc00fSSandeep Tripathy 	assert(gc);
92e61fc00fSSandeep Tripathy 
93e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
94e61fc00fSSandeep Tripathy 		return GPIO_LEVEL_HIGH;
95e61fc00fSSandeep Tripathy 	else
96e61fc00fSSandeep Tripathy 		return GPIO_LEVEL_LOW;
97e61fc00fSSandeep Tripathy }
98e61fc00fSSandeep Tripathy 
99e61fc00fSSandeep Tripathy static void iproc_gpio_set_dir(unsigned int gpio, enum gpio_dir dir)
100e61fc00fSSandeep Tripathy {
101e61fc00fSSandeep Tripathy 	if (dir == GPIO_DIR_OUT)
102e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
103e61fc00fSSandeep Tripathy 	else
104e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
105e61fc00fSSandeep Tripathy }
106e61fc00fSSandeep Tripathy 
107e61fc00fSSandeep Tripathy static enum gpio_dir iproc_gpio_get_dir(unsigned int gpio)
108e61fc00fSSandeep Tripathy {
109e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
110e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
111e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
112e61fc00fSSandeep Tripathy 
113e61fc00fSSandeep Tripathy 	assert(gc);
114e61fc00fSSandeep Tripathy 
115e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
116e61fc00fSSandeep Tripathy 		return GPIO_DIR_OUT;
117e61fc00fSSandeep Tripathy 	else
118e61fc00fSSandeep Tripathy 		return GPIO_DIR_IN;
119e61fc00fSSandeep Tripathy }
120e61fc00fSSandeep Tripathy 
121e61fc00fSSandeep Tripathy static enum gpio_interrupt iproc_gpio_get_itr(unsigned int gpio)
122e61fc00fSSandeep Tripathy {
123e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_INT_MSK_OFFSET);
124e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
125e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
126e61fc00fSSandeep Tripathy 
127e61fc00fSSandeep Tripathy 	assert(gc);
128e61fc00fSSandeep Tripathy 
129e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
130e61fc00fSSandeep Tripathy 		return GPIO_INTERRUPT_ENABLE;
131e61fc00fSSandeep Tripathy 	else
132e61fc00fSSandeep Tripathy 		return GPIO_INTERRUPT_DISABLE;
133e61fc00fSSandeep Tripathy }
134e61fc00fSSandeep Tripathy 
135e61fc00fSSandeep Tripathy static void iproc_gpio_set_itr(unsigned int gpio,
136e61fc00fSSandeep Tripathy 			       enum gpio_interrupt ena_dis)
137e61fc00fSSandeep Tripathy {
138e61fc00fSSandeep Tripathy 	if (ena_dis == GPIO_INTERRUPT_ENABLE)
139e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
140e61fc00fSSandeep Tripathy 	else
141e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
142e61fc00fSSandeep Tripathy }
143e61fc00fSSandeep Tripathy 
144e61fc00fSSandeep Tripathy static const struct gpio_ops bcm_gpio_ops = {
145e61fc00fSSandeep Tripathy 	.get_direction = iproc_gpio_get_dir,
146e61fc00fSSandeep Tripathy 	.set_direction = iproc_gpio_set_dir,
147e61fc00fSSandeep Tripathy 	.get_value = iproc_gpio_get,
148e61fc00fSSandeep Tripathy 	.set_value = iproc_gpio_set,
149e61fc00fSSandeep Tripathy 	.get_interrupt = iproc_gpio_get_itr,
150e61fc00fSSandeep Tripathy 	.set_interrupt = iproc_gpio_set_itr,
151e61fc00fSSandeep Tripathy };
152e61fc00fSSandeep Tripathy KEEP_PAGER(bcm_gpio_ops);
153e61fc00fSSandeep Tripathy 
154*9246c1f6SSheetal Tigadoli void iproc_gpio_set_secure(int gpiopin)
155*9246c1f6SSheetal Tigadoli {
156*9246c1f6SSheetal Tigadoli 	vaddr_t regaddr = 0;
157*9246c1f6SSheetal Tigadoli 	unsigned int shift = IPROC_GPIO_SHIFT(gpiopin);
158*9246c1f6SSheetal Tigadoli 	vaddr_t baseaddr = (vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE,
159*9246c1f6SSheetal Tigadoli 						 MEM_AREA_IO_SEC);
160*9246c1f6SSheetal Tigadoli 
161*9246c1f6SSheetal Tigadoli 	regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin);
162*9246c1f6SSheetal Tigadoli 
163*9246c1f6SSheetal Tigadoli 	io_clrbits32(regaddr, BIT(shift));
164*9246c1f6SSheetal Tigadoli }
165*9246c1f6SSheetal Tigadoli 
166e61fc00fSSandeep Tripathy static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr,
167e61fc00fSSandeep Tripathy 			    unsigned int gpio_base, unsigned int ngpios)
168e61fc00fSSandeep Tripathy {
169e61fc00fSSandeep Tripathy 	assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios));
170e61fc00fSSandeep Tripathy 
171e61fc00fSSandeep Tripathy 	gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC);
172e61fc00fSSandeep Tripathy 	gc->chip.ops = &bcm_gpio_ops;
173e61fc00fSSandeep Tripathy 	gc->gpio_base = gpio_base;
174e61fc00fSSandeep Tripathy 	gc->ngpios = ngpios;
175e61fc00fSSandeep Tripathy 
176e61fc00fSSandeep Tripathy 	SLIST_INSERT_HEAD(&gclist, gc, link);
177e61fc00fSSandeep Tripathy 
178e61fc00fSSandeep Tripathy 	DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios);
179e61fc00fSSandeep Tripathy }
180e61fc00fSSandeep Tripathy 
181e61fc00fSSandeep Tripathy static TEE_Result bcm_gpio_init(void)
182e61fc00fSSandeep Tripathy {
183e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = NULL;
184e61fc00fSSandeep Tripathy 
185e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE0
186e61fc00fSSandeep Tripathy 	gc = malloc(sizeof(*gc));
187e61fc00fSSandeep Tripathy 	if (gc == NULL)
188e61fc00fSSandeep Tripathy 		return TEE_ERROR_OUT_OF_MEMORY;
189e61fc00fSSandeep Tripathy 
190e61fc00fSSandeep Tripathy 	iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0);
191e61fc00fSSandeep Tripathy #endif
192e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE1
193e61fc00fSSandeep Tripathy 	gc = malloc(sizeof(*gc));
194e61fc00fSSandeep Tripathy 	if (gc == NULL)
195e61fc00fSSandeep Tripathy 		return TEE_ERROR_OUT_OF_MEMORY;
196e61fc00fSSandeep Tripathy 
197e61fc00fSSandeep Tripathy 	iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1);
198e61fc00fSSandeep Tripathy #endif
199e61fc00fSSandeep Tripathy 	return TEE_SUCCESS;
200e61fc00fSSandeep Tripathy }
201e61fc00fSSandeep Tripathy driver_init(bcm_gpio_init);
202