1 /*
2  * Copyright (c) 2019-2020, Broadcom
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <drivers/gpio.h>
10 #include <lib/mmio.h>
11 #include <plat/common/platform.h>
12 
13 #include <iproc_gpio.h>
14 #include <platform_def.h>
15 
16 #define IPROC_GPIO_DATA_IN_OFFSET     0x00
17 #define IPROC_GPIO_DATA_OUT_OFFSET    0x04
18 #define IPROC_GPIO_OUT_EN_OFFSET      0x08
19 #define IPROC_GPIO_PAD_RES_OFFSET     0x34
20 #define IPROC_GPIO_RES_EN_OFFSET      0x38
21 
22 #define PINMUX_OFFSET(gpio)           ((gpio) * 4)
23 #define PINCONF_OFFSET(gpio)          ((gpio) * 4)
24 #define PINCONF_PULL_UP               BIT(4)
25 #define PINCONF_PULL_DOWN             BIT(5)
26 
27 /*
28  * iProc GPIO bank is always 0x200 per bank,
29  * with each bank supporting 32 GPIOs.
30  */
31 #define GPIO_BANK_SIZE                0x200
32 #define NGPIOS_PER_BANK               32
33 #define GPIO_BANK(pin)                ((pin) / NGPIOS_PER_BANK)
34 
35 #define IPROC_GPIO_REG(pin, reg)      (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
36 #define IPROC_GPIO_SHIFT(pin)         ((pin) % NGPIOS_PER_BANK)
37 
38 #define MUX_GPIO_MODE                 0x3
39 
40 /*
41  * @base: base address of the gpio controller
42  * @pinconf_base: base address of the pinconf
43  * @pinmux_base: base address of the mux controller
44  * @nr_gpios: maxinum number of GPIOs
45  */
46 struct iproc_gpio {
47 	uintptr_t base;
48 	uintptr_t pinconf_base;
49 	uintptr_t pinmux_base;
50 	int nr_gpios;
51 };
52 
53 static struct iproc_gpio iproc_gpio;
54 
gpio_set_bit(uintptr_t base,unsigned int reg,int gpio,bool set)55 static void gpio_set_bit(uintptr_t base, unsigned int reg, int gpio, bool set)
56 {
57 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
58 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
59 	uint32_t val;
60 
61 	val = mmio_read_32(base + offset);
62 	if (set)
63 		val |= BIT(shift);
64 	else
65 		val &= ~BIT(shift);
66 
67 	mmio_write_32(base + offset, val);
68 }
69 
gpio_get_bit(uintptr_t base,unsigned int reg,int gpio)70 static bool gpio_get_bit(uintptr_t base, unsigned int reg, int gpio)
71 {
72 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
73 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
74 
75 	return !!(mmio_read_32(base + offset) & BIT(shift));
76 }
77 
mux_to_gpio(struct iproc_gpio * g,int gpio)78 static void mux_to_gpio(struct iproc_gpio *g, int gpio)
79 {
80 	/* mux pad to GPIO if IOPAD configuration is mandatory */
81 	if (g->pinmux_base)
82 		mmio_write_32(g->pinmux_base + PINMUX_OFFSET(gpio),
83 			      MUX_GPIO_MODE);
84 }
85 
set_direction(int gpio,int direction)86 static void set_direction(int gpio, int direction)
87 {
88 	struct iproc_gpio *g = &iproc_gpio;
89 	bool dir = (direction == GPIO_DIR_OUT) ? true : false;
90 
91 	assert(gpio < g->nr_gpios);
92 
93 	mux_to_gpio(g, gpio);
94 	gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, dir);
95 }
96 
get_direction(int gpio)97 static int get_direction(int gpio)
98 {
99 	struct iproc_gpio *g = &iproc_gpio;
100 	int dir;
101 
102 	assert(gpio < g->nr_gpios);
103 
104 	mux_to_gpio(g, gpio);
105 	dir = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
106 		GPIO_DIR_OUT : GPIO_DIR_IN;
107 
108 	return dir;
109 }
110 
get_value(int gpio)111 static int get_value(int gpio)
112 {
113 	struct iproc_gpio *g = &iproc_gpio;
114 	unsigned int offset;
115 
116 	assert(gpio < g->nr_gpios);
117 
118 	mux_to_gpio(g, gpio);
119 
120 	/*
121 	 * If GPIO is configured as output, read from the GPIO_OUT register;
122 	 * otherwise, read from the GPIO_IN register
123 	 */
124 	offset = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
125 		IPROC_GPIO_DATA_OUT_OFFSET : IPROC_GPIO_DATA_IN_OFFSET;
126 
127 	return gpio_get_bit(g->base, offset, gpio);
128 }
129 
set_value(int gpio,int val)130 static void set_value(int gpio, int val)
131 {
132 	struct iproc_gpio *g = &iproc_gpio;
133 
134 	assert(gpio < g->nr_gpios);
135 
136 	mux_to_gpio(g, gpio);
137 
138 	/* make sure GPIO is configured to output, and then set the value */
139 	gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
140 	gpio_set_bit(g->base, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
141 }
142 
get_pull(int gpio)143 static int get_pull(int gpio)
144 {
145 	struct iproc_gpio *g = &iproc_gpio;
146 	uint32_t val;
147 
148 	assert(gpio < g->nr_gpios);
149 	mux_to_gpio(g, gpio);
150 
151 	/* when there's a valid pinconf_base, use it */
152 	if (g->pinconf_base) {
153 		val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
154 
155 		if (val & PINCONF_PULL_UP)
156 			return GPIO_PULL_UP;
157 		else if (val & PINCONF_PULL_DOWN)
158 			return GPIO_PULL_DOWN;
159 		else
160 			return GPIO_PULL_NONE;
161 	}
162 
163 	/* no pinconf_base. fall back to GPIO internal pull control */
164 	if (!gpio_get_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio))
165 		return GPIO_PULL_NONE;
166 
167 	return gpio_get_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio) ?
168 		GPIO_PULL_UP : GPIO_PULL_DOWN;
169 }
170 
set_pull(int gpio,int pull)171 static void set_pull(int gpio, int pull)
172 {
173 	struct iproc_gpio *g = &iproc_gpio;
174 	uint32_t val;
175 
176 	assert(gpio < g->nr_gpios);
177 	mux_to_gpio(g, gpio);
178 
179 	/* when there's a valid pinconf_base, use it */
180 	if (g->pinconf_base) {
181 		val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
182 
183 		if (pull == GPIO_PULL_NONE) {
184 			val &= ~(PINCONF_PULL_UP | PINCONF_PULL_DOWN);
185 		} else if (pull == GPIO_PULL_UP) {
186 			val |= PINCONF_PULL_UP;
187 			val &= ~PINCONF_PULL_DOWN;
188 		} else if (pull == GPIO_PULL_DOWN) {
189 			val |= PINCONF_PULL_DOWN;
190 			val &= ~PINCONF_PULL_UP;
191 		} else {
192 			return;
193 		}
194 		mmio_write_32(g->pinconf_base + PINCONF_OFFSET(gpio), val);
195 	}
196 
197 	/* no pinconf_base. fall back to GPIO internal pull control */
198 	if (pull == GPIO_PULL_NONE) {
199 		gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
200 		return;
201 	}
202 
203 	/* enable pad register and pull up or down */
204 	gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
205 	gpio_set_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio,
206 		     !!(pull == GPIO_PULL_UP));
207 }
208 
209 const gpio_ops_t iproc_gpio_ops = {
210 	.get_direction = get_direction,
211 	.set_direction = set_direction,
212 	.get_value = get_value,
213 	.set_value = set_value,
214 	.get_pull = get_pull,
215 	.set_pull = set_pull,
216 };
217 
iproc_gpio_init(uintptr_t base,int nr_gpios,uintptr_t pinmux_base,uintptr_t pinconf_base)218 void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
219 		     uintptr_t pinconf_base)
220 {
221 	iproc_gpio.base = base;
222 	iproc_gpio.nr_gpios = nr_gpios;
223 
224 	/* pinmux/pinconf base is optional for some SoCs */
225 	if (pinmux_base)
226 		iproc_gpio.pinmux_base = pinmux_base;
227 
228 	if (pinconf_base)
229 		iproc_gpio.pinconf_base = pinconf_base;
230 
231 	gpio_init(&iproc_gpio_ops);
232 }
233