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 committed by d0k3
parent c4b3b582a7
commit a6e20c641a
6 changed files with 169 additions and 150 deletions

View File

@ -112,13 +112,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(mcuEventWait(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(mcuEventWait(0x3Fu<<24) != 0x28u<<24) __builtin_trap();
g_gfxState.lcdPower = 0x15; // All on.
// Make sure the fills finished.
@ -212,8 +212,9 @@ void GFX_powerOnBacklights(GfxBlight mask)
mask <<= 1;
MCU_controlLCDPower(mask); // Power on backlights.
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();
mcuEventWait(0x3F<<24);
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/
}
void GFX_powerOffBacklights(GfxBlight mask)
@ -221,8 +222,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();
mcuEventWait(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,35 @@
#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,
};
#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 +59,77 @@ 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 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;
spec_hid = 0;
return atomic_fetch_and(&pendingEvents, ~mask) & mask;
}
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;
}
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 +137,69 @@ 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 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
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&ints, sizeof(ints));
mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&mask, sizeof(mask));
while(ints != 0) {
u32 mcu_int_id = 31 - __builtin_clz(ints);
if (mask & MCUEV_HID_VOLUME_SLIDER)
mcuUpdateVolumeSlider();
switch(mcu_int_id) {
case MCU_PWR_BTN:
case MCU_PWR_HOLD:
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;
if (mask & MCUEV_HID_SHELL_OPEN) {
mcuResetLEDs();
mcuUpdateShellState(true);
}
ints &= ~BIT(mcu_int_id);
if (mask & MCUEV_HID_SHELL_CLOSE) {
mcuUpdateShellState(false);
}
atomic_fetch_or(&pendingEvents, mask);
}
void MCU_Init(void)
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 */
MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask));
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&clrpend, sizeof(clrpend));
// 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));
MCU_ResetLED();
mcuResetLEDs();
MCU_UpdateVolumeSlider();
MCU_UpdateShellState(MCU_ReadReg(REG_CONSOLE_STATE) & BIT(1));
mcuUpdateVolumeSlider();
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);
}

View File

@ -26,51 +26,54 @@
#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);
u32 mcuEventTest(u32 mask);
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;
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

@ -32,7 +32,7 @@
#include "system/sys.h"
static const u8 brLvlTbl[] = {
static const u8 brightness_lvls[] = {
0x10, 0x17, 0x1E, 0x25,
0x2C, 0x34, 0x3C, 0x44,
0x4D, 0x56, 0x60, 0x6B,
@ -40,19 +40,19 @@ static const u8 brLvlTbl[] = {
};
#ifndef FIXED_BRIGHTNESS
static int oldBrLvl;
static bool autoBr;
static int prev_bright_lvl;
static bool auto_brightness;
#endif
static SystemSHMEM __attribute__((section(".shared"))) SharedMemoryState;
void VBlank_Handler(u32 __attribute__((unused)) irqn)
void vblankHandler(u32 __attribute__((unused)) irqn)
{
#ifndef FIXED_BRIGHTNESS
int newBrLvl = (MCU_GetVolumeSlider() >> 2) % countof(brLvlTbl);
if ((newBrLvl != oldBrLvl) && autoBr) {
oldBrLvl = newBrLvl;
u8 br = brLvlTbl[newBrLvl];
int cur_bright_lvl = (mcuGetVolumeSlider() >> 2) % countof(brightness_lvls);
if ((cur_bright_lvl != prev_bright_lvl) && auto_brightness) {
prev_bright_lvl = cur_bright_lvl;
u8 br = brightness_lvls[cur_bright_lvl];
GFX_setBrightness(br, br);
}
#endif
@ -62,7 +62,7 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn)
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];
@ -138,7 +138,7 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
case PXI_NOTIFY_LED:
{
MCU_SetNotificationLED(args[0], args[1]);
mcuSetStatusLED(args[0], args[1]);
ret = 0;
break;
}
@ -180,21 +180,28 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
void __attribute__((noreturn)) MainLoop(void)
{
#ifdef FIXED_BRIGHTNESS
u8 fixBrLvl = brLvlTbl[clamp(FIXED_BRIGHTNESS, 0, countof(brLvlTbl)-1)];
GFX_setBrightness(fixBrLvl, fixBrLvl);
u8 fixed_bright_lvl = brightness_lvls[clamp(FIXED_BRIGHTNESS, 0, countof(brightness_lvls)-1)];
GFX_setBrightness(fixed_bright_lvl, fixed_bright_lvl);
#else
oldBrLvl = -1;
autoBr = true;
prev_bright_lvl = -1;
auto_brightness = true;
#endif
memset(&SharedMemoryState, 0, sizeof(SharedMemoryState));
// 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_PRIO2, pxiRxHandler);
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO1, mcuInterruptHandler);
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, vblankHandler);
// 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
@ -203,6 +210,14 @@ void __attribute__((noreturn)) MainLoop(void)
// Process IRQs until the ARM9 tells us it's time to boot something else
do {
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);
// Wait for the ARM9 to do its firmlaunch setup

View File

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