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