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
This commit is contained in:
Wolfvak 2020-08-21 23:36:00 -03:00
parent 03007c2b42
commit b4fccd4a3c
6 changed files with 159 additions and 140 deletions

View File

@ -112,13 +112,13 @@ unsigned GFX_init(GfxFbFmt mode)
TIMER_WaitMS(10); TIMER_WaitMS(10);
resetLcdsMaybe(); resetLcdsMaybe();
MCU_controlLCDPower(2u); // Power on LCDs. MCU_controlLCDPower(2u); // Power on LCDs.
if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) __builtin_trap(); if(mcuEventWait(0x3Fu<<24) != 2u<<24) __builtin_trap();
waitLcdsReady(); waitLcdsReady();
REG_LCD_ABL0_LIGHT_PWM = 0x1023E; REG_LCD_ABL0_LIGHT_PWM = 0x1023E;
REG_LCD_ABL1_LIGHT_PWM = 0x1023E; REG_LCD_ABL1_LIGHT_PWM = 0x1023E;
MCU_controlLCDPower(0x28u); // Power on backlights. MCU_controlLCDPower(0x28u); // Power on backlights.
if(MCU_waitEvents(0x3Fu<<24) != 0x28u<<24) __builtin_trap(); if(mcuEventWait(0x3Fu<<24) != 0x28u<<24) __builtin_trap();
g_gfxState.lcdPower = 0x15; // All on. g_gfxState.lcdPower = 0x15; // All on.
// Make sure the fills finished. // Make sure the fills finished.
@ -212,8 +212,9 @@ void GFX_powerOnBacklights(GfxBlight mask)
mask <<= 1; mask <<= 1;
MCU_controlLCDPower(mask); // Power on backlights. MCU_controlLCDPower(mask); // Power on backlights.
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) mcuEventWait(0x3F<<24);
__builtin_trap(); /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/
} }
void GFX_powerOffBacklights(GfxBlight mask) void GFX_powerOffBacklights(GfxBlight mask)
@ -221,8 +222,9 @@ void GFX_powerOffBacklights(GfxBlight mask)
g_gfxState.lcdPower &= ~mask; g_gfxState.lcdPower &= ~mask;
MCU_controlLCDPower(mask); // Power off backlights. MCU_controlLCDPower(mask); // Power off backlights.
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) mcuEventWait(0x3F<<24);
__builtin_trap(); /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/
} }
u8 GFX_getBrightness(void) u8 GFX_getBrightness(void)

View File

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

View File

