Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/arm11/drivers/lgy11.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ ALWAYS_INLINE Lgy11* getLgy11Regs(void)


void LGY11_switchMode(void);
void LGY11_setGbaKeypadWakeBridge(bool enabled);

static inline bool LGY11_isGbaSleeping(void)
{
return (getLgy11Regs()->sleep & BIT(1)) != 0u;
}

static inline void LGY11_wakeGba(void)
{
getLgy11Regs()->sleep |= (u16)(BIT(0) | BIT(1));
}

static inline void LGY11_setInputState(const u16 pressed)
{
Expand Down
5 changes: 4 additions & 1 deletion include/arm11/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "types.h"



#ifdef __cplusplus
extern "C"
{
#endif

bool power_sleep(void);
[[noreturn]] void power_off(void);
[[noreturn]] void power_reboot(void);

#ifdef __cplusplus
} // extern "C"
#endif
#endif
1 change: 0 additions & 1 deletion include/arm9/lgy7_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ extern const u32 _gba_vector_overlay_size[];

// ARM7 boot code for GBA mode.
[[noreturn]] void _gba_boot(void);
extern u8 _gba_boot_swi_a9_addr[]; // "swi 0x01" location in ARM9 address space.
extern const u32 _gba_boot_size[];

#ifdef __cplusplus
Expand Down
8 changes: 8 additions & 0 deletions include/drivers/gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ void GFX_sleep(void);
*/
void GFX_sleepAwake(void);

/**
* @brief Reinitializes graphics hardware after whole-system PDN sleep.
*
* Unlike GFX_sleepAwake(), this performs a full hardware reset.
* VRAM contents are lost and must be reconstructed by the caller.
*/
void GFX_sleepAwakeCold(void);

bool GFX_setupExceptionFrameBuffer(void);

#endif // #ifdef __ARM11__
Expand Down
1 change: 1 addition & 0 deletions include/drivers/lgy_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ typedef struct


Result LGY_prepareGbaMode(bool directBoot, const u32 saveType, const char *const savePath);
Result LGY_setGbaStopVector(bool enabled);
Result LGY_setGbaRtc(const GbaRtc rtc);
Result LGY_getGbaRtc(GbaRtc *const out);
Result LGY_backupGbaSave(void);
Expand Down
3 changes: 2 additions & 1 deletion include/ipc_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ typedef enum

// Miscellaneous API.
//IPC_CMD9_TEST = MAKE_CMD9(0, 0, 0),
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0) // Also used for panic() and guruMeditation().
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0), // Also used for panic() and guruMeditation().
IPC_CMD9_SET_GBA_STOP_VECTOR = MAKE_CMD9(0, 0, 1)
} IpcCmd9;

enum {_CMD11_C_BASE = __COUNTER__ + 1}; // Start at 0.
Expand Down
1 change: 1 addition & 0 deletions include/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern "C"
//void WEAK __systemInit(void);

#ifdef __ARM11__
void __systemWaitCore1Standby(void);
void __systemBootCore1(void (*entry)(void));
#endif

Expand Down
84 changes: 52 additions & 32 deletions source/arm11/drivers/gfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,35 +302,8 @@ static void oldBootloaderWorkaround(void)
(void)MCU_getIrqs(MCU_LCD_IRQ_MASK);
}

void GFX_init(const GfxFmt fmtTop, const GfxFmt fmtBot, const GfxTopMode mode)
static void initVramAfterReset(void)
{
// Initialize GFX state.
GfxState *const state = &g_gfxState;
const u8 mcuLcdState = MCU_LCD_PWR_TOP_BL_OFF | MCU_LCD_PWR_BOT_BL_OFF | MCU_LCD_PWR_OFF;
const u32 lcdLum = 1; // TODO: Better default.
state->swap = 0;
state->swapMask = 3; // Double buffering enabled for both.
state->mcuLcdState = mcuLcdState;
state->lcdLum = lcdLum;

// If the previous FIRM does not wait for LCD MCU events
// we will get them unexpectedly and this will most likely trigger a panic().
// TODO: If Luma3DS/fastboot3DS eventually fix this remove this workaround.
oldBootloaderWorkaround();

// Do a full hardware reset.
hardwareReset();

// Create IRQ events.
// PSC0, PSC1, PDC0, PDC1, PPF, P3D.
static_assert(IRQ_P3D - IRQ_PSC0 == 5);
for(unsigned i = 0; i < 6; i++)
{
KHandle kevent = createEvent(false);
bindInterruptToEvent(kevent, IRQ_PSC0 + i, 14);
state->events[i] = kevent;
}

// Not in gsp. Clear entire VRAM.
// Note: Benchmarks show that
// - 1 fill for the entire VRAM is the slowest.
Expand All @@ -349,17 +322,19 @@ void GFX_init(const GfxFmt fmtTop, const GfxFmt fmtBot, const GfxTopMode mode)
//GX_displayTransfer((u32*)VRAM_BASE, PPF_DIM(128, 128), (u32*)(VRAM_BASE + 0x8000), PPF_DIM(128, 128),
// PPF_O_FMT(GX_ABGR4) | PPF_I_FMT(GX_ABGR4) | PPF_NO_TILED_2_LINEAR);
GX_textureCopy((u32*)VRAM_BASE, 0, (u32*)(VRAM_BASE + 16), 0, 16);
}

