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