mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
Allow external interrupts.
- Set the external pin to interrupt in bus_setup_intr - Implement bus_config_intr for external interrupts - Extend arm_{,un}mask_irq to work with external interrupts Approved by: imp (mentor)
This commit is contained in:
parent
34f56898a1
commit
fa94061701
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=210458
@ -118,6 +118,8 @@ static int s3c24x0_setup_intr(device_t, device_t, struct resource *, int,
|
||||
driver_filter_t *, driver_intr_t *, void *, void **);
|
||||
static int s3c24x0_teardown_intr(device_t, device_t, struct resource *,
|
||||
void *);
|
||||
static int s3c24x0_config_intr(device_t, int, enum intr_trigger,
|
||||
enum intr_polarity);
|
||||
static struct resource *s3c24x0_alloc_resource(device_t, device_t, int, int *,
|
||||
u_long, u_long, u_long, u_int);
|
||||
static int s3c24x0_activate_resource(device_t, device_t, int, int,
|
||||
@ -134,6 +136,7 @@ static device_method_t s3c24x0_methods[] = {
|
||||
DEVMETHOD(device_identify, s3c24x0_identify),
|
||||
DEVMETHOD(bus_setup_intr, s3c24x0_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, s3c24x0_teardown_intr),
|
||||
DEVMETHOD(bus_config_intr, s3c24x0_config_intr),
|
||||
DEVMETHOD(bus_alloc_resource, s3c24x0_alloc_resource),
|
||||
DEVMETHOD(bus_activate_resource, s3c24x0_activate_resource),
|
||||
DEVMETHOD(bus_release_resource, s3c24x0_release_resource),
|
||||
@ -176,6 +179,30 @@ s3c24x0_add_child(device_t bus, int prio, const char *name, int unit)
|
||||
return (child);
|
||||
}
|
||||
|
||||
static void
|
||||
s3c24x0_enable_ext_intr(unsigned int irq)
|
||||
{
|
||||
uint32_t reg, value;
|
||||
int offset;
|
||||
|
||||
if (irq <= 7) {
|
||||
reg = GPIO_PFCON;
|
||||
offset = irq * 2;
|
||||
} else if (irq <= 23) {
|
||||
reg = GPIO_PGCON;
|
||||
offset = (irq - 8) * 2;
|
||||
} else
|
||||
return;
|
||||
|
||||
/* Make the pin an interrupt source */
|
||||
value = bus_space_read_4(s3c2xx0_softc->sc_iot,
|
||||
s3c2xx0_softc->sc_gpio_ioh, reg);
|
||||
value &= ~(3 << offset);
|
||||
value |= 2 << offset;
|
||||
bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
|
||||
reg, value);
|
||||
}
|
||||
|
||||
static int
|
||||
s3c24x0_setup_intr(device_t dev, device_t child,
|
||||
struct resource *ires, int flags, driver_filter_t *filt,
|
||||
@ -189,6 +216,10 @@ s3c24x0_setup_intr(device_t dev, device_t child,
|
||||
return (error);
|
||||
|
||||
for (irq = rman_get_start(ires); irq <= rman_get_end(ires); irq++) {
|
||||
if (irq >= S3C24X0_EXTIRQ_MIN && irq <= S3C24X0_EXTIRQ_MAX) {
|
||||
/* Enable the external interrupt pin */
|
||||
s3c24x0_enable_ext_intr(irq - S3C24X0_EXTIRQ_MIN);
|
||||
}
|
||||
arm_unmask_irq(irq);
|
||||
}
|
||||
return (0);
|
||||
@ -201,6 +232,59 @@ s3c24x0_teardown_intr(device_t dev, device_t child, struct resource *res,
|
||||
return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
|
||||
}
|
||||
|
||||
static int
|
||||
s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig,
|
||||
enum intr_polarity pol)
|
||||
{
|
||||
uint32_t mask, reg, value;
|
||||
int offset;
|
||||
|
||||
/* Only external interrupts can be configured */
|
||||
if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX)
|
||||
return (EINVAL);
|
||||
|
||||
/* There is no standard trigger or polarity for the bus */
|
||||
if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM)
|
||||
return (EINVAL);
|
||||
|
||||
irq -= S3C24X0_EXTIRQ_MIN;
|
||||
|
||||
/* Get the bits to set */
|
||||
mask = 0;
|
||||
if (pol == INTR_POLARITY_LOW) {
|
||||
mask = 2;
|
||||
} else if (pol == INTR_POLARITY_HIGH) {
|
||||
mask = 4;
|
||||
}
|
||||
if (trig == INTR_TRIGGER_LEVEL) {
|
||||
mask >>= 2;
|
||||
}
|
||||
|
||||
/* Get the register to set */
|
||||
if (irq <= 7) {
|
||||
reg = GPIO_EXTINT(0);
|
||||
offset = irq * 4;
|
||||
} else if (irq <= 15) {
|
||||
reg = GPIO_EXTINT(1);
|
||||
offset = (irq - 8) * 4;
|
||||
} else if (irq <= 23) {
|
||||
reg = GPIO_EXTINT(2);
|
||||
offset = (irq - 16) * 4;
|
||||
} else {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Set the new signaling method */
|
||||
value = bus_space_read_4(s3c2xx0_softc->sc_iot,
|
||||
s3c2xx0_softc->sc_gpio_ioh, reg);
|
||||
value &= ~(7 << offset);
|
||||
value |= mask << offset;
|
||||
bus_space_write_4(s3c2xx0_softc->sc_iot,
|
||||
s3c2xx0_softc->sc_gpio_ioh, reg, value);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags)
|
||||
@ -356,6 +440,7 @@ s3c24x0_attach(device_t dev)
|
||||
bus_space_tag_t iot;
|
||||
device_t child;
|
||||
unsigned int i, j;
|
||||
u_long irqmax;
|
||||
|
||||
s3c2xx0_softc = &(sc->sc_sx);
|
||||
sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag;
|
||||
@ -363,10 +448,6 @@ s3c24x0_attach(device_t dev)
|
||||
s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs";
|
||||
s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY;
|
||||
s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers";
|
||||
if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
|
||||
rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
|
||||
S3C2410_SUBIRQ_MAX) != 0) /* XXX Change S3C2440_SUBIRQ_MAX depending on micro */
|
||||
panic("s3c24x0_attach: failed to set up IRQ rman");
|
||||
/* Manage the registor memory space */
|
||||
if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) ||
|
||||
(rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
|
||||
@ -388,6 +469,22 @@ s3c24x0_attach(device_t dev)
|
||||
*/
|
||||
s3c24x0_identify_cpu(dev);
|
||||
|
||||
/*
|
||||
* Manage the interrupt space.
|
||||
* We need to put this after s3c24x0_identify_cpu as the avaliable
|
||||
* interrupts change depending on which CPU we have.
|
||||
*/
|
||||
if (sc->sc_sx.sc_cpu == CPU_S3C2410)
|
||||
irqmax = S3C2410_SUBIRQ_MAX;
|
||||
else
|
||||
irqmax = S3C2440_SUBIRQ_MAX;
|
||||
if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
|
||||
rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
|
||||
irqmax) != 0 ||
|
||||
rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman,
|
||||
S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX))
|
||||
panic("s3c24x0_attach: failed to set up IRQ rman");
|
||||
|
||||
/* calculate current clock frequency */
|
||||
s3c24x0_clock_freq(&sc->sc_sx);
|
||||
device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n",
|
||||
@ -607,6 +704,33 @@ arm_get_next_irq(int last __unused)
|
||||
return (irq);
|
||||
|
||||
return (S3C24X0_SUBIRQ_MIN + subirq);
|
||||
|
||||
case S3C24X0_INT_0:
|
||||
case S3C24X0_INT_1:
|
||||
case S3C24X0_INT_2:
|
||||
case S3C24X0_INT_3:
|
||||
/* There is a 1:1 mapping to the IRQ we are handling */
|
||||
return S3C24X0_INT_EXT(irq);
|
||||
|
||||
case S3C24X0_INT_4_7:
|
||||
case S3C24X0_INT_8_23:
|
||||
/* Find the external interrupt being called */
|
||||
subirq = 0x7fffff;
|
||||
subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND);
|
||||
subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
|
||||
if (subirq == 0)
|
||||
return (irq);
|
||||
|
||||
subirq = ffs(subirq) - 1;
|
||||
|
||||
/* Clear the external irq pending bit */
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND,
|
||||
(1 << subirq));
|
||||
|
||||
return S3C24X0_INT_EXT(subirq);
|
||||
}
|
||||
|
||||
return (irq);
|
||||
@ -619,18 +743,28 @@ arm_mask_irq(uintptr_t irq)
|
||||
{
|
||||
u_int32_t mask;
|
||||
|
||||
if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
|
||||
/* External interrupt 0..3 are directly mapped to irq 0..3 */
|
||||
irq -= S3C24X0_EXTIRQ_MIN;
|
||||
}
|
||||
if (irq < S3C24X0_SUBIRQ_MIN) {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
|
||||
mask |= (1 << irq);
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
|
||||
} else {
|
||||
} else if (irq < S3C24X0_EXTIRQ_MIN) {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
|
||||
mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN));
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
|
||||
} else {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
|
||||
mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN));
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,17 +773,27 @@ arm_unmask_irq(uintptr_t irq)
|
||||
{
|
||||
u_int32_t mask;
|
||||
|
||||
if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
|
||||
/* External interrupt 0..3 are directly mapped to irq 0..3 */
|
||||
irq -= S3C24X0_EXTIRQ_MIN;
|
||||
}
|
||||
if (irq < S3C24X0_SUBIRQ_MIN) {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
|
||||
mask &= ~(1 << irq);
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
|
||||
} else {
|
||||
} else if (irq < S3C24X0_EXTIRQ_MIN) {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
|
||||
mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN));
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
|
||||
} else {
|
||||
mask = bus_space_read_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
|
||||
mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN));
|
||||
bus_space_write_4(&s3c2xx0_bs_tag,
|
||||
s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +207,10 @@
|
||||
#define S3C24X0_INT_BFLT 7 /* Battery fault */
|
||||
#define S3C24X0_INT_8_23 5 /* Ext int 8..23 */
|
||||
#define S3C24X0_INT_4_7 4 /* Ext int 4..7 */
|
||||
#define S3C24X0_INT_EXT(n) (n) /* External interrupt [3:0] for 24{1,4}0 */
|
||||
#define S3C24X0_INT_3 3
|
||||
#define S3C24X0_INT_2 2
|
||||
#define S3C24X0_INT_1 1
|
||||
#define S3C24X0_INT_0 0
|
||||
|
||||
/* 24{1,4}0 has more than 32 interrupt sources. These are sub-sources
|
||||
* that are OR-ed into main interrupt sources, and controlled via
|
||||
@ -230,6 +233,15 @@
|
||||
#define S3C24X0_INT_TXD0 (S3C24X0_SUBIRQ_MIN+1) /* UART0 Tx */
|
||||
#define S3C24X0_INT_RXD0 (S3C24X0_SUBIRQ_MIN+0) /* UART0 Rx */
|
||||
|
||||
/*
|
||||
* Support for external interrupts. We use values from 48
|
||||
* to allow new CPU's to allocate new subirq's.
|
||||
*/
|
||||
#define S3C24X0_EXTIRQ_MIN 48
|
||||
#define S3C24X0_EXTIRQ_COUNT 24
|
||||
#define S3C24X0_EXTIRQ_MAX (S3C24X0_EXTIRQ_MIN + S3C24X0_EXTIRQ_COUNT - 1)
|
||||
#define S3C24X0_INT_EXT(n) (S3C24X0_EXTIRQ_MIN + (n))
|
||||
|
||||
/* DMA controller */
|
||||
/* XXX */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user