Compare commits

...

5 Commits

Author SHA1 Message Date
Wolfvak
7d2e729ac6 Merge remote-tracking branch 'origin/master' into mcuev 2020-11-18 22:12:56 -03:00
Wolfvak
670ff3345c event model seems to work
refactors all the ugly "pendingX" atomic operations into a single "Event" subsystem/interface thing with two operations

moves all existing code to use this instead

also changes the "bkpt" macro to also indicate unreachable code
2020-11-18 17:06:45 -03:00
Wolfvak
6b5ddf94d8 simplify the sharedmem buffers
also made the wait on boot unconditional
2020-11-18 17:06:30 -03:00
Wolfvak
e4dd8511cd make interrupt handlers more lazy, most processing is done in interruptible context now
- completely moved MCU interrupt handling outside of the critical section
- refactored a bit of the PXI code and command names
- merge the I2C read and write cmds to be one
- remove SET_VMODE cmd, now it's always initialized to BGR565 on boot and to RGB565 on firmlaunch
- atomic-ize more stuff
2020-08-25 10:49:52 -03:00
Wolfvak
b4fccd4a3c initial mcu events implementation
- backlight power control is reinstated but currently buggy, for some reason the __builtin_trap is tripped on GFX_powerOnBacklights and GFX_powerOffBacklights

- also refactored a bunch of other code pertaining to mcu and other hw init, moved the gpu init to a later point since lcd init now depends on mcu events
2020-08-21 23:36:00 -03:00
18 changed files with 387 additions and 315 deletions

View File

@ -19,8 +19,12 @@
#include <common.h>
#include <arm.h>
#include <stdatomic.h>
#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;
}

View File

