1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <drivers/pl061_gpio.h>
8 #include <io.h>
9 #include <keep.h>
10 #include <trace.h>
11 #include <util.h>
12 
13 #ifndef PLAT_PL061_MAX_GPIOS
14 # define PLAT_PL061_MAX_GPIOS	32
15 #endif	/* PLAT_PL061_MAX_GPIOS */
16 
17 #define MAX_GPIO_DEVICES	((PLAT_PL061_MAX_GPIOS + \
18 	(GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
19 
20 #define GPIOS_PER_PL061		8
21 
22 /* gpio register offsets */
23 #define GPIODIR		0x400
24 #define GPIOIS		0x404
25 #define GPIOIBE		0x408
26 #define GPIOIEV		0x40C
27 #define GPIOIE		0x410
28 #define GPIORIS		0x414
29 #define GPIOMIS		0x418
30 #define GPIOIC		0x41C
31 #define GPIOAFSEL	0x420
32 
33 /* gpio register masks */
34 #define GPIOIE_ENABLED		SHIFT_U32(1, 0)
35 #define GPIOIE_MASKED		SHIFT_U32(0, 0)
36 #define GPIOAFSEL_HW		SHIFT_U32(1, 0)
37 #define GPIOAFSEL_SW		SHIFT_U32(0, 0)
38 #define GPIODIR_OUT			SHIFT_U32(1, 0)
39 #define GPIODIR_IN			SHIFT_U32(0, 0)
40 
41 static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES];
42 
pl061_get_direction(struct gpio_chip * chip __unused,unsigned int gpio_pin)43 static enum gpio_dir pl061_get_direction(struct gpio_chip *chip __unused,
44 					 unsigned int gpio_pin)
45 {
46 	vaddr_t base_addr;
47 	uint8_t data;
48 	unsigned int offset;
49 
50 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
51 
52 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
53 	offset = gpio_pin % GPIOS_PER_PL061;
54 	data = io_read8(base_addr + GPIODIR);
55 	if (data & BIT(offset))
56 		return GPIO_DIR_OUT;
57 	return GPIO_DIR_IN;
58 }
59 
pl061_set_direction(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_dir direction)60 static void pl061_set_direction(struct gpio_chip *chip __unused,
61 				unsigned int gpio_pin, enum gpio_dir direction)
62 {
63 	vaddr_t base_addr;
64 	unsigned int offset;
65 
66 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
67 
68 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
69 	offset = gpio_pin % GPIOS_PER_PL061;
70 	if (direction == GPIO_DIR_OUT)
71 		io_setbits8(base_addr + GPIODIR, BIT(offset));
72 	else
73 		io_clrbits8(base_addr + GPIODIR, BIT(offset));
74 }
75 
76 /*
77  * The offset of GPIODATA register is 0.
78  * The values read from GPIODATA are determined for each bit, by the mask bit
79  * derived from the address used to access the data register, PADDR[9:2].
80  * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
81  * to be read, and bits that are 0 in the address mask cause the corresponding
82  * bits in GPIODATA to be read as 0, regardless of their value.
83  */
pl061_get_value(struct gpio_chip * chip __unused,unsigned int gpio_pin)84 static enum gpio_level pl061_get_value(struct gpio_chip *chip __unused,
85 				       unsigned int gpio_pin)
86 {
87 	vaddr_t base_addr;
88 	unsigned int offset;
89 
90 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
91 
92 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
93 	offset = gpio_pin % GPIOS_PER_PL061;
94 	if (io_read8(base_addr + BIT(offset + 2)))
95 		return GPIO_LEVEL_HIGH;
96 	return GPIO_LEVEL_LOW;
97 }
98 
99 /*
100  * In order to write GPIODATA, the corresponding bits in the mask, resulting
101  * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
102  * remain unchanged by the write.
103  */
pl061_set_value(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_level value)104 static void pl061_set_value(struct gpio_chip *chip __unused,
105 			    unsigned int gpio_pin, enum gpio_level value)
106 {
107 	vaddr_t base_addr;
108 	unsigned int offset;
109 
110 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
111 
112 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
113 	offset = gpio_pin % GPIOS_PER_PL061;
114 	if (value == GPIO_LEVEL_HIGH)
115 		io_write8(base_addr + BIT(offset + 2), BIT(offset));
116 	else
117 		io_write8(base_addr + BIT(offset + 2), 0);
118 }
119 
pl061_get_interrupt(struct gpio_chip * chip __unused,unsigned int gpio_pin)120 static enum gpio_interrupt pl061_get_interrupt(struct gpio_chip *chip __unused,
121 					       unsigned int gpio_pin)
122 {
123 	vaddr_t base_addr;
124 	uint8_t data;
125 	unsigned int offset;
126 
127 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
128 
129 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
130 	offset = gpio_pin % GPIOS_PER_PL061;
131 	data = io_read8(base_addr + GPIOIE);
132 	if (data & BIT(offset))
133 		return GPIO_INTERRUPT_ENABLE;
134 	return GPIO_INTERRUPT_DISABLE;
135 }
136 
pl061_set_interrupt(struct gpio_chip * chip __unused,unsigned int gpio_pin,enum gpio_interrupt ena_dis)137 static void pl061_set_interrupt(struct gpio_chip *chip __unused,
138 				unsigned int gpio_pin,
139 				enum gpio_interrupt ena_dis)
140 {
141 	vaddr_t base_addr;
142 	unsigned int offset;
143 
144 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
145 
146 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
147 	offset = gpio_pin % GPIOS_PER_PL061;
148 	if (ena_dis == GPIO_INTERRUPT_ENABLE)
149 		io_setbits8(base_addr + GPIOIE, BIT(offset));
150 	else
151 		io_clrbits8(base_addr + GPIOIE, BIT(offset));
152 }
153 
154 /*
155  * Register the PL061 GPIO controller with a base address and the offset
156  * of start pin in this GPIO controller.
157  * This function is called after pl061_init().
158  */
pl061_register(vaddr_t base_addr,unsigned int gpio_dev)159 void pl061_register(vaddr_t base_addr, unsigned int gpio_dev)
160 {
161 	assert(gpio_dev < MAX_GPIO_DEVICES);
162 
163 	pl061_reg_base[gpio_dev] = base_addr;
164 }
165 
166 static const struct gpio_ops pl061_ops = {
167 	.get_direction = pl061_get_direction,
168 	.set_direction = pl061_set_direction,
169 	.get_value = pl061_get_value,
170 	.set_value = pl061_set_value,
171 	.get_interrupt = pl061_get_interrupt,
172 	.set_interrupt = pl061_set_interrupt,
173 };
174 DECLARE_KEEP_PAGER(pl061_ops);
175 
176 /*
177  * Initialize PL061 GPIO controller
178  */
pl061_init(struct pl061_data * pd)179 void pl061_init(struct pl061_data *pd)
180 {
181 	COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0);
182 
183 	assert(pd);
184 	pd->chip.ops = &pl061_ops;
185 }
186 
pl061_get_mode_control(unsigned int gpio_pin)187 enum pl061_mode_control pl061_get_mode_control(unsigned int gpio_pin)
188 {
189 	vaddr_t base_addr;
190 	uint8_t data;
191 	unsigned int offset;
192 
193 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
194 
195 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
196 	offset = gpio_pin % GPIOS_PER_PL061;
197 	data = io_read8(base_addr + GPIOAFSEL);
198 	if (data & BIT(offset))
199 		return PL061_MC_HW;
200 	return PL061_MC_SW;
201 }
202 
pl061_set_mode_control(unsigned int gpio_pin,enum pl061_mode_control hw_sw)203 void pl061_set_mode_control(unsigned int gpio_pin,
204 	enum pl061_mode_control hw_sw)
205 {
206 	vaddr_t base_addr;
207 	unsigned int offset;
208 
209 	assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
210 
211 	base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
212 	offset = gpio_pin % GPIOS_PER_PL061;
213 	if (hw_sw == PL061_MC_HW)
214 		io_setbits8(base_addr + GPIOAFSEL, BIT(offset));
215 	else
216 		io_clrbits8(base_addr + GPIOAFSEL, BIT(offset));
217 }
218