xref: /openbsd/sys/dev/fdt/amlpinctrl.c (revision 37c734d3)
1 /*	$OpenBSD: amlpinctrl.c,v 1.12 2022/06/28 23:43:12 naddy Exp $	*/
2 /*
3  * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_gpio.h>
28 #include <dev/ofw/ofw_pinctrl.h>
29 #include <dev/ofw/fdt.h>
30 
31 #define BIAS_DISABLE	0x00
32 #define BIAS_PULL_UP	0x01
33 #define BIAS_PULL_DOWN	0x02
34 
35 #define GPIOZ_0		0
36 #define GPIOZ_1		1
37 #define GPIOZ_7		7
38 #define GPIOZ_8		8
39 #define GPIOZ_14	14
40 #define GPIOZ_15	15
41 #define GPIOH_0		16
42 #define GPIOH_1		17
43 #define GPIOH_2		18
44 #define GPIOH_3		19
45 #define GPIOH_5		21
46 #define GPIOH_6		22
47 #define GPIOH_7		23
48 #define BOOT_0		25
49 #define BOOT_1		26
50 #define BOOT_2		27
51 #define BOOT_3		28
52 #define BOOT_4		29
53 #define BOOT_5		30
54 #define BOOT_6		31
55 #define BOOT_7		32
56 #define BOOT_8		33
57 #define BOOT_10		35
58 #define BOOT_13		38
59 #define GPIOC_0		41
60 #define GPIOC_1		42
61 #define GPIOC_2		43
62 #define GPIOC_3		44
63 #define GPIOC_4		45
64 #define GPIOC_5		46
65 #define GPIOC_6		47
66 #define GPIOA_0		49
67 #define GPIOA_14	63
68 #define GPIOA_15	64
69 #define GPIOX_0		65
70 #define GPIOX_3		68
71 #define GPIOX_5		70
72 #define GPIOX_6		71
73 #define GPIOX_7		72
74 #define GPIOX_8		73
75 #define GPIOX_10	75
76 #define GPIOX_11	76
77 #define GPIOX_16	81
78 #define GPIOX_17	82
79 #define GPIOX_18	83
80 #define GPIOX_19	84
81 
82 #define GPIOAO_0	0
83 #define GPIOAO_1	1
84 #define GPIOAO_3	3
85 #define GPIOAO_4	4
86 #define GPIOAO_5	5
87 #define GPIOAO_6	6
88 #define GPIOAO_10	10
89 #define GPIOAO_11	11
90 #define GPIOE_0		12
91 #define GPIOE_1		13
92 #define GPIOE_2		14
93 
94 #define PERIPHS_PIN_MUX_0		0xb0
95 #define PERIPHS_PIN_MUX_3		0xb3
96 #define PERIPHS_PIN_MUX_6		0xb6
97 #define PERIPHS_PIN_MUX_9		0xb9
98 #define PERIPHS_PIN_MUX_B		0xbb
99 #define PERIPHS_PIN_MUX_D		0xbd
100 #define PREG_PAD_GPIO0_EN_N		0x10
101 #define PREG_PAD_GPIO0_O		0x11
102 #define PREG_PAD_GPIO0_I		0x12
103 #define PREG_PAD_GPIO1_EN_N		0x13
104 #define PREG_PAD_GPIO1_O		0x14
105 #define PREG_PAD_GPIO1_I		0x15
106 #define PREG_PAD_GPIO2_EN_N		0x16
107 #define PREG_PAD_GPIO2_O		0x16
108 #define PREG_PAD_GPIO2_I		0x18
109 #define PREG_PAD_GPIO3_EN_N		0x19
110 #define PREG_PAD_GPIO3_O		0x1a
111 #define PREG_PAD_GPIO3_I		0x1b
112 #define PREG_PAD_GPIO4_EN_N		0x1c
113 #define PREG_PAD_GPIO4_O		0x1d
114 #define PREG_PAD_GPIO4_I		0x1e
115 #define PREG_PAD_GPIO5_EN_N		0x20
116 #define PREG_PAD_GPIO5_O		0x21
117 #define PREG_PAD_GPIO5_I		0x22
118 #define PAD_PULL_UP_EN_0		0x48
119 #define PAD_PULL_UP_EN_1		0x49
120 #define PAD_PULL_UP_EN_2		0x4a
121 #define PAD_PULL_UP_EN_3		0x4b
122 #define PAD_PULL_UP_EN_4		0x4c
123 #define PAD_PULL_UP_EN_5		0x4d
124 #define PAD_PULL_UP_0			0x3a
125 #define PAD_PULL_UP_1			0x3b
126 #define PAD_PULL_UP_2			0x3c
127 #define PAD_PULL_UP_3			0x3d
128 #define PAD_PULL_UP_4			0x3e
129 #define PAD_PULL_UP_5			0x3f
130 #define PAD_DS_0A			0xd0
131 #define PAD_DS_1A			0xd1
132 #define PAD_DS_2A			0xd2
133 #define PAD_DS_3A			0xd4
134 #define PAD_DS_4A			0xd5
135 #define PAD_DS_5A			0xd6
136 
137 #define AO_RTI_PINMUX_0			0x05
138 #define AO_RTI_PINMUX_1			0x06
139 #define AO_PAD_DS_A			0x07
140 #define AO_PAD_DS_B			0x08
141 #define AO_GPIO_O_EN_N			0x09
142 #define AO_GPIO_I			0x0a
143 #define AO_GPIO_O			0x0d
144 #define AO_RTI_PULL_UP			0x0b
145 #define AO_RTI_PULL_UP_EN		0x0c
146 
147 struct aml_gpio_bank {
148 	uint8_t first_pin, num_pins;
149 	uint8_t mux_reg, mux_bit;
150 	uint8_t dir_reg, dir_bit;
151 	uint8_t in_reg, in_bit;
152 	uint8_t out_reg, out_bit;
153 	uint8_t pull_reg, pull_bit;
154 	uint8_t pull_en_reg, pull_en_bit;
155 	uint8_t ds_reg, ds_bit;
156 };
157 
158 struct aml_pin_group {
159 	const char *name;
160 	uint8_t	pin;
161 	uint8_t func;
162 	const char *function;
163 };
164 
165 const struct aml_gpio_bank aml_g12a_gpio_banks[] = {
166 	/* BOOT */
167 	{ BOOT_0, 16,
168 	  PERIPHS_PIN_MUX_0 - PERIPHS_PIN_MUX_0, 0,
169 	  PREG_PAD_GPIO0_EN_N - PREG_PAD_GPIO0_EN_N, 0,
170 	  PREG_PAD_GPIO0_I - PREG_PAD_GPIO0_EN_N, 0,
171 	  PREG_PAD_GPIO0_O - PREG_PAD_GPIO0_EN_N, 0,
172 	  PAD_PULL_UP_0 - PAD_PULL_UP_0, 0,
173 	  PAD_PULL_UP_EN_0 - PAD_PULL_UP_EN_0, 0,
174 	  PAD_DS_0A - PAD_DS_0A, 0 },
175 
176 	/* GPIOC */
177 	{ GPIOC_0, 8,
178 	  PERIPHS_PIN_MUX_9 - PERIPHS_PIN_MUX_0, 0,
179 	  PREG_PAD_GPIO1_EN_N - PREG_PAD_GPIO0_EN_N, 0,
180 	  PREG_PAD_GPIO1_I - PREG_PAD_GPIO0_EN_N, 0,
181 	  PREG_PAD_GPIO1_O - PREG_PAD_GPIO0_EN_N, 0,
182 	  PAD_PULL_UP_1 - PAD_PULL_UP_0, 0,
183 	  PAD_PULL_UP_EN_1 - PAD_PULL_UP_EN_0, 0,
184 	  PAD_DS_1A - PAD_DS_0A, 0 },
185 
186 	/* GPIOX */
187 	{ GPIOX_0, 20,
188 	  PERIPHS_PIN_MUX_3 - PERIPHS_PIN_MUX_0, 0,
189 	  PREG_PAD_GPIO2_EN_N - PREG_PAD_GPIO0_EN_N, 0,
190 	  PREG_PAD_GPIO2_I - PREG_PAD_GPIO0_EN_N, 0,
191 	  PREG_PAD_GPIO2_O - PREG_PAD_GPIO0_EN_N, 0,
192 	  PAD_PULL_UP_2 - PAD_PULL_UP_0, 0,
193 	  PAD_PULL_UP_EN_2 - PAD_PULL_UP_EN_0, 0,
194 	  PAD_DS_2A - PAD_DS_0A, 0 },
195 
196 	/* GPIOH */
197 	{ GPIOH_0, 9,
198 	  PERIPHS_PIN_MUX_B - PERIPHS_PIN_MUX_0, 0,
199 	  PREG_PAD_GPIO3_EN_N - PREG_PAD_GPIO0_EN_N, 0,
200 	  PREG_PAD_GPIO3_I - PREG_PAD_GPIO0_EN_N, 0,
201 	  PREG_PAD_GPIO3_O - PREG_PAD_GPIO0_EN_N, 0,
202 	  PAD_PULL_UP_3 - PAD_PULL_UP_0, 0,
203 	  PAD_PULL_UP_EN_3 - PAD_PULL_UP_EN_0, 0,
204 	  PAD_DS_3A - PAD_DS_0A, 0 },
205 
206 	/* GPIOZ */
207 	{ GPIOZ_0, 16,
208 	  PERIPHS_PIN_MUX_6 - PERIPHS_PIN_MUX_0, 0,
209 	  PREG_PAD_GPIO4_EN_N - PREG_PAD_GPIO0_EN_N, 0,
210 	  PREG_PAD_GPIO4_I - PREG_PAD_GPIO0_EN_N, 0,
211 	  PREG_PAD_GPIO4_O - PREG_PAD_GPIO0_EN_N, 0,
212 	  PAD_PULL_UP_4 - PAD_PULL_UP_0, 0,
213 	  PAD_PULL_UP_EN_4 - PAD_PULL_UP_EN_0, 0,
214 	  PAD_DS_4A - PAD_DS_0A, 0 },
215 
216 	/* GPIOA */
217 	{ GPIOA_0, 16,
218 	  PERIPHS_PIN_MUX_D - PERIPHS_PIN_MUX_0, 0,
219 	  PREG_PAD_GPIO5_EN_N - PREG_PAD_GPIO0_EN_N, 0,
220 	  PREG_PAD_GPIO5_I - PREG_PAD_GPIO0_EN_N, 0,
221 	  PREG_PAD_GPIO5_O - PREG_PAD_GPIO0_EN_N, 0,
222 	  PAD_PULL_UP_5 - PAD_PULL_UP_0, 0,
223 	  PAD_PULL_UP_EN_5 - PAD_PULL_UP_EN_0, 0,
224 	  PAD_DS_5A - PAD_DS_0A, 0 },
225 
226 	{ }
227 };
228 
229 const struct aml_pin_group aml_g12a_pin_groups[] = {
230 	/* GPIOZ */
231 	{ "i2c0_sda_z0", GPIOZ_0, 4, "i2c0" },
232 	{ "i2c0_sck_z1", GPIOZ_1, 4, "i2c0" },
233 	{ "i2c0_sda_z7", GPIOZ_7, 7, "i2c0" },
234 	{ "i2c0_sck_z8", GPIOZ_8, 7, "i2c0" },
235 	{ "i2c2_sda_z", GPIOZ_14, 3, "i2c2" },
236 	{ "i2c2_sck_z", GPIOZ_15, 3, "i2c2" },
237 
238 	/* GPIOA */
239 	{ "i2c3_sda_a", GPIOA_14, 2, "i2c3" },
240 	{ "i2c3_sck_a", GPIOA_15, 2, "i2c3" },
241 
242 	/* BOOT */
243 	{ "emmc_nand_d0", BOOT_0, 1, "emmc" },
244 	{ "emmc_nand_d1", BOOT_1, 1, "emmc" },
245 	{ "emmc_nand_d2", BOOT_2, 1, "emmc" },
246 	{ "emmc_nand_d3", BOOT_3, 1, "emmc" },
247 	{ "emmc_nand_d4", BOOT_4, 1, "emmc" },
248 	{ "emmc_nand_d5", BOOT_5, 1, "emmc" },
249 	{ "emmc_nand_d6", BOOT_6, 1, "emmc" },
250 	{ "emmc_nand_d7", BOOT_7, 1, "emmc" },
251 	{ "BOOT_8", BOOT_8, 0, "gpio_periphs" },
252 	{ "emmc_clk", BOOT_8, 1, "emmc" },
253 	{ "emmc_cmd", BOOT_10, 1, "emmc" },
254 	{ "emmc_nand_ds", BOOT_13, 1, "emmc" },
255 
256 	/* GPIOC */
257 	{ "sdcard_d0_c", GPIOC_0, 1, "sdcard" },
258 	{ "sdcard_d1_c", GPIOC_1, 1, "sdcard" },
259 	{ "sdcard_d2_c", GPIOC_2, 1, "sdcard" },
260 	{ "sdcard_d3_c", GPIOC_3, 1, "sdcard" },
261 	{ "GPIOC_4", GPIOC_4, 0, "gpio_periphs" },
262 	{ "pwm_c_c", GPIOC_4, 5, "pwm_c" },
263 	{ "sdcard_clk_c", GPIOC_4, 1, "sdcard" },
264 	{ "sdcard_cmd_c", GPIOC_5, 1, "sdcard" },
265 	{ "i2c0_sda_c", GPIOC_5, 3, "i2c0" },
266 	{ "i2c0_sck_c", GPIOC_6, 3, "i2c0" },
267 
268 	/* GPIOX */
269 	{ "pwm_d_x3", GPIOX_3, 4, "pwm_d" },
270 	{ "pwm_c_x5", GPIOX_5, 4, "pwm_c" },
271 	{ "pwm_a", GPIOX_6, 1, "pwm_a" },
272 	{ "pwm_d_x6", GPIOX_6, 4, "pwm_d" },
273 	{ "pwm_b_x7", GPIOX_7, 4, "pwm_b" },
274 	{ "pwm_f_x", GPIOX_7, 1, "pwm_f" },
275 	{ "pwm_c_x8", GPIOX_8, 5, "pwm_c" },
276 	{ "i2c1_sda_x", GPIOX_10, 5, "i2c1" },
277 	{ "i2c1_sck_x", GPIOX_11, 5, "i2c1" },
278 	{ "pwm_e", GPIOX_16, 1, "pwm_e" },
279 	{ "i2c2_sda_x", GPIOX_17, 1, "i2c2" },
280 	{ "i2c2_sck_x", GPIOX_18, 1, "i2c2" },
281 	{ "pwm_b_x19", GPIOX_19, 1, "pwm_b" },
282 
283 	/* GPIOH */
284 	{ "i2c3_sda_h", GPIOH_0, 2, "i2c3" },
285 	{ "i2c3_sck_h", GPIOH_1, 2, "i2c3" },
286 	{ "i2c1_sda_h2", GPIOH_2, 2, "i2c1" },
287 	{ "i2c1_sck_h3", GPIOH_3, 2, "i2c1" },
288 	{ "pwm_f_h", GPIOH_5, 4, "pwm_f" },
289 	{ "i2c1_sda_h6", GPIOH_6, 4, "i2c1" },
290 	{ "i2c1_sck_h7", GPIOH_7, 4, "i2c1" },
291 
292 	{ }
293 };
294 
295 const struct aml_gpio_bank aml_g12a_ao_gpio_banks[] = {
296 	/* GPIOAO */
297 	{ GPIOAO_0, 12,
298 	  AO_RTI_PINMUX_0 - AO_RTI_PINMUX_0, 0,
299 	  AO_GPIO_O_EN_N - AO_GPIO_O_EN_N, 0,
300 	  AO_GPIO_I - AO_GPIO_O_EN_N, 0,
301 	  AO_GPIO_O - AO_GPIO_O_EN_N, 0,
302 	  AO_RTI_PULL_UP - AO_RTI_PULL_UP, 0,
303 	  AO_RTI_PULL_UP_EN - AO_RTI_PULL_UP_EN, 0,
304 	  AO_PAD_DS_A - AO_PAD_DS_A, 0 },
305 
306 	/* GPIOE */
307 	{ GPIOE_0, 3,
308 	  AO_RTI_PINMUX_1 - AO_RTI_PINMUX_0, 16,
309 	  AO_GPIO_O_EN_N - AO_GPIO_O_EN_N, 16,
310 	  AO_GPIO_I - AO_GPIO_O_EN_N, 16,
311 	  AO_GPIO_O - AO_GPIO_O_EN_N, 16,
312 	  AO_RTI_PULL_UP - AO_RTI_PULL_UP, 16,
313 	  AO_RTI_PULL_UP_EN - AO_RTI_PULL_UP_EN, 16,
314 	  AO_PAD_DS_B - AO_PAD_DS_A, 0 },
315 
316 	{ }
317 };
318 
319 const struct aml_pin_group aml_g12a_ao_pin_groups[] = {
320 	/* GPIOAO */
321 	{ "uart_ao_a_tx", GPIOAO_0, 1, "uart_ao_a" },
322 	{ "uart_ao_a_rx", GPIOAO_1, 1, "uart_ao_a" },
323 	{ "pwm_ao_c_4", GPIOAO_4, 3, "pwm_ao_c" },
324 	{ "pwm_ao_c_hiz", GPIOAO_4, 4, "pwm_ao_c" },
325 	{ "pwm_ao_d_5", GPIOAO_5, 3, "pwm_ao_d" },
326 	{ "remote_ao_input", GPIOAO_5, 1, "remote_ao_input" },
327 	{ "pwm_ao_c_6", GPIOAO_6, 3, "pwm_ao_c" },
328 	{ "pwm_ao_d_10", GPIOAO_10, 3, "pwm_ao_d" },
329 	{ "pwm_ao_a", GPIOAO_11, 3, "pwm_ao_a" },
330 	{ "pwm_ao_a_hiz", GPIOAO_11, 2, "pwm_ao_a" },
331 
332 	/* GPIOE */
333 	{ "pwm_ao_b", GPIOE_0, 3, "pwm_ao_b" },
334 	{ "pwm_ao_d_e", GPIOE_1, 3, "pwm_ao_d" },
335 	{ "pwm_a_e", GPIOE_2, 3, "pwm_a_e" },
336 
337 	{ }
338 };
339 
340 struct amlpinctrl_softc {
341 	struct device		sc_dev;
342 	bus_space_tag_t		sc_iot;
343 	bus_space_handle_t	sc_gpio_ioh;
344 	bus_space_handle_t	sc_pull_ioh;
345 	bus_space_handle_t	sc_pull_en_ioh;
346 	bus_space_handle_t	sc_mux_ioh;
347 	bus_space_handle_t	sc_ds_ioh;
348 	int			sc_nobias;
349 
350 	const struct aml_gpio_bank *sc_gpio_banks;
351 	const struct aml_pin_group *sc_pin_groups;
352 
353 	struct gpio_controller	sc_gc;
354 };
355 
356 int	amlpinctrl_match(struct device *, void *, void *);
357 void	amlpinctrl_attach(struct device *, struct device *, void *);
358 
359 const struct cfattach amlpinctrl_ca = {
360 	sizeof(struct amlpinctrl_softc), amlpinctrl_match, amlpinctrl_attach
361 };
362 
363 struct cfdriver amlpinctrl_cd = {
364 	NULL, "amlpinctrl", DV_DULL
365 };
366 
367 int	amlpinctrl_pinctrl(uint32_t, void *);
368 void	amlpinctrl_config_pin(void *, uint32_t *, int);
369 int	amlpinctrl_get_pin(void *, uint32_t *);
370 void	amlpinctrl_set_pin(void *, uint32_t *, int);
371 
372 int
amlpinctrl_match(struct device * parent,void * match,void * aux)373 amlpinctrl_match(struct device *parent, void *match, void *aux)
374 {
375 	struct fdt_attach_args *faa = aux;
376 	int node = faa->fa_node;
377 
378 	return (OF_is_compatible(node, "amlogic,meson-g12a-periphs-pinctrl") ||
379 	    OF_is_compatible(node, "amlogic,meson-g12a-aobus-pinctrl"));
380 }
381 
382 void
amlpinctrl_attach(struct device * parent,struct device * self,void * aux)383 amlpinctrl_attach(struct device *parent, struct device *self, void *aux)
384 {
385 	struct amlpinctrl_softc *sc = (struct amlpinctrl_softc *)self;
386 	struct fdt_attach_args *faa = aux;
387 	uint64_t addr[5], size[5];
388 	uint32_t *cell;
389 	uint32_t acells, scells;
390 	uint32_t reg[20];
391 	int node = faa->fa_node;
392 	int child;
393 	int i, len, line;
394 
395 	for (child = OF_child(node); child; child = OF_peer(child)) {
396 		if (OF_getproplen(child, "gpio-controller") == 0)
397 			break;
398 	}
399 	if (child == 0) {
400 		printf(": no register banks\n");
401 		return;
402 	}
403 
404 	acells = OF_getpropint(node, "#address-cells", faa->fa_acells);
405 	scells = OF_getpropint(node, "#size-cells", faa->fa_scells);
406 	len = OF_getproplen(child, "reg");
407 	line = (acells + scells) * sizeof(uint32_t);
408 	if (acells < 1 || acells > 2 || scells < 1 || scells > 2 ||
409 	    len > sizeof(reg) || (len / line) > nitems(addr)) {
410 		printf(": unexpected register layout\n");
411 		return;
412 	}
413 
414 	memset(&size, 0, sizeof(size));
415 	OF_getpropintarray(child, "reg", reg, len);
416 	for (i = 0, cell = reg; i < len / line; i++) {
417 		addr[i] = cell[0];
418 		if (acells > 1)
419 			addr[i] = (addr[i] << 32) | cell[1];
420 		cell += acells;
421 		size[i] = cell[0];
422 		if (scells > 1)
423 			size[i] = (size[i] << 32) | cell[1];
424 		cell += scells;
425 	}
426 
427 	sc->sc_iot = faa->fa_iot;
428 
429 	i = OF_getindex(child, "gpio", "reg-names");
430 	if (i < 0 || i >= nitems(size) || size[i] == 0 ||
431 	    bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_gpio_ioh)) {
432 		printf(": can't map gpio registers\n");
433 		return;
434 	}
435 	i = OF_getindex(child, "mux", "reg-names");
436 	if (i < 0 || i >= nitems(size) || size[i] == 0 ||
437 	    bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_mux_ioh)) {
438 		printf(": can't map mux registers\n");
439 		return;
440 	}
441 	i = OF_getindex(child, "ds", "reg-names");
442 	if (i < 0 || i >= nitems(size) || size[i] == 0 ||
443 	    bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_ds_ioh)) {
444 		printf(": can't map ds registers\n");
445 		return;
446 	}
447 	i = OF_getindex(child, "pull", "reg-names");
448 	if (i < 0)
449 		sc->sc_nobias = 1;
450 	else if (i >= nitems(size) || size[i] == 0 ||
451 	    bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_pull_ioh)) {
452 		printf(": can't map pull registers\n");
453 		return;
454 	}
455 	i = OF_getindex(child, "pull-enable", "reg-names");
456 	if (i < 0)
457 		sc->sc_nobias = 1;
458 	else if (i >= nitems(size) || size[i] == 0 ||
459 	    bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_pull_en_ioh)) {
460 		printf(": can't map pull-enable registers\n");
461 		return;
462 	}
463 
464 	printf("\n");
465 
466 	if (OF_is_compatible(node, "amlogic,meson-g12a-periphs-pinctrl")) {
467 		sc->sc_gpio_banks = aml_g12a_gpio_banks;
468 		sc->sc_pin_groups = aml_g12a_pin_groups;
469 	} else {
470 		sc->sc_gpio_banks = aml_g12a_ao_gpio_banks;
471 		sc->sc_pin_groups = aml_g12a_ao_pin_groups;
472 	}
473 
474 	pinctrl_register(faa->fa_node, amlpinctrl_pinctrl, sc);
475 
476 	sc->sc_gc.gc_node = child;
477 	sc->sc_gc.gc_cookie = sc;
478 	sc->sc_gc.gc_config_pin = amlpinctrl_config_pin;
479 	sc->sc_gc.gc_get_pin = amlpinctrl_get_pin;
480 	sc->sc_gc.gc_set_pin = amlpinctrl_set_pin;
481 	gpio_controller_register(&sc->sc_gc);
482 }
483 
484 const struct aml_gpio_bank *
amlpinctrl_lookup_bank(struct amlpinctrl_softc * sc,uint32_t pin)485 amlpinctrl_lookup_bank(struct amlpinctrl_softc *sc, uint32_t pin)
486 {
487 	const struct aml_gpio_bank *bank;
488 
489 	for (bank = sc->sc_gpio_banks; bank->num_pins > 0; bank++) {
490 		if (pin >= bank->first_pin &&
491 		    pin < bank->first_pin + bank->num_pins)
492 			return bank;
493 	}
494 
495 	return NULL;
496 }
497 
498 const struct aml_pin_group *
amlpinctrl_lookup_group(struct amlpinctrl_softc * sc,const char * name)499 amlpinctrl_lookup_group(struct amlpinctrl_softc *sc, const char *name)
500 {
501 	const struct aml_pin_group *group;
502 
503 	for (group = sc->sc_pin_groups; group->name; group++) {
504 		if (strcmp(name, group->name) == 0)
505 			return group;
506 	}
507 
508 	return NULL;
509 }
510 
511 void
amlpinctrl_config_func(struct amlpinctrl_softc * sc,const char * name,const char * function,int bias,int ds)512 amlpinctrl_config_func(struct amlpinctrl_softc *sc, const char *name,
513     const char *function, int bias, int ds)
514 {
515 	const struct aml_pin_group *group;
516 	const struct aml_gpio_bank *bank;
517 	bus_addr_t off;
518 	uint32_t pin;
519 	uint32_t reg;
520 
521 	group = amlpinctrl_lookup_group(sc, name);
522 	if (group == NULL) {
523 		printf("%s: %s\n", __func__, name);
524 		return;
525 	}
526 	if (strcmp(function, group->function) != 0) {
527 		printf("%s: mismatched function %s\n", __func__, function);
528 		return;
529 	}
530 
531 	bank = amlpinctrl_lookup_bank(sc, group->pin);
532 	KASSERT(bank);
533 
534 	pin = group->pin - bank->first_pin;
535 
536 	/* mux */
537 	off = (bank->mux_reg + pin / 8) << 2;
538 	reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off);
539 	reg &= ~(0xf << (((pin % 8) * 4) + bank->mux_bit));
540 	reg |= (group->func << (((pin % 8) * 4) + bank->mux_bit));
541 	bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg);
542 
543 	if (!sc->sc_nobias) {
544 		/* pull */
545 		off = bank->pull_reg << 2;
546 		reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_ioh, off);
547 		if (bias == BIAS_PULL_UP)
548 			reg |= (1 << (pin + bank->pull_bit));
549 		else
550 			reg &= ~(1 << (pin + bank->pull_bit));
551 		bus_space_write_4(sc->sc_iot, sc->sc_pull_ioh, off, reg);
552 
553 		/* pull-enable */
554 		off = bank->pull_en_reg << 2;
555 		reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_en_ioh, off);
556 		if (bias != BIAS_DISABLE)
557 			reg |= (1 << (pin + bank->pull_en_bit));
558 		else
559 			reg &= ~(1 << (pin + bank->pull_en_bit));
560 		bus_space_write_4(sc->sc_iot, sc->sc_pull_en_ioh, off, reg);
561 	}
562 
563 	if (ds < 0)
564 		return;
565 	else if (ds <= 500)
566 		ds = 0;
567 	else if (ds <= 2500)
568 		ds = 1;
569 	else if (ds <= 3000)
570 		ds = 2;
571 	else if (ds <= 4000)
572 		ds = 3;
573 	else {
574 		printf("%s: invalid drive-strength %d\n", __func__, ds);
575 		ds = 3;
576 	}
577 
578 	/* ds */
579 	off = (bank->ds_reg + pin / 16) << 2;
580 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ds_ioh, off);
581 	reg &= ~(0x3 << (((pin % 16) * 2) + bank->ds_bit));
582 	reg |= (ds << (((pin % 16) * 2) + bank->ds_bit));
583 	bus_space_write_4(sc->sc_iot, sc->sc_ds_ioh, off, reg);
584 }
585 
586 int
amlpinctrl_pinctrl(uint32_t phandle,void * cookie)587 amlpinctrl_pinctrl(uint32_t phandle, void *cookie)
588 {
589 	struct amlpinctrl_softc *sc = cookie;
590 	int node, child;
591 
592 	node = OF_getnodebyphandle(phandle);
593 	if (node == 0)
594 		return -1;
595 
596 	for (child = OF_child(node); child; child = OF_peer(child)) {
597 		char function[16];
598 		char *groups;
599 		char *group;
600 		int bias, ds;
601 		int len;
602 
603 		memset(function, 0, sizeof(function));
604 		OF_getprop(child, "function", function, sizeof(function));
605 		function[sizeof(function) - 1] = 0;
606 
607 		/* Bias */
608 		if (OF_getproplen(child, "bias-pull-up") == 0)
609 			bias = BIAS_PULL_UP;
610 		else if (OF_getproplen(child, "bias-pull-down") == 0)
611 			bias = BIAS_PULL_DOWN;
612 		else
613 			bias = BIAS_DISABLE;
614 
615 		/* Drive-strength */
616 		ds = OF_getpropint(child, "drive-strength-microamp", -1);
617 
618 		len = OF_getproplen(child, "groups");
619 		if (len <= 0) {
620 			printf("%s: 0x%08x\n", __func__, phandle);
621 			continue;
622 		}
623 
624 		groups = malloc(len, M_TEMP, M_WAITOK);
625 		OF_getprop(child, "groups", groups, len);
626 
627 		group = groups;
628 		while (group < groups + len) {
629 			amlpinctrl_config_func(sc, group, function, bias, ds);
630 			group += strlen(group) + 1;
631 		}
632 
633 		free(groups, M_TEMP, len);
634 	}
635 
636 	return 0;
637 }
638 
639 void
amlpinctrl_config_pin(void * cookie,uint32_t * cells,int config)640 amlpinctrl_config_pin(void *cookie, uint32_t *cells, int config)
641 {
642 	struct amlpinctrl_softc *sc = cookie;
643 	const struct aml_gpio_bank *bank;
644 	bus_addr_t off;
645 	uint32_t pin = cells[0];
646 	uint32_t flags = cells[1];
647 	uint32_t reg;
648 
649 	bank = amlpinctrl_lookup_bank(sc, pin);
650 	if (bank == NULL) {
651 		printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
652 		return;
653 	}
654 
655 	pin = pin - bank->first_pin;
656 
657 	/* mux */
658 	off = (bank->mux_reg + pin / 8) << 2;
659 	reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off);
660 	reg &= ~(0xf << (((pin % 8) * 4) + bank->mux_bit));
661 	bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg);
662 
663 	/* Emulate open drain. */
664 	if (flags & GPIO_OPEN_DRAIN)
665 		config &= ~GPIO_CONFIG_OUTPUT;
666 
667 	/* gpio */
668 	off = bank->dir_reg << 2;
669 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
670 	if (config & GPIO_CONFIG_OUTPUT)
671 		reg &= ~(1 << (pin + bank->dir_bit));
672 	else
673 		reg |= (1 << (pin + bank->dir_bit));
674 	bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
675 }
676 
677 int
amlpinctrl_get_pin(void * cookie,uint32_t * cells)678 amlpinctrl_get_pin(void *cookie, uint32_t *cells)
679 {
680 	struct amlpinctrl_softc *sc = cookie;
681 	const struct aml_gpio_bank *bank;
682 	bus_addr_t off;
683 	uint32_t pin = cells[0];
684 	uint32_t flags = cells[1];
685 	uint32_t reg;
686 	int val;
687 
688 	bank = amlpinctrl_lookup_bank(sc, pin);
689 	if (bank == NULL) {
690 		printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
691 		return 0;
692 	}
693 
694 	pin = pin - bank->first_pin;
695 
696 	/* gpio */
697 	off = bank->in_reg << 2;
698 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
699 	val = (reg >> (pin + bank->in_bit)) & 1;
700 	if (flags & GPIO_ACTIVE_LOW)
701 		val = !val;
702 
703 	return val;
704 }
705 
706 void
amlpinctrl_set_pin(void * cookie,uint32_t * cells,int val)707 amlpinctrl_set_pin(void *cookie, uint32_t *cells, int val)
708 {
709 	struct amlpinctrl_softc *sc = cookie;
710 	const struct aml_gpio_bank *bank;
711 	bus_addr_t off;
712 	uint32_t pin = cells[0];
713 	uint32_t flags = cells[1];
714 	int reg;
715 
716 	bank = amlpinctrl_lookup_bank(sc, pin);
717 	if (bank == NULL) {
718 		printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
719 		return;
720 	}
721 
722 	pin = pin - bank->first_pin;
723 
724 	if (flags & GPIO_ACTIVE_LOW)
725 		val = !val;
726 
727 	/* Emulate open drain. */
728 	if (flags & GPIO_OPEN_DRAIN) {
729 		/* gpio */
730 		off = bank->dir_reg << 2;
731 		reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
732 		if (val)
733 			reg |= (1 << (pin + bank->dir_bit));
734 		else
735 			reg &= ~(1 << (pin + bank->dir_bit));
736 		bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
737 		if (val)
738 			return;
739 	}
740 
741 	/* gpio */
742 	off = bank->out_reg << 2;
743 	reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
744 	if (val)
745 		reg |= (1 << (pin + bank->out_bit));
746 	else
747 		reg &= ~(1 << (pin + bank->out_bit));
748 	bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
749 }
750