@ -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(MCU_waitEvents(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(MCU_waitEvents(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,8 +214,9 @@ void GFX_powerOnBacklights(GfxBlight mask)
mask <<= 1;
MCU_controlLCDPower(mask); // Power on backlights.
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();
eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/
}
void GFX_powerOffBacklights(GfxBlight mask)
@ -221,8 +224,9 @@ void GFX_powerOffBacklights(GfxBlight mask)
g_gfxState.lcdPower &= ~mask;
MCU_controlLCDPower(mask); // Power off backlights.
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();
eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/
}
u8 GFX_getBrightness(void)

View File

@ -52,7 +52,7 @@ u64 HID_GetState(void)
CODEC_Get(&codec);
ret = REG_HID | MCU_GetSpecialHID();
ret = REG_HID | mcuGetSpecialHID();
if (!(ret & BUTTON_ARROW))
ret |= HID_ConvertCPAD(codec.cpad_x, codec.cpad_y);

View File

@ -20,40 +20,37 @@
#include <types.h>
#include <arm.h>
#include <stdatomic.h>
#include "arm/timer.h"
#include "hw/gpio.h"
#include "hw/gpulcd.h"
#include "hw/mcu.h"
enum {
MCU_PWR_BTN = 0,
MCU_PWR_HOLD = 1,
MCU_HOME_BTN = 2,
MCU_HOME_LIFT = 3,
MCU_WIFI_SWITCH = 4,
MCU_SHELL_CLOSE = 5,
MCU_SHELL_OPEN = 6,
MCU_VOL_SLIDER = 22,
};
#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)
enum {
REG_VOL_SLIDER = 0x09,
MCUREG_VOLUME_SLIDER = 0x09,
REG_BATTERY_LEVEL = 0x0B,
REG_CONSOLE_STATE = 0x0F,
MCUREG_BATTERY_LEVEL = 0x0B,
MCUREG_CONSOLE_STATE = 0x0F,
REG_INT_MASK = 0x10,
REG_INT_EN = 0x18,
MCUREG_INT_MASK = 0x10,
MCUREG_INT_EN = 0x18,
REG_LCD_STATE = 0x22,
MCUREG_LCD_STATE = 0x22,
REG_LED_WIFI = 0x2A,
REG_LED_CAMERA = 0x2B,
REG_LED_SLIDER = 0x2C,
REG_LED_NOTIF = 0x2D,
MCUREG_LED_WIFI = 0x2A,
MCUREG_LED_CAMERA = 0x2B,
MCUREG_LED_SLIDER = 0x2C,
MCUREG_LED_STATUS = 0x2D,
REG_RTC = 0x30,
MCUREG_RTC = 0x30,
};
typedef struct {
@ -64,47 +61,73 @@ typedef struct {
u32 red[8];
u32 green[8];
u32 blue[8];
} PACKED_STRUCT MCU_NotificationLED;
} PACKED_STRUCT mcuStatusLED;
static u8 cached_volume_slider = 0;
static u32 spec_hid = 0, shell_state = 0;
static u8 volumeSliderValue;
static u32 shellState;
static _Atomic(u32) pendingEvents;
static void MCU_UpdateVolumeSlider(void)
static void mcuEventUpdate(void)
{
cached_volume_slider = MCU_ReadReg(REG_VOL_SLIDER);
u32 mask;
// lazily update the mask on each test attempt
if (!getEventIRQ()->test(MCU_INTERRUPT, true))
return;
// reading the pending mask automagically acknowledges
// the interrupts so all of them must be processed in one go
mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&mask, sizeof(mask));
if (mask & MCUEV_HID_VOLUME_SLIDER)
volumeSliderValue = mcuReadReg(MCUREG_VOLUME_SLIDER);
if (mask & MCUEV_HID_SHELL_OPEN) {
mcuResetLEDs();
shellState = SHELL_OPEN;
}
if (mask & MCUEV_HID_SHELL_CLOSE) {
shellState = SHELL_CLOSED;
}
atomic_fetch_or(&pendingEvents, mask);
}
static void MCU_UpdateShellState(bool open)
u8 mcuGetVolumeSlider(void)
{
shell_state = open ? SHELL_OPEN : SHELL_CLOSED;
mcuEventUpdate();
return volumeSliderValue;
}
u8 MCU_GetVolumeSlider(void)
u32 mcuGetSpecialHID(void)
{
return cached_volume_slider;
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))
ret |= BUTTON_POWER;
if (pend & MCUEV_HID_HOME_DOWN)
ret |= BUTTON_HOME;
if (pend & MCUEV_HID_HOME_UP)
ret &= ~BUTTON_HOME;
return ret | shellState;
}
u32 MCU_GetSpecialHID(void)
{
u32 ret = spec_hid | shell_state;
spec_hid = 0;
return ret;
}
void MCU_SetNotificationLED(u32 period_ms, u32 color)
void mcuSetStatusLED(u32 period_ms, u32 color)
{
u32 r, g, b;
MCU_NotificationLED led_state;
mcuStatusLED ledState;
// handle proper non-zero periods
// so small the hardware can't handle it
if (period_ms != 0 && period_ms < 63)
period_ms = 63;
led_state.delay = (period_ms * 0x10) / 1000;
led_state.smoothing = 0x40;
led_state.loop_delay = 0x10;
led_state.unk = 0;
ledState.delay = (period_ms * 0x10) / 1000;
ledState.smoothing = 0x40;
ledState.loop_delay = 0x10;
ledState.unk = 0;
// all colors look like 0x00ZZ00ZZ
// in order to alternate between
@ -112,93 +135,65 @@ void MCU_SetNotificationLED(u32 period_ms, u32 color)
r = (color >> 16) & 0xFF;
r |= r << 16;
for (int i = 0; i < 8; i++)
led_state.red[i] = r;
ledState.red[i] = r;
g = (color >> 8) & 0xFF;
g |= g << 16;
for (int i = 0; i < 8; i++)
led_state.green[i] = g;
ledState.green[i] = g;
b = color & 0xFF;
b |= b << 16;
for (int i = 0; i < 8; i++)
led_state.blue[i] = b;
ledState.blue[i] = b;
MCU_WriteRegBuf(REG_LED_NOTIF, (const u8*)&led_state, sizeof(led_state));
mcuWriteRegBuf(MCUREG_LED_STATUS, (const u8*)&ledState, sizeof(ledState));
}
void MCU_ResetLED(void)
void mcuResetLEDs(void)
{
MCU_WriteReg(REG_LED_WIFI, 0);
MCU_WriteReg(REG_LED_CAMERA, 0);
MCU_WriteReg(REG_LED_SLIDER, 0);
MCU_SetNotificationLED(0, 0);
mcuWriteReg(MCUREG_LED_WIFI, 0);
mcuWriteReg(MCUREG_LED_CAMERA, 0);
mcuWriteReg(MCUREG_LED_SLIDER, 0);
mcuSetStatusLED(0, 0);
}
void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn)
void mcuReset(void)
{
u32 ints;
u32 intmask = 0;
// Reading the pending mask automagically acknowledges
// the interrupts so all of them must be processed in one go
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&ints, sizeof(ints));
atomic_init(&pendingEvents, 0);
while(ints != 0) {
u32 mcu_int_id = 31 - __builtin_clz(ints);
// set register mask and clear any pending registers
mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask));
mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&intmask, sizeof(intmask));
switch(mcu_int_id) {
case MCU_PWR_BTN:
case MCU_PWR_HOLD:
spec_hid |= BUTTON_POWER;
break;
mcuResetLEDs();
case MCU_HOME_BTN:
spec_hid |= BUTTON_HOME;
break;
case MCU_HOME_LIFT:
spec_hid &= ~BUTTON_HOME;
break;
case MCU_WIFI_SWITCH:
spec_hid |= BUTTON_WIFI;
break;
case MCU_SHELL_OPEN:
MCU_UpdateShellState(true);
MCU_ResetLED();
break;
case MCU_SHELL_CLOSE:
MCU_UpdateShellState(false);
break;
case MCU_VOL_SLIDER:
MCU_UpdateVolumeSlider();
break;
default:
break;
}
ints &= ~BIT(mcu_int_id);
}
}
void MCU_Init(void)
{
u32 clrpend, mask = 0;
shell_state = SHELL_OPEN;
/* set register mask and clear any pending registers */
MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask));
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&clrpend, sizeof(clrpend));
MCU_ResetLED();
MCU_UpdateVolumeSlider();
MCU_UpdateShellState(MCU_ReadReg(REG_CONSOLE_STATE) & BIT(1));
volumeSliderValue = mcuReadReg(MCUREG_VOLUME_SLIDER);
shellState = SHELL_OPEN;
// assume the shell is always open on boot
// knowing the average 3DS user, there will be plenty
// of laughs when this comes back to bite us in the rear
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;
}