@ -20,40 +20,35 @@
#include <types.h> #include <types.h>
#include <arm.h> #include <arm.h>
#include <stdatomic.h>
#include "arm/timer.h" #include "arm/timer.h"
#include "hw/gpio.h" #include "hw/gpio.h"
#include "hw/gpulcd.h" #include "hw/gpulcd.h"
#include "hw/mcu.h" #include "hw/mcu.h"
enum { #define MCUEV_HID_MASK ( \
MCU_PWR_BTN = 0, MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \
MCU_PWR_HOLD = 1, MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH)
MCU_HOME_BTN = 2,
MCU_HOME_LIFT = 3,
MCU_WIFI_SWITCH = 4,
MCU_SHELL_CLOSE = 5,
MCU_SHELL_OPEN = 6,
MCU_VOL_SLIDER = 22,
};
enum { enum {
REG_VOL_SLIDER = 0x09, MCUREG_VOLUME_SLIDER = 0x09,
REG_BATTERY_LEVEL = 0x0B, MCUREG_BATTERY_LEVEL = 0x0B,
REG_CONSOLE_STATE = 0x0F, MCUREG_CONSOLE_STATE = 0x0F,
REG_INT_MASK = 0x10, MCUREG_INT_MASK = 0x10,
REG_INT_EN = 0x18, MCUREG_INT_EN = 0x18,
REG_LCD_STATE = 0x22, MCUREG_LCD_STATE = 0x22,
REG_LED_WIFI = 0x2A, MCUREG_LED_WIFI = 0x2A,
REG_LED_CAMERA = 0x2B, MCUREG_LED_CAMERA = 0x2B,
REG_LED_SLIDER = 0x2C, MCUREG_LED_SLIDER = 0x2C,
REG_LED_NOTIF = 0x2D, MCUREG_LED_STATUS = 0x2D,
REG_RTC = 0x30, MCUREG_RTC = 0x30,
}; };
typedef struct { typedef struct {
@ -64,47 +59,77 @@ typedef struct {
u32 red[8]; u32 red[8];
u32 green[8]; u32 green[8];
u32 blue[8]; u32 blue[8];
} PACKED_STRUCT MCU_NotificationLED; } PACKED_STRUCT mcuStatusLED;
static u8 cached_volume_slider = 0; static u8 volumeSliderValue;
static u32 spec_hid = 0, shell_state = 0; static u32 shellState;
static _Atomic(u32) pendingEvents;
static void MCU_UpdateVolumeSlider(void) static void mcuUpdateVolumeSlider(void)
{ {
cached_volume_slider = MCU_ReadReg(REG_VOL_SLIDER); volumeSliderValue = mcuReadReg(MCUREG_VOLUME_SLIDER);
} }
static void MCU_UpdateShellState(bool open) static void mcuUpdateShellState(bool open)
{ {
shell_state = open ? SHELL_OPEN : SHELL_CLOSED; shellState = open ? SHELL_OPEN : SHELL_CLOSED;
} }
u8 MCU_GetVolumeSlider(void) u32 mcuEventTest(u32 mask)
{ {
return cached_volume_slider; return atomic_load(&pendingEvents) & mask;
} }
u32 MCU_GetSpecialHID(void) u32 mcuEventClear(u32 mask)
{ {
u32 ret = spec_hid | shell_state; return atomic_fetch_and(&pendingEvents, ~mask) & mask;
spec_hid = 0; }
u32 mcuEventWait(u32 mask)
{
do {
u32 x = mcuEventClear(mask);
if (x) return x;
ARM_WFE();
} while(1);
}
u8 mcuGetVolumeSlider(void)
{
return volumeSliderValue;
}
u32 mcuGetSpecialHID(void)
{
u32 ret = shellState, pend = mcuEventClear(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; return ret;
} }
void MCU_SetNotificationLED(u32 period_ms, u32 color) void mcuSetStatusLED(u32 period_ms, u32 color)
{ {
u32 r, g, b; u32 r, g, b;
MCU_NotificationLED led_state; mcuStatusLED ledState;
// handle proper non-zero periods // handle proper non-zero periods
// so small the hardware can't handle it // so small the hardware can't handle it
if (period_ms != 0 && period_ms < 63) if (period_ms != 0 && period_ms < 63)
period_ms = 63; period_ms = 63;
led_state.delay = (period_ms * 0x10) / 1000; ledState.delay = (period_ms * 0x10) / 1000;
led_state.smoothing = 0x40; ledState.smoothing = 0x40;
led_state.loop_delay = 0x10; ledState.loop_delay = 0x10;
led_state.unk = 0; ledState.unk = 0;
// all colors look like 0x00ZZ00ZZ // all colors look like 0x00ZZ00ZZ
// in order to alternate between // in order to alternate between
@ -112,93 +137,69 @@ void MCU_SetNotificationLED(u32 period_ms, u32 color)
r = (color >> 16) & 0xFF; r = (color >> 16) & 0xFF;
r |= r << 16; r |= r << 16;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
led_state.red[i] = r; ledState.red[i] = r;
g = (color >> 8) & 0xFF; g = (color >> 8) & 0xFF;
g |= g << 16; g |= g << 16;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
led_state.green[i] = g; ledState.green[i] = g;
b = color & 0xFF; b = color & 0xFF;
b |= b << 16; b |= b << 16;
for (int i = 0; i < 8; i++) 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); mcuWriteReg(MCUREG_LED_WIFI, 0);
MCU_WriteReg(REG_LED_CAMERA, 0); mcuWriteReg(MCUREG_LED_CAMERA, 0);
MCU_WriteReg(REG_LED_SLIDER, 0); mcuWriteReg(MCUREG_LED_SLIDER, 0);
MCU_SetNotificationLED(0, 0); mcuSetStatusLED(0, 0);
} }
void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) void mcuInterruptHandler(u32 __attribute__((unused)) irqn)
{ {
u32 ints; u32 mask;
// Reading the pending mask automagically acknowledges // reading the pending mask automagically acknowledges
// the interrupts so all of them must be processed in one go // the interrupts so all of them must be processed in one go
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&ints, sizeof(ints)); mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&mask, sizeof(mask));
while(ints != 0) { if (mask & MCUEV_HID_VOLUME_SLIDER)
u32 mcu_int_id = 31 - __builtin_clz(ints); mcuUpdateVolumeSlider();
switch(mcu_int_id) { if (mask & MCUEV_HID_SHELL_OPEN) {
case MCU_PWR_BTN: mcuResetLEDs();
case MCU_PWR_HOLD: mcuUpdateShellState(true);
spec_hid |= BUTTON_POWER;
break;
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); if (mask & MCUEV_HID_SHELL_CLOSE) {
} mcuUpdateShellState(false);
} }
void MCU_Init(void) atomic_fetch_or(&pendingEvents, mask);
}
void mcuReset(void)
{ {
u32 clrpend, mask = 0; u32 intmask = 0;
shell_state = SHELL_OPEN; atomic_init(&pendingEvents, 0);
/* set register mask and clear any pending registers */ // set register mask and clear any pending registers
MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask)); mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask));
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&clrpend, sizeof(clrpend)); mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&intmask, sizeof(intmask));
MCU_ResetLED(); mcuResetLEDs();
MCU_UpdateVolumeSlider(); mcuUpdateVolumeSlider();
MCU_UpdateShellState(MCU_ReadReg(REG_CONSOLE_STATE) & BIT(1)); mcuUpdateShellState(true);
// 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); GPIO_setBit(19, 9);
} }

