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 ---------------------------------------------------------------------
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()):
if name in self.cpu.interrupts.keys():
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
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)
{
__attribute__((unused)) unsigned int irqs;
unsigned int irqs = irq_pending() & irq_getmask();
irqs = irq_pending() & irq_getmask();
#ifdef CSR_UART_BASE
#ifndef UART_POLLING
if(irqs & (1 << UART_INTERRUPT))
uart_isr();
#endif
#endif
while (irqs)
{
const unsigned int irq = __builtin_ctz(irqs);
if (irq < NR_IRQ && irq_table[irq].isr)
irq_table[irq].isr();
else {
irq_setmask(irq_getmask() & ~(1<<irq));
printf("\n*** disabled spurious irq %d ***\n", irq);
}
irqs &= irqs - 1; // clear this irq (the first bit set)
}
}
#endif

View File

@ -110,6 +110,8 @@ void uart_init(void)
uart_ev_pending_write(uart_ev_pending_read());
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));
}