soc/software: add irq_attach() / irq_detach()

cleaner mechanism for other software to use interrupts
This commit is contained in:
Andrew Dennison 2023-11-13 12:07:35 +11:00
parent 77ca872b3b
commit 737ced8fa6
4 changed files with 54 additions and 9 deletions

View File

@ -1320,6 +1320,7 @@ class SoC(LiteXModule, SoCCoreCompat):
# SoC IRQ Interconnect --------------------------------------------------------------------- # SoC IRQ Interconnect ---------------------------------------------------------------------
if hasattr(self, "cpu") and hasattr(self.cpu, "interrupt"): if hasattr(self, "cpu") and hasattr(self.cpu, "interrupt"):
self.add_constant("NR_IRQ", max(self.irq.locs.values()) + 1)
for name, loc in sorted(self.irq.locs.items()): for name, loc in sorted(self.irq.locs.items()):
if name in self.cpu.interrupts.keys(): if name in self.cpu.interrupts.keys():
continue continue

View File

@ -0,0 +1,15 @@
#pragma once
#include_next<irq.h>
typedef void (*isr_t)(void);
#ifdef __cplusplus
extern "C" {
#endif
extern int irq_attach(unsigned int irq, isr_t isr) __attribute__((weak));
extern int irq_detach(unsigned int irq) __attribute__((weak));
#ifdef __cplusplus
}
#endif

View File

@ -191,18 +191,45 @@ void isr(void)
} }
#else #else
struct irq_table
{
isr_t isr;
} irq_table[NR_IRQ];
int irq_attach(unsigned int irq, isr_t isr)
{
if (irq >= NR_IRQ) {
printf("Inv irq %d\n", irq);
return -1;
}
unsigned int ie = irq_getie();
irq_setie(0);
irq_table[irq].isr = isr;
irq_setie(ie);
return irq;
}
int irq_detach(unsigned int irq)
{
return irq_attach(irq, NULL);
}
void isr(void) void isr(void)
{ {
__attribute__((unused)) unsigned int irqs; unsigned int irqs = irq_pending() & irq_getmask();
irqs = irq_pending() & irq_getmask(); while (irqs)
{
#ifdef CSR_UART_BASE const unsigned int irq = __builtin_ctz(irqs);
#ifndef UART_POLLING if (irq < NR_IRQ && irq_table[irq].isr)
if(irqs & (1 << UART_INTERRUPT)) irq_table[irq].isr();
uart_isr(); else {
#endif irq_setmask(irq_getmask() & ~(1<<irq));
#endif printf("\n*** disabled spurious irq %d ***\n", irq);
}
irqs &= irqs - 1; // clear this irq (the first bit set)
}
} }
#endif #endif

View File

@ -110,6 +110,8 @@ void uart_init(void)
uart_ev_pending_write(uart_ev_pending_read()); uart_ev_pending_write(uart_ev_pending_read());
uart_ev_enable_write(UART_EV_TX | UART_EV_RX); uart_ev_enable_write(UART_EV_TX | UART_EV_RX);
if (irq_attach)
irq_attach(UART_INTERRUPT, uart_isr);
irq_setmask(irq_getmask() | (1 << UART_INTERRUPT)); irq_setmask(irq_getmask() | (1 << UART_INTERRUPT));
} }