diff --git a/arm11/source/arm/gic.c b/arm11/source/arm/gic.c index f396971..8ad10f2 100644 --- a/arm11/source/arm/gic.c +++ b/arm11/source/arm/gic.c @@ -19,8 +19,12 @@ #include #include +#include + #include "arm/gic.h" +#include "system/event.h" + /* Generic Interrupt Controller Registers */ #define REG_GIC(cpu, o, t) REG_ARM_PMR(0x200 + ((cpu) * 0x100) + (o), t) @@ -72,6 +76,7 @@ #define IRQN_IS_VALID(n) ((n) < DIC_MAX_IRQ) static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ]; +static _Atomic(u32) gicIrqPending[DIC_MAX_IRQ / 32]; static struct { u8 tgt; @@ -106,14 +111,13 @@ static u8 gicGetDefaultIrqCfg(u32 irqn) { return gicDefaultIrqCfg[i].mode; } // TODO: would it be considerably faster to use bsearch? - return GIC_RISINGEDGE_1N; } void gicTopHandler(void) { while(1) { - u32 irqn; + u32 irqn, irqsource, index, mask; /** If more than one of these CPUs reads the Interrupt Acknowledge Register at the @@ -121,16 +125,22 @@ void gicTopHandler(void) routine must ensure that only one of them tries to process the interrupt, with the others returning after writing the ID to the End of Interrupt Register. */ - irqn = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS); + irqsource = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS); - if (irqn == GIC_IRQ_SPURIOUS) // no further processing is needed + if (irqsource == GIC_IRQ_SPURIOUS) // no further processing is needed break; - (gicIrqHandlers[irqn & ~IRQN_SRC_MASK])(irqn); + irqn = irqsource & ~IRQN_SRC_MASK; + + index = irqn / 32; + mask = BIT(irqn % 32); + atomic_fetch_or(&gicIrqPending[index], mask); + + (gicIrqHandlers[irqn])(irqsource); // if the id is < 16, the source CPU can be obtained from irqn // if the handler isn't set, it'll try to branch to 0 and trigger a prefetch abort - REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqn; + REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqsource; } } @@ -152,6 +162,7 @@ void gicGlobalReset(void) gicn = MAX_CPU; // clear the interrupt handler and config table + getEventIRQ()->reset(); memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers)); memset(gicIrqConfig, 0, sizeof(gicIrqConfig)); @@ -263,3 +274,27 @@ void gicTriggerSoftInterrupt(u32 softirq) { REG_DIC_SOFTINT = softirq; } + +static void irqEvReset(void) { + memset(&gicIrqPending, 0, sizeof(gicIrqPending)); +} + +static u32 irqEvTest(u32 param, u32 clear) { + u32 index, tstmask, clrmask; + + if (param >= DIC_MAX_IRQ) + bkpt; + index = param / 32; + tstmask = BIT(param % 32); + clrmask = clear ? tstmask : 0; + return !!(atomic_fetch_and(&gicIrqPending[index], ~clrmask) & tstmask); +} + +static const EventInterface evIRQ = { + .reset = irqEvReset, + .test = irqEvTest +}; + +const EventInterface *getEventIRQ(void) { + return &evIRQ; +} diff --git a/arm11/source/hw/gpulcd.c b/arm11/source/hw/gpulcd.c index c134518..e89db05 100644 --- a/arm11/source/hw/gpulcd.c +++ b/arm11/source/hw/gpulcd.c @@ -27,6 +27,8 @@ #include "hw/mcu.h" #include "hw/gpulcd.h" +#include "system/event.h" + static struct { u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen. @@ -112,13 +114,13 @@ unsigned GFX_init(GfxFbFmt mode) TIMER_WaitMS(10); resetLcdsMaybe(); MCU_controlLCDPower(2u); // Power on LCDs. - if(mcuEventWait(0x3Fu<<24) != 2u<<24) __builtin_trap(); + if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 2u<<24) __builtin_trap(); waitLcdsReady(); REG_LCD_ABL0_LIGHT_PWM = 0x1023E; REG_LCD_ABL1_LIGHT_PWM = 0x1023E; MCU_controlLCDPower(0x28u); // Power on backlights. - if(mcuEventWait(0x3Fu<<24) != 0x28u<<24) __builtin_trap(); + if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 0x28u<<24) __builtin_trap(); g_gfxState.lcdPower = 0x15; // All on. // Make sure the fills finished. @@ -212,7 +214,7 @@ void GFX_powerOnBacklights(GfxBlight mask) mask <<= 1; MCU_controlLCDPower(mask); // Power on backlights. - mcuEventWait(0x3F<<24); + eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24); /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24) __builtin_trap();*/ } @@ -222,7 +224,7 @@ void GFX_powerOffBacklights(GfxBlight mask) g_gfxState.lcdPower &= ~mask; MCU_controlLCDPower(mask); // Power off backlights. - mcuEventWait(0x3F<<24); + eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24); /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24) __builtin_trap();*/ } diff --git a/arm11/source/hw/mcu.c b/arm11/source/hw/mcu.c index aa45c6d..33d1446 100755 --- a/arm11/source/hw/mcu.c +++ b/arm11/source/hw/mcu.c @@ -28,6 +28,8 @@ #include "hw/gpulcd.h" #include "hw/mcu.h" +#include "system/event.h" + #define MCUEV_HID_MASK ( \ MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \ MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH) @@ -63,13 +65,14 @@ typedef struct { static u8 volumeSliderValue; static u32 shellState; -static _Atomic(u32) pendingEvents, pendingUpdate; +static _Atomic(u32) pendingEvents; static void mcuEventUpdate(void) { u32 mask; - if (!atomic_exchange(&pendingUpdate, 0)) + // lazily update the mask on each test attempt + if (!getEventIRQ()->test(MCU_INTERRUPT, true)) return; // reading the pending mask automagically acknowledges @@ -91,27 +94,6 @@ static void mcuEventUpdate(void) atomic_fetch_or(&pendingEvents, mask); } -u32 mcuEventTest(u32 mask) -{ - mcuEventUpdate(); - return atomic_load(&pendingEvents) & mask; -} - -u32 mcuEventClear(u32 mask) -{ - mcuEventUpdate(); - return atomic_fetch_and(&pendingEvents, ~mask) & mask; -} - -u32 mcuEventWait(u32 mask) -{ - do { - mcuEventUpdate(); - u32 x = mcuEventClear(mask); - if (x) return x; - } while(1); -} - u8 mcuGetVolumeSlider(void) { mcuEventUpdate(); @@ -120,7 +102,7 @@ u8 mcuGetVolumeSlider(void) u32 mcuGetSpecialHID(void) { - u32 ret, pend = mcuEventClear(MCUEV_HID_MASK); + u32 ret = 0, pend = getEventMCU()->test(MCUEV_HID_MASK, MCUEV_HID_MASK); // hopefully gets unrolled if (pend & (MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD)) @@ -176,17 +158,11 @@ void mcuResetLEDs(void) mcuSetStatusLED(0, 0); } -void mcuInterruptHandler(u32 __attribute__((unused)) irqn) -{ - atomic_store(&pendingUpdate, 1); -} - void mcuReset(void) { u32 intmask = 0; atomic_init(&pendingEvents, 0); - atomic_init(&pendingUpdate, 0); // set register mask and clear any pending registers mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask)); @@ -202,3 +178,22 @@ void mcuReset(void) GPIO_setBit(19, 9); } + +static void evReset(void) { + atomic_store(&pendingEvents, 0); +} + +static u32 evTest(u32 mask, u32 clear) { + mcuEventUpdate(); + return atomic_fetch_and(&pendingEvents, ~clear) & mask; +} + +static const EventInterface evMCU = { + .reset = evReset, + .test = evTest +}; + +const EventInterface *getEventMCU(void) { + return &evMCU; +} + diff --git a/arm11/source/hw/mcu.h b/arm11/source/hw/mcu.h index 707c981..7521ff2 100755 --- a/arm11/source/hw/mcu.h +++ b/arm11/source/hw/mcu.h @@ -37,18 +37,12 @@ enum { MCUEV_HID_VOLUME_SLIDER = BIT(22), }; -u32 mcuEventTest(u32 mask); -u32 mcuEventClear(u32 mask); -u32 mcuEventWait(u32 mask); - u8 mcuGetVolumeSlider(void); u32 mcuGetSpecialHID(void); void mcuSetStatusLED(u32 period_ms, u32 color); void mcuResetLEDs(void); -void mcuInterruptHandler(u32 irqn); - void mcuReset(void); static inline u8 mcuReadReg(u8 addr) diff --git a/arm11/source/main.c b/arm11/source/main.c index 4c7a835..95238ed 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -22,8 +22,6 @@ #include #include -#include - #include "arm/gic.h" #include "hw/hid.h" @@ -33,6 +31,7 @@ #include "hw/nvram.h" #include "system/sys.h" +#include "system/event.h" static const u8 brightness_lvls[] = { 0x10, 0x17, 0x1E, 0x25, @@ -48,16 +47,9 @@ static bool auto_brightness; static SystemSHMEM __attribute__((section(".shared"))) sharedMem; -static _Atomic(u32) pendingVblank, pendingPxiRx; - -static void vblankHandler(u32 __attribute__((unused)) irqn) -{ - atomic_store(&pendingVblank, 1); -} - static void vblankUpdate(void) { - if (!atomic_exchange(&pendingVblank, 0)) + if (!getEventIRQ()->test(VBLANK_INTERRUPT, true)) return; #ifndef FIXED_BRIGHTNESS @@ -70,7 +62,8 @@ static void vblankUpdate(void) #endif // handle shell events - u32 shell = mcuEventClear(MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE); + static const u32 mcuEvShell = MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE; + u32 shell = getEventMCU()->test(mcuEvShell, mcuEvShell); if (shell & MCUEV_HID_SHELL_CLOSE) { GFX_powerOffBacklights(GFX_BLIGHT_BOTH); } else if (shell & MCUEV_HID_SHELL_OPEN) { @@ -80,16 +73,11 @@ static void vblankUpdate(void) sharedMem.hidState.full = HID_GetState(); } -static void pxiRxHandler(u32 __attribute__((unused)) irqn) -{ - atomic_store(&pendingPxiRx, 1); -} - static u32 pxiRxUpdate(u32 *args) { u32 msg, lo, hi; - if (!atomic_exchange(&pendingPxiRx, 0)) + if (!getEventIRQ()->test(PXI_RX_INTERRUPT, true)) return PXICMD_NONE; msg = PXI_Recv(); @@ -113,14 +101,14 @@ void __attribute__((noreturn)) MainLoop(void) #endif // initialize state stuff - atomic_init(&pendingVblank, 0); - atomic_init(&pendingPxiRx, 0); + getEventIRQ()->reset(); + getEventMCU()->reset(); memset(&sharedMem, 0, sizeof(sharedMem)); // configure interrupts - gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, pxiRxHandler); - gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, mcuInterruptHandler); - gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, vblankHandler); + gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, NULL); + gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, NULL); + gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, NULL); // enable interrupts gicEnableInterrupt(MCU_INTERRUPT); diff --git a/arm11/source/system/event.h b/arm11/source/system/event.h new file mode 100644 index 0000000..012d047 --- /dev/null +++ b/arm11/source/system/event.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +typedef struct { + void (*reset)(void); + u32 (*test)(u32 param, u32 clear); +} EventInterface; + +const EventInterface *getEventIRQ(void); +const EventInterface *getEventMCU(void); + +static inline void eventReset(const EventInterface *ei) { + ei->reset(); +} + +static inline u32 eventTest(const EventInterface *ei, u32 param, u32 clear) { + return ei->test(param, clear); +} + +static inline u32 eventWait(const EventInterface *ei, u32 param, u32 clear) { + while(1) { + u32 ret = ei->test(param, clear); + if (ret) return ret; + } +} diff --git a/common/common.h b/common/common.h index cf23116..ff1f1b3 100755 --- a/common/common.h +++ b/common/common.h @@ -53,7 +53,7 @@ (sizeof(x) / sizeof(*(x))) #define bkpt \ - __builtin_trap() + do{__builtin_trap(); __builtin_unreachable();}while(0) #define assert(x) \ (!!(x) ? (void)0 : __builtin_trap())