forked from Mirror/GodMode9
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7d2e729ac6 | ||
|
670ff3345c | ||
|
6b5ddf94d8 | ||
|
e4dd8511cd | ||
|
b4fccd4a3c |
@ -19,8 +19,12 @@
|
|||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <arm.h>
|
#include <arm.h>
|
||||||
|
|
||||||
|
#include <stdatomic.h>
|
||||||
|
|
||||||
#include "arm/gic.h"
|
#include "arm/gic.h"
|
||||||
|
|
||||||
|
#include "system/event.h"
|
||||||
|
|
||||||
/* Generic Interrupt Controller Registers */
|
/* Generic Interrupt Controller Registers */
|
||||||
#define REG_GIC(cpu, o, t) REG_ARM_PMR(0x200 + ((cpu) * 0x100) + (o), t)
|
#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)
|
#define IRQN_IS_VALID(n) ((n) < DIC_MAX_IRQ)
|
||||||
|
|
||||||
static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ];
|
static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ];
|
||||||
|
static _Atomic(u32) gicIrqPending[DIC_MAX_IRQ / 32];
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
u8 tgt;
|
u8 tgt;
|
||||||
@ -106,14 +111,13 @@ static u8 gicGetDefaultIrqCfg(u32 irqn) {
|
|||||||
return gicDefaultIrqCfg[i].mode;
|
return gicDefaultIrqCfg[i].mode;
|
||||||
}
|
}
|
||||||
// TODO: would it be considerably faster to use bsearch?
|
// TODO: would it be considerably faster to use bsearch?
|
||||||
|
|
||||||
return GIC_RISINGEDGE_1N;
|
return GIC_RISINGEDGE_1N;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gicTopHandler(void)
|
void gicTopHandler(void)
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
u32 irqn;
|
u32 irqn, irqsource, index, mask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If more than one of these CPUs reads the Interrupt Acknowledge Register at the
|
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
|
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.
|
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;
|
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 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
|
// 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;
|
gicn = MAX_CPU;
|
||||||
|
|
||||||
// clear the interrupt handler and config table
|
// clear the interrupt handler and config table
|
||||||
|
getEventIRQ()->reset();
|
||||||
memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers));
|
memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers));
|
||||||
memset(gicIrqConfig, 0, sizeof(gicIrqConfig));
|
memset(gicIrqConfig, 0, sizeof(gicIrqConfig));
|
||||||
|
|
||||||
@ -263,3 +274,27 @@ void gicTriggerSoftInterrupt(u32 softirq)
|
|||||||
{
|
{
|
||||||
REG_DIC_SOFTINT = 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;
|
||||||
|
}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include "hw/mcu.h"
|
#include "hw/mcu.h"
|
||||||
#include "hw/gpulcd.h"
|
#include "hw/gpulcd.h"
|
||||||
|
|
||||||
|
#include "system/event.h"
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
|
u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
|
||||||
@ -112,13 +114,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(eventWait(getEventMCU(), 0x3Fu<<24, 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(eventWait(getEventMCU(), 0x3Fu<<24, 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 +214,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)
|
eventWait(getEventMCU(), 0x3F<<24, 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 +224,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)
|
eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
|
||||||
__builtin_trap();
|
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
|
||||||
|
__builtin_trap();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 GFX_getBrightness(void)
|
u8 GFX_getBrightness(void)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -20,40 +20,37 @@
|
|||||||
#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 {
|
#include "system/event.h"
|
||||||
MCU_PWR_BTN = 0,
|
|
||||||
MCU_PWR_HOLD = 1,
|
#define MCUEV_HID_MASK ( \
|
||||||
MCU_HOME_BTN = 2,
|
MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \
|
||||||
MCU_HOME_LIFT = 3,
|
MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH)
|
||||||
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 +61,73 @@ 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 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)
|
void mcuSetStatusLED(u32 period_ms, u32 color)
|
||||||
{
|
|
||||||
u32 ret = spec_hid | shell_state;
|
|
||||||
spec_hid = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCU_SetNotificationLED(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 +135,65 @@ 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 mcuReset(void)
|
||||||
{
|
{
|
||||||
u32 ints;
|
u32 intmask = 0;
|
||||||
|
|
||||||
// Reading the pending mask automagically acknowledges
|
atomic_init(&pendingEvents, 0);
|
||||||
// the interrupts so all of them must be processed in one go
|
|
||||||
MCU_ReadRegBuf(REG_INT_MASK, (u8*)&ints, sizeof(ints));
|
|
||||||
|
|
||||||
while(ints != 0) {
|
// set register mask and clear any pending registers
|
||||||
u32 mcu_int_id = 31 - __builtin_clz(ints);
|
mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask));
|
||||||
|
mcuReadRegBuf(MCUREG_INT_MASK, (u8*)&intmask, sizeof(intmask));
|
||||||
|
|
||||||
switch(mcu_int_id) {
|
mcuResetLEDs();
|
||||||
case MCU_PWR_BTN:
|
|
||||||
case MCU_PWR_HOLD:
|
|
||||||
spec_hid |= BUTTON_POWER;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MCU_HOME_BTN:
|
volumeSliderValue = mcuReadReg(MCUREG_VOLUME_SLIDER);
|
||||||
spec_hid |= BUTTON_HOME;
|
shellState = SHELL_OPEN;
|
||||||
break;
|
// assume the shell is always open on boot
|
||||||
|
// knowing the average 3DS user, there will be plenty
|
||||||
case MCU_HOME_LIFT:
|
// of laughs when this comes back to bite us in the rear
|
||||||
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));
|
|
||||||
|
|
||||||
GPIO_setBit(19, 9);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -26,51 +26,48 @@
|
|||||||
#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);
|
u8 mcuGetVolumeSlider(void);
|
||||||
void MCU_ResetLED(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;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "hw/nvram.h"
|
#include "hw/nvram.h"
|
||||||
|
|
||||||
#include "system/sys.h"
|
#include "system/sys.h"
|
||||||
|
#include "system/event.h"
|
||||||
|
|
||||||
static const u8 brLvlTbl[] = {
|
static const u8 brLvlTbl[] = {
|
||||||
0x10, 0x17, 0x1E, 0x25,
|
0x10, 0x17, 0x1E, 0x25,
|
||||||
@ -44,12 +45,15 @@ static int oldBrLvl;
|
|||||||
static bool autoBr;
|
static bool autoBr;
|
||||||
#endif
|
#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
|
#ifndef FIXED_BRIGHTNESS
|
||||||
int newBrLvl = (MCU_GetVolumeSlider() >> 2) % countof(brLvlTbl);
|
int newBrLvl = (mcuGetVolumeSlider() >> 2) % countof(brLvlTbl);
|
||||||
if ((newBrLvl != oldBrLvl) && autoBr) {
|
if ((newBrLvl != oldBrLvl) && autoBr) {
|
||||||
oldBrLvl = newBrLvl;
|
oldBrLvl = newBrLvl;
|
||||||
u8 br = brLvlTbl[newBrLvl];
|
u8 br = brLvlTbl[newBrLvl];
|
||||||
@ -57,97 +61,135 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn)
|
|||||||
}
|
}
|
||||||
#endif
|
#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;
|
static u32 pxiRxUpdate(u32 *args)
|
||||||
|
|
||||||
void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
|
|
||||||
{
|
{
|
||||||
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();
|
msg = PXI_Recv();
|
||||||
cmd = msg & 0xFFFF;
|
lo = msg & 0xFFFF;
|
||||||
argc = msg >> 16;
|
hi = msg >> 16;
|
||||||
|
|
||||||
if (argc >= PXI_MAX_ARGS) {
|
PXI_RecvArray(args, hi);
|
||||||
PXI_Send(0xFFFFFFFF);
|
return lo;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PXI_RecvArray(args, argc);
|
void __attribute__((noreturn)) MainLoop(void)
|
||||||
|
{
|
||||||
|
bool runPxiCmdProcessor = true;
|
||||||
|
|
||||||
switch (cmd) {
|
#ifdef FIXED_BRIGHTNESS
|
||||||
case PXI_LEGACY_MODE:
|
u8 fixBrLvl = brLvlTbl[clamp(FIXED_BRIGHTNESS, 0, countof(brLvlTbl)-1)];
|
||||||
{
|
GFX_setBrightness(fixBrLvl, fixBrLvl);
|
||||||
// TODO: If SMP is enabled, an IPI should be sent here (with a DSB)
|
#else
|
||||||
legacy_boot = true;
|
oldBrLvl = -1;
|
||||||
ret = 0;
|
autoBr = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// initialize state stuff
|
||||||
|
getEventIRQ()->reset();
|
||||||
|
getEventMCU()->reset();
|
||||||
|
memset(&sharedMem, 0, sizeof(sharedMem));
|
||||||
|
|
||||||
|
// configure interrupts
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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 commands until the ARM9 tells
|
||||||
|
// us it's time to boot something else
|
||||||
|
// also handles VBlank events as needed
|
||||||
|
do {
|
||||||
|
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;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_GET_SHMEM:
|
// revert to legacy boot mode
|
||||||
{
|
case PXICMD_LEGACY_BOOT:
|
||||||
ret = (u32)&SharedMemoryState;
|
runPxiCmdProcessor = false;
|
||||||
|
pxiReply = 0;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_SET_VMODE:
|
// returns the shared memory address
|
||||||
{
|
case PXICMD_GET_SHMEM_ADDRESS:
|
||||||
GFX_init(args[0] ? GFX_BGR8 : GFX_RGB565);
|
pxiReply = (u32)&sharedMem;
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_I2C_READ:
|
// 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;
|
u32 devId, regAddr, size;
|
||||||
|
|
||||||
devId = (args[0] & 0xff);
|
devId = (args[0] & 0xff);
|
||||||
regAddr = (args[0] >> 8) & 0xff;
|
regAddr = (args[0] >> 8) & 0xFF;
|
||||||
size = (args[0] >> 16) % I2C_SHARED_BUFSZ;
|
size = (args[0] >> 16) % SHMEM_BUFFER_SIZE;
|
||||||
|
|
||||||
ret = I2C_readRegBuf(devId, regAddr, SharedMemoryState.i2cBuffer, 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PXI_I2C_WRITE:
|
// checks whether the NVRAM chip is online (not doing any work)
|
||||||
{
|
case PXICMD_NVRAM_ONLINE:
|
||||||
u32 devId, regAddr, size;
|
pxiReply = (NVRAM_Status() & NVRAM_SR_WIP) == 0;
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_NVRAM_ONLINE:
|
// reads data from the NVRAM chip
|
||||||
{
|
case PXICMD_NVRAM_READ:
|
||||||
ret = (NVRAM_Status() & NVRAM_SR_WIP) == 0;
|
NVRAM_Read(args[0], sharedMem.dataBuffer.w, args[1]);
|
||||||
|
pxiReply = 0;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_NVRAM_READ:
|
// sets the notification LED with the given color and period
|
||||||
{
|
case PXICMD_SET_NOTIFY_LED:
|
||||||
NVRAM_Read(args[0], (u32*)SharedMemoryState.spiBuffer, args[1]);
|
mcuSetStatusLED(args[0], args[1]);
|
||||||
ret = 0;
|
pxiReply = 0;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_NOTIFY_LED:
|
// sets the LCDs brightness (if FIXED_BRIGHTNESS is disabled)
|
||||||
|
case PXICMD_SET_BRIGHTNESS:
|
||||||
{
|
{
|
||||||
MCU_SetNotificationLED(args[0], args[1]);
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PXI_BRIGHTNESS:
|
|
||||||
{
|
|
||||||
ret = GFX_getBrightness();
|
|
||||||
#ifndef FIXED_BRIGHTNESS
|
|
||||||
s32 newbrightness = (s32)args[0];
|
s32 newbrightness = (s32)args[0];
|
||||||
|
pxiReply = GFX_getBrightness();
|
||||||
|
#ifndef FIXED_BRIGHTNESS
|
||||||
if ((newbrightness > 0) && (newbrightness < 0x100)) {
|
if ((newbrightness > 0) && (newbrightness < 0x100)) {
|
||||||
GFX_setBrightness(newbrightness, newbrightness);
|
GFX_setBrightness(newbrightness, newbrightness);
|
||||||
autoBr = false;
|
autoBr = false;
|
||||||
@ -159,51 +201,25 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New CMD template:
|
// replies -1 on default
|
||||||
case CMD_ID:
|
|
||||||
{
|
|
||||||
<var declarations/assignments>
|
|
||||||
<execute the command>
|
|
||||||
<set the return value>
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = 0xFFFFFFFF;
|
pxiReply = 0xFFFFFFFF;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PXI_Send(ret);
|
if (pxiCmd != PXICMD_NONE)
|
||||||
}
|
PXI_Send(pxiReply); // was a command sent from the ARM9, send a response
|
||||||
|
} while(runPxiCmdProcessor);
|
||||||
|
|
||||||
void __attribute__((noreturn)) MainLoop(void)
|
// perform deinit in reverse order
|
||||||
{
|
gicDisableInterrupt(VBLANK_INTERRUPT);
|
||||||
#ifdef FIXED_BRIGHTNESS
|
gicDisableInterrupt(PXI_RX_INTERRUPT);
|
||||||
u8 fixBrLvl = brLvlTbl[clamp(FIXED_BRIGHTNESS, 0, countof(brLvlTbl)-1)];
|
|
||||||
GFX_setBrightness(fixBrLvl, fixBrLvl);
|
|
||||||
#else
|
|
||||||
oldBrLvl = -1;
|
|
||||||
autoBr = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// configure interrupts
|
// unconditionally reinitialize the screens
|
||||||
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO2, PXI_RX_Handler);
|
// in RGB24 framebuffer mode
|
||||||
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO1, MCU_HandleInterrupts);
|
GFX_init(GFX_BGR8);
|
||||||
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, VBlank_Handler);
|
|
||||||
|
|
||||||
// enable interrupts
|
gicDisableInterrupt(MCU_INTERRUPT);
|
||||||
gicEnableInterrupt(PXI_RX_INTERRUPT);
|
|
||||||
gicEnableInterrupt(MCU_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
|
|
||||||
do {
|
|
||||||
ARM_WFI();
|
|
||||||
} while(!legacy_boot);
|
|
||||||
|
|
||||||
// Wait for the ARM9 to do its firmlaunch setup
|
// Wait for the ARM9 to do its firmlaunch setup
|
||||||
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
||||||
|
26
arm11/source/system/event.h
Normal file
26
arm11/source/system/event.h
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -107,20 +107,17 @@ void SYS_CoreZeroInit(void)
|
|||||||
mmuMapArea(0x20000000, 0x20000000, 128UL << 20, MMU_FLAGS(MMU_CACHE_WB, MMU_READ_WRITE, 1, 1));
|
mmuMapArea(0x20000000, 0x20000000, 128UL << 20, MMU_FLAGS(MMU_CACHE_WB, MMU_READ_WRITE, 1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SYS_IsNewConsole()) {
|
// screen init magicks
|
||||||
TIMER_WaitMS(150);
|
TIMER_WaitMS(64);
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize peripherals
|
// Initialize peripherals
|
||||||
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)
|
||||||
|
@ -19,7 +19,7 @@ static void SetNotificationLED(u32 period_ms, u32 rgb565_color)
|
|||||||
(rgb565_color >> 5) << (8+2) |
|
(rgb565_color >> 5) << (8+2) |
|
||||||
(rgb565_color << 3));
|
(rgb565_color << 3));
|
||||||
u32 args[] = {period_ms, rgb888_color};
|
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
|
// there's some weird thing going on when reading this
|
||||||
|
@ -12,7 +12,7 @@ u32 SetScreenBrightness(int level) {
|
|||||||
arg = 0;
|
arg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PXI_DoCMD(PXI_BRIGHTNESS, &arg, 1);
|
return PXI_DoCMD(PXICMD_SET_BRIGHTNESS, &arg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetBatteryPercent() {
|
u32 GetBatteryPercent() {
|
||||||
|
@ -108,8 +108,7 @@ u32 BootFirmHandler(const char* bootpath, bool verbose, bool delete) {
|
|||||||
if (delete) PathDelete(bootpath);
|
if (delete) PathDelete(bootpath);
|
||||||
DeinitExtFS();
|
DeinitExtFS();
|
||||||
DeinitSDCardFS();
|
DeinitSDCardFS();
|
||||||
PXI_DoCMD(PXI_SET_VMODE, (u32[]){1}, 1);
|
PXI_DoCMD(PXICMD_LEGACY_BOOT, NULL, 0);
|
||||||
PXI_DoCMD(PXI_LEGACY_MODE, NULL, 0);
|
|
||||||
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
||||||
BootFirm((FirmHeader*) firm, fixpath);
|
BootFirm((FirmHeader*) firm, fixpath);
|
||||||
while(1);
|
while(1);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "hid.h"
|
#include "hid.h"
|
||||||
|
|
||||||
SystemSHMEM *shmemGlobalBase;
|
SystemSHMEM *shmemBasePtr;
|
||||||
|
|
||||||
void main(int argc, char** argv, int entrypoint)
|
void main(int argc, char** argv, int entrypoint)
|
||||||
{
|
{
|
||||||
|
@ -8,32 +8,33 @@
|
|||||||
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
u8 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.b;
|
||||||
const u32 arg = devId | (regAddr << 8) | (size << 16);
|
const u32 arg = devId | (regAddr << 8) | (size << 16);
|
||||||
|
|
||||||
if (size >= I2C_SHARED_BUFSZ)
|
if (size >= SHMEM_BUFFER_SIZE)
|
||||||
return false;
|
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, dataBuffer, size);
|
||||||
memcpy(out, ARM_GetSHMEM()->i2cBuffer, size);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
|
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size)
|
||||||
{
|
{
|
||||||
int ret;
|
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;
|
return false;
|
||||||
|
|
||||||
ARM_InvDC_Range(ARM_GetSHMEM()->i2cBuffer, size);
|
memcpy(dataBuffer, in, size);
|
||||||
memcpy(ARM_GetSHMEM()->i2cBuffer, in, size);
|
ARM_WbDC_Range(dataBuffer, size);
|
||||||
ARM_WbDC_Range(ARM_GetSHMEM()->i2cBuffer, size);
|
|
||||||
ARM_DSB();
|
ARM_DSB();
|
||||||
|
|
||||||
ret = PXI_DoCMD(PXI_I2C_WRITE, &arg, 1);
|
ret = PXI_DoCMD(PXICMD_I2C_OP, &arg, 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,24 +5,25 @@
|
|||||||
|
|
||||||
bool spiflash_get_status(void)
|
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)
|
bool spiflash_read(u32 offset, u32 size, u8 *buf)
|
||||||
{
|
{
|
||||||
|
u32 *const dataBuffer = ARM_GetSHMEM()->dataBuffer.w;
|
||||||
u32 args[2];
|
u32 args[2];
|
||||||
|
|
||||||
while(size > 0) {
|
while(size > 0) {
|
||||||
u32 blksz = min(size, SPI_SHARED_BUFSZ);
|
u32 blksz = min(size, SHMEM_BUFFER_SIZE);
|
||||||
|
|
||||||
args[0] = offset;
|
args[0] = offset;
|
||||||
args[1] = blksz;
|
args[1] = blksz;
|
||||||
|
|
||||||
ARM_WbDC_Range(ARM_GetSHMEM()->spiBuffer, blksz);
|
PXI_DoCMD(PXICMD_NVRAM_READ, args, 2);
|
||||||
PXI_DoCMD(PXI_NVRAM_READ, args, 2);
|
ARM_InvDC_Range(dataBuffer, blksz);
|
||||||
ARM_InvDC_Range(ARM_GetSHMEM()->spiBuffer, blksz);
|
|
||||||
ARM_DSB();
|
ARM_DSB();
|
||||||
memcpy(buf, ARM_GetSHMEM()->spiBuffer, blksz);
|
|
||||||
|
memcpy(buf, dataBuffer, blksz);
|
||||||
|
|
||||||
buf += blksz;
|
buf += blksz;
|
||||||
size -= blksz;
|
size -= blksz;
|
||||||
|
@ -1426,8 +1426,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
|
|||||||
fixpath[255] = '\0';
|
fixpath[255] = '\0';
|
||||||
DeinitExtFS();
|
DeinitExtFS();
|
||||||
DeinitSDCardFS();
|
DeinitSDCardFS();
|
||||||
PXI_DoCMD(PXI_SET_VMODE, (u32[]){1}, 1);
|
PXI_DoCMD(PXICMD_LEGACY_BOOT, NULL, 0);
|
||||||
PXI_DoCMD(PXI_LEGACY_MODE, NULL, 0);
|
|
||||||
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
PXI_Barrier(PXI_FIRMLAUNCH_BARRIER);
|
||||||
BootFirm((FirmHeader*)(void*)firm, fixpath);
|
BootFirm((FirmHeader*)(void*)firm, fixpath);
|
||||||
while(1);
|
while(1);
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
(sizeof(x) / sizeof(*(x)))
|
(sizeof(x) / sizeof(*(x)))
|
||||||
|
|
||||||
#define bkpt \
|
#define bkpt \
|
||||||
__builtin_trap()
|
do{__builtin_trap(); __builtin_unreachable();}while(0)
|
||||||
|
|
||||||
#define assert(x) \
|
#define assert(x) \
|
||||||
(!!(x) ? (void)0 : __builtin_trap())
|
(!!(x) ? (void)0 : __builtin_trap())
|
||||||
|
17
common/pxi.h
17
common/pxi.h
@ -28,18 +28,17 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PXI_LEGACY_MODE = 0,
|
PXICMD_LEGACY_BOOT = 0,
|
||||||
PXI_GET_SHMEM,
|
PXICMD_GET_SHMEM_ADDRESS,
|
||||||
PXI_SET_VMODE,
|
|
||||||
|
|
||||||
PXI_I2C_READ,
|
PXICMD_I2C_OP,
|
||||||
PXI_I2C_WRITE,
|
PXICMD_NVRAM_ONLINE,
|
||||||
|
PXICMD_NVRAM_READ,
|
||||||
|
|
||||||
PXI_NVRAM_ONLINE,
|
PXICMD_SET_NOTIFY_LED,
|
||||||
PXI_NVRAM_READ,
|
PXICMD_SET_BRIGHTNESS,
|
||||||
|
|
||||||
PXI_NOTIFY_LED,
|
PXICMD_NONE,
|
||||||
PXI_BRIGHTNESS
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -20,8 +20,7 @@
|
|||||||
|
|
||||||
#include <arm.h>
|
#include <arm.h>
|
||||||
|
|
||||||
#define I2C_SHARED_BUFSZ 1024
|
#define SHMEM_BUFFER_SIZE 2048
|
||||||
#define SPI_SHARED_BUFSZ 1024
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
@ -29,14 +28,18 @@ typedef struct {
|
|||||||
u64 full;
|
u64 full;
|
||||||
} hidState;
|
} hidState;
|
||||||
|
|
||||||
u8 i2cBuffer[I2C_SHARED_BUFSZ];
|
union {
|
||||||
u32 spiBuffer[SPI_SHARED_BUFSZ/4];
|
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;
|
} __attribute__((packed, aligned(8))) SystemSHMEM;
|
||||||
|
|
||||||
#ifdef ARM9
|
#ifdef ARM9
|
||||||
#include <pxi.h>
|
#include <pxi.h>
|
||||||
|
|
||||||
extern SystemSHMEM *shmemGlobalBase;
|
extern SystemSHMEM *shmemBasePtr;
|
||||||
|
|
||||||
static inline SystemSHMEM *ARM_GetSHMEM(void)
|
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
|
// insert a compiler barrier to force the compiler not to assume
|
||||||
// memory values will remain constant in between calls to getSHMEM
|
// memory values will remain constant in between calls to getSHMEM
|
||||||
asm_v("":::"memory", "cc");
|
asm_v("":::"memory", "cc");
|
||||||
return shmemGlobalBase;
|
return shmemBasePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ARM_InitSHMEM(void)
|
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
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user