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 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 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 * 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 * 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 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 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 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 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 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