parent
4a6603d110
commit
1c680e7d52
|
@ -46,15 +46,15 @@
|
|||
#define REG_GPIO3_DAT2 *(( vu16*)(GPIO_REGS_BASE + 0x28)) // WiFi.
|
||||
|
||||
|
||||
#define GPIO_INPUT (0u)
|
||||
#define GPIO_OUTPUT (1u)
|
||||
#define GPIO_EDGE_FALLING (0u)
|
||||
#define GPIO_EDGE_RISING (1u<<1)
|
||||
#define GPIO_IRQ_ENABLE (1u<<2)
|
||||
#define GPIO_INPUT (0u)
|
||||
#define GPIO_OUTPUT (1u)
|
||||
#define GPIO_NO_IRQ (0u)
|
||||
#define GPIO_IRQ_FALLING (1u<<2 | 0u)
|
||||
#define GPIO_IRQ_RISING (1u<<2 | 1u<<1)
|
||||
|
||||
|
||||
// bits 3-7 pin number, bits 0-3 reg index.
|
||||
#define MAKE_GPIO(pin, reg) ((pin)<<3 | (reg))
|
||||
#define MAKE_GPIO(pin, reg) ((pin)<<3 | (reg))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
@ -19,114 +19,656 @@
|
|||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "arm11/drivers/i2c.h"
|
||||
#include "arm11/drivers/mcu_regmap.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
#define DEFAULT_MCU_IRQ_MASK (~(MCU_IRQ_TOP_BL_ON | MCU_IRQ_TOP_BL_OFF | MCU_IRQ_BOT_BL_ON | \
|
||||
MCU_IRQ_BOT_BL_OFF | MCU_IRQ_LCD_POWER_ON | MCU_IRQ_LCD_POWER_OFF | \
|
||||
MCU_IRQ_VOL_SLIDER_CHANGE | MCU_IRQ_BATT_CHARGE_START | \
|
||||
MCU_IRQ_BATT_CHARGE_STOP | MCU_IRQ_ACC_DATA_READY | MCU_IRQ_ACC_RW_DONE | \
|
||||
MCU_IRQ_WATCHDOG | MCU_IRQ_SHELL_OPEN | MCU_IRQ_SHELL_CLOSE | \
|
||||
MCU_IRQ_WIFI_PRESS | MCU_IRQ_HOME_RELEASE | MCU_IRQ_HOME_PRESS | \
|
||||
MCU_IRQ_POWER_HELD | MCU_IRQ_POWER_PRESS))
|
||||
|
||||
|
||||
/*typedef struct
|
||||
{
|
||||
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;
|
||||
// TODO
|
||||
} PowerLedPattern;*/
|
||||
|
||||
typedef enum
|
||||
/*typedef struct
|
||||
{
|
||||
PWLED_AUTO = 0u,
|
||||
//PWLED_BLUE = 1u, // wtf is "forced default blue"?
|
||||
PWLED_SLEEP = 2u,
|
||||
PWLED_OFF = 3u,
|
||||
PWLED_RED = 4u,
|
||||
PWLED_BLUE = 5u,
|
||||
PWLED_BLINK_RED = 6u
|
||||
} PwLedState;
|
||||
// TODO
|
||||
} InfoLedPattern;*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 s; // Second.
|
||||
u8 min; // Minute.
|
||||
u8 h; // Hour.
|
||||
u8 dow; // Unused day of week.
|
||||
u8 d; // Day.
|
||||
u8 mon; // Month.
|
||||
u8 y; // Year.
|
||||
} RtcTimeDate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 min; // Minute.
|
||||
u8 h; // Hour.
|
||||
u8 d; // Day.
|
||||
u8 mon; // Month.
|
||||
u8 y; // Year.
|
||||
} AlarmTimeDate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 z;
|
||||
} AccData;
|
||||
|
||||
/*typedef struct
|
||||
{
|
||||
// 6 bytes timestamps.
|
||||
// 336 bytes step counts.
|
||||
} PedometerHistory;*/
|
||||
|
||||
|
||||
|
||||
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);
|
||||
// TODO: For most functions check if the return value on error makes sense.
|
||||
|
||||
/**
|
||||
* @brief Initializes the MCU driver.
|
||||
*/
|
||||
void MCU_init(void);
|
||||
|
||||
bool MCU_setEventMask(u32 mask);
|
||||
/**
|
||||
* @brief Reboots the MCU.
|
||||
*
|
||||
* @return Returns true on success and false on failure.
|
||||
*/
|
||||
//bool MCU_reboot(void);
|
||||
|
||||
u32 MCU_getEvents(u32 mask);
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] mask The mask
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u32 MCU_getIrqs(u32 mask);
|
||||
|
||||
u32 MCU_waitEvents(u32 mask);
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] mask The mask
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u32 MCU_waitIrqs(u32 mask);
|
||||
|
||||
|
||||
static inline u8 MCU_getBatteryLevel(void)
|
||||
{
|
||||
u8 state;
|
||||
/**
|
||||
* @brief Reads the MCU firmware version.
|
||||
*
|
||||
* @return Returns the MCU firmware version.
|
||||
*/
|
||||
u16 MCU_getFirmwareVersion(void);
|
||||
|
||||
if(!MCU_readRegBuf(MCU_REG_BATTERY, &state, 1)) return 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
/**
|
||||
* @brief Reads MCU status bits.
|
||||
*
|
||||
* @return Returns the MCU status bits.
|
||||
*/
|
||||
u8 MCU_getStatus(void);
|
||||
|
||||
static inline u8 MCU_getExternalHwState(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_EX_HW_STATE);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] status The status
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setStatus(u8 status);
|
||||
|
||||
static inline void MCU_powerOffSys(void)
|
||||
{
|
||||
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getLcdVcomTop(void);
|
||||
|
||||
static inline void MCU_rebootSys(void)
|
||||
{
|
||||
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_POWER, 1u<<2);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] vcom The vcom
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setLcdVcomTop(u8 vcom);
|
||||
|
||||
static inline void MCU_controlLCDPower(u8 bits)
|
||||
{
|
||||
MCU_writeReg(MCU_REG_LCDs, bits);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getLcdVcomBot(void);
|
||||
|
||||
static inline bool MCU_setPowerLedState(PwLedState state)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_POWER_LED, state);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] vcom The vcom
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setLcdVcomBot(u8 vcom);
|
||||
|
||||
static inline bool MCU_getRTCTime(u8 rtc[7])
|
||||
{
|
||||
if(!rtc) return true;
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_get3dSliderPosition(void);
|
||||
|
||||
return MCU_readRegBuf(MCU_REG_RTC_TIME, rtc, 7);
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getVolumeSliderPosition(void);
|
||||
|
||||
static inline u8 MCU_getSystemModel(void)
|
||||
{
|
||||
u8 buf[10];
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getBatteryTemperature(void);
|
||||
|
||||
if(!MCU_readRegBuf(MCU_REG_RAW_STATE, buf, sizeof(buf))) return 0xFF;
|
||||
|
||||
return buf[9];
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
float MCU_getBatteryLevel(void);
|
||||
|
||||
static inline u8 MCU_getHidHeld(void)
|
||||
{
|
||||
u8 data[19];
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
float MCU_getBatteryVoltage(void);
|
||||
|
||||
if(!MCU_readRegBuf(MCU_REG_RAW_STATE, data, sizeof(data))) return 0xFF;
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u16 MCU_getExternalHardwareStatus(void);
|
||||
|
||||
return data[18];
|
||||
}
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u32 MCU_getIrqMask(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] mask The mask
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setIrqMask(u32 mask);
|
||||
|
||||
// TODO: MCU_setSystemPower()?
|
||||
|
||||
void MCU_powerOffSys(void);
|
||||
|
||||
void MCU_rebootSys(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] bits The bits
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setTwlIrq(u8 bits);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] bits The bits
|
||||
*/
|
||||
void MCU_setLcdPower(u8 bits);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getPoweroffDelay(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] delay The delay
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setPoweroffDelay(u8 delay);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getRegister0x25(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRegister0x25(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getRegister0x26(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRegister0x26(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getVolumeSliderPositionRaw(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setVolumeSliderPositionRaw(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getLedMasterBrightness(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] brightness The brightness
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setLedMasterBrightness(u8 brightness);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param pattern The pattern
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getPowerLedPattern(u8 pattern[5]); // TODO: Struct.
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] pattern The pattern
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setPowerLedPattern(const u8 pattern[5]); // TODO: Struct.
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getWifiLedState(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] state The state
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setWifiLedState(u8 state);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getCameraLedState(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] state The state
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setCameraLedState(u8 state);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_get3dLedState(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] state The state
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_set3dLedState(u8 state);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] pattern The pattern
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setInfoLedPattern(const u8 pattern[100]); // TODO: Struct.
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getInfoLedStatus(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param timeDate The time date
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getRtcTimeDate(RtcTimeDate *timeDate);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] timeDate The time date
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRtcTimeDate(const RtcTimeDate *timeDate);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getRtcErrorCorrection(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] correction The correction
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRtcErrorCorrection(u8 correction);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param timeDate The time date
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getAlarmTimeDate(AlarmTimeDate *timeDate);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] timeDate The time date
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setAlarmTimeDate(const AlarmTimeDate *timeDate);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u16 MCU_getRtcTick(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRegister0x3F(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return The acc configuration.
|
||||
*/
|
||||
AccCfg MCU_getAccelerometerConfig(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] cfg The configuration
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setAccelerometerConfig(AccCfg cfg);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] reg The register
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_readAccelerometerRegister(u8 reg);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] reg The register
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_writeAccelerometerRegister(u8 reg, u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param samples The samples
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getAccelerometerSamples(AccData *samples);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] steps The steps
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setPedometerStepCount(u32 steps);
|
||||
|
||||
// TODO: Reg 0x4E.
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param history The history
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getPedometerHistory(u8 history[6 + 336]); // TODO: Struct.
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getRegister0x50(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRegister0x50(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getRegister0x51(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setRegister0x51(u8 data);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param minMax The minimum maximum
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getVolumeSliderCalibrationPoints(u8 minMax[2]);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] minMax The minimum maximum
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setVolumeSliderCalibrationPoints(const u8 minMax[2]);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] off Off
|
||||
* @param out The out
|
||||
* @param[in] size The size
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_getFreeRamData(u8 off, u8 *out, u8 size);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @param[in] off Off
|
||||
* @param[in] in { parameter_description }
|
||||
* @param[in] size The size
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
bool MCU_setFreeRamData(u8 off, const u8 *in, u8 size);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getConsoleType(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getSystemModel(void);
|
||||
|
||||
/**
|
||||
* @brief { function_description }
|
||||
*
|
||||
* @return { description_of_the_return_value }
|
||||
*/
|
||||
u8 MCU_getEarlyButtonsHeld(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reads a single MCU register.
|
||||
*
|
||||
* @param[in] reg The MCU register to read.
|
||||
*
|
||||
* @return The MCU register data.
|
||||
*/
|
||||
u8 MCU_readReg(McuReg reg);
|
||||
|
||||
/**
|
||||
* @brief Writes a single MCU register.
|
||||
*
|
||||
* @param[in] reg The MCU register to write.
|
||||
* @param[in] data The data to write.
|
||||
*
|
||||
* @return Returns true on success and false on failure.
|
||||
*/
|
||||
bool MCU_writeReg(McuReg reg, u8 data);
|
||||
|
||||
/**
|
||||
* @brief Reads multiple MCU registers or buffers behind registers.
|
||||
*
|
||||
* @param[in] reg The MCU register(s) to read.
|
||||
* @param out The output data pointer.
|
||||
* @param[in] size The output buffer size.
|
||||
*
|
||||
* @return Returns true on success and false on failure.
|
||||
*/
|
||||
bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size);
|
||||
|
||||
/**
|
||||
* @brief Writes multiple MCU registers or buffers behind registers.
|
||||
*
|
||||
* @param[in] reg The MCU register(s) to write.
|
||||
* @param[in] in The input data pointer.
|
||||
* @param[in] size The input data size.
|
||||
*
|
||||
* @return Returns true on success and false on failure.
|
||||
*/
|
||||
bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size);
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of open_agb_firm
|
||||
* Copyright (C) 2022 derrek, profi200
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MCU_REG_VERS_MAJOR = 0x00u, // (ro) MCU firmware major version.
|
||||
MCU_REG_VERS_MINOR = 0x01u, // (ro) MCU firmware minor version.
|
||||
MCU_REG_STAT = 0x02u, // (rw) Reset status and TWL MCU emulation stuff.
|
||||
MCU_REG_LCD_VCOM_TOP = 0x03u, // (rw) Top LCD VCOM ("flicker").
|
||||
MCU_REG_LCD_VCOM_BOT = 0x04u, // (rw) Bottom LCD VCOM ("flicker").
|
||||
MCU_REG_FW_UPDATE = 0x05u, // (rw) 0x05-0x07 Firmware update magic "jhl" is written here. If we stop the transfer after the magic the MCU will just reset.
|
||||
MCU_REG_3D_SLIDER = 0x08u, // (ro) Raw 3D slider position (0-0x3F?).
|
||||
MCU_REG_VOL_SLIDER = 0x09u, // (ro) Volume slider position (0-0x3F).
|
||||
MCU_REG_BATT_TEMP = 0x0Au, // (ro) Battery temperature in celsius.
|
||||
MCU_REG_BATT_LEVEL = 0x0Bu, // (ro) Battery percentage (0-100).
|
||||
MCU_REG_BATT_LEVEL_FRAC = 0x0Cu, // (ro) Battery percentage fractional part (percent/256).
|
||||
MCU_REG_BATT_VOLT = 0x0Du, // (ro) Battery voltage in 20mV units.
|
||||
MCU_REG_EX_HW_STAT2 = 0x0Eu, // (ro) More hardware status bits.
|
||||
MCU_REG_EX_HW_STAT = 0x0Fu, // (ro) Hardware status bits.
|
||||
MCU_REG_IRQ = 0x10u, // (ro) 0x10-0x13 Interrupt status (clear on read).
|
||||
// 0x14 ro, 0x15-0x17 rw. All unused.
|
||||
MCU_REG_IRQ_MASK = 0x18u, // (rw) 0x18-0x1B Interrupt mask (each bit 0=enabled, 1=disabled).
|
||||
// 0x1C-0x1F rw and unused.
|
||||
MCU_REG_SYS_POW = 0x20u, // (wo) System power/reset control.
|
||||
MCU_REG_TWL_IRQ = 0x21u, // (wo) Various TWL MCU status change signals.
|
||||
MCU_REG_LCD_POW = 0x22u, // (wo) LCD power control.
|
||||
MCU_REG_RESTART = 0x23u, // (wo) Stubbed (on retail?) MCU restart register.
|
||||
MCU_REG_PWROFF_DELAY = 0x24u, // (rw) Force power off delay.
|
||||
MCU_REG_UNK25 = 0x25u, // (rw) Volume related? Volume value for override?
|
||||
MCU_REG_UNK26 = 0x26u, // (rw) Volume related? Bit 0: Enable/disable MCU reporting slider state to CODEC? Bit 1: Force? Bit 2: Mode? Bit 4: Trigger volume update from slider?
|
||||
MCU_REG_VOL_SLIDER_RAW = 0x27u, // (rw) Volume slider raw ADC data (0-0x3F?).
|
||||
MCU_REG_LED_BRIGHTNESS = 0x28u, // (rw) Master brightness of power/Wifi/3D (and camera?) LEDs.
|
||||
MCU_REG_POWER_LED = 0x29u, // (rw) 5 bytes power LED state + pattern.
|
||||
MCU_REG_WIFI_LED = 0x2Au, // (rw) WiFi LED state.
|
||||
MCU_REG_CAM_LED = 0x2Bu, // (rw) Camera LED state.
|
||||
MCU_REG_3D_LED = 0x2Cu, // (rw) 3D LED state.
|
||||
MCU_REG_INFO_LED = 0x2Du, // (wo) 100 bytes notification/info LED pattern.
|
||||
MCU_REG_INFO_LED_STAT = 0x2Eu, // (ro) Info LED status.
|
||||
// 0x2F wo with stubbed write handler.
|
||||
MCU_REG_RTC_S = 0x30u, // (rw) RTC second.
|
||||
MCU_REG_RTC_MIN = 0x31u, // (rw) RTC minute.
|
||||
MCU_REG_RTC_H = 0x32u, // (rw) RTC hour.
|
||||
MCU_REG_RTC_DOW = 0x33u, // (rw) RTC day of week (unused)?
|
||||
MCU_REG_RTC_D = 0x34u, // (rw) RTC day.
|
||||
MCU_REG_RTC_MON = 0x35u, // (rw) RTC month.
|
||||
MCU_REG_RTC_Y = 0x36u, // (rw) RTC year.
|
||||
MCU_REG_RTC_ERR_CORR = 0x37u, // (rw) RTC Watch error correction.
|
||||
MCU_REG_ALARM_MIN = 0x38u, // (rw) Alarm minute.
|
||||
MCU_REG_ALARM_H = 0x39u, // (rw) Alarm hour.
|
||||
MCU_REG_ALARM_D = 0x3Au, // (rw) Alarm day.
|
||||
MCU_REG_ALARM_MON = 0x3Bu, // (rw) Alarm month.
|
||||
MCU_REG_ALARM_Y = 0x3Cu, // (rw) Alarm year.
|
||||
MCU_REG_RTC_TICK_LO = 0x3Du, // (ro) RTC tick counter LSB in 32768 Hz units.
|
||||
MCU_REG_RTC_TICK_HI = 0x3Eu, // (ro) RTC tick counter MSB.
|
||||
MCU_REG_UNK3F = 0x3Fu, // (wo) Unknown state/control reg.
|
||||
MCU_REG_ACC_CFG = 0x40u, // (rw) Accelerometer configuration register.
|
||||
MCU_REG_ACC_READ_OFF = 0x41u, // (rw) Accelerometer I2C register offset for read (via MCU reg 0x44).
|
||||
// 0x42 rw unused.
|
||||
MCU_REG_ACC_WRITE_OFF = 0x43u, // (rw) Accelerometer I2C register offset for write (via MCU reg 0x44).
|
||||
MCU_REG_ACC_DATA = 0x44u, // (rw) Accelerometer I2C register data.
|
||||
MCU_REG_ACC_X_LO = 0x45u, // (ro) Accelerometer X sample data LSB.
|
||||
MCU_REG_ACC_X_HI = 0x46u, // (ro) Accelerometer X sample data MSB.
|
||||
MCU_REG_ACC_Y_LO = 0x47u, // (ro) Accelerometer Y sample data LSB.
|
||||
MCU_REG_ACC_Y_HI = 0x48u, // (ro) Accelerometer Y sample data MSB.
|
||||
MCU_REG_ACC_Z_LO = 0x49u, // (ro) Accelerometer Z sample data LSB.
|
||||
MCU_REG_ACC_Z_HI = 0x4Au, // (ro) Accelerometer Z sample data MSB.
|
||||
MCU_REG_PM_COUNT_LO = 0x4Bu, // (rw) Pedometer step count LSB.
|
||||
MCU_REG_PM_COUNT_MI = 0x4Cu, // (rw) Pedometer step count middle byte.
|
||||
MCU_REG_PM_COUNT_HI = 0x4Du, // (rw) Pedometer step count MSB.
|
||||
MCU_REG_PM_HIST_STAT = 0x4Eu, // (rw) Pedometer history state. TODO: Better name.
|
||||
MCU_REG_PM_HIST = 0x4Fu, // (ro) 6 + 336 bytes pedometer history data.
|
||||
MCU_REG_UNK50 = 0x50u, // (rw)
|
||||
MCU_REG_UNK51 = 0x51u, // (rw)
|
||||
// 0x52-0x57 rw unknown/unused.
|
||||
MCU_REG_VOL_SLIDER_MIN = 0x58u, // (rw) Volume slider minimum calibration point.
|
||||
MCU_REG_VOL_SLIDER_MAX = 0x59u, // (rw) Volume slider maximum calibration point.
|
||||
// 0x5A rw/ro depending on firmware version. Unused.
|
||||
// 0x5B-0x5F unused.
|
||||
MCU_REG_FREE_RAM_OFF = 0x60u, // (rw) Free RAM offset for MCU register 0x61.
|
||||
MCU_REG_FREE_RAM_DATA = 0x61u, // (rw) Free RAM data register.
|
||||
// 0x62-0x7E unused.
|
||||
MCU_REG_RAW_STATE = 0x7Fu // (ro) 19 bytes of various raw state.
|
||||
// 0x80-0xFF unused.
|
||||
} McuReg;
|
||||
|
||||
|
||||
// MCU_REG_IRQ and MCU_REG_IRQ_MASK.
|
||||
#define MCU_IRQ_POWER_PRESS (1u) // Power button pressed for 200 ms.
|
||||
#define MCU_IRQ_POWER_HELD (1u<<1) // Power button held for 3 seconds.
|
||||
#define MCU_IRQ_HOME_PRESS (1u<<2) // HOME button pressed for 40 ms.
|
||||
#define MCU_IRQ_HOME_RELEASE (1u<<3) // HOME button released.
|
||||
#define MCU_IRQ_WIFI_PRESS (1u<<4) // WiFi button pressed for 40 ms.
|
||||
#define MCU_IRQ_SHELL_CLOSE (1u<<5) // Shell has been closed.
|
||||
#define MCU_IRQ_SHELL_OPEN (1u<<6) // Shell has been opened.
|
||||
#define MCU_IRQ_WATCHDOG (1u<<7) // MCU has been reset by the watchdog.
|
||||
#define MCU_IRQ_CHARGER_UNPLUG (1u<<8) // Charger has been unplugged.
|
||||
#define MCU_IRQ_CHARGER_PLUG (1u<<9) // Charger has been plugged in.
|
||||
#define MCU_IRQ_RTC_ALARM (1u<<10) // RTC alarm.
|
||||
#define MCU_IRQ_ACC_RW_DONE (1u<<11) // Accelerometer I2C read/write done.
|
||||
#define MCU_IRQ_ACC_DATA_READY (1u<<12) // Accelerometer X/Y/Z sample data ready.
|
||||
#define MCU_IRQ_LOW_BATT (1u<<13) // Low battery warning IRQ triggered at 10, 5 and 0%. TODO: gbatek says 11, 6 and 1%.
|
||||
#define MCU_IRQ_BATT_CHARGE_STOP (1u<<14) // Battery charging stopped.
|
||||
#define MCU_IRQ_BATT_CHARGE_START (1u<<15) // Battery charging started.
|
||||
#define MCU_IRQ_TWL_RESET (1u<<16) // DS powerman register 0x10 bit 0 = 1 or TWL MCU register 0x11 = 1 (reset).
|
||||
#define MCU_IRQ_TWL_PWROFF (1u<<17) // DS powerman register 0x10 bit 6 = 1. Poweroff request?
|
||||
#define MCU_IRQ_TWL_BOT_BL_OFF (1u<<18) // DS powerman register 0x10 bit 2 = 0. Bottom LCD backlight off request?
|
||||
#define MCU_IRQ_TWL_BOT_BL_ON (1u<<19) // DS powerman register 0x10 bit 2 = 1. Bottom LCD backlight on request?
|
||||
#define MCU_IRQ_TWL_TOP_BL_OFF (1u<<20) // DS powerman register 0x10 bit 3 = 0. Top LCD backlight off request?
|
||||
#define MCU_IRQ_TWL_TOP_BL_ON (1u<<21) // DS powerman register 0x10 bit 3 = 1. Top LCD backlight on request?
|
||||
#define MCU_IRQ_VOL_SLIDER_CHANGE (1u<<22) // Volume slider position changed.
|
||||
#define MCU_IRQ_TWL_MCU_VER_READ (1u<<23) // TWL MCU version register (0x00) read.
|
||||
#define MCU_IRQ_LCD_POWER_OFF (1u<<24) // LCDs have been powered off.
|
||||
#define MCU_IRQ_LCD_POWER_ON (1u<<25) // LCDs have been powered on.
|
||||
#define MCU_IRQ_BOT_BL_OFF (1u<<26) // Bottom LCD backlight has been powered off.
|
||||
#define MCU_IRQ_BOT_BL_ON (1u<<27) // Bottom LCD backlight has been powered on.
|
||||
#define MCU_IRQ_TOP_BL_OFF (1u<<28) // Top LCD backlight has been powered off.
|
||||
#define MCU_IRQ_TOP_BL_ON (1u<<29) // Top LCD backlight has been powered on.
|
||||
|
||||
// MCU_REG_ACC_CFG
|
||||
typedef enum
|
||||
{
|
||||
ACC_CFG_ALL_OFF = 0u, // Accelerometer and pedometer off.
|
||||
ACC_CFG_ACC_ON_PM_OFF = 1u, // Accelerometer on and pedometer off.
|
||||
ACC_CFG_ACC_OFF_PM_ON = 2u, // Accelerometer off and pedometer on.
|
||||
ACC_CFG_ACC_ON_PM_ON = 3u // Accelerometer on and pedometer on.
|
||||
} AccCfg;
|
|
@ -21,8 +21,18 @@
|
|||
#include "types.h"
|
||||
|
||||
|
||||
#define SPIFLASH_CMD_RDSR (0x05)
|
||||
#define SPIFLASH_CMD_READ (0x03)
|
||||
#define SPIFLASH_PP (0x02u) // Page Program (0x100 bytes).
|
||||
#define SPIFLASH_READ (0x03u) // Read.
|
||||
#define SPIFLASH_WRDI (0x04u) // Write Disable.
|
||||
#define SPIFLASH_RDSR (0x05u) // Read Status Register.
|
||||
#define SPIFLASH_WREN (0x06u) // Write Enable.
|
||||
#define SPIFLASH_PW (0x0Au) // Page Write (0x100 bytes).
|
||||
#define SPIFLASH_FAST (0x0Bu) // Fast Read.
|
||||
#define SPIFLASH_RDP (0xABu) // Release from Deep Power-down.
|
||||
#define SPIFLASH_DP (0xB9u) // Deep Power-Down.
|
||||
#define SPIFLASH_SE (0xD8u) // Sector Erase (0x10000 bytes).
|
||||
#define SPIFLASH_PE (0xDBu) // Page Erase (0x100 bytes).
|
||||
#define SPIFLASH_RDID (0x9Fu) // Read JEDEC Identification.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@ static void legacyTouchscreenMode(bool enabled)
|
|||
static void headsetInit(void)
|
||||
{
|
||||
// Headset detection stuff.
|
||||
GPIO_config(GPIO_2_HEADPH_JACK, GPIO_IRQ_ENABLE | GPIO_EDGE_RISING | GPIO_INPUT); // Headphone jack IRQ.
|
||||
GPIO_config(GPIO_2_HEADPH_JACK, GPIO_IRQ_RISING | GPIO_INPUT); // Headphone jack IRQ.
|
||||
//maskReg(CDC_REG_HEADSET_SEL, GPIO_read(GPIO_2_HEADPH_JACK)<<HEADSET_SEL_HP_SHIFT | HEADSET_SEL_HP_EN, 0x30); // GPIO bitmask 8.
|
||||
maskReg(CDC_REG_HEADSET_SEL, 0, 0x30); // With automatic output switching.
|
||||
maskReg(CDC_REG_100_67, 0, 0x80); // TODO: Can we remove this?
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
#include "kevent.h"
|
||||
|
||||
|
||||
#define MCU_LCD_IRQ_MASK (MCU_IRQ_TOP_BL_ON | MCU_IRQ_TOP_BL_OFF | \
|
||||
MCU_IRQ_BOT_BL_ON | MCU_IRQ_BOT_BL_OFF | \
|
||||
MCU_IRQ_LCD_POWER_ON | MCU_IRQ_LCD_POWER_OFF)
|
||||
|
||||
|
||||
static struct
|
||||
{
|
||||
u32 swap; // Currently active framebuffer.
|
||||
|
@ -67,7 +72,7 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
|||
|
||||
// FIXME: Temporary workaround for screen init compatibility (Luma/fb3DS 1.2).
|
||||
TIMER_sleepMs(50);
|
||||
(void)MCU_getEvents(0x3Fu<<24); // Discard any screen init events.
|
||||
(void)MCU_getIrqs(MCU_LCD_IRQ_MASK); // Discard any screen init events.
|
||||
|
||||
getCfg11Regs()->gpuprot = GPUPROT_NO_PROT;
|
||||
|
||||
|
@ -131,10 +136,10 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
|||
REG_LCD_UNK00C = 0; // Starts H-/V-sync control signals?
|
||||
TIMER_sleepMs(10); // Wait for power supply (which?) to stabilize and LCD drivers to finish resetting.
|
||||
LCDI2C_init(); // Initialize LCD drivers.
|
||||
MCU_controlLCDPower(2u); // Power on LCDs (MCU --> PMIC).
|
||||
MCU_setLcdPower(2u); // Power on LCDs (MCU --> PMIC).
|
||||
// Timing critical part end.
|
||||
// Wait 50 us for LCD sync. The MCU event wait will cover this.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 2u<<24) panic();
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != MCU_IRQ_LCD_POWER_ON) panic();
|
||||
|
||||
// The transfer engine is (sometimes) borked on screen init.
|
||||
// Doing a dummy texture copy fixes it.
|
||||
|
@ -146,8 +151,8 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
|||
REG_LCD_ABL0_LIGHT = 1;
|
||||
REG_LCD_ABL1_LIGHT_PWM = 0x1023E; // TODO: Figure out how this works.
|
||||
REG_LCD_ABL1_LIGHT = 1;
|
||||
MCU_controlLCDPower(0x28u); // Power on backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 0x28u<<24) panic();
|
||||
MCU_setLcdPower(0x28u); // Power on backlights.
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (MCU_IRQ_TOP_BL_ON | MCU_IRQ_BOT_BL_ON)) panic();
|
||||
|
||||
// Make sure the fills finished.
|
||||
GFX_waitForPSC0();
|
||||
|
@ -176,8 +181,8 @@ void GFX_deinit(void)
|
|||
const u8 power = g_gfxState.lcdPower;
|
||||
if(power & ~1u)
|
||||
{
|
||||
MCU_controlLCDPower(power & ~1u);
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)(power & ~1u)<<24) panic();
|
||||
MCU_setLcdPower(power & ~1u);
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)(power & ~1u)<<24) panic();
|
||||
}
|
||||
GFX_setBrightness(0, 0);
|
||||
REG_LCD_ABL0_LIGHT_PWM = 0;
|
||||
|
@ -197,8 +202,8 @@ void GFX_deinit(void)
|
|||
// Power off LCDs if on.
|
||||
if(power & 1u)
|
||||
{
|
||||
MCU_controlLCDPower(1u);
|
||||
if(MCU_waitEvents(0x3Fu<<24) != 1u<<24) panic();
|
||||
MCU_setLcdPower(1u);
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != MCU_IRQ_LCD_POWER_OFF) panic();
|
||||
}
|
||||
|
||||
// TODO: Wait until PDC is not reading any data from mem.
|
||||
|
@ -365,8 +370,8 @@ void GFX_powerOnBacklights(GfxBlight mask)
|
|||
g_gfxState.lcdPower |= mask;
|
||||
|
||||
mask <<= 1;
|
||||
MCU_controlLCDPower(mask); // Power on backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) panic();
|
||||
MCU_setLcdPower(mask); // Power on backlights.
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)mask<<24) panic();
|
||||
}
|
||||
|
||||
void GFX_powerOffBacklights(GfxBlight mask)
|
||||
|
@ -374,8 +379,8 @@ void GFX_powerOffBacklights(GfxBlight mask)
|
|||
fb_assert((mask & ~GFX_BLIGHT_BOTH) == 0u);
|
||||
g_gfxState.lcdPower &= ~mask;
|
||||
|
||||
MCU_controlLCDPower(mask); // Power off backlights.
|
||||
if(MCU_waitEvents(0x3Fu<<24) != (u32)mask<<24) panic();
|
||||
MCU_setLcdPower(mask); // Power off backlights.
|
||||
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)mask<<24) panic();
|
||||
}
|
||||
|
||||
void GFX_setBrightness(u8 top, u8 bot)
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
#include "arm11/drivers/gpio.h"
|
||||
|
||||
|
||||
#define GPIO_EDGE_FALLING (0u)
|
||||
#define GPIO_EDGE_RISING (1u<<1)
|
||||
#define GPIO_IRQ_ENABLE (1u<<2)
|
||||
|
||||
|
||||
static vu16 *const g_datRegs[5] = {(vu16*)®_GPIO1_DAT, (vu16*)®_GPIO2_DAT,
|
||||
®_GPIO2_DAT2, ®_GPIO3_DAT, ®_GPIO3_DAT2};
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#include "arm11/drivers/codec.h"
|
||||
|
||||
|
||||
#define MCU_HID_IRQ_MASK (MCU_IRQ_VOL_SLIDER_CHANGE | MCU_IRQ_BATT_CHARGE_START | \
|
||||
MCU_IRQ_BATT_CHARGE_STOP | MCU_IRQ_SHELL_OPEN | \
|
||||
MCU_IRQ_SHELL_CLOSE | MCU_IRQ_WIFI_PRESS | \
|
||||
MCU_IRQ_HOME_RELEASE | MCU_IRQ_HOME_PRESS | \
|
||||
MCU_IRQ_POWER_HELD | MCU_IRQ_POWER_PRESS)
|
||||
|
||||
#define CPAD_THRESHOLD (400)
|
||||
|
||||
|
||||
|
@ -46,10 +52,10 @@ void hidInit(void)
|
|||
inited = true;
|
||||
|
||||
MCU_init();
|
||||
u8 state = MCU_getExternalHwState();
|
||||
u16 state = MCU_getExternalHardwareStatus();
|
||||
u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted.
|
||||
tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state
|
||||
state = MCU_getHidHeld();
|
||||
state = MCU_getEarlyButtonsHeld();
|
||||
tmp |= ~state<<1 & KEY_HOME; // Current HOME button state
|
||||
g_extraKeys = tmp;
|
||||
|
||||
|
@ -58,7 +64,7 @@ void hidInit(void)
|
|||
|
||||
static void updateMcuHidState(void)
|
||||
{
|
||||
const u32 state = MCU_getEvents(0x40C07F);
|
||||
const u32 state = MCU_getIrqs(MCU_HID_IRQ_MASK);
|
||||
if(state == 0) return;
|
||||
|
||||
u32 tmp = g_extraKeys;
|
||||
|
|
|
@ -124,7 +124,7 @@ Result LGY_prepareGbaMode(bool directBoot, u16 saveType, const char *const saveP
|
|||
|
||||
// Setup GBA Real-Time Clock.
|
||||
GbaRtc rtc;
|
||||
MCU_getRTCTime((u8*)&rtc);
|
||||
MCU_getRtcTimeDate((u8*)&rtc);
|
||||
rtc.time = __builtin_bswap32(rtc.time)>>8;
|
||||
rtc.date = __builtin_bswap32(rtc.date)>>8;
|
||||
calcDayOfWeek(&rtc);
|
||||
|
|
|
@ -16,20 +16,522 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdatomic.h>
|
||||
#include "arm11/drivers/mcu.h"
|
||||
#include "arm11/drivers/i2c.h"
|
||||
#include "arm11/debug.h"
|
||||
#include "arm11/drivers/interrupt.h"
|
||||
#include "arm11/drivers/gpio.h"
|
||||
|
||||
|
||||
static bool g_mcuIrq = false;
|
||||
static u32 g_mcuEvents = 0;
|
||||
static bool g_mcuNeedsIrqRead = false;
|
||||
static u32 g_mcuIrqs = 0;
|
||||
static struct
|
||||
{
|
||||
u16 version; // MCU firmware version ((MCU_REG_VERS_MAJOR - 0x10)<<8 | MCU_REG_VERS_MINOR).
|
||||
// TODO: Cache IRQ mask?
|
||||
u8 conType; // Console type (MCU_REG_RAW_STATE[0]).
|
||||
u8 systemModel; // System model (MCU_REG_RAW_STATE[9]).
|
||||
u8 earlyButtonsHeld; // Early button state (MCU_REG_RAW_STATE[18]);
|
||||
} g_mcuRegCache;
|
||||
|
||||
|
||||
|
||||
static void mcuIrqHandler(UNUSED u32 intSource);
|
||||
|
||||
static bool updateRegisterCache(void)
|
||||
{
|
||||
// Read major and minor version at once.
|
||||
u16 version;
|
||||
if(!MCU_readRegBuf(MCU_REG_VERS_MAJOR, (u8*)&version, sizeof(version))) return false;
|
||||
g_mcuRegCache.version = __builtin_bswap16(version - 0x10);
|
||||
|
||||
u8 tmp[19];
|
||||
if(!MCU_readRegBuf(MCU_REG_RAW_STATE, tmp, sizeof(tmp))) return false;
|
||||
g_mcuRegCache.conType = tmp[0];
|
||||
g_mcuRegCache.systemModel = tmp[9];
|
||||
g_mcuRegCache.earlyButtonsHeld = tmp[18];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MCU_init(void)
|
||||
{
|
||||
static bool mcuDriverInitialized = false;
|
||||
if(mcuDriverInitialized) return;
|
||||
mcuDriverInitialized = true;
|
||||
|
||||
// Make sure I2C is initialized.
|
||||
I2C_init();
|
||||
|
||||
// Configure GPIO for MCU IRQs.
|
||||
GPIO_config(GPIO_3_MCU, GPIO_IRQ_FALLING | GPIO_INPUT);
|
||||
|
||||
// TODO: Clear alarm regs here like mcu module? Is this really needed?
|
||||
|
||||
// Enable MCU IRQs.
|
||||
IRQ_registerIsr(IRQ_CTR_MCU, 14, 0, mcuIrqHandler);
|
||||
|
||||
// Do first MCU IRQ read to clear all bits.
|
||||
// Discard IRQs we don't care about.
|
||||
atomic_store_explicit(&g_mcuNeedsIrqRead, true, memory_order_relaxed);
|
||||
(void)MCU_getIrqs(~DEFAULT_MCU_IRQ_MASK);
|
||||
|
||||
// Set IRQ mask so we only get IRQs we are interested in.
|
||||
if(!MCU_setIrqMask(DEFAULT_MCU_IRQ_MASK)) panic();
|
||||
|
||||
// Initialize register cache.
|
||||
if(!updateRegisterCache()) panic();
|
||||
}
|
||||
|
||||
/*bool MCU_reboot(void)
|
||||
{
|
||||
// TODO: GPIO bitmask 0x40000 handling.
|
||||
|
||||
// Enters MCU update mode but since no firmware data
|
||||
// is incoming it will just reboot.
|
||||
if(!MCU_writeRegBuf(MCU_REG_FW_UPDATE, (const u8*)"jhl", 3)) return false;
|
||||
|
||||
// We need to wait 1 second for the MCU to reboot.
|
||||
TIMER_sleepMs(1000);
|
||||
|
||||
// TODO: Some state needs to be restored after a reboot.
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
static void mcuIrqHandler(UNUSED u32 intSource)
|
||||
{
|
||||
atomic_store_explicit(&g_mcuNeedsIrqRead, true, memory_order_relaxed);
|
||||
}
|
||||
|
||||
// TODO: Rewrite using events (needs timeout support).
|
||||
u32 MCU_getIrqs(u32 mask)
|
||||
{
|
||||
u32 irqs = g_mcuIrqs;
|
||||
|
||||
if(atomic_load_explicit(&g_mcuNeedsIrqRead, memory_order_relaxed))
|
||||
{
|
||||
atomic_store_explicit(&g_mcuNeedsIrqRead, false, memory_order_relaxed);
|
||||
|
||||
u32 newIrqs;
|
||||
if(!MCU_readRegBuf(MCU_REG_IRQ, (u8*)&newIrqs, sizeof(newIrqs))) return 0;
|
||||
|
||||
irqs |= newIrqs;
|
||||
}
|
||||
|
||||
g_mcuIrqs = irqs & ~mask;
|
||||
|
||||
return irqs & mask;
|
||||
}
|
||||
|
||||
// TODO: Rewrite using events (needs timeout support).
|
||||
u32 MCU_waitIrqs(u32 mask)
|
||||
{
|
||||
u32 irqs;
|
||||
|
||||
while((irqs = MCU_getIrqs(mask)) == 0u)
|
||||
{
|
||||
__wfi();
|
||||
}
|
||||
|
||||
return irqs;
|
||||
}
|
||||
|
||||
|
||||
u16 MCU_getFirmwareVersion(void)
|
||||
{
|
||||
return g_mcuRegCache.version;
|
||||
}
|
||||
|
||||
u8 MCU_getStatus(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_STAT);
|
||||
}
|
||||
|
||||
bool MCU_setStatus(u8 status)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_STAT, status);
|
||||
}
|
||||
|
||||
u8 MCU_getLcdVcomTop(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_LCD_VCOM_TOP);
|
||||
}
|
||||
|
||||
bool MCU_setLcdVcomTop(u8 vcom)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_LCD_VCOM_TOP, vcom);
|
||||
}
|
||||
|
||||
u8 MCU_getLcdVcomBot(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_LCD_VCOM_BOT);
|
||||
}
|
||||
|
||||
bool MCU_setLcdVcomBot(u8 vcom)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_LCD_VCOM_BOT, vcom);
|
||||
}
|
||||
|
||||
u8 MCU_get3dSliderPosition(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_3D_SLIDER);
|
||||
}
|
||||
|
||||
u8 MCU_getVolumeSliderPosition(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_VOL_SLIDER);
|
||||
}
|
||||
|
||||
u8 MCU_getBatteryTemperature(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_BATT_TEMP);
|
||||
}
|
||||
|
||||
float MCU_getBatteryLevel(void)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
// Read integer and fractional bytes at once.
|
||||
if(!MCU_readRegBuf(MCU_REG_BATT_LEVEL, buf, sizeof(buf))) return NAN;
|
||||
|
||||
return buf[0] + (float)buf[1] / 256u; // TODO: Verify this.
|
||||
}
|
||||
|
||||
float MCU_getBatteryVoltage(void)
|
||||
{
|
||||
return 0.02f * MCU_readReg(MCU_REG_BATT_VOLT);
|
||||
}
|
||||
|
||||
u16 MCU_getExternalHardwareStatus(void)
|
||||
{
|
||||
u16 status;
|
||||
|
||||
// Read both status regs at once.
|
||||
if(!MCU_readRegBuf(MCU_REG_EX_HW_STAT2, (u8*)&status, sizeof(status))) status = 0;
|
||||
|
||||
return __builtin_bswap16(status);
|
||||
}
|
||||
|
||||
u32 MCU_getIrqMask(void)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if(!MCU_readRegBuf(MCU_REG_IRQ_MASK, (u8*)&mask, sizeof(mask))) mask = 0;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
bool MCU_setIrqMask(u32 mask)
|
||||
{
|
||||
return MCU_writeRegBuf(MCU_REG_IRQ_MASK, (const u8*)&mask, sizeof(mask));
|
||||
}
|
||||
|
||||
// TODO: MCU_setSystemPower()?
|
||||
|
||||
void MCU_powerOffSys(void)
|
||||
{
|
||||
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_SYS_POW, 1u);
|
||||
}
|
||||
|
||||
void MCU_rebootSys(void)
|
||||
{
|
||||
I2C_writeRegIntSafe(I2C_DEV_CTR_MCU, MCU_REG_SYS_POW, 1u<<2);
|
||||
}
|
||||
|
||||
bool MCU_setTwlIrq(u8 bits)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_TWL_IRQ, bits);
|
||||
}
|
||||
|
||||
void MCU_setLcdPower(u8 bits)
|
||||
{
|
||||
MCU_writeReg(MCU_REG_LCD_POW, bits);
|
||||
}
|
||||
|
||||
u8 MCU_getPoweroffDelay(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_PWROFF_DELAY);
|
||||
}
|
||||
|
||||
bool MCU_setPoweroffDelay(u8 delay)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_PWROFF_DELAY, delay);
|
||||
}
|
||||
|
||||
u8 MCU_getRegister0x25(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_UNK25);
|
||||
}
|
||||
|
||||
bool MCU_setRegister0x25(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_UNK25, data);
|
||||
}
|
||||
|
||||
u8 MCU_getRegister0x26(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_UNK26);
|
||||
}
|
||||
|
||||
bool MCU_setRegister0x26(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_UNK26, data);
|
||||
}
|
||||
|
||||
u8 MCU_getVolumeSliderPositionRaw(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_VOL_SLIDER_RAW);
|
||||
}
|
||||
|
||||
bool MCU_setVolumeSliderPositionRaw(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_VOL_SLIDER_RAW, data);
|
||||
}
|
||||
|
||||
u8 MCU_getLedMasterBrightness(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_LED_BRIGHTNESS);
|
||||
}
|
||||
|
||||
bool MCU_setLedMasterBrightness(u8 brightness)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_LED_BRIGHTNESS, brightness);
|
||||
}
|
||||
|
||||
bool MCU_getPowerLedPattern(u8 pattern[5])
|
||||
{
|
||||
return MCU_readRegBuf(MCU_REG_POWER_LED, pattern, 5);
|
||||
}
|
||||
|
||||
bool MCU_setPowerLedPattern(const u8 pattern[5])
|
||||
{
|
||||
return MCU_writeRegBuf(MCU_REG_POWER_LED, pattern, 5);
|
||||
}
|
||||
|
||||
u8 MCU_getWifiLedState(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_WIFI_LED);
|
||||
}
|
||||
|
||||
bool MCU_setWifiLedState(u8 state)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_WIFI_LED, state);
|
||||
}
|
||||
|
||||
u8 MCU_getCameraLedState(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_CAM_LED);
|
||||
}
|
||||
|
||||
bool MCU_setCameraLedState(u8 state)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_CAM_LED, state);
|
||||
}
|
||||
|
||||
u8 MCU_get3dLedState(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_3D_LED);
|
||||
}
|
||||
|
||||
bool MCU_set3dLedState(u8 state)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_3D_LED, state);
|
||||
}
|
||||
|
||||
bool MCU_setInfoLedPattern(const u8 pattern[100])
|
||||
{
|
||||
return MCU_writeRegBuf(MCU_REG_INFO_LED, pattern, 100);
|
||||
}
|
||||
|
||||
u8 MCU_getInfoLedStatus(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_INFO_LED_STAT);
|
||||
}
|
||||
|
||||
bool MCU_getRtcTimeDate(RtcTimeDate *timeDate)
|
||||
{
|
||||
// Read time and date at once.
|
||||
return MCU_readRegBuf(MCU_REG_RTC_S, (u8*)timeDate, sizeof(RtcTimeDate));
|
||||
}
|
||||
|
||||
bool MCU_setRtcTimeDate(const RtcTimeDate *timeDate)
|
||||
{
|
||||
// Write time and date at once.
|
||||
return MCU_writeRegBuf(MCU_REG_RTC_S, (const u8*)timeDate, sizeof(RtcTimeDate));
|
||||
}
|
||||
|
||||
u8 MCU_getRtcErrorCorrection(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_RTC_ERR_CORR);
|
||||
}
|
||||
|
||||
bool MCU_setRtcErrorCorrection(u8 correction)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_RTC_ERR_CORR, correction);
|
||||
}
|
||||
|
||||
bool MCU_getAlarmTimeDate(AlarmTimeDate *timeDate)
|
||||
{
|
||||
// Read time and date at once.
|
||||
return MCU_readRegBuf(MCU_REG_ALARM_MIN, (u8*)timeDate, sizeof(AlarmTimeDate));
|
||||
}
|
||||
|
||||
bool MCU_setAlarmTimeDate(const AlarmTimeDate *timeDate)
|
||||
{
|
||||
// Write time and date at once.
|
||||
return MCU_writeRegBuf(MCU_REG_ALARM_MIN, (const u8*)timeDate, sizeof(AlarmTimeDate));
|
||||
}
|
||||
|
||||
u16 MCU_getRtcTick(void)
|
||||
{
|
||||
u16 tick;
|
||||
|
||||
// Read both tick bytes at once.
|
||||
if(!MCU_readRegBuf(MCU_REG_RTC_TICK_LO, (u8*)&tick, sizeof(tick))) tick = 0;
|
||||
|
||||
return tick;
|
||||
}
|
||||
|
||||
bool MCU_setRegister0x3F(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_UNK3F, data);
|
||||
}
|
||||
|
||||
AccCfg MCU_getAccelerometerConfig(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_ACC_CFG);
|
||||
}
|
||||
|
||||
bool MCU_setAccelerometerConfig(AccCfg cfg)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_ACC_CFG, cfg);
|
||||
}
|
||||
|
||||
u8 MCU_readAccelerometerRegister(u8 reg)
|
||||
{
|
||||
if(!MCU_writeReg(MCU_REG_ACC_READ_OFF, reg)) return 0;
|
||||
MCU_waitIrqs(MCU_IRQ_ACC_RW_DONE);
|
||||
|
||||
return MCU_readReg(MCU_REG_ACC_DATA);
|
||||
}
|
||||
|
||||
bool MCU_writeAccelerometerRegister(u8 reg, u8 data)
|
||||
{
|
||||
const u16 regData = (u16)data<<8 | reg;
|
||||
|
||||
// Write register and data at once.
|
||||
if(!MCU_writeRegBuf(MCU_REG_ACC_WRITE_OFF, (const u8*)®Data, sizeof(regData))) return false;
|
||||
MCU_waitIrqs(MCU_IRQ_ACC_RW_DONE); // TODO: Is this needed? mcu module doesn't wait for write.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MCU_getAccelerometerSamples(AccData *samples)
|
||||
{
|
||||
// Read all X/Y/Z sample bytes at once.
|
||||
const bool res = MCU_readRegBuf(MCU_REG_ACC_X_LO, (u8*)samples, sizeof(AccData));
|
||||
|
||||
// Sample data is in the upper 12 bits.
|
||||
samples->x >>= 4;
|
||||
samples->y >>= 4;
|
||||
samples->z >>= 4;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 MCU_getPedometerStepCount(void)
|
||||
{
|
||||
u32 steps;
|
||||
|
||||
// Read all step count bytes at once.
|
||||
if(!MCU_readRegBuf(MCU_REG_PM_COUNT_LO, (u8*)&steps, 3)) steps = 0;
|
||||
|
||||
return steps & ~0xFF000000u; // Make sure byte 4 is 0.
|
||||
}
|
||||
|
||||
bool MCU_setPedometerStepCount(u32 steps)
|
||||
{
|
||||
// Write all step count bytes at once.
|
||||
return MCU_writeRegBuf(MCU_REG_PM_COUNT_LO, (u8*)&steps, 3);
|
||||
}
|
||||
|
||||
// TODO: Reg 0x4E.
|
||||
|
||||
bool MCU_getPedometerHistory(u8 history[6 + 336])
|
||||
{
|
||||
// Read all history bytes at once.
|
||||
const bool res = MCU_readRegBuf(MCU_REG_PM_HIST, history, 6 + 336);
|
||||
|
||||
// TODO: BCD to decimal for the timestamps.
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 MCU_getRegister0x50(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_UNK50);
|
||||
}
|
||||
|
||||
bool MCU_setRegister0x50(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_UNK50, data);
|
||||
}
|
||||
|
||||
u8 MCU_getRegister0x51(void)
|
||||
{
|
||||
return MCU_readReg(MCU_REG_UNK51);
|
||||
}
|
||||
|
||||
bool MCU_setRegister0x51(u8 data)
|
||||
{
|
||||
return MCU_writeReg(MCU_REG_UNK51, data);
|
||||
}
|
||||
|
||||
bool MCU_getVolumeSliderCalibrationPoints(u8 minMax[2])
|
||||
{
|
||||
// Read min and max at once.
|
||||
return MCU_readRegBuf(MCU_REG_VOL_SLIDER_MIN, minMax, 2);
|
||||
}
|
||||
|
||||
bool MCU_setVolumeSliderCalibrationPoints(const u8 minMax[2])
|
||||
{
|
||||
// Write min and max at once.
|
||||
return MCU_writeRegBuf(MCU_REG_VOL_SLIDER_MIN, minMax, 2);
|
||||
}
|
||||
|
||||
bool MCU_getFreeRamData(u8 off, u8 *out, u8 size)
|
||||
{
|
||||
if(!MCU_writeReg(MCU_REG_FREE_RAM_OFF, off)) return false;
|
||||
|
||||
return MCU_readRegBuf(MCU_REG_FREE_RAM_DATA, out, size);
|
||||
}
|
||||
|
||||
bool MCU_setFreeRamData(u8 off, const u8 *in, u8 size)
|
||||
{
|
||||
if(!MCU_writeReg(MCU_REG_FREE_RAM_OFF, off)) return false;
|
||||
|
||||
return MCU_writeRegBuf(MCU_REG_FREE_RAM_DATA, in, size);
|
||||
}
|
||||
|
||||
u8 MCU_getConsoleType(void)
|
||||
{
|
||||
return g_mcuRegCache.conType;
|
||||
}
|
||||
|
||||
u8 MCU_getSystemModel(void)
|
||||
{
|
||||
return g_mcuRegCache.systemModel;
|
||||
}
|
||||
|
||||
u8 MCU_getEarlyButtonsHeld(void)
|
||||
{
|
||||
return g_mcuRegCache.earlyButtonsHeld;
|
||||
}
|
||||
|
||||
|
||||
u8 MCU_readReg(McuReg reg)
|
||||
{
|
||||
return I2C_readReg(I2C_DEV_CTR_MCU, reg);
|
||||
|
@ -49,62 +551,3 @@ bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size)
|
|||
{
|
||||
return I2C_writeRegBuf(I2C_DEV_CTR_MCU, reg, in, size);
|
||||
}
|
||||
|
||||
void MCU_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
if(inited) return;
|
||||
inited = true;
|
||||
|
||||
I2C_init();
|
||||
|
||||
// Configure GPIO for MCU event IRQs
|
||||
GPIO_config(GPIO_3_MCU, GPIO_INPUT | GPIO_EDGE_FALLING | GPIO_IRQ_ENABLE);
|
||||
IRQ_registerIsr(IRQ_CTR_MCU, 14, 0, mcuIrqHandler);
|
||||
|
||||
atomic_store_explicit(&g_mcuIrq, true, memory_order_relaxed);
|
||||
(void)MCU_getEvents(0);
|
||||
|
||||
MCU_setEventMask(0xC0BF3F80);
|
||||
}
|
||||
|
||||
static void mcuIrqHandler(UNUSED u32 intSource)
|
||||
{
|
||||
g_mcuIrq = true;
|
||||
}
|
||||
|
||||
bool MCU_setEventMask(u32 mask)
|
||||
{
|
||||
return MCU_writeRegBuf(MCU_REG_EVENT_MASK, (const u8*)&mask, 4);
|
||||
}
|
||||
|
||||
u32 MCU_getEvents(u32 mask)
|
||||
{
|
||||
u32 events = g_mcuEvents;
|
||||
|
||||
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_mcuEvents = events & ~mask;
|
||||
|
||||
return events & mask;
|
||||
}
|
||||
|
||||
u32 MCU_waitEvents(u32 mask)
|
||||
{
|
||||
u32 events;
|
||||
|
||||
while((events = MCU_getEvents(mask)) == 0u)
|
||||
{
|
||||
__wfi();
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ bool spiflash_get_status(void)
|
|||
{
|
||||
alignas(4) u8 cmd[4];
|
||||
|
||||
cmd[0] = SPIFLASH_CMD_RDSR;
|
||||
cmd[0] = SPIFLASH_RDSR;
|
||||
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_NVRAM, (u32*)cmd, (u32*)cmd, 1, 1);
|
||||
|
||||
if(cmd[0] & 1) return false;
|
||||
|
@ -35,7 +35,7 @@ bool spiflash_get_status(void)
|
|||
|
||||
void spiflash_read(u32 offset, u32 size, u32 *buf)
|
||||
{
|
||||
offset = __builtin_bswap32(offset & 0x00FFFFFFu) | SPIFLASH_CMD_READ;
|
||||
offset = __builtin_bswap32(offset & 0x00FFFFFFu) | SPIFLASH_READ;
|
||||
|
||||
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_NVRAM, &offset, buf, 4, size);
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ typedef struct
|
|||
u8 _0x10a[6];
|
||||
vu32 gba_rtc_bcd_date;
|
||||
vu32 gba_rtc_bcd_time;
|
||||
vu32 gba_rtc_hex_time; // Writing bit 7 completely hangs all(?) GBA hardware.
|
||||
vu32 gba_rtc_hex_date;
|
||||
vu32 gba_rtc_toffset; // Writing bit 7 completely hangs all(?) GBA hardware.
|
||||
vu32 gba_rtc_doffset;
|
||||
vu32 gba_save_timing[4];
|
||||
} Lgy;
|
||||
static_assert(offsetof(Lgy, gba_save_timing) == 0x120, "Error: Member gba_save_timing of Lgy is not at offset 0x120!");
|
||||
|
@ -138,8 +138,8 @@ Result LGY_setGbaRtc(const GbaRtc rtc)
|
|||
|
||||
//while(lgy->gba_rtc_cnt & LGY_RTC_CNT_BUSY);
|
||||
//lgy->gba_rtc_cnt = 0; // Legacy P9 does this. Useless?
|
||||
lgy->gba_rtc_hex_time = 1u<<15; // Time offset 0 and 24h format.
|
||||
lgy->gba_rtc_hex_date = 0; // Date offset 0.
|
||||
lgy->gba_rtc_toffset = 1u<<15; // Time offset 0 and 24h format.
|
||||
lgy->gba_rtc_doffset = 0; // Date offset 0.
|
||||
lgy->gba_rtc_cnt = LGY_RTC_CNT_WR;
|
||||
while(lgy->gba_rtc_cnt & LGY_RTC_CNT_BUSY);
|
||||
|
||||
|
|
Loading…
Reference in New Issue