View File

@ -26,51 +26,54 @@
#define MCU_INTERRUPT (0x71) #define MCU_INTERRUPT (0x71)
#define I2C_MCU_DEVICE (3) #define I2C_MCU_DEVICE (3)
u8 MCU_GetVolumeSlider(void); enum {
u32 MCU_GetSpecialHID(void); 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); u32 mcuEventTest(u32 mask);
void MCU_ResetLED(void); u32 mcuEventClear(u32 mask);
u32 mcuEventWait(u32 mask);
void MCU_HandleInterrupts(u32 irqn); u8 mcuGetVolumeSlider(void);
u32 mcuGetSpecialHID(void);
void MCU_Init(void); void mcuSetStatusLED(u32 period_ms, u32 color);
void mcuResetLEDs(void);
static inline u8 MCU_ReadReg(u8 addr) void mcuInterruptHandler(u32 irqn);
void mcuReset(void);
static inline u8 mcuReadReg(u8 addr)
{ {
u8 val; u8 val;
I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1); I2C_readRegBuf(I2C_MCU_DEVICE, addr, &val, 1);
return val; 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); 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); 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); 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) static inline void MCU_controlLCDPower(u8 bits)
{ {
MCU_WriteReg(0x22u, bits); mcuWriteReg(0x22u, bits);
} }

View File

@ -45,10 +45,10 @@ static bool auto_brightness;
static SystemSHMEM __attribute__((section(".shared"))) SharedMemoryState; static SystemSHMEM __attribute__((section(".shared"))) SharedMemoryState;
void VBlank_Handler(u32 __attribute__((unused)) irqn) void vblankHandler(u32 __attribute__((unused)) irqn)
{ {
#ifndef FIXED_BRIGHTNESS #ifndef FIXED_BRIGHTNESS
int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2) % countof(brightness_lvls); int cur_bright_lvl = (mcuGetVolumeSlider() >> 2) % countof(brightness_lvls);
if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) { if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) {
prev_bright_lvl = cur_bright_lvl; prev_bright_lvl = cur_bright_lvl;
u8 br = brightness_lvls[cur_bright_lvl]; u8 br = brightness_lvls[cur_bright_lvl];
@ -61,7 +61,7 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn)
static bool legacy_boot = false; static bool legacy_boot = false;
void PXI_RX_Handler(u32 __attribute__((unused)) irqn) void pxiRxHandler(u32 __attribute__((unused)) irqn)
{ {
u32 ret, msg, cmd, argc, args[PXI_MAX_ARGS]; u32 ret, msg, cmd, argc, args[PXI_MAX_ARGS];
@ -137,7 +137,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_NOTIFY_LED: case PXI_NOTIFY_LED:
{ {
MCU_SetNotificationLED(args[0], args[1]); mcuSetStatusLED(args[0], args[1]);
ret = 0; ret = 0;
break; break;
} }
@ -185,14 +185,21 @@ void __attribute__((noreturn)) MainLoop(void)
auto_brightness = true; auto_brightness = true;
#endif #endif
memset(&SharedMemoryState, 0, sizeof(SharedMemoryState));
// configure interrupts // configure interrupts
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO2, PXI_RX_Handler); gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO2, pxiRxHandler);
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO1, MCU_HandleInterrupts); gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO1, mcuInterruptHandler);
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, VBlank_Handler); gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, vblankHandler);
// enable interrupts // enable interrupts
gicEnableInterrupt(PXI_RX_INTERRUPT);
gicEnableInterrupt(MCU_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); gicEnableInterrupt(VBLANK_INTERRUPT);
// ARM9 won't try anything funny until this point // ARM9 won't try anything funny until this point
@ -201,6 +208,14 @@ void __attribute__((noreturn)) MainLoop(void)
// Process IRQs until the ARM9 tells us it's time to boot something else // Process IRQs until the ARM9 tells us it's time to boot something else
do { do {
ARM_WFI(); ARM_WFI();
// handle shell events
u32 shell = mcuEventClear(MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE);
if (shell & MCUEV_HID_SHELL_CLOSE) {
GFX_powerOffBacklights(GFX_BLIGHT_BOTH);
} else if (shell & MCUEV_HID_SHELL_OPEN) {
GFX_powerOnBacklights(GFX_BLIGHT_BOTH);
}
} while(!legacy_boot); } while(!legacy_boot);
SYS_CoreZeroShutdown(); SYS_CoreZeroShutdown();

View File

@ -115,12 +115,10 @@ void SYS_CoreZeroInit(void)
PXI_Reset(); PXI_Reset();
I2C_init(); I2C_init();
MCU_Init(); mcuReset();
SPI_Init(); SPI_Init();
CODEC_Init(); CODEC_Init();
GFX_init(GFX_RGB565);
} }
void SYS_CoreInit(void) void SYS_CoreInit(void)