xref: /optee_os/core/drivers/bcm_gpio.c (revision c2e4eb43b7b7211345cd38ceceac97773bd78d2c)
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 
279246c1f6SSheetal Tigadoli #define GPIO_BANK_CNT			5
289246c1f6SSheetal Tigadoli #define SEC_GPIO_SIZE			0x4
299246c1f6SSheetal Tigadoli #define IPROC_GPIO_SEC_CFG_REG(pin) \
309246c1f6SSheetal Tigadoli 	(((GPIO_BANK_CNT - 1) - GPIO_BANK(pin)) * SEC_GPIO_SIZE)
319246c1f6SSheetal Tigadoli 
32e61fc00fSSandeep Tripathy static SLIST_HEAD(, bcm_gpio_chip) gclist = SLIST_HEAD_INITIALIZER(gclist);
33e61fc00fSSandeep Tripathy 
bcm_gpio_pin_to_chip(unsigned int pin)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 
gpio_is_range_overlap(unsigned int start,unsigned int end)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 
iproc_set_bit(unsigned int reg,unsigned int gpio)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 
iproc_clr_bit(unsigned int reg,unsigned int gpio)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 
iproc_gpio_set(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_level val)77fc5d98e8SManish Tomar static void iproc_gpio_set(struct gpio_chip *chip __unused, unsigned int gpio,
78fc5d98e8SManish Tomar 			   enum gpio_level val)
79e61fc00fSSandeep Tripathy {
80e61fc00fSSandeep Tripathy 	if (val == GPIO_LEVEL_HIGH)
81e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
82e61fc00fSSandeep Tripathy 	else
83e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_DATA_OUT_OFFSET, gpio);
84e61fc00fSSandeep Tripathy }
85e61fc00fSSandeep Tripathy 
iproc_gpio_get(struct gpio_chip * chip __unused,unsigned int gpio)86fc5d98e8SManish Tomar static enum gpio_level iproc_gpio_get(struct gpio_chip *chip __unused,
87fc5d98e8SManish Tomar 				      unsigned int gpio)
88e61fc00fSSandeep Tripathy {
89e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_DATA_IN_OFFSET);
90e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
91e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
92e61fc00fSSandeep Tripathy 
93e61fc00fSSandeep Tripathy 	assert(gc);
94e61fc00fSSandeep Tripathy 
95e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
96e61fc00fSSandeep Tripathy 		return GPIO_LEVEL_HIGH;
97e61fc00fSSandeep Tripathy 	else
98e61fc00fSSandeep Tripathy 		return GPIO_LEVEL_LOW;
99e61fc00fSSandeep Tripathy }
100e61fc00fSSandeep Tripathy 
iproc_gpio_set_dir(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_dir dir)101fc5d98e8SManish Tomar static void iproc_gpio_set_dir(struct gpio_chip *chip __unused,
102fc5d98e8SManish Tomar 			       unsigned int gpio, enum gpio_dir dir)
103e61fc00fSSandeep Tripathy {
104e61fc00fSSandeep Tripathy 	if (dir == GPIO_DIR_OUT)
105e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
106e61fc00fSSandeep Tripathy 	else
107e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
108e61fc00fSSandeep Tripathy }
109e61fc00fSSandeep Tripathy 
iproc_gpio_get_dir(struct gpio_chip * chip __unused,unsigned int gpio)110fc5d98e8SManish Tomar static enum gpio_dir iproc_gpio_get_dir(struct gpio_chip *chip __unused,
111fc5d98e8SManish Tomar 					unsigned int gpio)
112e61fc00fSSandeep Tripathy {
113e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
114e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
115e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
116e61fc00fSSandeep Tripathy 
117e61fc00fSSandeep Tripathy 	assert(gc);
118e61fc00fSSandeep Tripathy 
119e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
120e61fc00fSSandeep Tripathy 		return GPIO_DIR_OUT;
121e61fc00fSSandeep Tripathy 	else
122e61fc00fSSandeep Tripathy 		return GPIO_DIR_IN;
123e61fc00fSSandeep Tripathy }
124e61fc00fSSandeep Tripathy 
iproc_gpio_get_itr(struct gpio_chip * chip __unused,unsigned int gpio)125fc5d98e8SManish Tomar static enum gpio_interrupt iproc_gpio_get_itr(struct gpio_chip *chip __unused,
126fc5d98e8SManish Tomar 					      unsigned int gpio)
127e61fc00fSSandeep Tripathy {
128e61fc00fSSandeep Tripathy 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_INT_MSK_OFFSET);
129e61fc00fSSandeep Tripathy 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
130e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = bcm_gpio_pin_to_chip(gpio);
131e61fc00fSSandeep Tripathy 
132e61fc00fSSandeep Tripathy 	assert(gc);
133e61fc00fSSandeep Tripathy 
134e61fc00fSSandeep Tripathy 	if (io_read32(gc->base + offset) & BIT(shift))
135e61fc00fSSandeep Tripathy 		return GPIO_INTERRUPT_ENABLE;
136e61fc00fSSandeep Tripathy 	else
137e61fc00fSSandeep Tripathy 		return GPIO_INTERRUPT_DISABLE;
138e61fc00fSSandeep Tripathy }
139e61fc00fSSandeep Tripathy 
iproc_gpio_set_itr(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_interrupt ena_dis)140fc5d98e8SManish Tomar static void iproc_gpio_set_itr(struct gpio_chip *chip __unused,
141fc5d98e8SManish Tomar 			       unsigned int gpio, enum gpio_interrupt ena_dis)
142e61fc00fSSandeep Tripathy {
143e61fc00fSSandeep Tripathy 	if (ena_dis == GPIO_INTERRUPT_ENABLE)
144e61fc00fSSandeep Tripathy 		iproc_set_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
145e61fc00fSSandeep Tripathy 	else
146e61fc00fSSandeep Tripathy 		iproc_clr_bit(IPROC_GPIO_OUT_EN_OFFSET, gpio);
147e61fc00fSSandeep Tripathy }
148e61fc00fSSandeep Tripathy 
149e61fc00fSSandeep Tripathy static const struct gpio_ops bcm_gpio_ops = {
150e61fc00fSSandeep Tripathy 	.get_direction = iproc_gpio_get_dir,
151e61fc00fSSandeep Tripathy 	.set_direction = iproc_gpio_set_dir,
152e61fc00fSSandeep Tripathy 	.get_value = iproc_gpio_get,
153e61fc00fSSandeep Tripathy 	.set_value = iproc_gpio_set,
154e61fc00fSSandeep Tripathy 	.get_interrupt = iproc_gpio_get_itr,
155e61fc00fSSandeep Tripathy 	.set_interrupt = iproc_gpio_set_itr,
156e61fc00fSSandeep Tripathy };
1573639b55fSJerome Forissier DECLARE_KEEP_PAGER(bcm_gpio_ops);
158e61fc00fSSandeep Tripathy 
iproc_gpio_set_secure(int gpiopin)1599246c1f6SSheetal Tigadoli void iproc_gpio_set_secure(int gpiopin)
1609246c1f6SSheetal Tigadoli {
1619246c1f6SSheetal Tigadoli 	vaddr_t regaddr = 0;
1629246c1f6SSheetal Tigadoli 	unsigned int shift = IPROC_GPIO_SHIFT(gpiopin);
163*c2e4eb43SAnton Rybakov 	vaddr_t baseaddr =
164*c2e4eb43SAnton Rybakov 		(vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE,
165*c2e4eb43SAnton Rybakov 				      MEM_AREA_IO_SEC,
166*c2e4eb43SAnton Rybakov 				      IPROC_GPIO_SEC_CFG_REG(gpiopin) +
167*c2e4eb43SAnton Rybakov 				      sizeof(uint32_t));
1689246c1f6SSheetal Tigadoli 
1699246c1f6SSheetal Tigadoli 	regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin);
1709246c1f6SSheetal Tigadoli 
1719246c1f6SSheetal Tigadoli 	io_clrbits32(regaddr, BIT(shift));
1729246c1f6SSheetal Tigadoli }
1739246c1f6SSheetal Tigadoli 
iproc_gpio_init(struct bcm_gpio_chip * gc,unsigned int paddr,unsigned int gpio_base,unsigned int ngpios)174e61fc00fSSandeep Tripathy static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr,
175e61fc00fSSandeep Tripathy 			    unsigned int gpio_base, unsigned int ngpios)
176e61fc00fSSandeep Tripathy {
177e61fc00fSSandeep Tripathy 	assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios));
178e61fc00fSSandeep Tripathy 
179*c2e4eb43SAnton Rybakov 	gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC, 1);
180e61fc00fSSandeep Tripathy 	gc->chip.ops = &bcm_gpio_ops;
181e61fc00fSSandeep Tripathy 	gc->gpio_base = gpio_base;
182e61fc00fSSandeep Tripathy 	gc->ngpios = ngpios;
183e61fc00fSSandeep Tripathy 
184e61fc00fSSandeep Tripathy 	SLIST_INSERT_HEAD(&gclist, gc, link);
185e61fc00fSSandeep Tripathy 
186e61fc00fSSandeep Tripathy 	DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios);
187e61fc00fSSandeep Tripathy }
188e61fc00fSSandeep Tripathy 
bcm_gpio_init(void)189e61fc00fSSandeep Tripathy static TEE_Result bcm_gpio_init(void)
190e61fc00fSSandeep Tripathy {
191e61fc00fSSandeep Tripathy 	struct bcm_gpio_chip *gc = NULL;
192e61fc00fSSandeep Tripathy 
193e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE0
194e61fc00fSSandeep Tripathy 	gc = malloc(sizeof(*gc));
195e61fc00fSSandeep Tripathy 	if (gc == NULL)
196e61fc00fSSandeep Tripathy 		return TEE_ERROR_OUT_OF_MEMORY;
197e61fc00fSSandeep Tripathy 
198e61fc00fSSandeep Tripathy 	iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0);
199e61fc00fSSandeep Tripathy #endif
200e61fc00fSSandeep Tripathy #ifdef SECURE_GPIO_BASE1
201e61fc00fSSandeep Tripathy 	gc = malloc(sizeof(*gc));
202e61fc00fSSandeep Tripathy 	if (gc == NULL)
203e61fc00fSSandeep Tripathy 		return TEE_ERROR_OUT_OF_MEMORY;
204e61fc00fSSandeep Tripathy 
205e61fc00fSSandeep Tripathy 	iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1);
206e61fc00fSSandeep Tripathy #endif
207e61fc00fSSandeep Tripathy 	return TEE_SUCCESS;
208e61fc00fSSandeep Tripathy }
209e61fc00fSSandeep Tripathy driver_init(bcm_gpio_init);
210