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