mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 20:55:17 -05:00
iPod Classic: rework on external interrupts
Change-Id: I5be450adeb12b16070d9bfa31503e2ef350b2981
This commit is contained in:
parent
3f17745930
commit
88caf222ed
3 changed files with 180 additions and 172 deletions
|
|
@ -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)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
|
||||
int flags = disable_irq_save();
|
||||
|
||||
/* fill handler struct */
|
||||
struct gpio_handler *handler = &l_handlers[n_handlers++];
|
||||
|
||||
handler->gpio_n = gpio_n;
|
||||
handler->isr = isr;
|
||||
handler->flags = (type ? FLAG_TYPE_LEVEL : 0)
|
||||
| (autoflip ? FLAG_AUTOFLIP : 0);
|
||||
|
||||
/* configure */
|
||||
GPIOIC_INTTYPE(group) |=
|
||||
(type ? GPIOIC_INTTYPE_LEVEL : GPIOIC_INTTYPE_EDGE) << index;
|
||||
GPIOIC_INTLEVEL(group) |=
|
||||
(level ? GPIOIC_INTLEVEL_HIGH : GPIOIC_INTLEVEL_LOW) << index;
|
||||
|
||||
restore_irq(flags);
|
||||
|
||||
/* XXX: valid only for gpio_n = 0..127 (IRQ_EXT0..IRQ_EXT3) */
|
||||
VIC0INTENABLE = 1 << (IRQ_EXT0 + (gpio_n >> 5));
|
||||
/* disable external interrupts */
|
||||
for (int i = 0; i < EIC_N_GROUPS; i++)
|
||||
EIC_INTEN(i) = 0;
|
||||
}
|
||||
|
||||
void gpio_int_enable(int gpio_n)
|
||||
{
|
||||
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);
|
||||
|
||||
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 eint_register(struct eint_handler *h)
|
||||
{
|
||||
int i;
|
||||
struct gpio_handler *handler;
|
||||
uint32_t ints, bit_mask;
|
||||
int flags = disable_irq_save();
|
||||
|
||||
ints = GPIOIC_INTSTAT(group) & GPIOIC_INTEN(group);
|
||||
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);
|
||||
|
||||
for (i = 0; i < n_handlers; i++) {
|
||||
handler = &l_handlers[i];
|
||||
EIC_INTTYPE(group) |= (h->type << index);
|
||||
EIC_INTLEVEL(group) |= (h->level << index);
|
||||
EIC_INTSTAT(group) = (1 << index); /* clear */
|
||||
EIC_INTEN(group) |= (1 << index); /* enable */
|
||||
|
||||
if (IC_GROUP(handler->gpio_n) != group)
|
||||
/* 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);
|
||||
|
||||
if (i == EINT_MAX_HANDLERS)
|
||||
panicf("%s(): too many handlers!", __func__);
|
||||
}
|
||||
|
||||
void eint_unregister(struct eint_handler *h)
|
||||
{
|
||||
int flags = disable_irq_save();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
restore_irq(flags);
|
||||
}
|
||||
|
||||
/* ISR */
|
||||
void ICODE_ATTR eint_handler(int group)
|
||||
{
|
||||
int i;
|
||||
uint32_t ints;
|
||||
|
||||
ints = EIC_INTSTAT(group) & EIC_INTEN(group);
|
||||
|
||||
for (i = 0; i < EINT_MAX_HANDLERS; i++) {
|
||||
struct eint_handler *h = l_handlers[i];
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ void system_init(void)
|
|||
pmu_preinit();
|
||||
#endif
|
||||
gpio_init();
|
||||
eint_init();
|
||||
pmu_init();
|
||||
dma_init();
|
||||
#ifdef HAVE_SERIAL
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue