Files
pico-loader/arm7/source/loader/DSMode.cpp
2025-11-23 17:14:17 +01:00

357 lines
15 KiB
C++

#include "common.h"
#include <libtwl/i2c/i2cMcu.h>
#include <libtwl/sound/twlI2s.h>
#include <libtwl/sound/sound.h>
#include <libtwl/spi/spiCodec.h>
#include <libtwl/spi/spiPmic.h>
#include <libtwl/sys/twlScfg.h>
#include "ipc.h"
#include "gameCode.h"
#include "DSMode.h"
void DSMode::SwitchToDSMode(u32 gameCode) const
{
SwitchToDSTouchAndSoundMode(gameCode);
mcu_writeReg(MCU_REG_MODE, 0);
*(vu16*)0x04004C04 |= (1 << 8); // ntr wifi
REG_SCFG_A9ROM = SCFG_A9ROM_DISABLE_SECURE | SCFG_A9ROM_NITRO;
REG_SCFG_A7ROM = SCFG_A7ROM_DISABLE_SECURE | SCFG_A7ROM_NITRO | SCFG_A7ROM_DISABLE_FUSE;
REG_SCFG_EXT = 0x12A03000u;
sendToArm9(IPC_COMMAND_ARM9_SWITCH_TO_DS_MODE);
receiveFromArm9();
LOG_DEBUG("Switched to ds mode\n");
}
void DSMode::SwitchToDSTouchAndSoundMode(u32 gameCode) const
{
REG_I2SCNT = I2SCNT_MIX_RATIO_DSP_0_NITRO_8 | I2SCNT_FREQUENCY_32728_HZ;
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_DAC_NDAC_VAL, 0x87);
codec_writeRegister(CODEC_REG_PAGE0_ADC_NADC_VAL, 0x87);
codec_writeRegister(CODEC_REG_PAGE0_PLL_J, 21);
}
REG_I2SCNT |= I2SCNT_ENABLE;
SwitchCodecToDSMode(gameCode);
REG_SOUNDCNT = SOUNDCNT_MASTER_ENABLE | SOUNDCNT_MASTER_VOLUME(0x7F);
LOG_DEBUG("Switched to ds touch and sound mode\n");
}
void DSMode::SwitchCodecToDSMode(u32 gameCode) const
{
// 0xAC: special setting (when found special gamecode)
// 0xA7: normal setting (for any other gamecodes)
u8 volLevel = ShouldUseVolumeFix(gameCode) ? 0xAC : 0xA7;
// Touchscreen
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_GPI3_PIN_CONTROL, 0x00);
codec_readRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC);
}
codec_setPage(CODEC_PAGE_3);
{
codec_readRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_1);
}
codec_setPage(CODEC_PAGE_0);
{
codec_readRegister(CODEC_REG_PAGE0_DAC_DATA_PATH_SETUP);
}
codec_setPage(CODEC_PAGE_1);
{
codec_readRegister(CODEC_REG_PAGE1_HPL_DRIVER);
codec_readRegister(CODEC_REG_PAGE1_SPL_DRIVER);
codec_readRegister(CODEC_REG_PAGE1_MICBIAS);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_VOLUME_CONTROL_FINE_ADJUST, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_DAC_VOLUME_CONTROL, 0x0C);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_LEFT_ANALOG_VOL_TO_HPL, 0xFF);
codec_writeRegister(CODEC_REG_PAGE1_RIGHT_ANALOG_VOL_TO_HPR, 0xFF);
codec_writeRegister(CODEC_REG_PAGE1_LEFT_ANALOG_VOL_TO_SPL, 0x7F);
codec_writeRegister(CODEC_REG_PAGE1_RIGHT_ANALOG_VOL_TO_SPR, 0x7F);
codec_writeRegister(CODEC_REG_PAGE1_HPL_DRIVER, 0x4A);
codec_writeRegister(CODEC_REG_PAGE1_HPR_DRIVER, 0x4A);
codec_writeRegister(CODEC_REG_PAGE1_SPL_DRIVER, 0x10);
codec_writeRegister(CODEC_REG_PAGE1_SPR_DRIVER, 0x10);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC, 0x00);
}
codec_setPage(CODEC_PAGE_3);
{
codec_readRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_1);
codec_writeRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_1, 0x98);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_DAC_L_DAC_R_OUTPUT_MIXER_ROUTING, 0x00);
codec_writeRegister(CODEC_REG_PAGE1_HEADPHONE_DRIVERS, 0x14);
codec_writeRegister(CODEC_REG_PAGE1_CLASS_D_SPEAKER_AMPLIFIER, 0x14);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_DAC_DATA_PATH_SETUP, 0x00);
codec_readRegister(CODEC_REG_PAGE0_DAC_NDAC_VAL);
codec_writeRegister(CODEC_REG_PAGE0_PLL_P_R, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_DAC_NDAC_VAL, 0x01);
codec_writeRegister(CODEC_REG_PAGE0_DAC_MDAC_VAL, 0x02);
codec_writeRegister(CODEC_REG_PAGE0_ADC_NADC_VAL, 0x01);
codec_writeRegister(CODEC_REG_PAGE0_ADC_MADC_VAL, 0x02);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_MICBIAS, 0x00);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_GPI3_PIN_CONTROL, 0x60);
codec_writeRegister(CODEC_REG_PAGE0_RESET, 0x01);
codec_writeRegister(CODEC_REG_PAGE0_GPI1_GPI2_PIN_CONTROL, 0x66);
}
codec_setPage(CODEC_PAGE_1);
{
codec_readRegister(CODEC_REG_PAGE1_CLASS_D_SPEAKER_AMPLIFIER);
codec_writeRegister(CODEC_REG_PAGE1_CLASS_D_SPEAKER_AMPLIFIER, 0x10);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_CLOCK_GEN_MUXING, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_ADC_NADC_VAL, 0x81);
codec_writeRegister(CODEC_REG_PAGE0_ADC_MADC_VAL, 0x82);
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC, 0x82);
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_CLOCK_GEN_MUXING, 0x03);
codec_writeRegister(CODEC_REG_PAGE0_PLL_P_R, 0xA1);
codec_writeRegister(CODEC_REG_PAGE0_PLL_J, 0x15);
codec_writeRegister(CODEC_REG_PAGE0_DAC_NDAC_VAL, 0x87);
codec_writeRegister(CODEC_REG_PAGE0_DAC_MDAC_VAL, 0x83);
codec_writeRegister(CODEC_REG_PAGE0_ADC_NADC_VAL, 0x87);
codec_writeRegister(CODEC_REG_PAGE0_ADC_MADC_VAL, 0x83);
}
codec_setPage(CODEC_PAGE_3);
{
codec_readRegister(CODEC_REG_PAGE3_SCAN_MODE_TIMER_CLOCK);
codec_writeRegister(CODEC_REG_PAGE3_SCAN_MODE_TIMER_CLOCK, 0x08);
}
codec_setPage(CODEC_PAGE_4);
{
codec_writeRegister(0x08, 0x7F);
codec_writeRegister(0x09, 0xE1);
codec_writeRegister(0x0A, 0x80);
codec_writeRegister(0x0B, 0x1F);
codec_writeRegister(0x0C, 0x7F);
codec_writeRegister(0x0D, 0xC1);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_DAC_LEFT_VOLUME_CONTROL, 0x08);
codec_writeRegister(CODEC_REG_PAGE0_DAC_RIGHT_VOLUME_CONTROL, 0x08);
codec_writeRegister(CODEC_REG_PAGE0_GPI3_PIN_CONTROL, 0x00);
}
codec_setPage(CODEC_PAGE_4);
{
codec_writeRegister(0x08, 0x7F);
codec_writeRegister(0x09, 0xE1);
codec_writeRegister(0x0A, 0x80);
codec_writeRegister(0x0B, 0x1F);
codec_writeRegister(0x0C, 0x7F);
codec_writeRegister(0x0D, 0xC1);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_MIC_PGA, 0x2B);
codec_writeRegister(CODEC_REG_PAGE1_DELTA_SIGMA_MONO_ADC_CHANNEL_FINE_GAIN_INPUT_SELECTION_FOR_P_TERMINAL, 0x40);
codec_writeRegister(CODEC_REG_PAGE1_ADC_INPUT_SELECTION_FOR_M_TERMINAL, 0x40);
codec_writeRegister(CODEC_REG_PAGE1_INPUT_CM_SETTINGS, 0x60);
}
codec_setPage(CODEC_PAGE_0);
{
codec_readRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL);
codec_writeRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL, 0x02);
codec_readRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL);
codec_writeRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL, 0x10);
codec_readRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL);
codec_writeRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL, 0x40);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_HP_OUTPUT_DRIVERS_POP_REMOVAL_SETTINGS, 0x20);
codec_writeRegister(CODEC_REG_PAGE1_OUTPUT_DRIVER_PGA_RAMP_DOWN_PERIOD_CONTROL, 0xF0);
}
codec_setPage(CODEC_PAGE_0);
{
codec_readRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC);
codec_readRegister(CODEC_REG_PAGE0_DAC_DATA_PATH_SETUP);
codec_writeRegister(CODEC_REG_PAGE0_DAC_DATA_PATH_SETUP, 0xD4);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_DAC_L_DAC_R_OUTPUT_MIXER_ROUTING, 0x44);
codec_writeRegister(CODEC_REG_PAGE1_HEADPHONE_DRIVERS, 0xD4);
codec_writeRegister(CODEC_REG_PAGE1_HPL_DRIVER, 0x4E);
codec_writeRegister(CODEC_REG_PAGE1_HPR_DRIVER, 0x4E);
codec_writeRegister(CODEC_REG_PAGE1_LEFT_ANALOG_VOL_TO_HPL, 0x9E);
codec_writeRegister(CODEC_REG_PAGE1_RIGHT_ANALOG_VOL_TO_HPR, 0x9E);
codec_writeRegister(CODEC_REG_PAGE1_CLASS_D_SPEAKER_AMPLIFIER, 0xD4);
codec_writeRegister(CODEC_REG_PAGE1_SPL_DRIVER, 0x14);
codec_writeRegister(CODEC_REG_PAGE1_SPR_DRIVER, 0x14);
codec_writeRegister(CODEC_REG_PAGE1_LEFT_ANALOG_VOL_TO_SPL, 0xA7);
codec_writeRegister(CODEC_REG_PAGE1_RIGHT_ANALOG_VOL_TO_SPR, 0xA7);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_DAC_VOLUME_CONTROL, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_GPI3_PIN_CONTROL, 0x60);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_LEFT_ANALOG_VOL_TO_SPL, volLevel);
codec_writeRegister(CODEC_REG_PAGE1_RIGHT_ANALOG_VOL_TO_SPR, volLevel);
codec_writeRegister(CODEC_REG_PAGE1_MICBIAS, 0x03);
}
codec_setPage(CODEC_PAGE_3);
{
codec_writeRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_2, 0x00);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_HP_OUTPUT_DRIVERS_POP_REMOVAL_SETTINGS, 0x20);
codec_writeRegister(CODEC_REG_PAGE1_OUTPUT_DRIVER_PGA_RAMP_DOWN_PERIOD_CONTROL, 0xF0);
codec_readRegister(CODEC_REG_PAGE1_OUTPUT_DRIVER_PGA_RAMP_DOWN_PERIOD_CONTROL);
codec_writeRegister(CODEC_REG_PAGE1_OUTPUT_DRIVER_PGA_RAMP_DOWN_PERIOD_CONTROL, 0x00);
}
codec_setPage(CODEC_PAGE_0);
{
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_VOLUME_CONTROL_FINE_ADJUST, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC, 0x00);
// Set remaining values
codec_writeRegister(0x03, 0x44);
codec_writeRegister(CODEC_REG_PAGE0_DAC_DOSR_VAL_MSB, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_DAC_DOSR_VAL_LSB, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_DAC_IDAC_VAL, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_DAC_MINIDSP_INTERPOLATION, 0x08);
codec_writeRegister(CODEC_REG_PAGE0_ADC_AOSR_VAL, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_ADC_IDAC_VAL, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_ADC_MINIDSP_DECIMATION, 0x04);
codec_writeRegister(CODEC_REG_PAGE0_CLKOUT_M_VAL, 0x01);
codec_writeRegister(CODEC_REG_PAGE0_BCLK_N_VAL, 0x01);
codec_writeRegister(CODEC_REG_PAGE0_ADC_FLAG_REGISTER, 0x80);
codec_writeRegister(CODEC_REG_PAGE0_GPIO1_IN_OUT_PIN_CONTROL, 0x34);
codec_writeRegister(CODEC_REG_PAGE0_GPIO2_IN_OUT_PIN_CONTROL, 0x32);
codec_writeRegister(CODEC_REG_PAGE0_SDOUT_OUT_PIN_CONTROL, 0x12);
codec_writeRegister(CODEC_REG_PAGE0_SDIN_IN_PIN_CONTROL, 0x03);
codec_writeRegister(CODEC_REG_PAGE0_MISO_OUT_PIN_CONTROL, 0x02);
codec_writeRegister(CODEC_REG_PAGE0_SCLK_IN_PIN_CONTROL, 0x03);
codec_writeRegister(CODEC_REG_PAGE0_DAC_INSTRUCTION_SET, 0x19);
codec_writeRegister(CODEC_REG_PAGE0_ADC_INSTRUCTION_SET, 0x05);
codec_writeRegister(CODEC_REG_PAGE0_DRC_CONTROL_1, 0x0F);
codec_writeRegister(CODEC_REG_PAGE0_DRC_CONTROL_2, 0x38);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_LENGTH_MSB, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_LENGTH_MID, 0x00);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_LENGTH_LSB, 0xEE);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_SIN_MSB, 0x10);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_SIN_LSB, 0xD8);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_COS_MSB, 0x7E);
codec_writeRegister(CODEC_REG_PAGE0_BEEP_COS_LSB, 0xE3);
codec_writeRegister(CODEC_REG_PAGE0_AGC_MAXIMUM_GAIN, 0x7F);
codec_writeRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_SAR_ADC_VOLUME_CONTROL, 0xD2);
codec_writeRegister(CODEC_REG_PAGE0_VOL_MICDET_PIN_GAIN, 0x2C);
}
codec_setPage(CODEC_PAGE_1);
{
codec_writeRegister(CODEC_REG_PAGE1_OUTPUT_DRIVER_PGA_RAMP_DOWN_PERIOD_CONTROL, 0x70);
codec_writeRegister(CODEC_REG_PAGE1_HP_DRIVER_CONTROL, 0x20);
}
// Finish up!
codec_setPage(CODEC_PAGE_3);
{
codec_readRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_1);
codec_writeRegister(CODEC_REG_PAGE3_SAR_ADC_CONTROL_1, 0x98);
}
codec_setPage(CODEC_PAGE_255);
{
codec_writeRegister(CODEC_REG_PAGE255_BACKWARDS_COMPATIBILITY_MODE, CODEC_PAGE255_BACKWARDS_COMPATIBILITY_MODE_ON);
}
pmic_setAmplifierEnable(true);
}
bool DSMode::ShouldUseVolumeFix(u32 gameCode) const
{
switch (gameCode & 0xFFFFFF)
{
case GAMECODE_NO_REGION("A3T"):
case GAMECODE_NO_REGION("A4U"):
case GAMECODE_NO_REGION("A5H"):
case GAMECODE_NO_REGION("A5I"):
case GAMECODE_NO_REGION("A8N"):
case GAMECODE_NO_REGION("ABJ"):
case GAMECODE_NO_REGION("ABN"):
case GAMECODE_NO_REGION("ABX"):
case GAMECODE_NO_REGION("ACC"):
case GAMECODE_NO_REGION("ACL"):
case GAMECODE_NO_REGION("ACZ"):
case GAMECODE_NO_REGION("ADA"):
case GAMECODE_NO_REGION("AHD"):
case GAMECODE_NO_REGION("AJU"):
case GAMECODE_NO_REGION("AKA"):
case GAMECODE_NO_REGION("AKE"):
case GAMECODE_NO_REGION("ALH"):
case GAMECODE_NO_REGION("AMH"):
case GAMECODE_NO_REGION("AN9"):
case GAMECODE_NO_REGION("ANR"):
case GAMECODE_NO_REGION("APA"):
case GAMECODE_NO_REGION("APY"):
case GAMECODE_NO_REGION("ART"):
case GAMECODE_NO_REGION("AV2"):
case GAMECODE_NO_REGION("AV3"):
case GAMECODE_NO_REGION("AV4"):
case GAMECODE_NO_REGION("AV5"):
case GAMECODE_NO_REGION("AV6"):
case GAMECODE_NO_REGION("AVI"):
case GAMECODE_NO_REGION("AVT"):
case GAMECODE_NO_REGION("AWH"):
case GAMECODE_NO_REGION("AWY"):
case GAMECODE_NO_REGION("AXB"):
case GAMECODE_NO_REGION("AXJ"):
case GAMECODE_NO_REGION("AY7"):
case GAMECODE_NO_REGION("AYK"):
case GAMECODE_NO_REGION("AZW"):
case GAMECODE_NO_REGION("CPU"):
case GAMECODE_NO_REGION("YB2"):
case GAMECODE_NO_REGION("YB3"):
case GAMECODE_NO_REGION("YBO"):
case GAMECODE_NO_REGION("YCH"):
case GAMECODE_NO_REGION("YCQ"):
case GAMECODE_NO_REGION("YFE"):
case GAMECODE_NO_REGION("YFS"):
case GAMECODE_NO_REGION("YG8"):
case GAMECODE_NO_REGION("YGD"):
case GAMECODE_NO_REGION("YKR"):
case GAMECODE_NO_REGION("YNZ"):
case GAMECODE_NO_REGION("YO9"):
case GAMECODE_NO_REGION("YON"):
case GAMECODE_NO_REGION("YRM"):
case GAMECODE_NO_REGION("YT3"):
case GAMECODE_NO_REGION("YW2"):
case GAMECODE_NO_REGION("YYK"):
{
return true;
}
default:
{
return false;
}
}
}