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