View File

@ -26,51 +26,48 @@
#define MCU_INTERRUPT (0x71)
#define I2C_MCU_DEVICE (3)
u8 MCU_GetVolumeSlider(void);
u32 MCU_GetSpecialHID(void);
enum {
MCUEV_HID_PWR_DOWN = BIT(0),
MCUEV_HID_PWR_HOLD = BIT(1),
MCUEV_HID_HOME_DOWN = BIT(2),
MCUEV_HID_HOME_UP = BIT(3),
MCUEV_HID_WIFI_SWITCH = BIT(4),
MCUEV_HID_SHELL_CLOSE = BIT(5),
MCUEV_HID_SHELL_OPEN = BIT(6),
MCUEV_HID_VOLUME_SLIDER = BIT(22),
};
void MCU_SetNotificationLED(u32 period_ms, u32 color);
void MCU_ResetLED(void);
u8 mcuGetVolumeSlider(void);
u32 mcuGetSpecialHID(void);
void MCU_HandleInterrupts(u32 irqn);
void mcuSetStatusLED(u32 period_ms, u32 color);
void mcuResetLEDs(void);
void MCU_Init(void);
void mcuReset(void);
static inline u8 MCU_ReadReg(u8 addr)
static inline u8 mcuReadReg(u8 addr)
{
u8 val;
I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1);
return val;
}
static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u32 size)
static inline bool mcuReadRegBuf(u8 addr, u8 *buf, u32 size)
{
return I2C_readRegBuf(I2C_MCU_DEVICE, addr, buf, size);
}
static inline bool MCU_WriteReg(u8 addr, u8 val)
static inline bool mcuWriteReg(u8 addr, u8 val)
{
return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, &val, 1);
}
static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u32 size)
static inline bool mcuWriteRegBuf(u8 addr, const u8 *buf, u32 size)
{
return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size);
}
static inline u32 MCU_waitEvents(u32 mask) {
u32 v;
while(1) {
TIMER_WaitMS(10);
MCU_ReadRegBuf(0x10, (u8*)&v, 4);
v &= mask;
if (v)
break;
}
return v;
}
static inline void MCU_controlLCDPower(u8 bits)
{
MCU_WriteReg(0x22u, bits);
mcuWriteReg(0x22u, bits);
}

