diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 13:46:41 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-24 13:46:41 -0700 |
commit | 93b063fedfcf7409a67df035170ea5670cad22e1 (patch) | |
tree | a23321a7465d966b1ccf196ca00e65a70c9f9110 /02-usart/src/kern/gpio/gpio_manager.c | |
parent | b040195d31df6ad759f16ea3456471897f55daa1 (diff) | |
download | stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.gz stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.tar.bz2 stm32l4-93b063fedfcf7409a67df035170ea5670cad22e1.zip |
Moved action to top level.
Removed old iterations of the project and moved the files from 02-usart
to the root directory since that's the sole place where the action is
and that subproject has outgrown its initial title.
Diffstat (limited to '02-usart/src/kern/gpio/gpio_manager.c')
-rw-r--r-- | 02-usart/src/kern/gpio/gpio_manager.c | 402 |
1 files changed, 0 insertions, 402 deletions
diff --git a/02-usart/src/kern/gpio/gpio_manager.c b/02-usart/src/kern/gpio/gpio_manager.c deleted file mode 100644 index 82dd0ba..0000000 --- a/02-usart/src/kern/gpio/gpio_manager.c +++ /dev/null @@ -1,402 +0,0 @@ -#include "kern/gpio/gpio_manager.h" - -#include "arch/stm32l4xxx/peripherals/irq.h" -#include "arch/stm32l4xxx/peripherals/rcc.h" - -/* A list of whether the pins are in use or not as a bitmask. */ -uint32_t pins_inuse[N_GPIO_PINS / 32 + (N_GPIO_PINS % 32 != 0)]; - -struct gpio_afn_and_pin { - int8_t afn_number; - gpio_pin_t gpio_pin; -}; - -/* - * Returns which (pin, afn) pairs provide the given alternate function. - * The out array needs to have 5 positions. - * - * This function will use afn_number = -1 as the terminal. - * - * Note that EVENTOUT is a special case because all pins have an event out - * at afn=15 and should be assumed by other logic and thus is not handled - * by this function. - */ -static void get_ports_and_pins_for_alternate_function( - gpio_alternate_function_t afn, struct gpio_afn_and_pin* out) -{ - switch (afn) { -#define AFN1(fn, ...) \ - static_assert(false, "Unable to parse afn_table at " #fn); -#define AFN3(fn, ...) \ - static_assert(false, "Unable to parse afn_table at " #fn); -#define AFN5(fn, ...) \ - static_assert(false, "Unable to parse afn_table at " #fn); -#define AFN7(fn, ...) \ - static_assert(false, "Unable to parse afn_table at " #fn); - -#define AFN2(fn, afn, pin) \ - out[0].afn_number = afn; \ - out[0].gpio_pin = GPIO_PIN_ ## pin - -#define AFN4(fn, afn0, pin0, afn1, pin1) \ - AFN2(fn, afn0, pin0); \ - out[1].afn_number = afn1; \ - out[1].gpio_pin = GPIO_PIN_ ## pin1 - -#define AFN6(fn, afn0, pin0, afn1, pin1, afn2, pin2) \ - AFN4(fn, afn0, pin0, afn1, pin1); \ - out[2].afn_number = afn2; \ - out[2].gpio_pin = GPIO_PIN_ ## pin2 - -#define AFN8(fn, afn0, pin0, afn1, pin1, afn2, pin2, afn3, pin3) \ - AFN6(fn, afn0, pin0, afn1, pin1, afn2, pin2); \ - out[2].afn_number = afn3; \ - out[2].gpio_pin = GPIO_PIN_ ## pin3 - -#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME -#define GET_N(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME -#define AFN(fn, ...) \ - case GPIO_ALTERNATE_FUNCTION_ ## fn: \ - GET_MACRO(__VA_ARGS__, AFN8, AFN7, AFN6, AFN5, AFN4, AFN3, AFN2, AFN1)\ - (fn, __VA_ARGS__); \ - out[GET_N(__VA_ARGS__, 4, 4, 3, 3, 2, 2, 1, 1)] = \ - (struct gpio_afn_and_pin){-1, -1}; \ - break; - -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc" - case GPIO_ALTERNATE_FUNCTION_EVENTOUT: - return; - } -} - -static inline int offset_for_gpio_pin(gpio_pin_t pin) -{ - switch (pin) { -#define PORT(p, pn) \ - case GPIO_PIN_P ## p ## pn: return pn; -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" -#undef PORT - case N_GPIO_PINS: return -1; - } - - /* Should be unreachable. */ - return -1; -} - -inline bool gpio_pin_in_use(gpio_pin_t pin) -{ - return !!(pins_inuse[pin / 32] & (1 << (pin % 32))); -} - -#define A(...) -#define B(...) -#define C(...) -#define D(...) -#define E(...) -#define F(...) -#define G(...) -#define H(...) -#define I(...) -#define SELECT_MACRO(PORT) PORT -#define PORT(port, pin) \ - SELECT_MACRO(port)(GPIO_PIN_P ## port ## pin, pin) -static int gc_port_a() -{ - return 0 -#undef A -#define A(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef A -#define A(...) -} - -static int gc_port_b() -{ - return 0 -#undef B -#define B(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef B -#define B(...) -} - -static int gc_port_c() -{ - return 0 -#undef C -#define C(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef C -#define C(...) -} - -static int gc_port_d() -{ - return 0 -#undef D -#define D(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef D -#define D(...) -} - -static int gc_port_e() -{ - return 0 -#undef E -#define E(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef E -#define E(...) -} - -static int gc_port_f() -{ - return 0 -#undef F -#define F(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef F -#define F(...) -} - -static int gc_port_g() -{ - return 0 -#undef G -#define G(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef G -#define G(...) -} - -static int gc_port_h() -{ - return 0 -#undef H -#define H(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef H -#define H(...) -} - -static int gc_port_i() -{ - return 0 -#undef I -#define I(abspin, relpin) \ - | (gpio_pin_in_use(abspin) << (relpin)) -#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc" - ; -#undef I -#define I(...) -} - - -static inline bool gpio_pin_try_reserve(gpio_pin_t pin) -{ - int in_use = __sync_fetch_and_or( - &pins_inuse[pin / 32], 1 << (pin % 32)); - return !(in_use & (1 << (pin % 32))); -} - -inline static gpio_port_config_t* get_gpio_port_config(gpio_port_t port) -{ - switch(port) { - case GPIO_PORT_A: return (gpio_port_config_t*) GPIOA_BASE; - case GPIO_PORT_B: return (gpio_port_config_t*) GPIOB_BASE; - case GPIO_PORT_C: return (gpio_port_config_t*) GPIOC_BASE; - case GPIO_PORT_H: return (gpio_port_config_t*) GPIOH_BASE; - default: return NULL; - } -} - -inline static gpio_port_config_t* get_gpio_port_config_for_pin(gpio_pin_t pin) -{ - gpio_port_t port = get_port_for_pin(pin); - return get_gpio_port_config(port); -} - -gpio_reserved_pin_t reserve_gpio_pin( - gpio_pin_t pin, gpio_pin_opts_t* opts, int* error_out) -{ - *error_out = 0; - if (!gpio_pin_try_reserve(pin)) { - *error_out = GPIO_ERROR_IN_USE; - return (gpio_reserved_pin_t) { .v_ = -1 }; - } - - gpio_port_t port = get_port_for_pin(pin); - regset(RCC.ahb2en_r, rcc_gpioen(port), 1); - - gpio_port_config_t* port_config = get_gpio_port_config(port); - - - int off = offset_for_gpio_pin(pin); - - regset(port_config->mode_r, gpio_mode_n(off), opts->mode); - regset(port_config->pupd_r, gpio_pupd_n(off), opts->pull_dir); - - switch(opts->mode) { - case GPIO_MODE_INPUT: - break; - - case GPIO_MODE_OUTPUT: - regset(port_config->ospeed_r, gpio_ospeed_n(off), opts->output_opts.speed); - regset(port_config->otype_r, gpio_otype_n(off), opts->output_opts.type); - break; - - case GPIO_MODE_ALTERNATE: - if (off < 8) { - regset( - port_config->af_rl, - gpio_afsel_n(off), - opts->alternate_opts.function); - } else { - regset( - port_config->af_rh, - gpio_afsel_n(off - 8), - opts->alternate_opts.function); - } - break; - - case GPIO_MODE_ANALOG: - regset(port_config->asc_r, gpio_asc_n(off), 1); - break; - } - - return (gpio_reserved_pin_t) { .v_ = pin }; -} - -gpio_reserved_pin_t gpio_enable_alternate_function( - gpio_alternate_function_t fn, - gpio_pin_t hint, - int* error_out) -{ - int i = 0; - gpio_pin_opts_t opts; - struct gpio_afn_and_pin afn_and_pin[5]; - - if (gpio_pin_out_of_range(hint) && hint != -1) { - *error_out = GPIO_ERROR_INVALID_PIN; - return (gpio_reserved_pin_t) { .v_ = -1 }; - } - - opts.mode = GPIO_MODE_ALTERNATE; - - if (fn == GPIO_ALTERNATE_FUNCTION_EVENTOUT) { - afn_and_pin[i].afn_number = GPIO_ALTERNATE_FUNCTION_EVENTOUT; - if (hint == -1) { - hint = GPIO_PIN_PA0; - } - afn_and_pin[i].gpio_pin = hint; - } else { - get_ports_and_pins_for_alternate_function(fn, afn_and_pin); - - if (hint == -1) { - hint = afn_and_pin[0].gpio_pin; - } - - for(i = 0; - i < 5 - && afn_and_pin[i].gpio_pin != hint - && afn_and_pin[i].gpio_pin != -1; - ++ i); - - if (afn_and_pin[i].gpio_pin == -1 || i == 5) { - *error_out = GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION; - return (gpio_reserved_pin_t) { .v_ = -1 }; - } - } - - opts.alternate_opts.function = afn_and_pin[i].afn_number; - return reserve_gpio_pin(afn_and_pin[i].gpio_pin, &opts, error_out); -} - -void release_gpio_pin(gpio_reserved_pin_t rpin) -{ - gpio_pin_t pin = rpin.v_; - // TODO this should be a critical section. - gpio_port_t port = get_port_for_pin(pin); - pins_inuse[pin / 32] &= ~(1 << (pin % 32)); - - int used; - switch(port) { - case GPIO_PORT_A: - used = gc_port_a(); - break; - case GPIO_PORT_B: - used = gc_port_b(); - break; - case GPIO_PORT_C: - used = gc_port_c(); - break; - case GPIO_PORT_D: - used = gc_port_d(); - break; - case GPIO_PORT_E: - used = gc_port_e(); - break; - case GPIO_PORT_F: - used = gc_port_f(); - break; - case GPIO_PORT_G: - used = gc_port_g(); - break; - case GPIO_PORT_H: - used = gc_port_h(); - break; - case GPIO_PORT_I: - used = gc_port_i(); - break; - - case N_GPIO_PORTS: - used = 1; - break; - } - - if (!used) { - regset(RCC.ahb2en_r, rcc_gpioen(port), 0); - } -} - -inline void get_gpio_pin_port_off( - gpio_pin_t pin, gpio_port_config_t** out_cfg, int* out_off) -{ - *out_cfg = get_gpio_port_config_for_pin(pin); - *out_off = offset_for_gpio_pin(pin); -} - -void set_gpio_pin_high(gpio_reserved_pin_t pin) -{ - int off; - gpio_port_config_t* portcfg; - get_gpio_pin_port_off(pin.v_, &portcfg, &off); - - regset(portcfg->od_r, (1 << off), 1); -} - -void set_gpio_pin_low(gpio_reserved_pin_t pin) -{ - int off; - gpio_port_config_t* portcfg; - get_gpio_pin_port_off(pin.v_, &portcfg, &off); - - regset(portcfg->od_r, (1 << off), 0); -} |