summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/target/arm/s5l8702/gpio-s5l8702.c193
-rw-r--r--firmware/target/arm/s5l8702/gpio-s5l8702.h126
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c1
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