View File

@ -31,6 +31,7 @@
#include "hw/nvram.h"
#include "system/sys.h"
#include "system/event.h"
static const u8 brLvlTbl[] = {
0x10, 0x17, 0x1E, 0x25,
@ -44,12 +45,15 @@ static int oldBrLvl;
static bool autoBr;
#endif
static SystemSHMEM __attribute__((section(".shared"))) SharedMemoryState;
static SystemSHMEM __attribute__((section(".shared"))) sharedMem;
void VBlank_Handler(u32 __attribute__((unused)) irqn)
static void vblankUpdate(void)
{
if (!getEventIRQ()->test(VBLANK_INTERRUPT, true))
return;
#ifndef FIXED_BRIGHTNESS
int newBrLvl = (MCU_GetVolumeSlider() >> 2) % countof(brLvlTbl);
int newBrLvl = (mcuGetVolumeSlider() >> 2) % countof(brLvlTbl);
if ((newBrLvl != oldBrLvl) && autoBr) {
oldBrLvl = newBrLvl;
u8 br = brLvlTbl[newBrLvl];
@ -57,128 +61,37 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn)
}
#endif
SharedMemoryState.hidState.full = HID_GetState();
// handle shell events
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) {
GFX_powerOnBacklights(GFX_BLIGHT_BOTH);
}
sharedMem.hidState.full = HID_GetState();
}
static bool legacy_boot = false;
void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
static u32 pxiRxUpdate(u32 *args)
{
u32 ret, msg, cmd, argc, args[PXI_MAX_ARGS];
u32 msg, lo, hi;
if (!getEventIRQ()->test(PXI_RX_INTERRUPT, true))
return PXICMD_NONE;
msg = PXI_Recv();
cmd = msg & 0xFFFF;
argc = msg >> 16;
lo = msg & 0xFFFF;
hi = msg >> 16;
if (argc >= PXI_MAX_ARGS) {
PXI_Send(0xFFFFFFFF);
return;
}
PXI_RecvArray(args, argc);
switch (cmd) {
case PXI_LEGACY_MODE:
{
// TODO: If SMP is enabled, an IPI should be sent here (with a DSB)
legacy_boot = true;
ret = 0;
break;
}
case PXI_GET_SHMEM:
{
ret = (u32)&SharedMemoryState;
break;
}
case PXI_SET_VMODE:
{
GFX_init(args[0] ? GFX_BGR8 : GFX_RGB565);
ret = 0;
break;
}
case PXI_I2C_READ:
{
u32 devId, regAddr, size;
devId = (args[0] & 0xff);
regAddr = (args[0] >> 8) & 0xff;
size = (args[0] >> 16) % I2C_SHARED_BUFSZ;
ret = I2C_readRegBuf(devId, regAddr, SharedMemoryState.i2cBuffer, size);
break;
}
case PXI_I2C_WRITE:
{
u32 devId, regAddr, size;
devId = (args[0] & 0xff);
regAddr = (args[0] >> 8) & 0xff;
size = (args[0] >> 16) % I2C_SHARED_BUFSZ;
ret = I2C_writeRegBuf(devId, regAddr, SharedMemoryState.i2cBuffer, size);
break;
}
case PXI_NVRAM_ONLINE:
{
ret = (NVRAM_Status() & NVRAM_SR_WIP) == 0;
break;
}
case PXI_NVRAM_READ:
{
NVRAM_Read(args[0], (u32*)SharedMemoryState.spiBuffer, args[1]);
ret = 0;
break;
}
case PXI_NOTIFY_LED:
{
MCU_SetNotificationLED(args[0], args[1]);
ret = 0;
break;
}
case PXI_BRIGHTNESS:
{
ret = GFX_getBrightness();
#ifndef FIXED_BRIGHTNESS
s32 newbrightness = (s32)args[0];
if ((newbrightness > 0) && (newbrightness < 0x100)) {
GFX_setBrightness(newbrightness, newbrightness);
autoBr = false;
} else {
oldBrLvl = -1;
autoBr = true;
}
#endif
break;
}
/* New CMD template:
case CMD_ID:
{
<var declarations/assignments>
<execute the command>
<set the return value>
break;
}
*/
default:
ret = 0xFFFFFFFF;
break;
}
PXI_Send(ret);
PXI_RecvArray(args, hi);
return lo;
}
void __attribute__((noreturn)) MainLoop(void)
{
bool runPxiCmdProcessor = true;
#ifdef FIXED_BRIGHTNESS
u8 fixBrLvl = brLvlTbl[clamp(FIXED_BRIGHTNESS, 0, countof(brLvlTbl)-1)];
GFX_setBrightness(fixBrLvl, fixBrLvl);
@ -187,23 +100,126 @@ void __attribute__((noreturn)) MainLoop(void)
autoBr = true;
#endif
// initialize state stuff
getEventIRQ()->reset();
getEventMCU()->reset();
memset(&sharedMem, 0, sizeof(sharedMem));
// configure interrupts
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO2, PXI_RX_Handler);
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO1, MCU_HandleInterrupts);
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, VBlank_Handler);
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(PXI_RX_INTERRUPT);
gicEnableInterrupt(MCU_INTERRUPT);
// perform gpu init after initializing mcu but before
// enabling the pxi system and the vblank handler
GFX_init(GFX_RGB565);
gicEnableInterrupt(PXI_RX_INTERRUPT);
gicEnableInterrupt(VBLANK_INTERRUPT);
// ARM9 won't try anything funny until this point
PXI_Barrier(PXI_BOOT_BARRIER);
// Process IRQs until the ARM9 tells us it's time to boot something else
// Process commands until the ARM9 tells
// us it's time to boot something else
// also handles VBlank events as needed
do {
ARM_WFI();
} while(!legacy_boot);
u32 pxiCmd, pxiReply, args[PXI_MAX_ARGS];
vblankUpdate();
pxiCmd = pxiRxUpdate(args);
switch(pxiCmd) {
// ignore args and just wait until the next event
case PXICMD_NONE:
ARM_WFI();
break;
// revert to legacy boot mode
case PXICMD_LEGACY_BOOT:
runPxiCmdProcessor = false;
pxiReply = 0;
break;
// returns the shared memory address
case PXICMD_GET_SHMEM_ADDRESS:
pxiReply = (u32)&sharedMem;
break;
// takes in a single argument word and performs either an
// I2C read or write depending on the value of the top bit
case PXICMD_I2C_OP:
{
u32 devId, regAddr, size;
devId = (args[0] & 0xff);
regAddr = (args[0] >> 8) & 0xFF;
size = (args[0] >> 16) % SHMEM_BUFFER_SIZE;
if (args[0] & BIT(31)) {
pxiReply = I2C_writeRegBuf(devId, regAddr, sharedMem.dataBuffer.b, size);
} else {
pxiReply = I2C_readRegBuf(devId, regAddr, sharedMem.dataBuffer.b, size);
}
break;
}
// checks whether the NVRAM chip is online (not doing any work)
case PXICMD_NVRAM_ONLINE:
pxiReply = (NVRAM_Status() & NVRAM_SR_WIP) == 0;
break;
// reads data from the NVRAM chip
case PXICMD_NVRAM_READ:
NVRAM_Read(args[0], sharedMem.dataBuffer.w, args[1]);
pxiReply = 0;
break;
// sets the notification LED with the given color and period
case PXICMD_SET_NOTIFY_LED:
mcuSetStatusLED(args[0], args[1]);
pxiReply = 0;
break;
// sets the LCDs brightness (if FIXED_BRIGHTNESS is disabled)
case PXICMD_SET_BRIGHTNESS:
{
s32 newbrightness = (s32)args[0];
pxiReply = GFX_getBrightness();
#ifndef FIXED_BRIGHTNESS
if ((newbrightness > 0) && (newbrightness < 0x100)) {
GFX_setBrightness(newbrightness, newbrightness);
autoBr = false;
} else {
oldBrLvl = -1;
autoBr = true;
}
#endif
break;
}
// replies -1 on default
default:
pxiReply = 0xFFFFFFFF;
break;
}
if (pxiCmd != PXICMD_NONE)
PXI_Send(pxiReply); // was a command sent from the ARM9, send a response
} while(runPxiCmdProcessor);
// perform deinit in reverse order
gicDisableInterrupt(VBLANK_INTERRUPT);
gicDisableInterrupt(PXI_RX_INTERRUPT);
// unconditionally reinitialize the screens
// in RGB24 framebuffer mode
GFX_init(GFX_BGR8);
gicDisableInterrupt(MCU_INTERRUPT);
// Wait for the ARM9 to do its firmlaunch setup
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);