// Allocate our frame buffers.
allocateFramebufs(fmtTop, fmtBot, mode);
static void initDisplayAfterReset(void)
{
const GfxState *const state = &g_gfxState;

// Get the display controllers up and running.
// This needs to happen before LCD init (LCDs need some clock pulses to reset?).
displayControllerInit(mode);
displayControllerInit(state->mode);

// Initialize/power on the LCDs.
// Note: This will also enable forced black output.
LCD_init(mcuLcdState<<1, lcdLum);
LCD_init(state->mcuLcdState<<1, state->lcdLum);

// Not in gsp. Ensure VRAM is cleared.
// Also wait for the dummy display transfer/texture copy.
Expand All @@ -371,6 +346,43 @@ void GFX_init(const GfxFmt fmtTop, const GfxFmt fmtBot, const GfxTopMode mode)
GFX_setForceBlack(false, false);
}

void GFX_init(const GfxFmt fmtTop, const GfxFmt fmtBot, const GfxTopMode mode)
{
// Initialize GFX state.
GfxState *const state = &g_gfxState;
const u8 mcuLcdState = MCU_LCD_PWR_TOP_BL_OFF | MCU_LCD_PWR_BOT_BL_OFF | MCU_LCD_PWR_OFF;
const u32 lcdLum = 1; // TODO: Better default.
state->swap = 0;
state->swapMask = 3; // Double buffering enabled for both.
state->mcuLcdState = mcuLcdState;
state->lcdLum = lcdLum;

// If the previous FIRM does not wait for LCD MCU events
// we will get them unexpectedly and this will most likely trigger a panic().
// TODO: If Luma3DS/fastboot3DS eventually fix this remove this workaround.
oldBootloaderWorkaround();

// Do a full hardware reset.
hardwareReset();

// Create IRQ events.
// PSC0, PSC1, PDC0, PDC1, PPF, P3D.
static_assert(IRQ_P3D - IRQ_PSC0 == 5);
for(unsigned i = 0; i < 6; i++)
{
KHandle kevent = createEvent(false);
bindInterruptToEvent(kevent, IRQ_PSC0 + i, 14);
state->events[i] = kevent;
}

initVramAfterReset();

// Allocate our frame buffers.
allocateFramebufs(fmtTop, fmtBot, mode);

initDisplayAfterReset();
}

void GFX_deinit(void)
{
// Power off backlights and LCDs if on.
Expand Down Expand Up @@ -665,6 +677,14 @@ void GFX_sleepAwake(void)
GFX_setForceBlack(false, false);
}

void GFX_sleepAwakeCold(void)
{
// Whole-system PDN sleep resets the graphics blocks and loses VRAM.
hardwareReset();
initVramAfterReset();
initDisplayAfterReset();
}

bool GFX_setupExceptionFrameBuffer(void)
{
// Check if we can access GX regs.
Expand Down
31 changes: 27 additions & 4 deletions source/arm11/drivers/lgy11.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,25 @@



static volatile bool g_gbaKeypadWakeEnabled = true;

static void lgySleepIsr(u32 intSource)
{
Lgy11 *const lgy11 = getLgy11Regs();
if(intSource == IRQ_LGY_SLEEP)
{
// Workaround for The Legend of Zelda - A Link to the Past.
// This game doesn't set the IRQ enable bit so we force it
// on the 3DS side. Unknown if other games have this bug.
REG_HID_PADCNT = lgy11->padcnt | BIT(14);
if(g_gbaKeypadWakeEnabled)
{
// Workaround for The Legend of Zelda - A Link to the Past.
// This game doesn't set the IRQ enable bit so we force it
// on the 3DS side. Unknown if other games have this bug.
REG_HID_PADCNT = lgy11->padcnt | BIT(14);
}
else
{
// Host-controlled sleep is woken explicitly through LGY_SLEEP_CNT.
REG_HID_PADCNT = 0;
}
}
else // IRQ_HID_PADCNT
{
Expand Down Expand Up @@ -120,13 +130,26 @@ Result LGY_prepareGbaMode(bool directBoot, const u32 saveType, const char *const
setFcramModeForLegacy(LGY_MODE_AGB);

// Setup IRQ handlers and sleep mode handling.
g_gbaKeypadWakeEnabled = true;
getLgy11Regs()->sleep = BIT(15);
IRQ_registerIsr(IRQ_LGY_SLEEP, 14, 0, lgySleepIsr);
IRQ_registerIsr(IRQ_HID_PADCNT, 14, 0, lgySleepIsr);

return RES_OK;
}

Result LGY_setGbaStopVector(const bool enabled)
{
const u32 cmdBuf[1] = {enabled};
return PXI_sendCmd(IPC_CMD9_SET_GBA_STOP_VECTOR, cmdBuf, 1);
}

void LGY11_setGbaKeypadWakeBridge(const bool enabled)
{
g_gbaKeypadWakeEnabled = enabled;
if(!enabled) REG_HID_PADCNT = 0;
}

Result LGY_setGbaRtc(const GbaRtc rtc)
{
return PXI_sendCmd(IPC_CMD9_SET_GBA_RTC, (u32*)&rtc, sizeof(GbaRtc) / 4);
Expand Down
Loading