diff --git a/arm11/source/hw/mcu.c b/arm11/source/hw/mcu.c index c6ad52f..b91ea04 100755 --- a/arm11/source/hw/mcu.c +++ b/arm11/source/hw/mcu.c @@ -1,87 +1,189 @@ -#include -#include -#include - -#include "hw/gpio.h" -#include "hw/gpulcd.h" -#include "hw/i2c.h" -#include "hw/mcu.h" - -enum { - PWR_BTN = 0, - PWR_HOLD = 1, - HOME_BTN = 2, - HOME_HOLD = 3, - WIFI_SWITCH = 4, - SHELL_CLOSE = 5, - SHELL_OPEN = 6, - VOL_SLIDER = 22, -}; - -static u8 cached_volume_slider = 0; -static u32 spec_hid = 0; - -static void MCU_UpdateVolumeSlider(void) -{ - cached_volume_slider = MCU_ReadReg(0x09); -} - -void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) -{ - u32 ints; - - // Reading the pending mask automagically acknowledges - // all the interrupts, so we must be sure to process all - // of them in one go, possibly keep reading from the - // register until it returns all zeroes - MCU_ReadRegBuf(0x10, (u8*)&ints, sizeof(ints)); - - while(ints != 0) { - u32 mcu_int_id = 31 - __builtin_clz(ints); - - switch(mcu_int_id) { - case PWR_BTN: - case PWR_HOLD: - spec_hid |= BUTTON_POWER; - break; - - case HOME_BTN: - case HOME_HOLD: - spec_hid |= BUTTON_HOME; - break; - - case WIFI_SWITCH: - spec_hid |= BUTTON_WIFI; - break; - - case VOL_SLIDER: - MCU_UpdateVolumeSlider(); - break; - - default: - break; - } - - ints &= ~BIT(mcu_int_id); - } -} - -void MCU_Init(void) -{ - u32 mask = 0xFFBF0000 | BIT(11); - I2C_writeRegBuf(3, 0x18, (const u8*)&mask, sizeof(mask)); - MCU_UpdateVolumeSlider(); - GPIO_setBit(19, 9); // enables MCU interrupts? -} - -u8 MCU_GetVolumeSlider(void) -{ - return cached_volume_slider; -} - -u32 MCU_GetSpecialHID(void) -{ - u32 ret = spec_hid; - spec_hid = 0; - return ret; -} +#include +#include +#include + +#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, +}; + +enum { + REG_VOL_SLIDER = 0x09, + + REG_BATTERY_LEVEL = 0x0B, + REG_CONSOLE_STATE = 0x0F, + + REG_INT_MASK = 0x10, + REG_INT_EN = 0x18, + + REG_LCD_STATE = 0x22, + + REG_LED_WIFI = 0x2A, + REG_LED_CAMERA = 0x2B, + REG_LED_SLIDER = 0x2C, + REG_LED_NOTIF = 0x2D, + + REG_RTC = 0x30, +}; + +typedef struct { + u8 delay; + u8 smoothing; + u8 loop_delay; + u8 unk; + u32 red[8]; + u32 green[8]; + u32 blue[8]; +} __attribute__((packed)) MCU_NotificationLED; + +static u8 cached_volume_slider = 0; +static u32 spec_hid = 0, shell_state = SHELL_OPEN; + +static void MCU_UpdateVolumeSlider(void) +{ + cached_volume_slider = MCU_ReadReg(REG_VOL_SLIDER); +} + +static void MCU_UpdateShellState(bool open) +{ + shell_state = open ? SHELL_OPEN : SHELL_CLOSED; +} + +u8 MCU_GetVolumeSlider(void) +{ + return cached_volume_slider; +} + +u32 MCU_GetSpecialHID(void) +{ + u32 ret = spec_hid | shell_state; + spec_hid = 0; + return ret; +} + +void MCU_SetNotificationLED(u32 period_ms, u32 color) +{ + u32 r, g, b; + MCU_NotificationLED led_state; + + // 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; + + // all colors look like 0x00ZZ00ZZ + // in order to alternate between + // LED "off" and the wanted color + r = (color >> 16) & 0xFF; + r |= r << 16; + for (int i = 0; i < 8; i++) + led_state.red[i] = r; + + g = (color >> 8) & 0xFF; + g |= g << 16; + for (int i = 0; i < 8; i++) + led_state.green[i] = g; + + b = color & 0xFF; + b |= b << 16; + for (int i = 0; i < 8; i++) + led_state.blue[i] = b; + + MCU_WriteRegBuf(REG_LED_NOTIF, (const u8*)&led_state, sizeof(led_state)); +} + +void MCU_ResetLED(void) +{ + MCU_WriteReg(REG_LED_WIFI, 0); + MCU_WriteReg(REG_LED_CAMERA, 0); + MCU_WriteReg(REG_LED_SLIDER, 0); + MCU_SetNotificationLED(0, 0); +} + +void MCU_PushToLCD(bool enable) +{ + MCU_WriteReg(REG_LCD_STATE, enable ? 0x2A : 0x01); +} + +void MCU_HandleInterrupts(u32 __attribute__((unused)) irqn) +{ + u32 ints; + + // 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)); + + while(ints != 0) { + u32 mcu_int_id = 31 - __builtin_clz(ints); + + 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_PushToLCD(true); + MCU_UpdateShellState(true); + TIMER_WaitTicks(CLK_MS_TO_TICKS(10)); + MCU_ResetLED(); + break; + + case MCU_SHELL_CLOSE: + MCU_PushToLCD(false); + MCU_UpdateShellState(false); + TIMER_WaitTicks(CLK_MS_TO_TICKS(10)); + break; + + case MCU_VOL_SLIDER: + MCU_UpdateVolumeSlider(); + break; + + default: + break; + } + + ints &= ~BIT(mcu_int_id); + } +} + +void MCU_Init(void) +{ + u32 mask = 0xFFBF0800; + MCU_WriteRegBuf(REG_INT_EN, (const u8*)&mask, sizeof(mask)); + MCU_ResetLED(); + + MCU_UpdateVolumeSlider(); + MCU_UpdateShellState(MCU_ReadReg(REG_CONSOLE_STATE) & BIT(1)); + + GPIO_setBit(19, 9); +} diff --git a/arm11/source/hw/mcu.h b/arm11/source/hw/mcu.h index 9758708..400c3e4 100755 --- a/arm11/source/hw/mcu.h +++ b/arm11/source/hw/mcu.h @@ -7,12 +7,18 @@ #define MCU_INTERRUPT (0x71) #define I2C_MCU_DEVICE (3) -void MCU_HandleInterrupts(u32 irqn); -void MCU_Init(void); - u8 MCU_GetVolumeSlider(void); u32 MCU_GetSpecialHID(void); +void MCU_SetNotificationLED(u32 period_ms, u32 color); +void MCU_ResetLED(void); + +void MCU_PushToLCD(bool enable); + +void MCU_HandleInterrupts(u32 irqn); + +void MCU_Init(void); + static inline u8 MCU_ReadReg(u8 addr) { u8 val; @@ -20,7 +26,7 @@ static inline u8 MCU_ReadReg(u8 addr) return val; } -static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u8 size) +static inline bool MCU_ReadRegBuf(u8 addr, u8 *buf, u32 size) { return I2C_readRegBuf(I2C_MCU_DEVICE, addr, buf, size); } @@ -30,7 +36,7 @@ static inline bool MCU_WriteReg(u8 addr, u8 val) return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, &val, 1); } -static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u8 size) +static inline bool MCU_WriteRegBuf(u8 addr, const u8 *buf, u32 size) { return I2C_writeRegBuf(I2C_MCU_DEVICE, addr, buf, size); } diff --git a/arm11/source/main.c b/arm11/source/main.c index a4d30fb..892f412 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -14,9 +14,8 @@ #include "system/sys.h" -static bool legacy = false; - static GlobalSharedMemory SharedMemory_State; + static const u8 brightness_lvls[] = { 0x10, 0x17, 0x1E, 0x25, 0x2C, 0x34, 0x3C, 0x44, @@ -27,9 +26,7 @@ static int prev_bright_lvl = -1; void VBlank_Handler(u32 __attribute__((unused)) irqn) { - int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2); - cur_bright_lvl %= countof(brightness_lvls); - + int cur_bright_lvl = (MCU_GetVolumeSlider() >> 2) % countof(brightness_lvls); if (cur_bright_lvl != prev_bright_lvl) { prev_bright_lvl = cur_bright_lvl; LCD_SetBrightness(brightness_lvls[cur_bright_lvl]); @@ -43,6 +40,8 @@ void VBlank_Handler(u32 __attribute__((unused)) irqn) ARM_DMB(); } +static bool legacy = false; + void PXI_RX_Handler(u32 __attribute__((unused)) irqn) { u32 ret, msg, cmd, argc, args[PXI_MAX_ARGS]; @@ -90,6 +89,12 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) break; } + case PXI_NVRAM_ONLINE: + { + ret = (NVRAM_Status() & NVRAM_SR_WIP) == 0; + break; + } + case PXI_NVRAM_READ: { ARM_InvDC_Range((void*)args[1], args[2]); @@ -100,6 +105,13 @@ void PXI_RX_Handler(u32 __attribute__((unused)) irqn) break; } + case PXI_NOTIFY_LED: + { + MCU_SetNotificationLED(args[0], args[1]); + ret = 0; + break; + } + /* New CMD template: case CMD_ID: { diff --git a/arm11/source/system/sys.c b/arm11/source/system/sys.c index 49141c5..69d2f6a 100755 --- a/arm11/source/system/sys.c +++ b/arm11/source/system/sys.c @@ -101,7 +101,7 @@ void SYS_CoreZeroInit(void) GPU_SetFramebufferMode(0, PDC_RGB24); GPU_SetFramebufferMode(1, PDC_RGB24); - MCU_WriteReg(0x22, 0x2A); + MCU_PushToLCD(true); TIMER_WaitTicks(CLK_MS_TO_TICKS(10)); } diff --git a/arm9/source/common/hid.c b/arm9/source/common/hid.c index 9eaed2a..a7bd26d 100644 --- a/arm9/source/common/hid.c +++ b/arm9/source/common/hid.c @@ -92,8 +92,6 @@ bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, in return true; } -#include "ui.h" - u32 InputWait(u32 timeout_sec) { static u64 delay = 0; u64 timer = timer_start(); diff --git a/arm9/source/system/spiflash.h b/arm9/source/system/spiflash.h index 77a7301..a3af1c6 100644 --- a/arm9/source/system/spiflash.h +++ b/arm9/source/system/spiflash.h @@ -27,7 +27,7 @@ // true if spiflash is installed, false otherwise static inline bool spiflash_get_status(void) { // there should probably be a command for this... - return true; + return PXI_DoCMD(PXI_NVRAM_ONLINE, NULL, 0); } static inline void spiflash_read(u32 offset, u32 size, u8 *buf) diff --git a/common/hid_map.h b/common/hid_map.h index 4544b1f..1ed722a 100755 --- a/common/hid_map.h +++ b/common/hid_map.h @@ -24,9 +24,12 @@ #define BUTTON_WIFI ((u32)1 << 14) #define BUTTON_TOUCH ((u32)1 << 15) -#define CART_INSERT ((u32)1 << 16) -#define CART_EJECT ((u32)1 << 17) -#define SD_INSERT ((u32)1 << 18) -#define SD_EJECT ((u32)1 << 19) +#define SHELL_OPEN ((u32)1 << 16) +#define SHELL_CLOSED ((u32)1 << 17) + +#define CART_INSERT ((u32)1 << 18) +#define CART_EJECT ((u32)1 << 19) +#define SD_INSERT ((u32)1 << 20) +#define SD_EJECT ((u32)1 << 21) #define TIMEOUT_HID ((u32)1 << 31) diff --git a/common/pxi.h b/common/pxi.h index b6ca971..c1b316a 100644 --- a/common/pxi.h +++ b/common/pxi.h @@ -21,7 +21,10 @@ enum { PXI_I2C_READ, PXI_I2C_WRITE, + PXI_NVRAM_ONLINE, PXI_NVRAM_READ, + + PXI_NOTIFY_LED, }; /*