diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 02169c99d..d3cbae4c1 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -11,6 +11,7 @@ #define PINMUX_BASE (APB_MISC_BASE + 0x3000) #define PMC_BASE 0x7000E400 #define MAX_GPIOS 0x3D +#define MAX_PINMUX 0xA2 extern "C" { extern u32 __start__; @@ -41,7 +42,7 @@ void __libnx_initheap(void) { void __appInit(void) { Result rc; - /* Initialize services we need (TODO: SPL, NCM) */ + /* Initialize services we need (TODO: NCM) */ rc = smInitialize(); if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); @@ -50,10 +51,14 @@ void __appInit(void) { if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); - rc = pmshellInitialize(); + rc = splInitialize(); if (R_FAILED(rc)) fatalSimple(0xCAFE << 4 | 1); + rc = pmshellInitialize(); + if (R_FAILED(rc)) + fatalSimple(0xCAFE << 4 | 2); + fsdevInit(); } @@ -61,11 +66,13 @@ void __appExit(void) { /* Cleanup services. */ fsdevExit(); pmshellExit(); + splExit(); fsExit(); smExit(); } static const std::tuple g_gpio_map[] = { + /* Icosa, Copper, Hoag and Mariko */ {0xFFFFFFFF, false, false}, /* Invalid */ {0x000000CC, true, false}, /* Port Z, Pin 4 */ {0x00000024, true, false}, /* Port E, Pin 4 */ @@ -127,22 +134,31 @@ static const std::tuple g_gpio_map[] = { {0x00000058, true, false}, /* Port L, Pin 0 */ {0x0000003E, false, false}, /* Port H, Pin 6 */ {0x00000026, false, false}, /* Port E, Pin 6 */ + + /* Copper only */ {0xFFFFFFFF, false, false}, /* Invalid */ {0x00000033, false, false}, /* Port G, Pin 3 */ {0x0000001C, false, false}, /* Port D, Pin 4 */ - {0x000000D9, false, false}, /* Port BB, Pin 1 */ + {0x000000D9, true, false}, /* Port BB, Pin 1 */ {0x0000000C, false, false}, /* Port B, Pin 4 */ {0x0000000D, false, false}, /* Port B, Pin 5 */ - {0x00000021, false, false}, /* Port E, Pin 1 */ + {0x00000021, true, false}, /* Port E, Pin 1 */ {0x00000027, false, false}, /* Port E, Pin 7 */ {0x00000092, false, false}, /* Port S, Pin 2 */ - {0x00000095, false, false}, /* Port S, Pin 5 */ - {0x00000098, false, false}, /* Port T, Pin 0 */ - {0x00000010, false, false}, /* Port C, Pin 0 */ - {0x00000011, false, false}, /* Port C, Pin 1 */ - {0x00000012, false, false}, /* Port C, Pin 2 */ - {0x00000042, false, false}, /* Port I, Pin 2 */ + {0x00000095, true, false}, /* Port S, Pin 5 */ + {0x00000098, true, false}, /* Port T, Pin 0 */ + {0x00000010, true, false}, /* Port C, Pin 0 */ + {0x00000011, true, false}, /* Port C, Pin 1 */ + {0x00000012, true, false}, /* Port C, Pin 2 */ + {0x00000042, true, false}, /* Port I, Pin 2 */ {0x000000E6, false, false}, /* Port CC, Pin 6 */ + + /* 2.0.0+ Copper only */ + {0x000000AC, true, false}, /* Port V, Pin 4 */ + {0x000000E1, false, false}, /* Port CC, Pin 1 */ + + /* 5.0.0+ Copper only (unused) */ + {0x00000056, false, false}, /* Port K, Pin 6 */ }; static int gpio_configure(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { @@ -174,7 +190,7 @@ static int gpio_set_direction(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { /* Convert the GPIO pad descriptor into its register offset */ u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C)); - /* Set the direction bit and lock values (bug?) */ + /* Set the direction bit and lock values */ u32 gpio_oe_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (is_out << (gpio_pad_desc & 0x07))); /* Write to the appropriate GPIO_OE_x register (upper offset) */ @@ -186,7 +202,7 @@ static int gpio_set_direction(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { return gpio_oe_val; } -static int gpio_set_output(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { +static int gpio_set_value(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { /* Fetch this GPIO's pad descriptor */ u32 gpio_pad_desc = std::get<0>(g_gpio_map[gpio_pad_name]); @@ -196,7 +212,7 @@ static int gpio_set_output(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { /* Convert the GPIO pad descriptor into its register offset */ u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C)); - /* Set the output bit and lock values (bug?) */ + /* Set the output bit and lock values */ u32 gpio_out_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (is_high << (gpio_pad_desc & 0x07))); /* Write to the appropriate GPIO_OUT_x register (upper offset) */ @@ -208,6 +224,198 @@ static int gpio_set_output(u64 gpio_base_vaddr, unsigned int gpio_pad_name) { return gpio_out_val; } +static const std::tuple g_pinmux_map[] = { + {0x00003000, 0x72FF, 0x01}, /* Sdmmc1Clk */ + {0x00003004, 0x72FF, 0x02}, /* Sdmmc1Cmd */ + {0x00003008, 0x72FF, 0x02}, /* Sdmmc1Dat3 */ + {0x0000300C, 0x72FF, 0x02}, /* Sdmmc1Dat2 */ + {0x00003010, 0x72FF, 0x02}, /* Sdmmc1Dat1 */ + {0x00003014, 0x72FF, 0x01}, /* Sdmmc1Dat0 */ + {0x0000301C, 0x72FF, 0x01}, /* Sdmmc3Clk */ + {0x00003020, 0x72FF, 0x01}, /* Sdmmc3Cmd */ + {0x00003024, 0x72FF, 0x01}, /* Sdmmc3Dat0 */ + {0x00003028, 0x72FF, 0x01}, /* Sdmmc3Dat1 */ + {0x0000302C, 0x72FF, 0x01}, /* Sdmmc3Dat2 */ + {0x00003030, 0x72FF, 0x01}, /* Sdmmc3Dat3 */ + {0x00003038, 0x1DFF, 0x01}, /* PexL0RstN */ + {0x0000303C, 0x1DFF, 0x01}, /* PexL0ClkreqN */ + {0x00003040, 0x1DFF, 0x01}, /* PexWakeN */ + {0x00003044, 0x1DFF, 0x01}, /* PexL1RstN */ + {0x00003048, 0x1DFF, 0x01}, /* PexL1ClkreqN */ + {0x0000304C, 0x19FF, 0x01}, /* SataLedActive */ + {0x00003050, 0x1F2FF, 0x01}, /* Spi1Mosi */ + {0x00003054, 0x1F2FF, 0x01}, /* Spi1Miso */ + {0x00003058, 0x1F2FF, 0x01}, /* Spi1Sck */ + {0x0000305C, 0x1F2FF, 0x01}, /* Spi1Cs0 */ + {0x00003060, 0x1F2FF, 0x01}, /* Spi1Cs1 */ + {0x00003064, 0x72FF, 0x02}, /* Spi2Mosi */ + {0x00003068, 0x72FF, 0x02}, /* Spi2Miso */ + {0x0000306C, 0x72FF, 0x02}, /* Spi2Sck */ + {0x00003070, 0x72FF, 0x02}, /* Spi2Cs0 */ + {0x00003074, 0x72FF, 0x01}, /* Spi2Cs1 */ + {0x00003078, 0x1F2FF, 0x01}, /* Spi4Mosi */ + {0x0000307C, 0x1F2FF, 0x01}, /* Spi4Miso */ + {0x00003080, 0x1F2FF, 0x01}, /* Spi4Sck */ + {0x00003084, 0x1F2FF, 0x01}, /* Spi4Cs0 */ + {0x00003088, 0x72FF, 0x01}, /* QspiSck */ + {0x0000308C, 0x72FF, 0x01}, /* QspiCsN */ + {0x00003090, 0x72FF, 0x01}, /* QspiIo0 */ + {0x00003094, 0x72FF, 0x01}, /* QspiIo1 */ + {0x00003098, 0x72FF, 0x01}, /* QspiIo2 */ + {0x0000309C, 0x72FF, 0x01}, /* QspiIo3 */ + {0x000030A4, 0x19FF, 0x02}, /* Dmic1Clk */ + {0x000030A8, 0x19FF, 0x02}, /* Dmic1Dat */ + {0x000030AC, 0x19FF, 0x02}, /* Dmic2Clk */ + {0x000030B0, 0x19FF, 0x02}, /* Dmic2Dat */ + {0x000030B4, 0x19FF, 0x02}, /* Dmic3Clk */ + {0x000030B8, 0x19FF, 0x02}, /* Dmic3Dat */ + {0x000030BC, 0x1DFF, 0x01}, /* Gen1I2cScl */ + {0x000030C0, 0x1DFF, 0x01}, /* Gen1I2cSda */ + {0x000030C4, 0x1DFF, 0x01}, /* Gen2I2cScl */ + {0x000030C8, 0x1DFF, 0x01}, /* Gen2I2cSda */ + {0x000030CC, 0x1DFF, 0x01}, /* Gen3I2cScl */ + {0x000030D0, 0x1DFF, 0x01}, /* Gen3I2cSda */ + {0x000030D4, 0x1DFF, 0x02}, /* CamI2cScl */ + {0x000030D8, 0x1DFF, 0x02}, /* CamI2cSda */ + {0x000030DC, 0x1DFF, 0x01}, /* PwrI2cScl */ + {0x000030E0, 0x1DFF, 0x01}, /* PwrI2cSda */ + {0x000030E4, 0x19FF, 0x01}, /* Uart1Tx */ + {0x000030E8, 0x19FF, 0x01}, /* Uart1Rx */ + {0x000030EC, 0x19FF, 0x01}, /* Uart1Rts */ + {0x000030F0, 0x19FF, 0x01}, /* Uart1Cts */ + {0x000030F4, 0x19FF, 0x00}, /* Uart2Tx */ + {0x000030F8, 0x19FF, 0x00}, /* Uart2Rx */ + {0x000030FC, 0x19FF, 0x02}, /* Uart2Rts */ + {0x00003100, 0x19FF, 0x02}, /* Uart2Cts */ + {0x00003104, 0x19FF, 0x02}, /* Uart3Tx */ + {0x00003108, 0x19FF, 0x02}, /* Uart3Rx */ + {0x0000310C, 0x19FF, 0x02}, /* Uart3Rts */ + {0x00003110, 0x19FF, 0x02}, /* Uart3Cts */ + {0x00003114, 0x19FF, 0x02}, /* Uart4Tx */ + {0x00003118, 0x19FF, 0x02}, /* Uart4Rx */ + {0x0000311C, 0x19FF, 0x02}, /* Uart4Rts */ + {0x00003120, 0x19FF, 0x02}, /* Uart4Cts */ + {0x00003124, 0x72FF, 0x01}, /* Dap1Fs */ + {0x00003128, 0x72FF, 0x01}, /* Dap1Din */ + {0x0000312C, 0x72FF, 0x01}, /* Dap1Dout */ + {0x00003130, 0x72FF, 0x01}, /* Dap1Sclk */ + {0x00003134, 0x72FF, 0x01}, /* Dap2Fs */ + {0x00003138, 0x72FF, 0x01}, /* Dap2Din */ + {0x0000313C, 0x72FF, 0x01}, /* Dap2Dout */ + {0x00003140, 0x72FF, 0x01}, /* Dap2Sclk */ + {0x00003144, 0x72FF, 0x01}, /* Dap4Fs */ + {0x00003148, 0x72FF, 0x01}, /* Dap4Din */ + {0x0000314C, 0x72FF, 0x01}, /* Dap4Dout */ + {0x00003150, 0x72FF, 0x01}, /* Dap4Sclk */ + {0x00003154, 0x72FF, 0x01}, /* Cam1Mclk */ + {0x00003158, 0x72FF, 0x01}, /* Cam2Mclk */ + {0x0000315C, 0x72FF, 0x01}, /* JtagRtck */ + {0x00003160, 0x118C, 0xFF}, /* Clk32kIn */ + {0x00003164, 0x72FF, 0x02}, /* Clk32kOut */ + {0x00003168, 0x1DFF, 0x01}, /* BattBcl */ + {0x0000316C, 0x11CC, 0xFF}, /* ClkReq */ + {0x00003170, 0x11CC, 0xFF}, /* CpuPwrReq */ + {0x00003174, 0x11CC, 0xFF}, /* PwrIntN */ + {0x00003178, 0x11CC, 0xFF}, /* Shutdown */ + {0x0000317C, 0x11CC, 0xFF}, /* CorePwrReq */ + {0x00003180, 0x19FF, 0x01}, /* AudMclk */ + {0x00003184, 0x19FF, 0x00}, /* DvfsPwm */ + {0x00003188, 0x19FF, 0x00}, /* DvfsClk */ + {0x0000318C, 0x19FF, 0x00}, /* GpioX1Aud */ + {0x00003190, 0x19FF, 0x00}, /* GpioX3Aud */ + {0x00003194, 0x1DFF, 0x00}, /* GpioPcc7 */ + {0x00003198, 0x1DFF, 0x01}, /* HdmiCec */ + {0x0000319C, 0x1DFF, 0x01}, /* HdmiIntDpHpd */ + {0x000031A0, 0x19FF, 0x01}, /* SpdifOut */ + {0x000031A4, 0x19FF, 0x01}, /* SpdifIn */ + {0x000031A8, 0x1DFF, 0x01}, /* UsbVbusEn0 */ + {0x000031AC, 0x1DFF, 0x01}, /* UsbVbusEn1 */ + {0x000031B0, 0x19FF, 0x01}, /* DpHpd0 */ + {0x000031B4, 0x19FF, 0x00}, /* WifiEn */ + {0x000031B8, 0x19FF, 0x00}, /* WifiRst */ + {0x000031BC, 0x19FF, 0x00}, /* WifiWakeAp */ + {0x000031C0, 0x19FF, 0x00}, /* ApWakeBt */ + {0x000031C4, 0x19FF, 0x00}, /* BtRst */ + {0x000031C8, 0x19FF, 0x00}, /* BtWakeAp */ + {0x000031CC, 0x19FF, 0x00}, /* ApWakeNfc */ + {0x000031D0, 0x19FF, 0x00}, /* NfcEn */ + {0x000031D4, 0x19FF, 0x00}, /* NfcInt */ + {0x000031D8, 0x19FF, 0x00}, /* GpsEn */ + {0x000031DC, 0x19FF, 0x00}, /* GpsRst */ + {0x000031E0, 0x19FF, 0x01}, /* CamRst */ + {0x000031E4, 0x19FF, 0x02}, /* CamAfEn */ + {0x000031E8, 0x19FF, 0x02}, /* CamFlashEn */ + {0x000031EC, 0x19FF, 0x01}, /* Cam1Pwdn */ + {0x000031F0, 0x19FF, 0x01}, /* Cam2Pwdn */ + {0x000031F4, 0x19FF, 0x01}, /* Cam1Strobe */ + {0x000031F8, 0x19FF, 0x01}, /* LcdTe */ + {0x000031FC, 0x19FF, 0x03}, /* LcdBlPwm */ + {0x00003200, 0x19FF, 0x00}, /* LcdBlEn */ + {0x00003204, 0x19FF, 0x00}, /* LcdRst */ + {0x00003208, 0x19FF, 0x01}, /* LcdGpio1 */ + {0x0000320C, 0x19FF, 0x02}, /* LcdGpio2 */ + {0x00003210, 0x19FF, 0x00}, /* ApReady */ + {0x00003214, 0x19FF, 0x00}, /* TouchRst */ + {0x00003218, 0x19FF, 0x01}, /* TouchClk */ + {0x0000321C, 0x19FF, 0x00}, /* ModemWakeAp */ + {0x00003220, 0x19FF, 0x00}, /* TouchInt */ + {0x00003224, 0x19FF, 0x00}, /* MotionInt */ + {0x00003228, 0x19FF, 0x00}, /* AlsProxInt */ + {0x0000322C, 0x19FF, 0x00}, /* TempAlert */ + {0x00003230, 0x19FF, 0x00}, /* ButtonPowerOn */ + {0x00003234, 0x19FF, 0x00}, /* ButtonVolUp */ + {0x00003238, 0x19FF, 0x00}, /* ButtonVolDown */ + {0x0000323C, 0x19FF, 0x00}, /* ButtonSlideSw */ + {0x00003240, 0x19FF, 0x00}, /* ButtonHome */ + {0x00003244, 0x19FF, 0x01}, /* GpioPa6 */ + {0x00003248, 0x19FF, 0x00}, /* GpioPe6 */ + {0x0000324C, 0x19FF, 0x00}, /* GpioPe7 */ + {0x00003250, 0x19FF, 0x00}, /* GpioPh6 */ + {0x00003254, 0x72FF, 0x02}, /* GpioPk0 */ + {0x00003258, 0x72FF, 0x02}, /* GpioPk1 */ + {0x0000325C, 0x72FF, 0x02}, /* GpioPk2 */ + {0x00003260, 0x72FF, 0x02}, /* GpioPk3 */ + {0x00003264, 0x72FF, 0x01}, /* GpioPk4 */ + {0x00003268, 0x72FF, 0x01}, /* GpioPk5 */ + {0x0000326C, 0x72FF, 0x01}, /* GpioPk6 */ + {0x00003270, 0x72FF, 0x01}, /* GpioPk7 */ + {0x00003274, 0x72FF, 0x00}, /* GpioPl0 */ + {0x00003278, 0x72FF, 0x01}, /* GpioPl1 */ + {0x0000327C, 0x72FF, 0x01}, /* GpioPz0 */ + {0x00003280, 0x72FF, 0x02}, /* GpioPz1 */ + {0x00003284, 0x72FF, 0x02}, /* GpioPz2 */ + {0x00003288, 0x72FF, 0x01}, /* GpioPz3 */ + {0x0000328C, 0x72FF, 0x01}, /* GpioPz4 */ + {0x00003290, 0x72FF, 0x01}, /* GpioPz5 */ +}; + +static int pinmux_update_park(u64 pinmux_base_vaddr, unsigned int pinmux_idx) { + /* Fetch this PINMUX's register offset */ + u32 pinmux_reg_offset = std::get<0>(g_pinmux_map[pinmux_idx]); + + /* Fetch this PINMUX's mask value */ + u32 pinmux_mask_val = std::get<1>(g_pinmux_map[pinmux_idx]); + + /* Read from the PINMUX register */ + u32 pinmux_val = *((u32 *)pinmux_base_vaddr + pinmux_reg_offset); + + /* This PINMUX supports park change */ + if (pinmux_mask_val & 0x20) { + /* Clear park status if set */ + if (pinmux_val & 0x20) { + pinmux_val &= ~(0x20); + } + } + + /* Write to the appropriate PINMUX register */ + *((u32 *)pinmux_base_vaddr + pinmux_reg_offset) = pinmux_val; + + /* Do a dummy read from the PINMUX register */ + pinmux_val = *((u32 *)pinmux_base_vaddr + pinmux_reg_offset); + + return pinmux_val; +} + int main(int argc, char **argv) { consoleDebugInit(debugDevice_SVC); @@ -239,7 +447,19 @@ int main(int argc, char **argv) /* Change GPIO voltage to 1.8v */ if (kernelAbove200()) { - /* TODO: svcReadWriteRegister */ + u32 rw_reg_val = 0; + + /* Use svcReadWriteRegister to write APBDEV_PMC_PWR_DET_0 */ + rc = svcReadWriteRegister(&rw_reg_val, PMC_BASE + 0x48, 0xA42000, 0xA42000); + if (R_FAILED(rc)) { + return rc; + } + + /* Use svcReadWriteRegister to write APBDEV_PMC_PWR_DET_VAL_0 */ + rc = svcReadWriteRegister(&rw_reg_val, PMC_BASE + 0xE4, 0, 0xA42000); + if (R_FAILED(rc)) { + return rc; + } } else { /* Map the PMC registers directly */ rc = svcQueryIoMapping(&pmc_base_vaddr, PMC_BASE, 0x3000); @@ -252,10 +472,10 @@ int main(int argc, char **argv) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_IoError)); /* Write to APBDEV_PMC_PWR_DET_0 */ - *((u32 *)pmc_base_vaddr + 0x48) |= 0x00A42000; + *((u32 *)pmc_base_vaddr + 0x48) |= 0xA42000; /* Write to APBDEV_PMC_PWR_DET_VAL_0 */ - *((u32 *)pmc_base_vaddr + 0xE4) &= 0xFF5BDFFF; + *((u32 *)pmc_base_vaddr + 0xE4) &= ~(0xA42000); } /* Wait for changes to take effect */ @@ -265,10 +485,58 @@ int main(int argc, char **argv) for (unsigned int i = 1; i < MAX_GPIOS; i++) { gpio_configure(gpio_base_vaddr, i); gpio_set_direction(gpio_base_vaddr, i); - gpio_set_output(gpio_base_vaddr, i); + gpio_set_value(gpio_base_vaddr, i); } - /* TODO: Hardware setup, NAND repair, NotifyBootFinished */ + u64 hardware_type = 0; + + /* Get the hardware type from SPL */ + rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type); + if (R_FAILED(rc)) { + return rc; + } + + /* This is ignored in Copper hardware */ + if (hardware_type != 0x01) { + /* TODO: Battery charge check */ + } + + /* Update PINMUX park status */ + for (unsigned int i = 0; i < MAX_PINMUX; i++) { + pinmux_update_park(pinmux_base_vaddr, i); + } + + /* TODO: Set initial PINMUX configuration */ + /* TODO: Set initial PINMUX drive pad configuration */ + /* TODO: Set initial wake pin configuration */ + + /* This is ignored in Copper hardware */ + if (hardware_type != 0x01) { + /* Configure PMC clock out */ + if (kernelAbove200()) { + u32 rw_reg_val = 0; + + /* Use svcReadWriteRegister to write APBDEV_PMC_CLK_OUT_CNTRL_0 */ + rc = svcReadWriteRegister(&rw_reg_val, PMC_BASE + 0x1A8, 0xC4, 0xC4); + if (R_FAILED(rc)) { + return rc; + } + } else { + /* Write to APBDEV_PMC_CLK_OUT_CNTRL_0 */ + *((u32 *)pmc_base_vaddr + 0x1A8) |= 0xC4; + } + } + + /* Setup GPIO 0x4B for Copper hardware only */ + if (hardware_type == 0x01) { + gpio_configure(gpio_base_vaddr, 0x4B); + gpio_set_direction(gpio_base_vaddr, 0x4B); + gpio_set_value(gpio_base_vaddr, 0x4B); + } + + /* TODO: NAND repair */ + + /* pmshellNotifyBootFinished(); */ rc = 0; return rc;