#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_gpio.h>
#include <dev/ofw/ofw_pinctrl.h>
#include <dev/ofw/fdt.h>
#define BIAS_DISABLE 0x00
#define BIAS_PULL_UP 0x01
#define BIAS_PULL_DOWN 0x02
#define GPIOZ_0 0
#define GPIOZ_1 1
#define GPIOZ_7 7
#define GPIOZ_8 8
#define GPIOZ_14 14
#define GPIOZ_15 15
#define GPIOH_0 16
#define GPIOH_1 17
#define GPIOH_2 18
#define GPIOH_3 19
#define GPIOH_5 21
#define GPIOH_6 22
#define GPIOH_7 23
#define BOOT_0 25
#define BOOT_1 26
#define BOOT_2 27
#define BOOT_3 28
#define BOOT_4 29
#define BOOT_5 30
#define BOOT_6 31
#define BOOT_7 32
#define BOOT_8 33
#define BOOT_10 35
#define BOOT_13 38
#define GPIOC_0 41
#define GPIOC_1 42
#define GPIOC_2 43
#define GPIOC_3 44
#define GPIOC_4 45
#define GPIOC_5 46
#define GPIOC_6 47
#define GPIOA_0 49
#define GPIOA_14 63
#define GPIOA_15 64
#define GPIOX_0 65
#define GPIOX_3 68
#define GPIOX_5 70
#define GPIOX_6 71
#define GPIOX_7 72
#define GPIOX_8 73
#define GPIOX_10 75
#define GPIOX_11 76
#define GPIOX_16 81
#define GPIOX_17 82
#define GPIOX_18 83
#define GPIOX_19 84
#define GPIOAO_0 0
#define GPIOAO_1 1
#define GPIOAO_3 3
#define GPIOAO_4 4
#define GPIOAO_5 5
#define GPIOAO_6 6
#define GPIOAO_10 10
#define GPIOAO_11 11
#define GPIOE_0 12
#define GPIOE_1 13
#define GPIOE_2 14
#define PERIPHS_PIN_MUX_0 0xb0
#define PERIPHS_PIN_MUX_3 0xb3
#define PERIPHS_PIN_MUX_6 0xb6
#define PERIPHS_PIN_MUX_9 0xb9
#define PERIPHS_PIN_MUX_B 0xbb
#define PERIPHS_PIN_MUX_D 0xbd
#define PREG_PAD_GPIO0_EN_N 0x10
#define PREG_PAD_GPIO0_O 0x11
#define PREG_PAD_GPIO0_I 0x12
#define PREG_PAD_GPIO1_EN_N 0x13
#define PREG_PAD_GPIO1_O 0x14
#define PREG_PAD_GPIO1_I 0x15
#define PREG_PAD_GPIO2_EN_N 0x16
#define PREG_PAD_GPIO2_O 0x16
#define PREG_PAD_GPIO2_I 0x18
#define PREG_PAD_GPIO3_EN_N 0x19
#define PREG_PAD_GPIO3_O 0x1a
#define PREG_PAD_GPIO3_I 0x1b
#define PREG_PAD_GPIO4_EN_N 0x1c
#define PREG_PAD_GPIO4_O 0x1d
#define PREG_PAD_GPIO4_I 0x1e
#define PREG_PAD_GPIO5_EN_N 0x20
#define PREG_PAD_GPIO5_O 0x21
#define PREG_PAD_GPIO5_I 0x22
#define PAD_PULL_UP_EN_0 0x48
#define PAD_PULL_UP_EN_1 0x49
#define PAD_PULL_UP_EN_2 0x4a
#define PAD_PULL_UP_EN_3 0x4b
#define PAD_PULL_UP_EN_4 0x4c
#define PAD_PULL_UP_EN_5 0x4d
#define PAD_PULL_UP_0 0x3a
#define PAD_PULL_UP_1 0x3b
#define PAD_PULL_UP_2 0x3c
#define PAD_PULL_UP_3 0x3d
#define PAD_PULL_UP_4 0x3e
#define PAD_PULL_UP_5 0x3f
#define PAD_DS_0A 0xd0
#define PAD_DS_1A 0xd1
#define PAD_DS_2A 0xd2
#define PAD_DS_3A 0xd4
#define PAD_DS_4A 0xd5
#define PAD_DS_5A 0xd6
#define AO_RTI_PINMUX_0 0x05
#define AO_RTI_PINMUX_1 0x06
#define AO_PAD_DS_A 0x07
#define AO_PAD_DS_B 0x08
#define AO_GPIO_O_EN_N 0x09
#define AO_GPIO_I 0x0a
#define AO_GPIO_O 0x0d
#define AO_RTI_PULL_UP 0x0b
#define AO_RTI_PULL_UP_EN 0x0c
struct aml_gpio_bank {
uint8_t first_pin, num_pins;
uint8_t mux_reg, mux_bit;
uint8_t dir_reg, dir_bit;
uint8_t in_reg, in_bit;
uint8_t out_reg, out_bit;
uint8_t pull_reg, pull_bit;
uint8_t pull_en_reg, pull_en_bit;
uint8_t ds_reg, ds_bit;
};
struct aml_pin_group {
const char *name;
uint8_t pin;
uint8_t func;
const char *function;
};
const struct aml_gpio_bank aml_g12a_gpio_banks[] = {
{ BOOT_0, 16,
PERIPHS_PIN_MUX_0 - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO0_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO0_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO0_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_0 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_0 - PAD_PULL_UP_EN_0, 0,
PAD_DS_0A - PAD_DS_0A, 0 },
{ GPIOC_0, 8,
PERIPHS_PIN_MUX_9 - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO1_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO1_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO1_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_1 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_1 - PAD_PULL_UP_EN_0, 0,
PAD_DS_1A - PAD_DS_0A, 0 },
{ GPIOX_0, 20,
PERIPHS_PIN_MUX_3 - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO2_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO2_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO2_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_2 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_2 - PAD_PULL_UP_EN_0, 0,
PAD_DS_2A - PAD_DS_0A, 0 },
{ GPIOH_0, 9,
PERIPHS_PIN_MUX_B - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO3_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO3_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO3_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_3 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_3 - PAD_PULL_UP_EN_0, 0,
PAD_DS_3A - PAD_DS_0A, 0 },
{ GPIOZ_0, 16,
PERIPHS_PIN_MUX_6 - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO4_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO4_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO4_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_4 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_4 - PAD_PULL_UP_EN_0, 0,
PAD_DS_4A - PAD_DS_0A, 0 },
{ GPIOA_0, 16,
PERIPHS_PIN_MUX_D - PERIPHS_PIN_MUX_0, 0,
PREG_PAD_GPIO5_EN_N - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO5_I - PREG_PAD_GPIO0_EN_N, 0,
PREG_PAD_GPIO5_O - PREG_PAD_GPIO0_EN_N, 0,
PAD_PULL_UP_5 - PAD_PULL_UP_0, 0,
PAD_PULL_UP_EN_5 - PAD_PULL_UP_EN_0, 0,
PAD_DS_5A - PAD_DS_0A, 0 },
{ }
};
const struct aml_pin_group aml_g12a_pin_groups[] = {
{ "i2c0_sda_z0", GPIOZ_0, 4, "i2c0" },
{ "i2c0_sck_z1", GPIOZ_1, 4, "i2c0" },
{ "i2c0_sda_z7", GPIOZ_7, 7, "i2c0" },
{ "i2c0_sck_z8", GPIOZ_8, 7, "i2c0" },
{ "i2c2_sda_z", GPIOZ_14, 3, "i2c2" },
{ "i2c2_sck_z", GPIOZ_15, 3, "i2c2" },
{ "i2c3_sda_a", GPIOA_14, 2, "i2c3" },
{ "i2c3_sck_a", GPIOA_15, 2, "i2c3" },
{ "emmc_nand_d0", BOOT_0, 1, "emmc" },
{ "emmc_nand_d1", BOOT_1, 1, "emmc" },
{ "emmc_nand_d2", BOOT_2, 1, "emmc" },
{ "emmc_nand_d3", BOOT_3, 1, "emmc" },
{ "emmc_nand_d4", BOOT_4, 1, "emmc" },
{ "emmc_nand_d5", BOOT_5, 1, "emmc" },
{ "emmc_nand_d6", BOOT_6, 1, "emmc" },
{ "emmc_nand_d7", BOOT_7, 1, "emmc" },
{ "BOOT_8", BOOT_8, 0, "gpio_periphs" },
{ "emmc_clk", BOOT_8, 1, "emmc" },
{ "emmc_cmd", BOOT_10, 1, "emmc" },
{ "emmc_nand_ds", BOOT_13, 1, "emmc" },
{ "sdcard_d0_c", GPIOC_0, 1, "sdcard" },
{ "sdcard_d1_c", GPIOC_1, 1, "sdcard" },
{ "sdcard_d2_c", GPIOC_2, 1, "sdcard" },
{ "sdcard_d3_c", GPIOC_3, 1, "sdcard" },
{ "GPIOC_4", GPIOC_4, 0, "gpio_periphs" },
{ "pwm_c_c", GPIOC_4, 5, "pwm_c" },
{ "sdcard_clk_c", GPIOC_4, 1, "sdcard" },
{ "sdcard_cmd_c", GPIOC_5, 1, "sdcard" },
{ "i2c0_sda_c", GPIOC_5, 3, "i2c0" },
{ "i2c0_sck_c", GPIOC_6, 3, "i2c0" },
{ "pwm_d_x3", GPIOX_3, 4, "pwm_d" },
{ "pwm_c_x5", GPIOX_5, 4, "pwm_c" },
{ "pwm_a", GPIOX_6, 1, "pwm_a" },
{ "pwm_d_x6", GPIOX_6, 4, "pwm_d" },
{ "pwm_b_x7", GPIOX_7, 4, "pwm_b" },
{ "pwm_f_x", GPIOX_7, 1, "pwm_f" },
{ "pwm_c_x8", GPIOX_8, 5, "pwm_c" },
{ "i2c1_sda_x", GPIOX_10, 5, "i2c1" },
{ "i2c1_sck_x", GPIOX_11, 5, "i2c1" },
{ "pwm_e", GPIOX_16, 1, "pwm_e" },
{ "i2c2_sda_x", GPIOX_17, 1, "i2c2" },
{ "i2c2_sck_x", GPIOX_18, 1, "i2c2" },
{ "pwm_b_x19", GPIOX_19, 1, "pwm_b" },
{ "i2c3_sda_h", GPIOH_0, 2, "i2c3" },
{ "i2c3_sck_h", GPIOH_1, 2, "i2c3" },
{ "i2c1_sda_h2", GPIOH_2, 2, "i2c1" },
{ "i2c1_sck_h3", GPIOH_3, 2, "i2c1" },
{ "pwm_f_h", GPIOH_5, 4, "pwm_f" },
{ "i2c1_sda_h6", GPIOH_6, 4, "i2c1" },
{ "i2c1_sck_h7", GPIOH_7, 4, "i2c1" },
{ }
};
const struct aml_gpio_bank aml_g12a_ao_gpio_banks[] = {
{ GPIOAO_0, 12,
AO_RTI_PINMUX_0 - AO_RTI_PINMUX_0, 0,
AO_GPIO_O_EN_N - AO_GPIO_O_EN_N, 0,
AO_GPIO_I - AO_GPIO_O_EN_N, 0,
AO_GPIO_O - AO_GPIO_O_EN_N, 0,
AO_RTI_PULL_UP - AO_RTI_PULL_UP, 0,
AO_RTI_PULL_UP_EN - AO_RTI_PULL_UP_EN, 0,
AO_PAD_DS_A - AO_PAD_DS_A, 0 },
{ GPIOE_0, 3,
AO_RTI_PINMUX_1 - AO_RTI_PINMUX_0, 16,
AO_GPIO_O_EN_N - AO_GPIO_O_EN_N, 16,
AO_GPIO_I - AO_GPIO_O_EN_N, 16,
AO_GPIO_O - AO_GPIO_O_EN_N, 16,
AO_RTI_PULL_UP - AO_RTI_PULL_UP, 16,
AO_RTI_PULL_UP_EN - AO_RTI_PULL_UP_EN, 16,
AO_PAD_DS_B - AO_PAD_DS_A, 0 },
{ }
};
const struct aml_pin_group aml_g12a_ao_pin_groups[] = {
{ "uart_ao_a_tx", GPIOAO_0, 1, "uart_ao_a" },
{ "uart_ao_a_rx", GPIOAO_1, 1, "uart_ao_a" },
{ "pwm_ao_c_4", GPIOAO_4, 3, "pwm_ao_c" },
{ "pwm_ao_c_hiz", GPIOAO_4, 4, "pwm_ao_c" },
{ "pwm_ao_d_5", GPIOAO_5, 3, "pwm_ao_d" },
{ "remote_ao_input", GPIOAO_5, 1, "remote_ao_input" },
{ "pwm_ao_c_6", GPIOAO_6, 3, "pwm_ao_c" },
{ "pwm_ao_d_10", GPIOAO_10, 3, "pwm_ao_d" },
{ "pwm_ao_a", GPIOAO_11, 3, "pwm_ao_a" },
{ "pwm_ao_a_hiz", GPIOAO_11, 2, "pwm_ao_a" },
{ "pwm_ao_b", GPIOE_0, 3, "pwm_ao_b" },
{ "pwm_ao_d_e", GPIOE_1, 3, "pwm_ao_d" },
{ "pwm_a_e", GPIOE_2, 3, "pwm_a_e" },
{ }
};
struct amlpinctrl_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_gpio_ioh;
bus_space_handle_t sc_pull_ioh;
bus_space_handle_t sc_pull_en_ioh;
bus_space_handle_t sc_mux_ioh;
bus_space_handle_t sc_ds_ioh;
int sc_nobias;
const struct aml_gpio_bank *sc_gpio_banks;
const struct aml_pin_group *sc_pin_groups;
struct gpio_controller sc_gc;
};
int amlpinctrl_match(struct device *, void *, void *);
void amlpinctrl_attach(struct device *, struct device *, void *);
const struct cfattach amlpinctrl_ca = {
sizeof(struct amlpinctrl_softc), amlpinctrl_match, amlpinctrl_attach
};
struct cfdriver amlpinctrl_cd = {
NULL, "amlpinctrl", DV_DULL
};
int amlpinctrl_pinctrl(uint32_t, void *);
void amlpinctrl_config_pin(void *, uint32_t *, int);
int amlpinctrl_get_pin(void *, uint32_t *);
void amlpinctrl_set_pin(void *, uint32_t *, int);
int
amlpinctrl_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
int node = faa->fa_node;
return (OF_is_compatible(node, "amlogic,meson-g12a-periphs-pinctrl") ||
OF_is_compatible(node, "amlogic,meson-g12a-aobus-pinctrl"));
}
void
amlpinctrl_attach(struct device *parent, struct device *self, void *aux)
{
struct amlpinctrl_softc *sc = (struct amlpinctrl_softc *)self;
struct fdt_attach_args *faa = aux;
uint64_t addr[5], size[5];
uint32_t *cell;
uint32_t acells, scells;
uint32_t reg[20];
int node = faa->fa_node;
int child;
int i, len, line;
for (child = OF_child(node); child; child = OF_peer(child)) {
if (OF_getproplen(child, "gpio-controller") == 0)
break;
}
if (child == 0) {
printf(": no register banks\n");
return;
}
acells = OF_getpropint(node, "#address-cells", faa->fa_acells);
scells = OF_getpropint(node, "#size-cells", faa->fa_scells);
len = OF_getproplen(child, "reg");
line = (acells + scells) * sizeof(uint32_t);
if (acells < 1 || acells > 2 || scells < 1 || scells > 2 ||
len > sizeof(reg) || (len / line) > nitems(addr)) {
printf(": unexpected register layout\n");
return;
}
memset(&size, 0, sizeof(size));
OF_getpropintarray(child, "reg", reg, len);
for (i = 0, cell = reg; i < len / line; i++) {
addr[i] = cell[0];
if (acells > 1)
addr[i] = (addr[i] << 32) | cell[1];
cell += acells;
size[i] = cell[0];
if (scells > 1)
size[i] = (size[i] << 32) | cell[1];
cell += scells;
}
sc->sc_iot = faa->fa_iot;
i = OF_getindex(child, "gpio", "reg-names");
if (i < 0 || i >= nitems(size) || size[i] == 0 ||
bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_gpio_ioh)) {
printf(": can't map gpio registers\n");
return;
}
i = OF_getindex(child, "mux", "reg-names");
if (i < 0 || i >= nitems(size) || size[i] == 0 ||
bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_mux_ioh)) {
printf(": can't map mux registers\n");
return;
}
i = OF_getindex(child, "ds", "reg-names");
if (i < 0 || i >= nitems(size) || size[i] == 0 ||
bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_ds_ioh)) {
printf(": can't map ds registers\n");
return;
}
i = OF_getindex(child, "pull", "reg-names");
if (i < 0)
sc->sc_nobias = 1;
else if (i >= nitems(size) || size[i] == 0 ||
bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_pull_ioh)) {
printf(": can't map pull registers\n");
return;
}
i = OF_getindex(child, "pull-enable", "reg-names");
if (i < 0)
sc->sc_nobias = 1;
else if (i >= nitems(size) || size[i] == 0 ||
bus_space_map(sc->sc_iot, addr[i], size[i], 0, &sc->sc_pull_en_ioh)) {
printf(": can't map pull-enable registers\n");
return;
}
printf("\n");
if (OF_is_compatible(node, "amlogic,meson-g12a-periphs-pinctrl")) {
sc->sc_gpio_banks = aml_g12a_gpio_banks;
sc->sc_pin_groups = aml_g12a_pin_groups;
} else {
sc->sc_gpio_banks = aml_g12a_ao_gpio_banks;
sc->sc_pin_groups = aml_g12a_ao_pin_groups;
}
pinctrl_register(faa->fa_node, amlpinctrl_pinctrl, sc);
sc->sc_gc.gc_node = child;
sc->sc_gc.gc_cookie = sc;
sc->sc_gc.gc_config_pin = amlpinctrl_config_pin;
sc->sc_gc.gc_get_pin = amlpinctrl_get_pin;
sc->sc_gc.gc_set_pin = amlpinctrl_set_pin;
gpio_controller_register(&sc->sc_gc);
}
const struct aml_gpio_bank *
amlpinctrl_lookup_bank(struct amlpinctrl_softc *sc, uint32_t pin)
{
const struct aml_gpio_bank *bank;
for (bank = sc->sc_gpio_banks; bank->num_pins > 0; bank++) {
if (pin >= bank->first_pin &&
pin < bank->first_pin + bank->num_pins)
return bank;
}
return NULL;
}
const struct aml_pin_group *
amlpinctrl_lookup_group(struct amlpinctrl_softc *sc, const char *name)
{
const struct aml_pin_group *group;
for (group = sc->sc_pin_groups; group->name; group++) {
if (strcmp(name, group->name) == 0)
return group;
}
return NULL;
}
void
amlpinctrl_config_func(struct amlpinctrl_softc *sc, const char *name,
const char *function, int bias, int ds)
{
const struct aml_pin_group *group;
const struct aml_gpio_bank *bank;
bus_addr_t off;
uint32_t pin;
uint32_t reg;
group = amlpinctrl_lookup_group(sc, name);
if (group == NULL) {
printf("%s: %s\n", __func__, name);
return;
}
if (strcmp(function, group->function) != 0) {
printf("%s: mismatched function %s\n", __func__, function);
return;
}
bank = amlpinctrl_lookup_bank(sc, group->pin);
KASSERT(bank);
pin = group->pin - bank->first_pin;
off = (bank->mux_reg + pin / 8) << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off);
reg &= ~(0xf << (((pin % 8) * 4) + bank->mux_bit));
reg |= (group->func << (((pin % 8) * 4) + bank->mux_bit));
bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg);
if (!sc->sc_nobias) {
off = bank->pull_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_ioh, off);
if (bias == BIAS_PULL_UP)
reg |= (1 << (pin + bank->pull_bit));
else
reg &= ~(1 << (pin + bank->pull_bit));
bus_space_write_4(sc->sc_iot, sc->sc_pull_ioh, off, reg);
off = bank->pull_en_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_en_ioh, off);
if (bias != BIAS_DISABLE)
reg |= (1 << (pin + bank->pull_en_bit));
else
reg &= ~(1 << (pin + bank->pull_en_bit));
bus_space_write_4(sc->sc_iot, sc->sc_pull_en_ioh, off, reg);
}
if (ds < 0)
return;
else if (ds <= 500)
ds = 0;
else if (ds <= 2500)
ds = 1;
else if (ds <= 3000)
ds = 2;
else if (ds <= 4000)
ds = 3;
else {
printf("%s: invalid drive-strength %d\n", __func__, ds);
ds = 3;
}
off = (bank->ds_reg + pin / 16) << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_ds_ioh, off);
reg &= ~(0x3 << (((pin % 16) * 2) + bank->ds_bit));
reg |= (ds << (((pin % 16) * 2) + bank->ds_bit));
bus_space_write_4(sc->sc_iot, sc->sc_ds_ioh, off, reg);
}
int
amlpinctrl_pinctrl(uint32_t phandle, void *cookie)
{
struct amlpinctrl_softc *sc = cookie;
int node, child;
node = OF_getnodebyphandle(phandle);
if (node == 0)
return -1;
for (child = OF_child(node); child; child = OF_peer(child)) {
char function[16];
char *groups;
char *group;
int bias, ds;
int len;
memset(function, 0, sizeof(function));
OF_getprop(child, "function", function, sizeof(function));
function[sizeof(function) - 1] = 0;
if (OF_getproplen(child, "bias-pull-up") == 0)
bias = BIAS_PULL_UP;
else if (OF_getproplen(child, "bias-pull-down") == 0)
bias = BIAS_PULL_DOWN;
else
bias = BIAS_DISABLE;
ds = OF_getpropint(child, "drive-strength-microamp", -1);
len = OF_getproplen(child, "groups");
if (len <= 0) {
printf("%s: 0x%08x\n", __func__, phandle);
continue;
}
groups = malloc(len, M_TEMP, M_WAITOK);
OF_getprop(child, "groups", groups, len);
group = groups;
while (group < groups + len) {
amlpinctrl_config_func(sc, group, function, bias, ds);
group += strlen(group) + 1;
}
free(groups, M_TEMP, len);
}
return 0;
}
void
amlpinctrl_config_pin(void *cookie, uint32_t *cells, int config)
{
struct amlpinctrl_softc *sc = cookie;
const struct aml_gpio_bank *bank;
bus_addr_t off;
uint32_t pin = cells[0];
uint32_t flags = cells[1];
uint32_t reg;
bank = amlpinctrl_lookup_bank(sc, pin);
if (bank == NULL) {
printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
return;
}
pin = pin - bank->first_pin;
off = (bank->mux_reg + pin / 8) << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off);
reg &= ~(0xf << (((pin % 8) * 4) + bank->mux_bit));
bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg);
if (flags & GPIO_OPEN_DRAIN)
config &= ~GPIO_CONFIG_OUTPUT;
off = bank->dir_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
if (config & GPIO_CONFIG_OUTPUT)
reg &= ~(1 << (pin + bank->dir_bit));
else
reg |= (1 << (pin + bank->dir_bit));
bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
}
int
amlpinctrl_get_pin(void *cookie, uint32_t *cells)
{
struct amlpinctrl_softc *sc = cookie;
const struct aml_gpio_bank *bank;
bus_addr_t off;
uint32_t pin = cells[0];
uint32_t flags = cells[1];
uint32_t reg;
int val;
bank = amlpinctrl_lookup_bank(sc, pin);
if (bank == NULL) {
printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
return 0;
}
pin = pin - bank->first_pin;
off = bank->in_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
val = (reg >> (pin + bank->in_bit)) & 1;
if (flags & GPIO_ACTIVE_LOW)
val = !val;
return val;
}
void
amlpinctrl_set_pin(void *cookie, uint32_t *cells, int val)
{
struct amlpinctrl_softc *sc = cookie;
const struct aml_gpio_bank *bank;
bus_addr_t off;
uint32_t pin = cells[0];
uint32_t flags = cells[1];
int reg;
bank = amlpinctrl_lookup_bank(sc, pin);
if (bank == NULL) {
printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]);
return;
}
pin = pin - bank->first_pin;
if (flags & GPIO_ACTIVE_LOW)
val = !val;
if (flags & GPIO_OPEN_DRAIN) {
off = bank->dir_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
if (val)
reg |= (1 << (pin + bank->dir_bit));
else
reg &= ~(1 << (pin + bank->dir_bit));
bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
if (val)
return;
}
off = bank->out_reg << 2;
reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off);
if (val)
reg |= (1 << (pin + bank->out_bit));
else
reg &= ~(1 << (pin + bank->out_bit));
bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg);
}