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
bcm_gpio_pin_to_chip(unsigned int pin)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
gpio_is_range_overlap(unsigned int start,unsigned int end)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
iproc_set_bit(unsigned int reg,unsigned int gpio)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
iproc_clr_bit(unsigned int reg,unsigned int gpio)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
iproc_gpio_set(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_level val)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
iproc_gpio_get(struct gpio_chip * chip __unused,unsigned int gpio)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
iproc_gpio_set_dir(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_dir dir)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
iproc_gpio_get_dir(struct gpio_chip * chip __unused,unsigned int gpio)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
iproc_gpio_get_itr(struct gpio_chip * chip __unused,unsigned int gpio)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
iproc_gpio_set_itr(struct gpio_chip * chip __unused,unsigned int gpio,enum gpio_interrupt ena_dis)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
iproc_gpio_set_secure(int gpiopin)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 =
164 (vaddr_t)phys_to_virt(CHIP_SECURE_GPIO_CONTROL0_BASE,
165 MEM_AREA_IO_SEC,
166 IPROC_GPIO_SEC_CFG_REG(gpiopin) +
167 sizeof(uint32_t));
168
169 regaddr = baseaddr + IPROC_GPIO_SEC_CFG_REG(gpiopin);
170
171 io_clrbits32(regaddr, BIT(shift));
172 }
173
iproc_gpio_init(struct bcm_gpio_chip * gc,unsigned int paddr,unsigned int gpio_base,unsigned int ngpios)174 static void iproc_gpio_init(struct bcm_gpio_chip *gc, unsigned int paddr,
175 unsigned int gpio_base, unsigned int ngpios)
176 {
177 assert(!gpio_is_range_overlap(gpio_base, gpio_base + gc->ngpios));
178
179 gc->base = core_mmu_get_va(paddr, MEM_AREA_IO_SEC, 1);
180 gc->chip.ops = &bcm_gpio_ops;
181 gc->gpio_base = gpio_base;
182 gc->ngpios = ngpios;
183
184 SLIST_INSERT_HEAD(&gclist, gc, link);
185
186 DMSG("gpio chip for <%u - %u>", gpio_base, gpio_base + ngpios);
187 }
188
bcm_gpio_init(void)189 static TEE_Result bcm_gpio_init(void)
190 {
191 struct bcm_gpio_chip *gc = NULL;
192
193 #ifdef SECURE_GPIO_BASE0
194 gc = malloc(sizeof(*gc));
195 if (gc == NULL)
196 return TEE_ERROR_OUT_OF_MEMORY;
197
198 iproc_gpio_init(gc, SECURE_GPIO_BASE0, GPIO_NUM_START0, NUM_GPIOS0);
199 #endif
200 #ifdef SECURE_GPIO_BASE1
201 gc = malloc(sizeof(*gc));
202 if (gc == NULL)
203 return TEE_ERROR_OUT_OF_MEMORY;
204
205 iproc_gpio_init(gc, SECURE_GPIO_BASE1, GPIO_NUM_START1, NUM_GPIOS1);
206 #endif
207 return TEE_SUCCESS;
208 }
209 driver_init(bcm_gpio_init);
210