View File

@ -0,0 +1,26 @@
#pragma once
#include <types.h>
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;
}
}

View File

@ -107,20 +107,17 @@ void SYS_CoreZeroInit(void)
mmuMapArea(0x20000000, 0x20000000, 128UL << 20, MMU_FLAGS(MMU_CACHE_WB, MMU_READ_WRITE, 1, 1));
}
if (SYS_IsNewConsole()) {
TIMER_WaitMS(150);
}
// screen init magicks
TIMER_WaitMS(64);
// Initialize peripherals
PXI_Reset();
I2C_init();
MCU_Init();
mcuReset();
SPI_Init();
CODEC_Init();
GFX_init(GFX_RGB565);
}
void SYS_CoreInit(void)

View File

@ -19,7 +19,7 @@ static void SetNotificationLED(u32 period_ms, u32 rgb565_color)
(rgb565_color >> 5) << (8+2) |
(rgb565_color << 3));
u32 args[] = {period_ms, rgb888_color};
PXI_DoCMD(PXI_NOTIFY_LED, args, 2);
PXI_DoCMD(PXICMD_SET_NOTIFY_LED, args, 2);
}
// there's some weird thing going on when reading this

View File

@ -12,7 +12,7 @@ u32 SetScreenBrightness(int level) {
arg = 0;
}
return PXI_DoCMD(PXI_BRIGHTNESS, &arg, 1);
return PXI_DoCMD(PXICMD_SET_BRIGHTNESS, &arg, 1);
}
u32 GetBatteryPercent() {

View File

@ -108,8 +108,7 @@ u32 BootFirmHandler(const char* bootpath, bool verbose, bool delete) {
if (delete) PathDelete(bootpath);
DeinitExtFS();
DeinitSDCardFS();
PXI_DoCMD(PXI_SET_VMODE, (u32[]){1}, 1);
PXI_DoCMD(PXI_LEGACY_MODE, NULL, 0);
PXI_DoCMD(PXICMD_LEGACY_BOOT, NULL, 0);
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
BootFirm((FirmHeader*) firm, fixpath);
while(1);

View File

@ -7,7 +7,7 @@
#include "hid.h"
SystemSHMEM *shmemGlobalBase;
SystemSHMEM *shmemBasePtr;
void main(int argc, char** argv, int entrypoint)
{

View File

@ -8,32 +8,33 @@
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
{
int ret;
u8 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.b;
const u32 arg = devId | (regAddr << 8) | (size << 16);
if (size >= I2C_SHARED_BUFSZ)
if (size >= SHMEM_BUFFER_SIZE)
return false;
ret = PXI_DoCMD(PXI_I2C_READ, &arg, 1);
ret = PXI_DoCMD(PXICMD_I2C_OP, &arg, 1);
ARM_InvDC_Range(dataBuffer, size);
ARM_InvDC_Range(ARM_GetSHMEM()->i2cBuffer, size);
memcpy(out, ARM_GetSHMEM()->i2cBuffer, size);
memcpy(out, dataBuffer, size);
return ret;
}
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
{
int ret;
const u32 arg = devId | (regAddr << 8) | (size << 16);
u8 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.b;
const u32 arg = devId | (regAddr << 8) | (size << 16) | BIT(31);
if (size >= I2C_SHARED_BUFSZ)
if (size >= SHMEM_BUFFER_SIZE)
return false;
ARM_InvDC_Range(ARM_GetSHMEM()->i2cBuffer, size);
memcpy(ARM_GetSHMEM()->i2cBuffer, in, size);
ARM_WbDC_Range(ARM_GetSHMEM()->i2cBuffer, size);
memcpy(dataBuffer, in, size);
ARM_WbDC_Range(dataBuffer, size);
ARM_DSB();
ret = PXI_DoCMD(PXI_I2C_WRITE, &arg, 1);
ret = PXI_DoCMD(PXICMD_I2C_OP, &arg, 1);
return ret;
}

View File

@ -5,24 +5,25 @@
bool spiflash_get_status(void)
{
return PXI_DoCMD(PXI_NVRAM_ONLINE, NULL, 0);
return PXI_DoCMD(PXICMD_NVRAM_ONLINE, NULL, 0);
}
bool spiflash_read(u32 offset, u32 size, u8 *buf)
{
u32 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.w;
u32 args[2];
while(size > 0) {
u32 blksz = min(size, SPI_SHARED_BUFSZ);
u32 blksz = min(size, SHMEM_BUFFER_SIZE);
args[0] = offset;
args[1] = blksz;
ARM_WbDC_Range(ARM_GetSHMEM()->spiBuffer, blksz);
PXI_DoCMD(PXI_NVRAM_READ, args, 2);
ARM_InvDC_Range(ARM_GetSHMEM()->spiBuffer, blksz);
PXI_DoCMD(PXICMD_NVRAM_READ, args, 2);
ARM_InvDC_Range(dataBuffer, blksz);
ARM_DSB();
memcpy(buf, ARM_GetSHMEM()->spiBuffer, blksz);
memcpy(buf, dataBuffer, blksz);
buf += blksz;
size -= blksz;

View File

@ -1426,8 +1426,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
fixpath[255] = '\0';
DeinitExtFS();
DeinitSDCardFS();
PXI_DoCMD(PXI_SET_VMODE, (u32[]){1}, 1);
PXI_DoCMD(PXI_LEGACY_MODE, NULL, 0);
PXI_DoCMD(PXICMD_LEGACY_BOOT, NULL, 0);
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
BootFirm((FirmHeader*)(void*)firm, fixpath);
while(1);

View File

@ -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())

View File

@ -28,18 +28,17 @@
#endif
enum {
PXI_LEGACY_MODE = 0,
PXI_GET_SHMEM,
PXI_SET_VMODE,
PXICMD_LEGACY_BOOT = 0,
PXICMD_GET_SHMEM_ADDRESS,
PXI_I2C_READ,
PXI_I2C_WRITE,
PXICMD_I2C_OP,
PXICMD_NVRAM_ONLINE,
PXICMD_NVRAM_READ,
PXI_NVRAM_ONLINE,
PXI_NVRAM_READ,
PXICMD_SET_NOTIFY_LED,
PXICMD_SET_BRIGHTNESS,
PXI_NOTIFY_LED,
PXI_BRIGHTNESS
PXICMD_NONE,
};
/*

View File

@ -20,8 +20,7 @@
#include <arm.h>
#define I2C_SHARED_BUFSZ 1024
#define SPI_SHARED_BUFSZ 1024
#define SHMEM_BUFFER_SIZE 2048
typedef struct {
union {
@ -29,14 +28,18 @@ typedef struct {
u64 full;
} hidState;
u8 i2cBuffer[I2C_SHARED_BUFSZ];
u32 spiBuffer[SPI_SHARED_BUFSZ/4];
union {
uint8_t b[SHMEM_BUFFER_SIZE];
uint16_t s[SHMEM_BUFFER_SIZE / 2];
uint32_t w[SHMEM_BUFFER_SIZE / 4];
uint64_t q[SHMEM_BUFFER_SIZE / 8];
} dataBuffer;
} __attribute__((packed, aligned(8))) SystemSHMEM;
#ifdef ARM9
#include <pxi.h>
extern SystemSHMEM *shmemGlobalBase;
extern SystemSHMEM *shmemBasePtr;
static inline SystemSHMEM *ARM_GetSHMEM(void)
{
@ -44,11 +47,11 @@ static inline SystemSHMEM *ARM_GetSHMEM(void)
// insert a compiler barrier to force the compiler not to assume
// memory values will remain constant in between calls to getSHMEM
asm_v("":::"memory", "cc");
return shmemGlobalBase;
return shmemBasePtr;
}
static inline void ARM_InitSHMEM(void)
{
shmemGlobalBase = (SystemSHMEM*)PXI_DoCMD(PXI_GET_SHMEM, NULL, 0);
shmemBasePtr = (SystemSHMEM*)PXI_DoCMD(PXICMD_GET_SHMEM_ADDRESS, NULL, 0);
}
#endif