diff --git a/include/arm11/hardware/mcu.h b/include/arm11/hardware/mcu.h index 181cdaa..161ae08 100644 --- a/include/arm11/hardware/mcu.h +++ b/include/arm11/hardware/mcu.h @@ -19,19 +19,33 @@ */ #include "types.h" +#include "arm11/hardware/i2c.h" -#define MCU_HID_POWER_BUTTON_PRESSED (1u) -#define MCU_HID_POWER_BUTTON_LONG_PRESSED (1u<<1) -#define MCU_HID_HOME_BUTTON_PRESSED (1u<<2) -#define MCU_HID_HOME_BUTTON_RELEASED (1u<<3) -#define MCU_HID_HOME_BUTTON_NOT_HELD (1u<<1) -#define MCU_HID_SHELL_GOT_CLOSED (1u<<5) -#define MCU_HID_SHELL_GOT_OPENED (1u<<6) - typedef enum { - PWLED_NORMAL = 0u, + MCU_REG_VERS_HIGH = 0x00u, + MCU_REG_VERS_LOW = 0x01u, + MCU_REG_3D_SLIDER = 0x08u, + MCU_REG_VOL_SLIDER = 0x09u, // 0-0x3F + MCU_REG_BATTERY = 0x0Bu, + MCU_REG_EX_HW_STATE = 0x0Fu, + MCU_REG_EVENTS = 0x10u, + MCU_REG_EVENT_MASK = 0x18u, + MCU_REG_POWER = 0x20u, + MCU_REG_LCDs = 0x22u, + MCU_REG_POWER_LED = 0x29u, + MCU_REG_WIFI_LED = 0x2Au, + MCU_REG_CAM_LED = 0x2Bu, + MCU_REG_3D_LED = 0x2Cu, + MCU_REG_RTC_TIME = 0x30u, + MCU_REG_RAW_STATE = 0x7Fu +} McuReg; + +typedef enum +{ + PWLED_AUTO = 0u, + //PWLED_BLUE = 1u, // wtf is "forced default blue"? PWLED_SLEEP = 2u, PWLED_OFF = 3u, PWLED_RED = 4u, @@ -42,17 +56,89 @@ typedef enum void MCU_init(void); -void MCU_disableLEDs(void); -void MCU_powerOnLCDs(void); -void MCU_powerOffLCDs(void); -void MCU_triggerPowerOff(void); -void MCU_triggerReboot(void); -u8 MCU_readBatteryLevel(void); -u8 MCU_readExternalHwState(void); -u8 MCU_readSystemModel(void); -void MCU_readRTC(void *rtc); -u32 MCU_readReceivedIrqs(void); -bool MCU_setIrqBitmask(u32 mask); -u8 MCU_readHidHeld(void); -bool MCU_powerOnLcdBacklights(void); -bool MCU_setPowerLedState(PwLedState state); + +bool MCU_setEventMask(u32 mask); + +u32 MCU_getEvents(u32 mask); + +u32 MCU_waitEvents(u32 mask); + +u8 MCU_readReg(McuReg reg); + +bool MCU_writeReg(McuReg reg, u8 data); + +bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size); + +bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size); + + +static inline u8 MCU_getBatteryLevel(void) +{ + u8 state; + + if(!MCU_readRegBuf(MCU_REG_BATTERY, &state, 1)) return 0; + + return state; +} + +static inline u8 MCU_getExternalHwState(void) +{ + return MCU_readReg(MCU_REG_EX_HW_STATE); +} + +static inline void MCU_powerOffSys(void) +{ + I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u); +} + +static inline void MCU_rebootSys(void) +{ + I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u<<2); +} + +static inline void MCU_powerOnLCDs(void) +{ + // bit1 = lcd power enable for both screens + MCU_writeReg(MCU_REG_LCDs, 1u<<1); +} + +static inline void MCU_powerOffLCDs(void) +{ + // bit0 = lcd power disable for both screens (also disables backlight) + MCU_writeReg(MCU_REG_LCDs, 1u); +} + +static inline bool MCU_powerOnLcdLights(void) +{ + return MCU_writeReg(MCU_REG_LCDs, 1<<5 | 1<<3); // bit3 = lower screen, bit5 = upper +} + +static inline bool MCU_setPowerLedState(PwLedState state) +{ + return MCU_writeReg(MCU_REG_POWER_LED, state); +} + +static inline bool MCU_getRTCTime(u8 *rtc) +{ + if(!rtc) return true; + + return MCU_readRegBuf(MCU_REG_RTC_TIME, rtc, 8); +} + +static inline u8 MCU_getSystemModel(void) +{ + u8 buf[10]; + + if(!MCU_readRegBuf(MCU_REG_RAW_STATE, buf, sizeof(buf))) return 0xFF; + + return buf[9]; +} + +static inline u8 MCU_getHidHeld(void) +{ + u8 data[19]; + + if(!MCU_readRegBuf(MCU_REG_RAW_STATE, data, sizeof(data))) return 0xFF; + + return data[18]; +} diff --git a/include/hardware/gfx.h b/include/hardware/gfx.h index c2a8c54..e04b5fc 100644 --- a/include/hardware/gfx.h +++ b/include/hardware/gfx.h @@ -22,23 +22,23 @@ #include "types.h" -#define SCREEN_TOP (1) -#define SCREEN_SUB (0) +#define SCREEN_TOP (0u) +#define SCREEN_BOT (1u) -#define SCREEN_WIDTH_TOP (400) -#define SCREEN_HEIGHT_TOP (240) +#define SCREEN_WIDTH_TOP (400u) +#define SCREEN_HEIGHT_TOP (240u) #define SCREEN_SIZE_TOP (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2) -#define SCREEN_WIDTH_SUB (320) -#define SCREEN_HEIGHT_SUB (240) -#define SCREEN_SIZE_SUB (SCREEN_WIDTH_SUB * SCREEN_HEIGHT_SUB * 2) +#define SCREEN_WIDTH_BOT (320u) +#define SCREEN_HEIGHT_BOT (240u) +#define SCREEN_SIZE_BOT (SCREEN_WIDTH_BOT * SCREEN_HEIGHT_BOT * 2) -#define FRAMEBUF_TOP_A_1 (VRAM_BASE) -#define FRAMEBUF_SUB_A_1 (FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP) -#define FRAMEBUF_TOP_A_2 (VRAM_BASE + 0x100000) -#define FRAMEBUF_SUB_A_2 (FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP) +#define FRAMEBUF_TOP_A_1 ((void*)VRAM_BASE) +#define FRAMEBUF_BOT_A_1 ((void*)FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP) +#define FRAMEBUF_TOP_A_2 ((void*)VRAM_BASE + 0x100000) +#define FRAMEBUF_BOT_A_2 ((void*)FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP) -#define RENDERBUF_TOP (VRAM_BASE + 0x200000 - SCREEN_SIZE_TOP - SCREEN_SIZE_SUB) -#define RENDERBUF_SUB (VRAM_BASE + 0x200000 - SCREEN_SIZE_SUB) +#define RENDERBUF_TOP ((void*)VRAM_BASE + 0x200000 - SCREEN_SIZE_TOP - SCREEN_SIZE_BOT) +#define RENDERBUF_BOT ((void*)VRAM_BASE + 0x200000 - SCREEN_SIZE_BOT) #define DEFAULT_BRIGHTNESS (0x30) @@ -66,9 +66,9 @@ void GFX_setBrightness(u32 top, u32 sub); void* GFX_getFramebuffer(u8 screen); void GFX_swapFramebufs(void); void GFX_waitForEvent(GfxEvent event, bool discard); -void GFX_init(bool clearScreens); -void GFX_enterLowPowerState(void); -void GFX_returnFromLowPowerState(void); +void GFX_init(void); +//void GFX_enterLowPowerState(void); +//void GFX_returnFromLowPowerState(void); void GFX_deinit(bool keepLcdsOn); #endif diff --git a/source/arm11/console.c b/source/arm11/console.c index 7aee7c6..bd640d2 100644 --- a/source/arm11/console.c +++ b/source/arm11/console.c @@ -526,12 +526,12 @@ PrintConsole* consoleInit(int screen, PrintConsole* console, bool clear) { console->consoleInitialised = 1; - if(screen==1) { + if(screen==0) { console->frameBuffer = (u16*)RENDERBUF_TOP; console->consoleWidth = 66; console->windowWidth = 66; } - else console->frameBuffer = (u16*)RENDERBUF_SUB; + else console->frameBuffer = (u16*)RENDERBUF_BOT; if(clear) consoleCls('2'); diff --git a/source/arm11/debug.c b/source/arm11/debug.c index da0d2fc..ce2c551 100644 --- a/source/arm11/debug.c +++ b/source/arm11/debug.c @@ -36,10 +36,10 @@ noreturn void panic() { enterCriticalSection(); - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n"); GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); //PXI_sendPanicCmd(IPC_CMD9_PANIC); @@ -50,7 +50,7 @@ noreturn void panic() hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } @@ -58,11 +58,11 @@ noreturn void panicMsg(const char *msg) { enterCriticalSection(); - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\n"); ee_printf("\nERROR MESSAGE:\n%s\n", msg); GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); //PXI_sendPanicCmd(IPC_CMD9_PANIC); @@ -73,7 +73,7 @@ noreturn void panicMsg(const char *msg) hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } @@ -92,7 +92,7 @@ noreturn void guruMeditation(u8 type, const u32 *excStack) if(prevHash != debugHash) codeChanged = true;*/ - consoleInit(SCREEN_SUB, NULL, false); + consoleInit(SCREEN_BOT, NULL, false); if(excStack[16] & 0x20) instSize = 2; // Processor was in Thumb mode? if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort @@ -131,7 +131,7 @@ noreturn void guruMeditation(u8 type, const u32 *excStack) //if(codeChanged) ee_printf("Attention: RO section data changed!!"); GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); //PXI_sendPanicCmd(IPC_CMD9_EXCEPTION); @@ -142,7 +142,7 @@ noreturn void guruMeditation(u8 type, const u32 *excStack) hidScanInput(); } while(!(hidKeysDown() & (KEY_A | KEY_B | KEY_X | KEY_Y))); - MCU_triggerPowerOff(); + MCU_powerOffSys(); while(1) __wfi(); } diff --git a/source/arm11/hardware/gfx.c b/source/arm11/hardware/gfx.c index 83413d2..843bab0 100644 --- a/source/arm11/hardware/gfx.c +++ b/source/arm11/hardware/gfx.c @@ -85,103 +85,97 @@ #define REG_GX_PPF_TC_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C28)) // Texture copy output width and gap in 16 byte units. -static u32 activeFb = 0; -static bool eventTable[6] = {false}; +static struct +{ + u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen. + bool lcdIdsRead; + bool events[6]; + u32 activeFb; + void *framebufs[2][4]; // A1, A2, B1, B2 + u32 formats[2]; // Top, bottom +} g_gfxState = +{ + 0, + false, + {false, false, false, false, false, false}, + 0, + { + {FRAMEBUF_TOP_A_1, FRAMEBUF_TOP_A_2, FRAMEBUF_TOP_A_1, FRAMEBUF_TOP_A_2}, + {FRAMEBUF_BOT_A_1, FRAMEBUF_BOT_A_2, FRAMEBUF_BOT_A_1, FRAMEBUF_BOT_A_2} + }, + {8<<16 | 3<<8 | 1<<6 | 0<<4 | 3, 8<<16 | 3<<8 | 0<<6 | 0<<4 | 3} +}; +static u8 fmt2PixSize(u32 format) +{ + u8 size; + + switch(format & 7u) + { + // Pretend RGBA8 doesn't exist because it makes no sense for framebuffers. + //case 0: // RGBA8888 + // size = 4; + // break; + case 1: // RGBA8880 + size = 3; + break; + default: // 2 = RGBA5650, 3 = RGBA5551, 4 = RGBA4444 + size = 2; + } + + return size; +} + static void gfxSetupFramebuf(u8 lcd) { if(lcd > 1) return; - static const u32 framebufCfgs[2][25] = + static const u32 framebufCfgs[2][24] = { { // 0-0x4C - 450, - 209, - 449, - 449, - 0, - 207, - 209, - 453<<16 | 449, - 1<<16 | 0, - 413, - 2, - 402, - 402, - 402, - 1, - 2, - 406<<16 | 402, - 0, - 0<<4 | 0, - 0<<16 | 0xFF<<8 | 0, + 450, 209, 449, 449, 0, 207, 209, 453<<16 | 449, + 1<<16 | 0, 413, 2, 402, 402, 402, 1, 2, + 406<<16 | 402, 0, 0<<4 | 0, 0<<16 | 0xFF<<8 | 0, // 0x5C-0x64 - SCREEN_WIDTH_TOP<<16 | SCREEN_HEIGHT_TOP, // Width and height + 400<<16 | 240, // Width and height 449<<16 | 209, 402<<16 | 2, - // 0x90 - SCREEN_HEIGHT_TOP * 2, // Stride (no gap) // 0x9C 0<<16 | 0 }, { // 0-0x4C - 450, - 209, - 449, - 449, - 205, - 207, - 209, - 453<<16 | 449, - 1<<16 | 0, - 413, - 82, - 402, - 402, - 79, - 80, - 82, - 408<<16 | 404, - 0, - 1<<4 | 1, - 0<<16 | 0<<8 | 0xFF, + 450, 209, 449, 449, 205, 207, 209, 453<<16 | 449, + 1<<16 | 0, 413, 82, 402, 402, 79, 80, 82, + 408<<16 | 404, 0, 1<<4 | 1, 0<<16 | 0<<8 | 0xFF, // 0x5C-0x64 - SCREEN_WIDTH_SUB<<16 | SCREEN_HEIGHT_SUB, // Width and height + 320<<16 | 240, // Width and height 449<<16 | 209, 402<<16 | 82, - // 0x90 - SCREEN_HEIGHT_SUB * 2, // Stride (no gap) // 0x9C 0<<16 | 0 } }; const u32 *const cfg = framebufCfgs[lcd]; - vu32 *regs; - if(lcd == 0) regs = (vu32*)0x10400400; - else regs = (vu32*)0x10400500; + vu32 *const regs = (vu32*)(GX_REGS_BASE + 0x400 + (0x100u * lcd)); - iomemcpy(regs, cfg, 0x50); // 0-0x4C - iomemcpy(regs + 23, &cfg[20], 0xC); // 0x5C-0x64 - regs[36] = cfg[23]; // 0x90 - regs[39] = cfg[24]; // 0x9C + const u32 format = g_gfxState.formats[lcd]; + iomemcpy(regs, cfg, 0x50); // 0-0x4C + iomemcpy(regs + 23, &cfg[20], 0xC); // 0x5C-0x64 + regs[36] = 240u * fmt2PixSize(format); // 0x90 stride without gap. + regs[39] = cfg[23]; // 0x9C - static const u32 addrAndFmt[2][3] = - { - {FRAMEBUF_TOP_A_1, FRAMEBUF_TOP_A_2, 8<<16 | 3<<8 | 1<<6 | 0<<4 | 3}, - {FRAMEBUF_SUB_A_1, FRAMEBUF_SUB_A_2, 8<<16 | 3<<8 | 0<<6 | 0<<4 | 3} - }; // 0x68, 0x6C, 0x94, 0x98 and 0x70 - regs[26] = addrAndFmt[lcd][0]; // Framebuffer A first address. - regs[27] = addrAndFmt[lcd][1]; // Framebuffer A second address. - regs[37] = addrAndFmt[lcd][0]; // Framebuffer B first address. - regs[38] = addrAndFmt[lcd][1]; // Framebuffer B second address. - regs[28] = addrAndFmt[lcd][2]; // Format GL_RGB5_A1_OES + regs[26] = (u32)g_gfxState.framebufs[lcd][0]; // Framebuffer A first address. + regs[27] = (u32)g_gfxState.framebufs[lcd][1]; // Framebuffer A second address. + regs[37] = (u32)g_gfxState.framebufs[lcd][2]; // Framebuffer B first address. + regs[38] = (u32)g_gfxState.framebufs[lcd][3]; // Framebuffer B second address. + regs[28] = format; // Format regs[32] = 0; // Gamma table index 0. @@ -245,52 +239,73 @@ void GFX_setBrightness(u32 top, u32 sub) void* GFX_getFramebuffer(u8 screen) { - static void *const framebufTable[2][2] = - { - {(void*)FRAMEBUF_SUB_A_2, (void*)FRAMEBUF_SUB_A_1}, - {(void*)FRAMEBUF_TOP_A_2, (void*)FRAMEBUF_TOP_A_1} - }; - - return framebufTable[screen][activeFb]; + return g_gfxState.framebufs[screen][g_gfxState.activeFb ^ 1u]; } void GFX_swapFramebufs(void) { - activeFb ^= 1u; + u32 fb = g_gfxState.activeFb; + fb ^= 1u; + g_gfxState.activeFb = fb; - const u32 tmp = 0x70000u | activeFb; // Acknowledge IRQs? - *((vu32*)0x10400478) = tmp; - *((vu32*)0x10400578) = tmp; + fb |= 0x70000u; // Acknowledge IRQs. + *((vu32*)0x10400478) = fb; + *((vu32*)0x10400578) = fb; } static void gfxIrqHandler(u32 intSource) { - atomic_store_explicit(&eventTable[intSource - IRQ_PSC0], true, memory_order_relaxed); + bool *const events = g_gfxState.events; + + atomic_store_explicit(&events[intSource - IRQ_PSC0], true, memory_order_relaxed); } void GFX_waitForEvent(GfxEvent event, bool discard) { - if(discard) atomic_store_explicit(&eventTable[event], false, memory_order_relaxed); - while(!atomic_load_explicit(&eventTable[event], memory_order_relaxed)) __wfe(); - atomic_store_explicit(&eventTable[event], false, memory_order_relaxed); + bool *const events = g_gfxState.events; + + if(discard) atomic_store_explicit(&events[event], false, memory_order_relaxed); + while(!atomic_load_explicit(&events[event], memory_order_relaxed)) __wfe(); + atomic_store_explicit(&events[event], false, memory_order_relaxed); +} + +static u16 getLcdIds(void) +{ + u16 ids; + + if(!g_gfxState.lcdIdsRead) + { + g_gfxState.lcdIdsRead = true; + + u16 top, bot; + I2C_writeReg(I2C_DEV_LCD0, 0x40, 0xFF); + I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); + I2C_writeReg(I2C_DEV_LCD1, 0x40, 0xFF); + I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2); + + ids = top>>8; + ids |= bot & 0xFF00u; + g_gfxState.lcdIds = ids; + } + else ids = g_gfxState.lcdIds; + + return ids; } static void resetLcdsMaybe(void) { - u16 top, bot; - I2C_writeReg(I2C_DEV_LCD0, 0x40, 0xFF); - I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); - I2C_writeReg(I2C_DEV_LCD1, 0x40, 0xFF); - I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2); + const u16 ids = getLcdIds(); - if(top>>8) I2C_writeReg(I2C_DEV_LCD0, 0xFE, 0xAA); + // Top screen + if(ids & 0xFFu) I2C_writeReg(I2C_DEV_LCD0, 0xFE, 0xAA); else { I2C_writeReg(I2C_DEV_LCD0, 0x11, 0x10); I2C_writeReg(I2C_DEV_LCD0, 0x50, 1); } - if(bot>>8) I2C_writeReg(I2C_DEV_LCD1, 0xFE, 0xAA); + // Bottom screen + if(ids>>8) I2C_writeReg(I2C_DEV_LCD1, 0xFE, 0xAA); else I2C_writeReg(I2C_DEV_LCD1, 0x11, 0x10); I2C_writeReg(I2C_DEV_LCD0, 0x60, 0); @@ -301,13 +316,9 @@ static void resetLcdsMaybe(void) static void waitLcdsReady(void) { - u16 top, bot; - I2C_writeReg(I2C_DEV_LCD0, 0x40, 0xFF); - I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); - I2C_writeReg(I2C_DEV_LCD1, 0x40, 0xFF); - I2C_readRegBuf(I2C_DEV_LCD1, 0x40, (u8*)&bot, 2); + const u16 ids = getLcdIds(); - if((top>>8) == 0 || (bot>>8) == 0) // Unknown LCD? + if((ids & 0xFFu) == 0 || (ids>>8) == 0) // Unknown LCD? { TIMER_sleepMs(150); } @@ -316,6 +327,7 @@ static void waitLcdsReady(void) u32 i = 0; do { + u16 top, bot; I2C_writeReg(I2C_DEV_LCD0, 0x40, 0x62); I2C_readRegBuf(I2C_DEV_LCD0, 0x40, (u8*)&top, 2); I2C_writeReg(I2C_DEV_LCD1, 0x40, 0x62); @@ -329,87 +341,7 @@ static void waitLcdsReady(void) } } -/*void GFX_init(bool clearScreens) -{ - if(REG_PDN_GPU_CNT == 0x1007F) GFX_deinit(false); - - // Reset - REG_PDN_GPU_CNT = 0x10000; - wait(12); - REG_PDN_GPU_CNT = 0x1007F; - REG_GX_GPU_CLK = 0x100; // 0x70100 on GPU init. - REG_GX_PSC_UNK = 0; - - // LCD framebuffer setup. - gfxSetupFramebuf(0); - gfxSetupFramebuf(1); - // Bit 0 next framebuffer, bit 4 current framebuffer?, bit 8 reset FIFO?, - // bit 16 ack HBlank IRQ, bit 17 ack VBlank IRQ, bit 18 ack error IRQ? - *((vu32*)0x10400478) = 0x70100; // Framebuffer select 0. - *((vu32*)0x10400578) = 0x70100; // Framebuffer select 0. - *((vu32*)0x10400474) = 0x10700; - *((vu32*)0x10400574) = 0x10700; - - // LCD reg setup. - REG_LCD_FILL_TOP = 1u<<24; // Force blackscreen - REG_LCD_FILL_BOT = 1u<<24; // Force blackscreen - *((vu32*)0x10202000) = 0; - *((vu32*)0x10202004) = 0xA390A39; - *((vu32*)0x10202014) = 0; - *((vu32*)0x1020200C) = 0x10001; - - // Register IRQ handlers. - IRQ_registerHandler(IRQ_PSC0, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PSC1, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PDC0, 14, 0, true, gfxIrqHandler); - IRQ_registerHandler(IRQ_PPF, 14, 0, true, gfxIrqHandler); - //IRQ_registerHandler(IRQ_P3D, 14, 0, true, gfxIrqHandler); - - // Backlight related stuff. - if((REG_LCD_LIGHT_PWM_TOP & 1u<<16) == 0) - { - *((vu32*)0x10202240) = 64; - *((vu32*)0x10202200) &= ~1u; - REG_LCD_LIGHT_PWM_TOP &= ~0x20000u; - } - if((REG_LCD_LIGHT_PWM_BOT & 1u<<16) == 0) - { - *((vu32*)0x10202A40) = 64; - *((vu32*)0x10202A00) &= ~1u; - REG_LCD_LIGHT_PWM_BOT &= ~0x20000u; - } - - GFX_setBrightness(DEFAULT_BRIGHTNESS, DEFAULT_BRIGHTNESS); - *((vu32*)0x10202014) = 1; - *((vu32*)0x1020200C) = 0; - - MCU_powerOnLCDs(); // Power on LCDs. - if(clearScreens) - { - // Warning. The GPU mem fill races against the console. - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC1, true); - GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_SUB, 1u<<9, SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC0, true); - - // The transfer engine is (sometimes) borked on screen init. - // Doing a dummy texture copy fixes it. - // TODO: Proper fix. - //GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)RENDERBUF_SUB, 0, 16); - } - waitLcdsReady(); - // Bit 0 enable? bit 8 HBlank IRQ enable, bit 9 VBlank IRQ enable, bit 10 error IRQ enable?, bit 16 output enable? - *((vu32*)0x10400474) = 0x10501; - *((vu32*)0x10400574) = 0x10501; - REG_LCD_LIGHT_PWM_TOP = 0x1023E; - REG_LCD_LIGHT_PWM_BOT = 0x1023E; - MCU_powerOnLcdBacklights(); - - REG_LCD_FILL_TOP = 0; - REG_LCD_FILL_BOT = 0; -}*/ -void GFX_init(bool clearScreens) +void GFX_init(void) { if(REG_PDN_GPU_CNT == 0x1007F) GFX_deinit(false); @@ -458,33 +390,32 @@ void GFX_init(bool clearScreens) TIMER_sleepMs(10); resetLcdsMaybe(); MCU_powerOnLCDs(); // Power on LCDs. - // Wait for MCU event 25. 24 on poweroff. - if(clearScreens) // TODO: Where does this belong? - { - // Warning. The GPU mem fill races against the console. - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC1, true); - GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_SUB, 1u<<9, SCREEN_SIZE_SUB, 0); - GFX_waitForEvent(GFX_EVENT_PSC0, true); + MCU_waitEvents(0x3Fu<<24); // Wait for MCU event 25. 24 on poweroff. + + GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT, 0, + (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT, 0); + GFX_waitForEvent(GFX_EVENT_PSC1, true); + GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_BOT, 1u<<9, SCREEN_SIZE_BOT, 0); + GFX_waitForEvent(GFX_EVENT_PSC0, true); + + // The transfer engine is (sometimes) borked on screen init. + // Doing a dummy texture copy fixes it. + // TODO: Proper fix. + GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)RENDERBUF_BOT, 0, 16); - // The transfer engine is (sometimes) borked on screen init. - // Doing a dummy texture copy fixes it. - // TODO: Proper fix. - GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)RENDERBUF_SUB, 0, 16); - } waitLcdsReady(); REG_LCD_LIGHT_PWM_TOP = 0x1023E; REG_LCD_LIGHT_PWM_BOT = 0x1023E; - MCU_powerOnLcdBacklights(); - // Wait for MCU event 29 and 27. 28 and 26 on poweroff. + MCU_powerOnLcdLights(); + MCU_waitEvents(0x3Fu<<24); // Wait for MCU event 29 (top) and 27 (bot). 28 and 26 on poweroff. // Weird VBlank wait? REG_LCD_FILL_TOP = 0; REG_LCD_FILL_BOT = 0; } -void GFX_enterLowPowerState(void) +// TODO: Sleep mode stuff needs some work. +/*void GFX_enterLowPowerState(void) { REG_LCD_FILL_TOP = 1u<<24; // Force blackscreen REG_LCD_FILL_BOT = 1u<<24; // Force blackscreen @@ -494,28 +425,29 @@ void GFX_enterLowPowerState(void) void GFX_returnFromLowPowerState(void) { - GFX_init(false); -} + GFX_init(); +}*/ void GFX_deinit(bool keepLcdsOn) { if(keepLcdsOn) { - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0); + GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT + 0x2A300, 0, + (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT + 0x2A300, 0); GFX_waitForEvent(GFX_EVENT_PSC1, true); - *((vu32*)(0x10400400+0x70)) = 0x80341; // Format GL_RGB8_OES. - *((vu32*)(0x10400400+0x78)) = 0; // Select first framebuffer. - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 3; // Stride (no gap). - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1 + 0x17700; // Bottom framebuffer first address. - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2 + 0x17700; // Bottom framebuffer second address. - *((vu32*)(0x10400500+0x70)) = 0x80301; // Format GL_RGB8_OES. - *((vu32*)(0x10400500+0x78)) = 0; // Select first framebuffer. - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 3; // Stride (no gap). + *((vu32*)(0x10400400+0x70)) = 0x80341; // Format GL_RGB8_OES. + *((vu32*)(0x10400400+0x78)) = 0; // Select first framebuffer. + *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 3; // Stride (no gap). + *((vu32*)(0x10400500+0x68)) = (u32)FRAMEBUF_BOT_A_1 + 0x17700; // Bottom framebuffer first address. + *((vu32*)(0x10400500+0x6C)) = (u32)FRAMEBUF_BOT_A_2 + 0x17700; // Bottom framebuffer second address. + *((vu32*)(0x10400500+0x70)) = 0x80301; // Format GL_RGB8_OES. + *((vu32*)(0x10400500+0x78)) = 0; // Select first framebuffer. + *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_BOT * 3; // Stride (no gap). } else { MCU_powerOffLCDs(); + MCU_waitEvents(0x3Fu<<24); GFX_setBrightness(0, 0); REG_LCD_LIGHT_PWM_TOP = 0; REG_LCD_LIGHT_PWM_BOT = 0; diff --git a/source/arm11/hardware/hid.c b/source/arm11/hardware/hid.c index a4e41bc..234450e 100644 --- a/source/arm11/hardware/hid.c +++ b/source/arm11/hardware/hid.c @@ -36,44 +36,32 @@ static u32 kHeld, kDown, kUp; static u32 extraKeys; //TouchPos tPos; //CpadPos cPos; -static volatile bool mcuIrq; -static void hidIrqHandler(UNUSED u32 intSource); - void hidInit(void) { - kUp = kDown = kHeld = 0; - mcuIrq = false; + static bool inited = false; + if(inited) return; + inited = true; - (void)MCU_readReceivedIrqs(); - u8 state = MCU_readExternalHwState(); + kUp = kDown = kHeld = 0; + + MCU_init(); + u8 state = MCU_getExternalHwState(); u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted. tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state - state = MCU_readHidHeld(); + state = MCU_getHidHeld(); tmp |= ~state<<1 & KEY_HOME; // Current HOME button state extraKeys = tmp; - IRQ_registerHandler(IRQ_CTR_MCU, 14, 0, true, hidIrqHandler); - MCU_setIrqBitmask(0xFFBF3F80u); - // Configure GPIO for MCU event IRQs - GPIO_config(GPIO_4_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE); - //CODEC_init(); } -static void hidIrqHandler(UNUSED u32 intSource) +static void updateMcuHidState(void) { - mcuIrq = true; -} - -static void updateMcuIrqState(void) -{ - if(!mcuIrq) return; - mcuIrq = false; - - const u32 state = MCU_readReceivedIrqs(); + const u32 state = MCU_getEvents(0x40C07F); + if(state == 0) return; u32 tmp = extraKeys; tmp |= state & (KEY_POWER | KEY_POWER_HELD | KEY_HOME); // Power button pressed/held, HOME button pressed @@ -117,7 +105,7 @@ static void updateMcuIrqState(void) void hidScanInput(void) { - updateMcuIrqState(); + updateMcuHidState(); const u32 kOld = kHeld; kHeld = /*rawCodec2Hid() |*/ REG_HID_PAD; diff --git a/source/arm11/hardware/mcu.c b/source/arm11/hardware/mcu.c index 52d10cc..6358099 100644 --- a/source/arm11/hardware/mcu.c +++ b/source/arm11/hardware/mcu.c @@ -16,125 +16,94 @@ * along with this program. If not, see . */ -/* - * Based on code from https://github.com/smealum/ctrulib - */ - -#include "mem_map.h" -#include "arm11/hardware/i2c.h" +#include #include "arm11/hardware/mcu.h" +#include "arm11/hardware/i2c.h" +#include "arm11/hardware/interrupt.h" +#include "arm11/hardware/gpio.h" -enum McuRegisters { - RegBattery = 0x0Bu, - RegExHW = 0x0Fu, - RegPower = 0x20u, - RegLCDs = 0x22u, - RegWifiLED = 0x2Au, - RegCamLED = 0x2Bu, - Reg3DLED = 0x2Cu, - RegRTC = 0x30u, - RegSysModel = 0x7Fu -}; +static bool g_mcuIrq = false; +static u32 g_events = 0; +static void mcuIrqHandler(UNUSED u32 intSource); + void MCU_init(void) { + static bool inited = false; + if(inited) return; + inited = true; + I2C_init(); + + atomic_store_explicit(&g_mcuIrq, true, memory_order_relaxed); + (void)MCU_getEvents(0xFFFFFFFFu); + + MCU_setEventMask(0xC0BF3F80); + // Configure GPIO for MCU event IRQs + GPIO_config(GPIO_4_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE); + IRQ_registerHandler(IRQ_CTR_MCU, 14, 0, true, mcuIrqHandler); } -void MCU_disableLEDs(void) +static void mcuIrqHandler(UNUSED u32 intSource) { - // disable wifi LED - I2C_writeReg(I2C_DEV_CTR_MCU, RegWifiLED, 0); - - // disable 3D LED - I2C_writeReg(I2C_DEV_CTR_MCU, Reg3DLED, 0); - - // disable camera LED - I2C_writeReg(I2C_DEV_CTR_MCU, RegCamLED, 0); + g_mcuIrq = true; } -void MCU_powerOnLCDs(void) +bool MCU_setEventMask(u32 mask) { - // bit1 = lcd power enable for both screens - I2C_writeReg(I2C_DEV_CTR_MCU, RegLCDs, 1<<1); + return MCU_writeRegBuf(MCU_REG_EVENT_MASK, (const u8*)&mask, 4); } -void MCU_powerOffLCDs(void) +u32 MCU_getEvents(u32 mask) { - // bit0 = lcd power disable for both screens (also disables backlight) - I2C_writeReg(I2C_DEV_CTR_MCU, RegLCDs, 1); + u32 events = g_events; + + if(atomic_load_explicit(&g_mcuIrq, memory_order_relaxed)) + { + atomic_store_explicit(&g_mcuIrq, false, memory_order_relaxed); + + u32 data; + if(!MCU_readRegBuf(MCU_REG_EVENTS, (u8*)&data, 4)) return 0; + + events |= data; + } + + g_mcuIrq = events & ~mask; + + return events & mask; } -void MCU_triggerPowerOff(void) +u32 MCU_waitEvents(u32 mask) { - I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, RegPower, 1); + u32 events; + + while((events = MCU_getEvents(mask)) == 0u) + { + __wfi(); + } + + return events; } -void MCU_triggerReboot(void) +u8 MCU_readReg(McuReg reg) { - I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, RegPower, 1u << 2); + return I2C_readReg(I2C_DEV_CTR_MCU, reg); } -u8 MCU_readBatteryLevel(void) +bool MCU_writeReg(McuReg reg, u8 data) { - u8 state; - - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, RegBattery, &state, 1)) - return 0; - - return state; + return I2C_writeReg(I2C_DEV_CTR_MCU, reg, data); } -u8 MCU_readExternalHwState(void) +bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size) { - return I2C_readReg(I2C_DEV_CTR_MCU, RegExHW); + return I2C_readRegBuf(I2C_DEV_CTR_MCU, reg, out, size); } -u8 MCU_readSystemModel(void) +bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size) { - u8 sysinfo[0x13]; - - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, RegSysModel, sysinfo, sizeof sysinfo)) - return 0xFF; - - return sysinfo[9]; -} - -void MCU_readRTC(void *rtc) -{ - if(!rtc) return; - - I2C_readRegBuf(I2C_DEV_CTR_MCU, RegRTC, rtc, 8); -} - -u32 MCU_readReceivedIrqs(void) -{ - u32 data; - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, 0x10, (u8*)&data, 4)) return 0; - return data; -} - -bool MCU_setIrqBitmask(u32 mask) -{ - return I2C_writeRegBuf(I2C_DEV_CTR_MCU, 0x18, (const u8*)&mask, 4); -} - -u8 MCU_readHidHeld(void) -{ - u8 data[19]; - if(!I2C_readRegBuf(I2C_DEV_CTR_MCU, 0x7F, data, sizeof(data))) return 0xFF; - return data[18]; -} - -bool MCU_powerOnLcdBacklights(void) -{ - return I2C_writeReg(I2C_DEV_CTR_MCU, 0x22, 1<<5 | 1<<3); // bit3 = lower screen, bit5 = upper -} - -bool MCU_setPowerLedState(PwLedState state) -{ - return I2C_writeReg(I2C_DEV_CTR_MCU, 0x29, state); + return I2C_writeRegBuf(I2C_DEV_CTR_MCU, reg, in, size); } diff --git a/source/arm11/main.c b/source/arm11/main.c index 6b45e80..cde5c78 100644 --- a/source/arm11/main.c +++ b/source/arm11/main.c @@ -31,14 +31,14 @@ void clearScreens(void) { - GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_SUB, 1u<<9, SCREEN_SIZE_SUB, 0); + GX_memoryFill((u64*)RENDERBUF_TOP, 1u<<9, SCREEN_SIZE_TOP, 0, (u64*)RENDERBUF_BOT, 1u<<9, SCREEN_SIZE_BOT, 0); GFX_waitForEvent(GFX_EVENT_PSC0, true); } void updateScreens(void) { GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_waitForEvent(GFX_EVENT_PPF, true); // Texture copy GFX_swapFramebufs(); GFX_waitForEvent(GFX_EVENT_PDC0, true); // VBlank @@ -46,7 +46,7 @@ void updateScreens(void) int main(void) { - GFX_init(true); + GFX_init(); consoleInit(SCREEN_TOP, NULL, false); CODEC_init(); diff --git a/source/arm11/power.c b/source/arm11/power.c index dd37cfc..9e6ef54 100644 --- a/source/arm11/power.c +++ b/source/arm11/power.c @@ -42,7 +42,7 @@ noreturn void power_off(void) { power_safe_halt(); - MCU_triggerPowerOff(); + MCU_powerOffSys(); __cpsid(aif); while(1) __wfi(); @@ -52,7 +52,7 @@ noreturn void power_reboot(void) { power_safe_halt(); - MCU_triggerReboot(); + MCU_rebootSys(); __cpsid(aif); while(1) __wfi(); diff --git a/source/arm9/debug.c b/source/arm9/debug.c index 6097da8..5fc9881 100644 --- a/source/arm9/debug.c +++ b/source/arm9/debug.c @@ -39,8 +39,8 @@ noreturn void panic() while(1) { const u32 color = RGB8_to_565(0, 255, 0)<<16 | RGB8_to_565(0, 255, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } @@ -53,8 +53,8 @@ noreturn void panicMsg(UNUSED const char *msg) while(1) { const u32 color = RGB8_to_565(0, 255, 0)<<16 | RGB8_to_565(0, 255, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } @@ -69,8 +69,8 @@ noreturn void guruMeditation(UNUSED u8 type, UNUSED const u32 *excStack) while(1) { const u32 color = RGB8_to_565(255, 0, 0)<<16 | RGB8_to_565(255, 0, 0); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); } } diff --git a/source/fb_assert.c b/source/fb_assert.c index f475852..329e7d9 100644 --- a/source/fb_assert.c +++ b/source/fb_assert.c @@ -43,7 +43,7 @@ noreturn void __fb_assert(const char *const str, u32 line) #elif ARM11 ee_printf("Assertion failed: %s:%" PRIu32, str, line); GX_textureCopy((u64*)RENDERBUF_TOP, 0, (u64*)GFX_getFramebuffer(SCREEN_TOP), - 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); + 0, SCREEN_SIZE_TOP + SCREEN_SIZE_BOT); GFX_swapFramebufs(); //PXI_sendCmd(IPC_CMD9_PANIC, NULL, 0); #endif @@ -52,8 +52,8 @@ noreturn void __fb_assert(const char *const str, u32 line) { #ifdef ARM9 const u32 color = RGB8_to_565(0, 0, 255)<<16 | RGB8_to_565(0, 0, 255); - NDMA_fill((u32*)FRAMEBUF_SUB_A_1, color, SCREEN_SIZE_SUB); - NDMA_fill((u32*)FRAMEBUF_SUB_A_2, color, SCREEN_SIZE_SUB); + NDMA_fill((u32*)FRAMEBUF_BOT_A_1, color, SCREEN_SIZE_BOT); + NDMA_fill((u32*)FRAMEBUF_BOT_A_2, color, SCREEN_SIZE_BOT); #elif ARM11 __wfi(); #endif