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