From e85bc74b307365e9a7b4adab51d646638db12fbd Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sat, 5 Jun 2021 00:12:01 +0100 Subject: x1000: GPIO refactor The GPIO API was pretty clunky and pin settings were decentralized, making it hard to see what was happening and making GPIO stuff look like a mess, frankly. Instead of passing clunky (port, pin) pairs everywhere, GPIOs are now identified with a single int. The extra overhead should be minimal as GPIO configuration is generally not on a performance-critical path. Pin assignments are now mostly consolidated in gpio-target.h and put in various tables so gpio_init() can assign most pins at boot time. Most drivers no longer need to touch GPIOs and basic pin I/O stuff can happen without config since pins are put into the right state. IRQ pins still need to be configured manually before use. Change-Id: Ic5326284b0b2a2f613e9e76a41cb50e24af3aa47 --- firmware/target/mips/ingenic_x1000/gpio-x1000.c | 88 ++++++++++++++++++++----- 1 file changed, 71 insertions(+), 17 deletions(-) (limited to 'firmware/target/mips/ingenic_x1000/gpio-x1000.c') diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.c b/firmware/target/mips/ingenic_x1000/gpio-x1000.c index 40e4c5e631..14195359df 100644 --- a/firmware/target/mips/ingenic_x1000/gpio-x1000.c +++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.c @@ -20,37 +20,91 @@ ****************************************************************************/ #include "gpio-x1000.h" -#include "kernel.h" + +const struct gpio_setting gpio_settings[PIN_COUNT] = { +#define DEFINE_GPIO(_name, _gpio, _func) \ + {.gpio = _gpio, .func = _func}, +#define DEFINE_PINGROUP(...) +#include "gpio-target.h" +#undef DEFINE_GPIO +#undef DEFINE_PINGROUP +}; + +const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = { +#define DEFINE_GPIO(...) +#define DEFINE_PINGROUP(_name, _port, _pins, _func) \ + {.port = _port, .pins = _pins, .func = _func}, +#include "gpio-target.h" +#undef DEFINE_GPIO +#undef DEFINE_PINGROUP +}; + +const char* const gpio_names[PIN_COUNT] = { +#define DEFINE_GPIO(_name, ...) #_name, +#define DEFINE_PINGROUP(...) +#include "gpio-target.h" +#undef DEFINE_GPIO +#undef DEFINE_PINGROUP +}; + +const char* const pingroup_names[PINGROUP_COUNT] = { +#define DEFINE_GPIO(...) +#define DEFINE_PINGROUP(_name, ...) #_name, +#include "gpio-target.h" +#undef DEFINE_GPIO +#undef DEFINE_PINGROUP +}; void gpio_init(void) { + /* Apply all initial GPIO settings */ + for(int i = 0; i < PINGROUP_COUNT; ++i) { + const struct pingroup_setting* d = &pingroup_settings[i]; + if(d->pins != 0) + gpioz_configure(d->port, d->pins, d->func); + } + + for(int i = 0; i < PIN_COUNT; ++i) { + const struct gpio_setting* d = &gpio_settings[i]; + if(d->gpio != GPIO_NONE) + gpioz_configure(GPION_PORT(d->gpio), GPION_MASK(d->gpio), d->func); + } + /* Any GPIO pins left in an IRQ trigger state need to be switched off, * because the drivers won't be ready to handle the interrupts until they * get initialized later in the boot. */ for(int i = 0; i < 4; ++i) { uint32_t intbits = REG_GPIO_INT(i); if(intbits) { - gpio_config(i, intbits, GPIO_INPUT); + gpioz_configure(i, intbits, GPIOF_INPUT); jz_clr(GPIO_FLAG(i), intbits); } } } -void gpio_config(int port, unsigned pinmask, int func) +void gpioz_configure(int port, uint32_t pins, int func) { - unsigned intr = REG_GPIO_INT(port); - unsigned mask = REG_GPIO_MSK(port); - unsigned pat1 = REG_GPIO_PAT1(port); - unsigned pat0 = REG_GPIO_PAT0(port); - - if(func & 8) jz_set(GPIO_INT(GPIO_Z), (intr & pinmask) ^ pinmask); - else jz_clr(GPIO_INT(GPIO_Z), (~intr & pinmask) ^ pinmask); - if(func & 4) jz_set(GPIO_MSK(GPIO_Z), (mask & pinmask) ^ pinmask); - else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pinmask) ^ pinmask); - if(func & 2) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pinmask) ^ pinmask); - else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pinmask) ^ pinmask); - if(func & 1) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pinmask) ^ pinmask); - else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pinmask) ^ pinmask); + uint32_t intr = REG_GPIO_INT(port); + uint32_t mask = REG_GPIO_MSK(port); + uint32_t pat1 = REG_GPIO_PAT1(port); + uint32_t pat0 = REG_GPIO_PAT0(port); + + /* Note: GPIO Z has _only_ set and clear registers, which are used to + * atomically manipulate the selected GPIO port when we write GID2LD. + * So there's not really any direct setting or clearing going on here... + */ + if(func & GPIO_F_INT) jz_set(GPIO_INT(GPIO_Z), (intr & pins) ^ pins); + else jz_clr(GPIO_INT(GPIO_Z), (~intr & pins) ^ pins); + if(func & GPIO_F_MASK) jz_set(GPIO_MSK(GPIO_Z), (mask & pins) ^ pins); + else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pins) ^ pins); + if(func & GPIO_F_PAT1) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pins) ^ pins); + else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pins) ^ pins); + if(func & GPIO_F_PAT0) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pins) ^ pins); + else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pins) ^ pins); REG_GPIO_Z_GID2LD = port; - gpio_set_pull(port, pinmask, func & 16); + + if(func & GPIO_F_PULL) + jz_set(GPIO_PULL(port), pins); + else + jz_clr(GPIO_PULL(port), pins); } -- cgit v1.2.3