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