diff options
-rw-r--r-- | firmware/target/arm/s5l8702/gpio-s5l8702.c | 193 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/gpio-s5l8702.h | 126 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/system-s5l8702.c | 1 |
3 files changed, 164 insertions, 156 deletions
diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.c b/firmware/target/arm/s5l8702/gpio-s5l8702.c index 3b2c02861f..0f7a029fb6 100644 --- a/firmware/target/arm/s5l8702/gpio-s5l8702.c +++ b/firmware/target/arm/s5l8702/gpio-s5l8702.c @@ -23,11 +23,30 @@ #include "config.h" #include "system.h" -#include "gpio-s5l8702.h" #include "panic.h" +#include "gpio-s5l8702.h" + + int rec_hw_ver; +static uint32_t gpio_data[] = +{ + 0x5322222F, 0xEEEEEE00, 0x2332EEEE, 0x3333E222, + 0x33333333, 0x33333333, 0x3F000E33, 0xEEEEEEEE, + 0xEEEEEEEE, 0xEEEEEEEE, 0xE0EEEEEE, 0xEE00EE0E, + 0xEEEE0EEE, 0xEEEEEEEE, 0xEE2222EE, 0xEEEE0EEE +}; + +void INIT_ATTR gpio_preinit(void) +{ + for (int i = 0; i < 16; i++) { + PCON(i) = gpio_data[i]; + PUNB(i) = 0; + PUNC(i) = 0; + } +} + void INIT_ATTR gpio_init(void) { /* Capture hardware versions: @@ -44,9 +63,8 @@ void INIT_ATTR gpio_init(void) */ GPIOCMD = 0xe0700; rec_hw_ver = (PDAT(14) & (1 << 7)) ? 0 : 1; + GPIOCMD = 0xe070e; /* restore default configuration */ - /* default GPIO configuration */ - GPIOCMD = 0xe070e; if (rec_hw_ver == 0) { GPIOCMD = 0xe060e; } @@ -56,31 +74,9 @@ void INIT_ATTR gpio_init(void) GPIOCMD = 0xe0600; PUNB(14) |= (1 << 6); } - - /* TODO: initialize GPIO ports for minimum power consumption */ } - -/* - * XXX: disabled, not used and never tested! - */ #if 0 -/* handlers list */ -#define GPIOIC_MAX_HANDLERS 2 - -#define FLAG_TYPE_LEVEL (1 << 0) -#define FLAG_AUTOFLIP (1 << 1) - -struct gpio_handler { - int gpio_n; - void (*isr)(void); - int flags; -}; -static struct gpio_handler l_handlers[GPIOIC_MAX_HANDLERS] IDATA_ATTR; -static int n_handlers = 0; - - -/* API */ uint32_t gpio_group_get(int group) { uint32_t pcon = PCON(group); @@ -103,131 +99,128 @@ void gpio_group_set(int group, uint32_t mask, uint32_t cfg) { PCON(group) = (PCON(group) & ~mask) | (cfg & mask); } +#endif -void gpio_int_register(int gpio_n, void *isr, int type, int level, int autoflip) -{ - if (n_handlers >= GPIOIC_MAX_HANDLERS) - panicf("gpio_int_register(): too many handlers!"); - int group = IC_GROUP(gpio_n); - int index = IC_IDX(gpio_n); +/* + * eINT API + */ +#ifndef EINT_MAX_HANDLERS +#define EINT_MAX_HANDLERS 1 +#endif +static struct eint_handler* l_handlers[EINT_MAX_HANDLERS] IDATA_ATTR; +void INIT_ATTR eint_init(void) +{ + /* disable external interrupts */ + for (int i = 0; i < EIC_N_GROUPS; i++) + EIC_INTEN(i) = 0; +} + +void eint_register(struct eint_handler *h) +{ + int i; int flags = disable_irq_save(); - /* fill handler struct */ - struct gpio_handler *handler = &l_handlers[n_handlers++]; + for (i = 0; i < EINT_MAX_HANDLERS; i++) { + if (!l_handlers[i]) { + int group = EIC_GROUP(h->gpio_n); + int index = EIC_INDEX(h->gpio_n); - handler->gpio_n = gpio_n; - handler->isr = isr; - handler->flags = (type ? FLAG_TYPE_LEVEL : 0) - | (autoflip ? FLAG_AUTOFLIP : 0); + EIC_INTTYPE(group) |= (h->type << index); + EIC_INTLEVEL(group) |= (h->level << index); + EIC_INTSTAT(group) = (1 << index); /* clear */ + EIC_INTEN(group) |= (1 << index); /* enable */ - /* configure */ - GPIOIC_INTTYPE(group) |= - (type ? GPIOIC_INTTYPE_LEVEL : GPIOIC_INTTYPE_EDGE) << index; - GPIOIC_INTLEVEL(group) |= - (level ? GPIOIC_INTLEVEL_HIGH : GPIOIC_INTLEVEL_LOW) << index; + /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */ + VIC0INTENABLE = 1 << (IRQ_EXT0 + (h->gpio_n >> 5)); + + l_handlers[i] = h; + break; + } + } restore_irq(flags); - /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */ - VIC0INTENABLE = 1 << (IRQ_EXT0 + (gpio_n >> 5)); + if (i == EINT_MAX_HANDLERS) + panicf("%s(): too many handlers!", __func__); } -void gpio_int_enable(int gpio_n) +void eint_unregister(struct eint_handler *h) { - int group = IC_GROUP(gpio_n); - uint32_t bit_mask = 1 << IC_IDX(gpio_n); - int flags = disable_irq_save(); - GPIOIC_INTSTAT(group) = bit_mask; /* clear */ - GPIOIC_INTEN(group) |= bit_mask; /* enable */ - restore_irq(flags); -} -void gpio_int_disable(int gpio_n) -{ - int group = IC_GROUP(gpio_n); - uint32_t bit_mask = 1 << IC_IDX(gpio_n); + for (int i = 0; i < EINT_MAX_HANDLERS; i++) { + if (l_handlers[i] == h) { + int group = EIC_GROUP(h->gpio_n); + int index = EIC_INDEX(h->gpio_n); + + EIC_INTEN(group) &= ~(1 << index); /* disable */ + + /* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */ + if (EIC_INTEN(group) == 0) + VIC0INTENCLEAR = 1 << (IRQ_EXT0 + (h->gpio_n >> 5)); + + l_handlers[i] = NULL; + break; + } + } - int flags = disable_irq_save(); - GPIOIC_INTEN(group) &= ~bit_mask; /* disable */ - GPIOIC_INTSTAT(group) = bit_mask; /* clear */ restore_irq(flags); } - /* ISR */ -void ICODE_ATTR gpio_handler(int group) +void ICODE_ATTR eint_handler(int group) { int i; - struct gpio_handler *handler; - uint32_t ints, bit_mask; + uint32_t ints; - ints = GPIOIC_INTSTAT(group) & GPIOIC_INTEN(group); + ints = EIC_INTSTAT(group) & EIC_INTEN(group); - for (i = 0; i < n_handlers; i++) { - handler = &l_handlers[i]; + for (i = 0; i < EINT_MAX_HANDLERS; i++) { + struct eint_handler *h = l_handlers[i]; - if (IC_GROUP(handler->gpio_n) != group) + if (!h || (EIC_GROUP(h->gpio_n) != group)) continue; - bit_mask = 1 << IC_IDX(handler->gpio_n); + uint32_t bit = 1 << EIC_INDEX(h->gpio_n); - if (ints & bit_mask) { - if ((handler->flags & FLAG_TYPE_LEVEL) == 0) - GPIOIC_INTSTAT(group) = bit_mask; /* clear */ + if (ints & bit) { + /* Clear INTTYPE_EDGE interrupt, to clear INTTYPE_LEVEL + interrupts the source (line level) must be "cleared" */ + if (h->type == EIC_INTTYPE_EDGE) + EIC_INTSTAT(group) = bit; /* clear */ - if (handler->flags & FLAG_AUTOFLIP) - GPIOIC_INTLEVEL(group) ^= bit_mask; /* swap level */ + if (h->autoflip) + EIC_INTLEVEL(group) ^= bit; /* swap level */ - if (handler->isr) - handler->isr(); /* exec GPIO handler */ - - GPIOIC_INTSTAT(group) = bit_mask; /* clear */ + if (h->isr) + h->isr(h); /* exec GPIO handler */ } } } void ICODE_ATTR INT_EXT0(void) { - gpio_handler(6); + eint_handler(6); } void ICODE_ATTR INT_EXT1(void) { - gpio_handler(5); + eint_handler(5); } void ICODE_ATTR INT_EXT2(void) { - gpio_handler(4); + eint_handler(4); } void ICODE_ATTR INT_EXT3(void) { - gpio_handler(3); + eint_handler(3); } void ICODE_ATTR INT_EXT6(void) { - gpio_handler(0); -} -#endif - -static uint32_t gpio_data[16] = -{ - 0x5322222F, 0xEEEEEE00, 0x2332EEEE, 0x3333E222, - 0x33333333, 0x33333333, 0x3F000E33, 0xEEEEEEEE, - 0xEEEEEEEE, 0xEEEEEEEE, 0xE0EEEEEE, 0xEE00EE0E, - 0xEEEE0EEE, 0xEEEEEEEE, 0xEE2222EE, 0xEEEE0EEE -}; - -void gpio_preinit(void) -{ - for (int i = 0; i < 16; i++) { - PCON(i) = gpio_data[i]; - PUNB(i) = 0; - PUNC(i) = 0; - } + eint_handler(0); } diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.h b/firmware/target/arm/s5l8702/gpio-s5l8702.h index 19bc36a139..9259fb05ef 100644 --- a/firmware/target/arm/s5l8702/gpio-s5l8702.h +++ b/firmware/target/arm/s5l8702/gpio-s5l8702.h @@ -23,6 +23,69 @@ #define __GPIO_S5L8702_H__ #include <stdint.h> + +#define REG32_PTR_T volatile uint32_t * + +/* + * s5l8702 External (GPIO) Interrupt Controller + * + * 7 groups of 32 interrupts, GPIO pins are seen as 'wired' + * to groups 6..3 in reverse order. + * On group 3, last four bits are dissbled (GPIO 124..127). + * All bits in groups 1 and 2 are disabled (not used). + * On group 0, all bits are masked except bits 0 and 2: + * bit 0: if unmasked, EINT6 is generated when ALVTCNT + * reachs ALVTEND. + * bit 2: if unmasked, EINT6 is generated when USB cable + * is plugged and/or(TBC) unplugged. + * + * IC_GROUP0..6 are connected to EINT6..0 of the VIC. + */ +#define EIC_N_GROUPS 7 + +/* get EIC group and bit for a given GPIO port */ +#define EIC_GROUP(n) (6 - (n >> 5)) +#define EIC_INDEX(n) ((0x18 - (n & 0x18)) | (n & 0x7)) + +/* SoC EINTs uses these 'gpio' numbers */ +#define GPIO_EINT_USB 0xd8 +#define GPIO_EINT_ALIVE 0xda + +/* probably a part of the system controller */ +#define EIC_BASE 0x39a00000 + +#define EIC_INTLEVEL(g) (*((REG32_PTR_T)(EIC_BASE + 0x80 + 4*(g)))) +#define EIC_INTSTAT(g) (*((REG32_PTR_T)(EIC_BASE + 0xA0 + 4*(g)))) +#define EIC_INTEN(g) (*((REG32_PTR_T)(EIC_BASE + 0xC0 + 4*(g)))) +#define EIC_INTTYPE(g) (*((REG32_PTR_T)(EIC_BASE + 0xE0 + 4*(g)))) + +#define EIC_INTLEVEL_LOW 0 +#define EIC_INTLEVEL_HIGH 1 + +#define EIC_INTTYPE_EDGE 0 +#define EIC_INTTYPE_LEVEL 1 + + +struct eint_handler { + uint8_t gpio_n; + uint8_t type; /* EIC_INTTYPE_ */ + uint8_t level; /* EIC_INTLEVEL_ */ + uint8_t autoflip; + void (*isr)(struct eint_handler*); +}; + +void eint_register(struct eint_handler *h); +void eint_unregister(struct eint_handler *h); +void eint_init(void); + +void gpio_init(void); +/* get/set configuration for GPIO groups (0..15) */ +uint32_t gpio_group_get(int group); +void gpio_group_set(int group, uint32_t mask, uint32_t cfg); + +void gpio_preinit(void); + + /* This is very preliminary work in progress, ATM this region is called * system 'alive' because it seems there are similiarities when mixing * concepts from: @@ -47,9 +110,6 @@ * +-->| 1/UNKDIV |--> Unknown * |___________| */ - -#define REG32_PTR_T volatile uint32_t * - #define SYSALV_BASE 0x39a00000 #define ALVCON (*((REG32_PTR_T)(SYSALV_BASE + 0x0))) @@ -81,67 +141,21 @@ /* * System Alive timer - */ -/* ALVCOM_RUN_BIT starts/stops count on ALVTCNT, counter frequency + * + * ALVCOM_RUN_BIT starts/stops count on ALVTCNT, counter frequency * is SClk / ALVTDIV. When count reachs ALVTEND then ALVTSTAT[0] * and ALVUNK4[0] are set, optionally an interrupt is generated (see * GPIO_IC below). Writing 1 to ALVTCOM_RST_BIT clears ALVSTAT[0] * and ALVUNK4[0] and initializes ALVTCNT to zero. */ -#define ALVTCOM (*((REG32_PTR_T)(SYSALV_BASE + 0x6c))) +#define ALVTCOM (*((REG32_PTR_T)(SYSALV_BASE + 0x6c))) #define ALVTCOM_RUN_BIT (1 << 0) /* 0 -> Stop, 1 -> Start */ #define ALVTCOM_RST_BIT (1 << 1) /* 1 -> Reset */ -#define ALVTEND (*((REG32_PTR_T)(SYSALV_BASE + 0x70))) -#define ALVTDIV (*((REG32_PTR_T)(SYSALV_BASE + 0x74))) +#define ALVTEND (*((REG32_PTR_T)(SYSALV_BASE + 0x70))) +#define ALVTDIV (*((REG32_PTR_T)(SYSALV_BASE + 0x74))) -#define ALVTCNT (*((REG32_PTR_T)(SYSALV_BASE + 0x78))) -#define ALVTSTAT (*((REG32_PTR_T)(SYSALV_BASE + 0x7c))) - - -/* - * s5l8702 GPIO Interrupt Controller - */ -#define GPIOIC_BASE 0x39a00000 /* probably a part of the system controller */ - -#define GPIOIC_INTLEVEL(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0x80 + 4*(g)))) -#define GPIOIC_INTSTAT(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xA0 + 4*(g)))) -#define GPIOIC_INTEN(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xC0 + 4*(g)))) -#define GPIOIC_INTTYPE(g) (*((REG32_PTR_T)(GPIOIC_BASE + 0xE0 + 4*(g)))) - -#define GPIOIC_INTLEVEL_LOW 0 -#define GPIOIC_INTLEVEL_HIGH 1 - -#define GPIOIC_INTTYPE_EDGE 0 -#define GPIOIC_INTTYPE_LEVEL 1 - -/* 7 groups of 32 interrupts, GPIO pins are seen as 'wired' - * to groups 6..3 in reverse order. - * On group 3, last four bits are dissbled (GPIO 124..127). - * All bits in groups 1 and 2 are disabled (not used). - * On group 0, all bits are masked except bits 0 and 2: - * bit 0: if unmasked, EINT6 is generated when ALVTCNT - * reachs ALVTEND. - * bit 2: if unmasked, EINT6 is generated when USB cable - * is plugged and/or(TBC) unplugged. - * - * IC_GROUP0..6 are connected to EINT6..0 of the VIC. - */ - -/* get GPIOIC group and bit for a given GPIO port */ -#define IC_GROUP(n) (6 - (n >> 5)) -#define IC_IDX(n) ((0x18 - (n & 0x18)) | (n & 0x7)) - -void gpio_init(void); -void gpio_int_register(int gpio_n, void *isr, - int type, int level, int autoflip); -void gpio_int_enable(int gpio_n); -void gpio_int_disable(int gpio_n); - -/* get/set configuration for GPIO groups (0..15) */ -uint32_t gpio_group_get(int group); -void gpio_group_set(int group, uint32_t mask, uint32_t cfg); - -void gpio_preinit(void); +#define ALVTCNT (*((REG32_PTR_T)(SYSALV_BASE + 0x78))) +#define ALVTSTAT (*((REG32_PTR_T)(SYSALV_BASE + 0x7c))) #endif /* __GPIO_S5L8702_H__ */ diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c index e94e12a153..cbe8bfcaf7 100644 --- a/firmware/target/arm/s5l8702/system-s5l8702.c +++ b/firmware/target/arm/s5l8702/system-s5l8702.c @@ -206,6 +206,7 @@ void system_init(void) pmu_preinit(); #endif gpio_init(); + eint_init(); pmu_init(); dma_init(); #ifdef HAVE_SERIAL |