/* * Copyright (c) 2018 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 . */ #include #include #include #include #include #include #include #define CAR_BASE 0x60006000 #define GPIO_BASE 0x6000D000 #define APB_MISC_BASE 0x70000000 #define PINMUX_BASE (APB_MISC_BASE + 0x3000) #define PMC_BASE 0x7000E400 #define MAX_GPIO_ICOSA 0x3C #define MAX_GPIO_COPPER 0x2C #define MAX_GPIO_MARIKO 0x3A #define MAX_PINMUX 0xA2 #define MAX_PINMUX_MARIKO 0xAF #define MAX_PINMUX_DRIVEPAD 0x2F #define MAX_PMC_CONTROL 0x09 #define MAX_PMC_WAKE_PIN 0x31 extern "C" { extern u32 __start__; u32 __nx_applet_type = AppletType_None; #define INNER_HEAP_SIZE 0x200000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; void __libnx_initheap(void); void __appInit(void); void __appExit(void); } void __libnx_initheap(void) { void* addr = nx_inner_heap; size_t size = nx_inner_heap_size; /* Newlib */ extern char* fake_heap_start; extern char* fake_heap_end; fake_heap_start = (char*)addr; fake_heap_end = (char*)addr + size; } void __appInit(void) { Result rc; /* Initialize services we need (TODO: NCM) */ rc = smInitialize(); if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); rc = fsInitialize(); if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); rc = splInitialize(); if (R_FAILED(rc)) fatalSimple(0xCAFE << 4 | 1); rc = pmshellInitialize(); if (R_FAILED(rc)) fatalSimple(0xCAFE << 4 | 2); fsdevMountSdmc(); CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION); } void __appExit(void) { /* Cleanup services. */ fsdevUnmountAll(); pmshellExit(); splExit(); fsExit(); smExit(); } typedef enum { HARDWARETYPE_ICOSA = 0, HARDWARETYPE_COPPER = 1, HARDWARETYPE_HOAG = 2, HARDWARETYPE_MARIKO = 3, HARDWARETYPE_INVALID = 4 } HardwareType; static const std::tuple g_gpio_map[] = { /* Icosa, Copper, Hoag and Mariko */ {0xFFFFFFFF, 0xFFFFFFFF}, /* Invalid */ {0x000000CC, 0xFFFFFFFF}, /* Port Z, Pin 4 */ {0x00000024, 0xFFFFFFFF}, /* Port E, Pin 4 */ {0x0000003C, 0xFFFFFFFF}, /* Port H, Pin 4 */ {0x000000DA, 0xFFFFFFFF}, /* Port BB, Pin 2 */ {0x000000DB, 0xFFFFFFFF}, /* Port BB, Pin 3 */ {0x000000DC, 0xFFFFFFFF}, /* Port BB, Pin 4 */ {0x00000025, 0xFFFFFFFF}, /* Port E, Pin 5 */ {0x00000090, 0xFFFFFFFF}, /* Port S, Pin 0 */ {0x00000091, 0xFFFFFFFF}, /* Port S, Pin 1 */ {0x00000096, 0xFFFFFFFF}, /* Port S, Pin 6 */ {0x00000097, 0xFFFFFFFF}, /* Port S, Pin 7 */ {0x00000026, 0x00000004}, /* Port E, Pin 6 */ {0x00000005, 0xFFFFFFFF}, /* Port A, Pin 5 */ {0x00000078, 0xFFFFFFFF}, /* Port P, Pin 0 */ {0x00000093, 0x00000030}, /* Port S, Pin 3 */ {0x0000007D, 0xFFFFFFFF}, /* Port P, Pin 5 */ {0x0000007C, 0xFFFFFFFF}, /* Port P, Pin 4 */ {0x0000007B, 0xFFFFFFFF}, /* Port P, Pin 3 */ {0x0000007A, 0xFFFFFFFF}, /* Port P, Pin 2 */ {0x000000BC, 0xFFFFFFFF}, /* Port X, Pin 4 */ {0x000000AE, 0xFFFFFFFF}, /* Port V, Pin 6 */ {0x000000BA, 0xFFFFFFFF}, /* Port X, Pin 2 */ {0x000000B9, 0xFFFFFFFF}, /* Port X, Pin 1 */ {0x000000BD, 0xFFFFFFFF}, /* Port X, Pin 5 */ {0x000000BE, 0xFFFFFFFF}, /* Port X, Pin 6 */ {0x000000BF, 0xFFFFFFFF}, /* Port X, Pin 7 */ {0x000000C0, 0x0000001B}, /* Port Y, Pin 0 */ {0x000000C1, 0xFFFFFFFF}, /* Port Y, Pin 1 */ {0x000000A9, 0xFFFFFFFF}, /* Port V, Pin 1 */ {0x000000AA, 0xFFFFFFFF}, /* Port V, Pin 2 */ {0x00000055, 0xFFFFFFFF}, /* Port K, Pin 5 */ {0x000000AD, 0xFFFFFFFF}, /* Port V, Pin 5 */ {0x000000C8, 0x00000022}, /* Port Z, Pin 0 */ {0x000000CA, 0xFFFFFFFF}, /* Port Z, Pin 2 */ {0x000000CB, 0xFFFFFFFF}, /* Port Z, Pin 3 */ {0x0000004F, 0xFFFFFFFF}, /* Port J, Pin 7 */ {0x00000050, 0xFFFFFFFF}, /* Port K, Pin 0 */ {0x00000051, 0xFFFFFFFF}, /* Port K, Pin 1 */ {0x00000052, 0xFFFFFFFF}, /* Port K, Pin 2 */ {0x00000054, 0x0000000E}, /* Port K, Pin 4 */ {0x00000056, 0xFFFFFFFF}, /* Port K, Pin 6 */ {0x00000057, 0xFFFFFFFF}, /* Port K, Pin 7 */ {0x00000053, 0xFFFFFFFF}, /* Port K, Pin 3 */ {0x000000E3, 0xFFFFFFFF}, /* Port CC, Pin 3 */ {0x00000038, 0xFFFFFFFF}, /* Port H, Pin 0 */ {0x00000039, 0xFFFFFFFF}, /* Port H, Pin 1 */ {0x0000003B, 0xFFFFFFFF}, /* Port H, Pin 3 */ {0x0000003D, 0x00000034}, /* Port H, Pin 5 */ {0x0000003F, 0xFFFFFFFF}, /* Port H, Pin 7 */ {0x00000040, 0xFFFFFFFF}, /* Port I, Pin 0 */ {0x00000041, 0xFFFFFFFF}, /* Port I, Pin 1 */ {0x0000003E, 0x0000000A}, /* Port H, Pin 6 */ {0x000000E2, 0xFFFFFFFF}, /* Port CC, Pin 2 */ {0x000000E4, 0xFFFFFFFF}, /* Port CC, Pin 4 */ {0x0000003A, 0x00000008}, /* Port H, Pin 2 */ {0x000000C9, 0x00000023}, /* Port Z, Pin 1 */ {0x0000004D, 0xFFFFFFFF}, /* Port J, Pin 5 */ {0x00000058, 0xFFFFFFFF}, /* Port L, Pin 0 */ {0x0000003E, 0xFFFFFFFF}, /* Port H, Pin 6 */ {0x00000026, 0xFFFFFFFF}, /* Port E, Pin 6 */ /* Copper only */ {0xFFFFFFFF, 0x00000033}, /* Invalid */ {0x00000033, 0x00000006}, /* Port G, Pin 3 */ {0x0000001C, 0x00000007}, /* Port D, Pin 4 */ {0x000000D9, 0xFFFFFFFF}, /* Port BB, Pin 1 */ {0x0000000C, 0xFFFFFFFF}, /* Port B, Pin 4 */ {0x0000000D, 0xFFFFFFFF}, /* Port B, Pin 5 */ {0x00000021, 0xFFFFFFFF}, /* Port E, Pin 1 */ {0x00000027, 0xFFFFFFFF}, /* Port E, Pin 7 */ {0x00000092, 0xFFFFFFFF}, /* Port S, Pin 2 */ {0x00000095, 0xFFFFFFFF}, /* Port S, Pin 5 */ {0x00000098, 0xFFFFFFFF}, /* Port T, Pin 0 */ {0x00000010, 0xFFFFFFFF}, /* Port C, Pin 0 */ {0x00000011, 0xFFFFFFFF}, /* Port C, Pin 1 */ {0x00000012, 0xFFFFFFFF}, /* Port C, Pin 2 */ {0x00000042, 0xFFFFFFFF}, /* Port I, Pin 2 */ {0x000000E6, 0xFFFFFFFF}, /* Port CC, Pin 6 */ /* 2.0.0+ Copper only */ {0x000000AC, 0xFFFFFFFF}, /* Port V, Pin 4 */ {0x000000E1, 0xFFFFFFFF}, /* Port CC, Pin 1 */ /* 5.0.0+ Copper only (unused) */ {0x00000056, 0xFFFFFFFF}, /* Port K, Pin 6 */ }; static const std::tuple g_gpio_config_map_icosa[] = { {0x04, false, true}, {0x05, true, false}, {0x06, false, false}, {0x02, true, false}, {0x07, true, false}, {0x3C, false, false}, {0x0F, false, true}, {0x08, false, false}, {0x09, false, false}, {0x0A, true, false}, {0x0B, false, true}, {0x0D, true, false}, {0x0E, false, false}, {0x10, false, false}, {0x11, false, false}, {0x12, false, false}, {0x13, false, false}, {0x14, false, true}, {0x16, false, false}, {0x15, false, false}, {0x17, false, true}, {0x18, false, false}, {0x19, false, true}, {0x1A, false, true}, {0x1B, false, true}, {0x1C, false, false}, {0x1D, true, false}, {0x1E, true, false}, {0x20, true, false}, {0x21, false, true}, {0x38, false, true}, {0x22, false, false}, {0x23, false, true}, {0x01, true, false}, {0x39, true, false}, {0x24, true, false}, {0x34, false, false}, {0x25, false, false}, {0x26, false, false}, {0x27, false, false}, {0x2B, true, false}, {0x28, false, true}, {0x1F, true, false}, {0x29, false, true}, {0x2A, false, true}, {0x3A, true, false}, {0x0C, false, false}, {0x2D, true, false}, {0x2E, true, false}, {0x37, false, false}, {0x2F, true, false}, {0x03, true, false}, {0x30, false, false}, {0x3B, false, false}, {0x31, true, false}, {0x32, true, false}, {0x33, true, false}, {0x35, false, true}, {0x2C, true, false}, {0x36, true, false}, }; static const std::tuple g_gpio_config_map_copper[] = { {0x40, true, false}, {0x05, true, false}, {0x41, false, true}, {0x42, false, false}, {0x43, true, false}, {0x02, true, false}, {0x07, true, false}, {0x44, false, true}, {0x45, false, true}, {0x0F, false, true}, {0x46, true, false}, {0x47, true, false}, {0x10, false, false}, {0x11, false, false}, {0x12, false, false}, {0x13, false, false}, {0x14, false, true}, {0x18, false, false}, {0x19, false, true}, {0x1A, false, true}, {0x1C, false, true}, {0x4D, true, false}, {0x20, true, false}, {0x38, false, true}, {0x23, false, true}, {0x25, false, false}, {0x26, false, false}, {0x27, false, false}, {0x28, false, true}, {0x29, false, true}, {0x2A, false, true}, {0x48, true, false}, {0x49, true, false}, {0x4A, true, false}, {0x2D, true, false}, {0x2E, true, false}, {0x37, false, false}, {0x2F, true, false}, {0x03, true, false}, {0x30, false, false}, {0x31, true, false}, {0x4B, true, false}, {0x4C, false, true}, {0x4E, false, false}, }; static const std::tuple g_gpio_config_map_mariko[] = { {0x04, false, true}, {0x05, true, false}, {0x06, false, false}, {0x02, true, false}, {0x3C, false, false}, {0x0F, false, true}, {0x08, false, false}, {0x09, false, false}, {0x0A, true, false}, {0x0B, false, false}, {0x0D, true, false}, {0x0E, false, false}, {0x10, false, false}, {0x11, false, false}, {0x12, false, false}, {0x13, false, false}, {0x14, false, true}, {0x16, false, false}, {0x15, false, false}, {0x17, false, true}, {0x18, false, false}, {0x19, false, true}, {0x1A, false, true}, {0x1B, false, false}, {0x1C, false, false}, {0x1D, true, false}, {0x1E, true, false}, {0x20, true, false}, {0x21, false, false}, {0x38, false, true}, {0x22, false, false}, {0x23, false, true}, {0x01, true, false}, {0x39, true, false}, {0x24, true, false}, {0x34, false, false}, {0x25, false, false}, {0x26, false, false}, {0x27, false, false}, {0x2B, true, false}, {0x28, false, true}, {0x1F, true, false}, {0x29, false, true}, {0x3A, true, false}, {0x0C, false, false}, {0x2D, true, false}, {0x2E, true, false}, {0x37, false, false}, {0x2F, true, false}, {0x03, true, false}, {0x30, false, false}, {0x3B, false, false}, {0x31, true, false}, {0x32, true, false}, {0x33, true, false}, {0x35, false, true}, {0x2C, true, false}, {0x36, true, false}, }; static int gpio_configure(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]); /* Discard invalid GPIOs */ if (gpio_pad_desc < 0) { return -1; } /* Convert the GPIO pad descriptor into its register offset */ u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C)); /* Extract the bit and lock values from the GPIO pad descriptor */ u32 gpio_cnf_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (0x01 << (gpio_pad_desc & 0x07))); /* Write to the appropriate GPIO_CNF_x register (upper offset) */ *((u32 *)gpio_base_vaddr + gpio_reg_offset + 0x80) = gpio_cnf_val; /* Do a dummy read from GPIO_CNF_x register (lower offset) */ gpio_cnf_val = *((u32 *)gpio_base_vaddr + gpio_reg_offset); return gpio_cnf_val; } static int gpio_set_direction(u64 gpio_base_vaddr, unsigned int gpio_pad_name, bool is_out) { /* Fetch this GPIO's pad descriptor */ u32 gpio_pad_desc = std::get<0>(g_gpio_map[gpio_pad_name]); /* Discard invalid GPIOs */ if (gpio_pad_desc < 0) { return -1; } /* 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 */ 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) */ *((u32 *)gpio_base_vaddr + gpio_reg_offset + 0x90) = gpio_oe_val; /* Do a dummy read from GPIO_OE_x register (lower offset) */ gpio_oe_val = *((u32 *)gpio_base_vaddr + gpio_reg_offset); return gpio_oe_val; } static int gpio_set_value(u64 gpio_base_vaddr, unsigned int gpio_pad_name, bool is_high) { /* Fetch this GPIO's pad descriptor */ u32 gpio_pad_desc = std::get<0>(g_gpio_map[gpio_pad_name]); /* Discard invalid GPIOs */ if (gpio_pad_desc < 0) { return -1; } /* 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 */ 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) */ *((u32 *)gpio_base_vaddr + gpio_reg_offset + 0xA0) = gpio_out_val; /* Do a dummy read from GPIO_OUT_x register (lower offset) */ gpio_out_val = *((u32 *)gpio_base_vaddr + gpio_reg_offset); 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 */ /* 5.0.0+ only */ {0x00003294, 0x1F2FF, 0x02}, /* Sdmmc2Dat0 */ {0x00003298, 0x1F2FF, 0x02}, /* Sdmmc2Dat1 */ {0x0000329C, 0x1F2FF, 0x02}, /* Sdmmc2Dat2 */ {0x000032A0, 0x1F2FF, 0x02}, /* Sdmmc2Dat3 */ {0x000032A4, 0x1F2FF, 0x02}, /* Sdmmc2Dat4 */ {0x000032A8, 0x1F2FF, 0x02}, /* Sdmmc2Dat5 */ {0x000032AC, 0x1F2FF, 0x02}, /* Sdmmc2Dat6 */ {0x000032B0, 0x1F2FF, 0x02}, /* Sdmmc2Dat7 */ {0x000032B4, 0x1F2FF, 0x02}, /* Sdmmc2Clk */ {0x000032B8, 0x1F2FF, 0x00}, /* Sdmmc2Clkb */ {0x000032BC, 0x1F2FF, 0x02}, /* Sdmmc2Cmd */ {0x000032C0, 0x1F2FF, 0x00}, /* Sdmmc2Dqs */ {0x000032C4, 0x1F2FF, 0x00}, /* Sdmmc2Dqsb */ }; static const std::tuple g_pinmux_config_map_icosa[] = { {0x5D, 0x00, 0x67}, {0x47, 0x28, 0x7F}, {0x48, 0x00, 0x67}, {0x46, 0x00, 0x67}, {0x49, 0x00, 0x67}, {0x30, 0x40, 0x27F}, {0x31, 0x40, 0x27F}, {0x0D, 0x20, 0x27F}, {0x0C, 0x00, 0x267}, {0x10, 0x20, 0x27F}, {0x0F, 0x00, 0x267}, {0x0E, 0x20, 0x27F}, {0x00, 0x48, 0x7F}, {0x01, 0x50, 0x7F}, {0x05, 0x50, 0x7F}, {0x04, 0x50, 0x7F}, {0x03, 0x50, 0x7F}, {0x02, 0x50, 0x7F}, {0x5B, 0x00, 0x78}, {0x7C, 0x01, 0x67}, {0x80, 0x01, 0x7F}, {0x34, 0x40, 0x27F}, {0x35, 0x40, 0x27F}, {0x55, 0x20, 0x78}, {0x56, 0x20, 0x7F}, {0xA1, 0x30, 0x7F}, {0x5C, 0x00, 0x78}, {0x59, 0x00, 0x60}, {0x5A, 0x30, 0x78}, {0x2C, 0x40, 0x27F}, {0x2D, 0x40, 0x27F}, {0x2E, 0x40, 0x27F}, {0x2F, 0x40, 0x27F}, {0x3B, 0x20, 0x7F}, {0x3C, 0x00, 0x67}, {0x3D, 0x20, 0x7F}, {0x36, 0x00, 0x67}, {0x37, 0x30, 0x7F}, {0x38, 0x00, 0x67}, {0x39, 0x28, 0x7F}, {0x54, 0x00, 0x67}, {0x9B, 0x30, 0x7F}, {0x1C, 0x00, 0x67}, {0x1D, 0x30, 0x7F}, {0x1E, 0x00, 0x67}, {0x1F, 0x00, 0x67}, {0x3F, 0x20, 0x7F}, {0x40, 0x00, 0x67}, {0x41, 0x20, 0x7F}, {0x42, 0x00, 0x67}, {0x43, 0x28, 0x7F}, {0x44, 0x00, 0x67}, {0x45, 0x28, 0x7F}, {0x22, 0x00, 0x67}, {0x23, 0x28, 0x7F}, {0x20, 0x00, 0x67}, {0x21, 0x00, 0x67}, {0x4B, 0x28, 0x7F}, {0x4C, 0x00, 0x67}, {0x4A, 0x00, 0x67}, {0x4D, 0x00, 0x67}, {0x64, 0x20, 0x27F}, {0x5F, 0x34, 0x7F}, {0x60, 0x04, 0x67}, {0x61, 0x2C, 0x7F}, {0x2A, 0x04, 0x67}, {0x2B, 0x04, 0x67}, {0x8F, 0x24, 0x7F}, {0x33, 0x34, 0x27F}, {0x52, 0x2C, 0x7F}, {0x53, 0x24, 0x7F}, {0x77, 0x04, 0x67}, {0x78, 0x34, 0x7F}, {0x11, 0x04, 0x67}, {0x06, 0x2C, 0x7F}, {0x08, 0x24, 0x7F}, {0x09, 0x24, 0x7F}, {0x0A, 0x24, 0x7F}, {0x0B, 0x24, 0x7F}, {0x88, 0x34, 0x7F}, {0x86, 0x2C, 0x7F}, {0x82, 0x24, 0x7F}, {0x85, 0x34, 0x7F}, {0x89, 0x24, 0x7F}, {0x8A, 0x34, 0x7F}, {0x8B, 0x34, 0x7F}, {0x8C, 0x34, 0x7F}, {0x8D, 0x24, 0x7F}, {0x7D, 0x04, 0x67}, {0x7E, 0x04, 0x67}, {0x81, 0x04, 0x67}, {0x9C, 0x34, 0x7F}, {0x9D, 0x34, 0x7F}, {0x9E, 0x2C, 0x7F}, {0x9F, 0x34, 0x7F}, {0xA0, 0x04, 0x67}, {0x4F, 0x04, 0x67}, {0x51, 0x04, 0x67}, {0x3A, 0x24, 0x7F}, {0x92, 0x4C, 0x7F}, {0x93, 0x4C, 0x7F}, {0x94, 0x44, 0x7F}, {0x95, 0x04, 0x67}, {0x96, 0x34, 0x7F}, {0x97, 0x04, 0x67}, {0x98, 0x34, 0x7F}, {0x99, 0x34, 0x7F}, {0x9A, 0x04, 0x67}, {0x3E, 0x24, 0x7F}, {0x6A, 0x04, 0x67}, {0x6B, 0x04, 0x67}, {0x6C, 0x2C, 0x7F}, {0x6D, 0x04, 0x67}, {0x6E, 0x04, 0x67}, {0x6F, 0x24, 0x7F}, {0x91, 0x24, 0x7F}, {0x70, 0x04, 0x7F}, {0x71, 0x04, 0x67}, {0x72, 0x04, 0x67}, {0x65, 0x34, 0x7F}, {0x66, 0x04, 0x67}, {0x67, 0x04, 0x267}, {0x5E, 0x05, 0x07}, {0x17, 0x05, 0x07}, {0x18, 0x05, 0x07}, {0x19, 0x05, 0x07}, {0x1A, 0x05, 0x07}, {0x1B, 0x05, 0x07}, {0x26, 0x05, 0x07}, {0x27, 0x05, 0x07}, {0x28, 0x05, 0x07}, {0x29, 0x05, 0x07}, {0x90, 0x05, 0x07}, {0x32, 0x05, 0x07}, {0x75, 0x05, 0x07}, {0x76, 0x05, 0x07}, {0x79, 0x05, 0x07}, {0x7A, 0x05, 0x07}, {0x8E, 0x05, 0x07}, {0x07, 0x05, 0x07}, {0x87, 0x05, 0x07}, {0x83, 0x05, 0x07}, {0x84, 0x05, 0x07}, {0x7B, 0x05, 0x07}, {0x7F, 0x05, 0x07}, {0x58, 0x00, 0x00}, {0x50, 0x05, 0x07}, {0x4E, 0x05, 0x07}, {0x12, 0x05, 0x07}, {0x13, 0x05, 0x07}, {0x14, 0x05, 0x07}, {0x15, 0x05, 0x07}, {0x16, 0x05, 0x07}, {0x73, 0x05, 0x07}, {0x74, 0x05, 0x07}, {0x24, 0x05, 0x07}, {0x25, 0x05, 0x07}, {0x62, 0x05, 0x07}, {0x68, 0x05, 0x07}, {0x69, 0x05, 0x07}, {0x63, 0x05, 0x07}, }; static const std::tuple g_pinmux_config_map_copper[] = { {0x10, 0x20, 0x27F}, {0x0F, 0x00, 0x267}, {0x0E, 0x20, 0x27F}, {0x5B, 0x00, 0x00}, {0x80, 0x01, 0x7F}, {0x34, 0x40, 0x267}, {0x35, 0x40, 0x267}, {0x55, 0x00, 0x18}, {0x56, 0x01, 0x67}, {0x5C, 0x00, 0x00}, {0x59, 0x00, 0x00}, {0x5A, 0x10, 0x18}, {0x2C, 0x40, 0x267}, {0x2D, 0x40, 0x267}, {0x2E, 0x40, 0x267}, {0x2F, 0x40, 0x267}, {0x36, 0x00, 0x67}, {0x37, 0x30, 0x7F}, {0x38, 0x00, 0x67}, {0x39, 0x28, 0x7F}, {0x54, 0x00, 0x67}, {0x9B, 0x30, 0x7F}, {0x42, 0x00, 0x67}, {0x43, 0x28, 0x7F}, {0x44, 0x00, 0x67}, {0x45, 0x28, 0x7F}, {0x4B, 0x28, 0x7F}, {0x4C, 0x00, 0x67}, {0x4A, 0x00, 0x67}, {0x4D, 0x00, 0x67}, {0x64, 0x20, 0x27F}, {0x63, 0x40, 0x267}, {0x5E, 0x04, 0x67}, {0x60, 0x04, 0x67}, {0x17, 0x24, 0x7F}, {0x18, 0x24, 0x7F}, {0x27, 0x04, 0x67}, {0x2A, 0x04, 0x67}, {0x2B, 0x04, 0x67}, {0x90, 0x24, 0x7F}, {0x32, 0x24, 0x27F}, {0x33, 0x34, 0x27F}, {0x76, 0x04, 0x67}, {0x79, 0x04, 0x67}, {0x08, 0x24, 0x7F}, {0x09, 0x24, 0x7F}, {0x0A, 0x24, 0x7F}, {0x0B, 0x24, 0x7F}, {0x88, 0x34, 0x7F}, {0x89, 0x24, 0x7F}, {0x8A, 0x34, 0x7F}, {0x8B, 0x34, 0x7F}, {0x8D, 0x34, 0x7F}, {0x81, 0x04, 0x67}, {0x9D, 0x34, 0x7F}, {0x9F, 0x34, 0x7F}, {0xA1, 0x34, 0x7F}, {0x92, 0x4C, 0x7F}, {0x93, 0x4C, 0x7F}, {0x94, 0x44, 0x7F}, {0x96, 0x34, 0x7F}, {0x98, 0x34, 0x7F}, {0x99, 0x34, 0x7F}, {0x12, 0x04, 0x7F}, {0x13, 0x04, 0x67}, {0x14, 0x04, 0x7F}, {0x6A, 0x04, 0x67}, {0x6B, 0x04, 0x67}, {0x6C, 0x2C, 0x7F}, {0x6D, 0x04, 0x67}, {0x6E, 0x04, 0x67}, {0x6F, 0x24, 0x7F}, {0x70, 0x04, 0x7F}, {0x73, 0x04, 0x67}, {0x69, 0x24, 0x7F}, {0x5D, 0x05, 0x07}, {0x5F, 0x05, 0x07}, {0x61, 0x05, 0x07}, {0x47, 0x05, 0x07}, {0x48, 0x05, 0x07}, {0x46, 0x05, 0x07}, {0x49, 0x05, 0x07}, {0x19, 0x05, 0x07}, {0x1A, 0x05, 0x07}, {0x1B, 0x05, 0x07}, {0x26, 0x05, 0x07}, {0x28, 0x05, 0x07}, {0x29, 0x05, 0x07}, {0x8F, 0x05, 0x07}, {0x30, 0x05, 0x07}, {0x31, 0x05, 0x07}, {0x52, 0x05, 0x07}, {0x53, 0x05, 0x07}, {0x75, 0x05, 0x07}, {0x77, 0x05, 0x07}, {0x78, 0x05, 0x07}, {0x7A, 0x05, 0x07}, {0x0D, 0x05, 0x07}, {0x0C, 0x05, 0x07}, {0x11, 0x05, 0x07}, {0x8E, 0x05, 0x07}, {0x00, 0x05, 0x07}, {0x01, 0x05, 0x07}, {0x05, 0x05, 0x07}, {0x04, 0x05, 0x07}, {0x03, 0x05, 0x07}, {0x02, 0x05, 0x07}, {0x06, 0x05, 0x07}, {0x07, 0x05, 0x07}, {0x87, 0x05, 0x07}, {0x86, 0x05, 0x07}, {0x82, 0x05, 0x07}, {0x83, 0x05, 0x07}, {0x85, 0x05, 0x07}, {0x84, 0x05, 0x07}, {0x8C, 0x05, 0x07}, {0x7B, 0x05, 0x07}, {0x7C, 0x05, 0x07}, {0x7D, 0x05, 0x07}, {0x7E, 0x05, 0x07}, {0x7F, 0x05, 0x07}, {0x9C, 0x05, 0x07}, {0x9E, 0x05, 0x07}, {0xA0, 0x05, 0x07}, {0x58, 0x00, 0x00}, {0x4F, 0x05, 0x07}, {0x50, 0x05, 0x07}, {0x4E, 0x05, 0x07}, {0x51, 0x05, 0x07}, {0x3A, 0x05, 0x07}, {0x3B, 0x05, 0x07}, {0x3C, 0x05, 0x07}, {0x3D, 0x05, 0x07}, {0x95, 0x05, 0x07}, {0x97, 0x05, 0x07}, {0x9A, 0x05, 0x07}, {0x15, 0x05, 0x07}, {0x16, 0x05, 0x07}, {0x1C, 0x05, 0x07}, {0x1D, 0x05, 0x07}, {0x1E, 0x05, 0x07}, {0x1F, 0x05, 0x07}, {0x3E, 0x05, 0x07}, {0x3F, 0x05, 0x07}, {0x40, 0x05, 0x07}, {0x41, 0x05, 0x07}, {0x91, 0x05, 0x07}, {0x71, 0x05, 0x07}, {0x72, 0x05, 0x07}, {0x74, 0x05, 0x07}, {0x22, 0x05, 0x07}, {0x23, 0x05, 0x07}, {0x20, 0x05, 0x07}, {0x21, 0x05, 0x07}, {0x24, 0x05, 0x07}, {0x25, 0x05, 0x07}, {0x62, 0x05, 0x07}, {0x65, 0x05, 0x07}, {0x66, 0x05, 0x07}, {0x67, 0x05, 0x07}, {0x68, 0x05, 0x07}, }; static const std::tuple g_pinmux_config_map_mariko[] = { {0x5D, 0x00, 0x7F}, {0x47, 0x28, 0x7F}, {0x48, 0x00, 0x7F}, {0x46, 0x00, 0x7F}, {0x49, 0x00, 0x7F}, {0x30, 0x40, 0x27F}, {0x31, 0x40, 0x27F}, {0x0D, 0x20, 0x27F}, {0x0C, 0x00, 0x27F}, {0x10, 0x40, 0x27F}, {0x0F, 0x00, 0x27F}, {0x0E, 0x20, 0x27F}, {0x00, 0x40, 0x7F}, {0x01, 0x50, 0x7F}, {0x05, 0x50, 0x7F}, {0x04, 0x50, 0x7F}, {0x03, 0x50, 0x7F}, {0x02, 0x50, 0x7F}, {0xAA, 0x40, 0x7F}, {0xAC, 0x40, 0x7F}, {0xA2, 0x50, 0x7F}, {0xA3, 0x50, 0x7F}, {0xA4, 0x50, 0x7F}, {0xA5, 0x50, 0x7F}, {0xA6, 0x50, 0x7F}, {0xA7, 0x50, 0x7F}, {0xA8, 0x50, 0x7F}, {0xA9, 0x50, 0x7F}, {0x5B, 0x00, 0x78}, {0x7C, 0x01, 0x67}, {0x80, 0x01, 0x7F}, {0x34, 0x40, 0x27F}, {0x35, 0x40, 0x27F}, {0x55, 0x20, 0x78}, {0x56, 0x20, 0x7F}, {0xA1, 0x30, 0x7F}, {0x5C, 0x00, 0x78}, {0x5A, 0x20, 0x78}, {0x2C, 0x40, 0x27F}, {0x2D, 0x40, 0x27F}, {0x2E, 0x40, 0x27F}, {0x2F, 0x40, 0x27F}, {0x3B, 0x20, 0x7F}, {0x3C, 0x00, 0x7F}, {0x3D, 0x20, 0x7F}, {0x36, 0x00, 0x7F}, {0x37, 0x30, 0x7F}, {0x38, 0x00, 0x7F}, {0x39, 0x28, 0x7F}, {0x54, 0x00, 0x67}, {0x9B, 0x30, 0x7F}, {0x1C, 0x00, 0x7F}, {0x1D, 0x30, 0x7F}, {0x1E, 0x00, 0x7F}, {0x1F, 0x00, 0x7F}, {0x3F, 0x20, 0x7F}, {0x40, 0x00, 0x7F}, {0x41, 0x20, 0x7F}, {0x42, 0x00, 0x7F}, {0x43, 0x28, 0x7F}, {0x44, 0x00, 0x7F}, {0x45, 0x28, 0x7F}, {0x4B, 0x28, 0x7F}, {0x4C, 0x00, 0x7F}, {0x4A, 0x00, 0x7F}, {0x4D, 0x00, 0x7F}, {0x64, 0x20, 0x27F}, {0x5F, 0x34, 0x7F}, {0x60, 0x04, 0x67}, {0x61, 0x2C, 0x7F}, {0x2A, 0x04, 0x67}, {0x8F, 0x24, 0x7F}, {0x33, 0x34, 0x27F}, {0x52, 0x2C, 0x7F}, {0x53, 0x24, 0x7F}, {0x77, 0x04, 0x67}, {0x78, 0x24, 0x7F}, {0x11, 0x04, 0x67}, {0x06, 0x2C, 0x7F}, {0x08, 0x24, 0x7F}, {0x09, 0x24, 0x7F}, {0x0A, 0x24, 0x7F}, {0x0B, 0x24, 0x7F}, {0x88, 0x34, 0x7F}, {0x86, 0x2C, 0x7F}, {0x82, 0x24, 0x7F}, {0x85, 0x34, 0x7F}, {0x89, 0x24, 0x7F}, {0x8A, 0x34, 0x7F}, {0x8B, 0x34, 0x7F}, {0x8C, 0x24, 0x7F}, {0x8D, 0x24, 0x7F}, {0x7D, 0x04, 0x67}, {0x7E, 0x04, 0x67}, {0x81, 0x04, 0x67}, {0x9C, 0x24, 0x7F}, {0x9D, 0x34, 0x7F}, {0x9E, 0x2C, 0x7F}, {0x9F, 0x34, 0x7F}, {0xA0, 0x04, 0x67}, {0x4F, 0x04, 0x67}, {0x51, 0x04, 0x67}, {0x3A, 0x24, 0x7F}, {0x92, 0x4C, 0x7F}, {0x93, 0x4C, 0x7F}, {0x94, 0x44, 0x7F}, {0x95, 0x04, 0x67}, {0x96, 0x34, 0x7F}, {0x97, 0x04, 0x67}, {0x98, 0x34, 0x7F}, {0x9A, 0x04, 0x67}, {0x3E, 0x24, 0x7F}, {0x6A, 0x04, 0x67}, {0x6B, 0x04, 0x67}, {0x6C, 0x2C, 0x7F}, {0x6D, 0x04, 0x67}, {0x6E, 0x04, 0x67}, {0x6F, 0x24, 0x7F}, {0x91, 0x24, 0x7F}, {0x70, 0x04, 0x7F}, {0x71, 0x04, 0x67}, {0x72, 0x04, 0x67}, {0x65, 0x34, 0x7F}, {0x66, 0x04, 0x67}, {0x67, 0x04, 0x267}, {0x5E, 0x05, 0x07}, {0x17, 0x05, 0x07}, {0x18, 0x05, 0x07}, {0x19, 0x05, 0x07}, {0x1A, 0x05, 0x07}, {0x1B, 0x05, 0x07}, {0x26, 0x05, 0x07}, {0x27, 0x05, 0x07}, {0x28, 0x05, 0x07}, {0x29, 0x05, 0x07}, {0x2B, 0x05, 0x07}, {0x90, 0x05, 0x07}, {0x32, 0x05, 0x07}, {0x75, 0x05, 0x07}, {0x76, 0x05, 0x07}, {0x79, 0x05, 0x07}, {0x7A, 0x05, 0x07}, {0x8E, 0x05, 0x07}, {0xAB, 0x05, 0x07}, {0xAD, 0x05, 0x07}, {0xAE, 0x05, 0x07}, {0x07, 0x05, 0x07}, {0x87, 0x05, 0x07}, {0x83, 0x05, 0x07}, {0x84, 0x05, 0x07}, {0x7B, 0x05, 0x07}, {0x7F, 0x05, 0x07}, {0x58, 0x00, 0x00}, {0x59, 0x00, 0x00}, {0x50, 0x05, 0x07}, {0x4E, 0x05, 0x07}, {0x99, 0x05, 0x07}, {0x12, 0x05, 0x07}, {0x13, 0x05, 0x07}, {0x14, 0x05, 0x07}, {0x15, 0x05, 0x07}, {0x16, 0x05, 0x07}, {0x73, 0x05, 0x07}, {0x74, 0x05, 0x07}, {0x22, 0x05, 0x07}, {0x23, 0x05, 0x07}, {0x20, 0x05, 0x07}, {0x21, 0x05, 0x07}, {0x24, 0x05, 0x07}, {0x25, 0x05, 0x07}, {0x62, 0x05, 0x07}, {0x68, 0x05, 0x07}, {0x69, 0x05, 0x07}, {0x63, 0x05, 0x07}, }; 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; } static int pinmux_update_pad(u64 pinmux_base_vaddr, unsigned int pinmux_idx, unsigned int pinmux_config_val, unsigned int pinmux_config_mask_val) { /* 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 register is locked */ if (pinmux_val & 0x80) return pinmux_val; u32 pm_config_val = (pinmux_config_val & 0x07); u32 pm_val = pm_config_val; /* Adjust PM */ if (pinmux_config_mask_val & 0x07) { /* Default to safe value */ if (pm_config_val >= 0x06) pm_val = 0x04; /* Apply additional changes first */ if (pm_config_val == 0x05) { /* This pin supports PUPD change */ if (pinmux_mask_val & 0x0C) { /* Change PUPD */ if ((pinmux_val & 0x0C) != 0x04) { pinmux_val &= 0xFFFFFFF3; pinmux_val |= 0x04; } } /* This pin supports Tristate change */ if (pinmux_mask_val & 0x10) { /* Change Tristate */ if (!(pinmux_val & 0x10)) { pinmux_val |= 0x10; } } /* This pin supports EInput change */ if (pinmux_mask_val & 0x40) { /* Change EInput */ if (pinmux_val & 0x40) { pinmux_val &= 0xFFFFFFBF; } } /* Default to safe value */ pm_val = 0x04; } /* Translate PM value if necessary */ if ((pm_val & 0xFF) == 0x04) pm_val = std::get<2>(g_pinmux_map[pinmux_idx]); /* This pin supports PM change */ if (pinmux_mask_val & 0x03) { /* Change PM */ if ((pinmux_val & 0x03) != (pm_val & 0x03)) { pinmux_val &= 0xFFFFFFFC; pinmux_val |= (pm_val & 0x03); } } } u32 pupd_config_val = (pinmux_config_val & 0x18); /* Adjust PUPD */ if (pinmux_config_mask_val & 0x18) { if (pupd_config_val < 0x11) { /* This pin supports PUPD change */ if (pinmux_mask_val & 0x0C) { /* Change PUPD */ if ((pinmux_val & 0x0C) != (pupd_config_val >> 0x03)) { pinmux_val &= 0xFFFFFFF3; pinmux_val |= (pupd_config_val >> 0x01); } } } } u32 eod_config_val = (pinmux_config_val & 0x60); /* Adjust EOd field */ if (pinmux_config_mask_val & 0x60) { if (eod_config_val == 0x20) { /* This pin supports Tristate change */ if (pinmux_mask_val & 0x10) { /* Change Tristate */ if (!(pinmux_val & 0x10)) { pinmux_val |= 0x10; } } /* This pin supports EInput change */ if (pinmux_mask_val & 0x40) { /* Change EInput */ if (!(pinmux_val & 0x40)) { pinmux_val |= 0x40; } } /* This pin supports EOd change */ if (pinmux_mask_val & 0x800) { /* Change EOd */ if (pinmux_val & 0x800) { pinmux_val &= 0xFFFFF7FF; } } } else if (eod_config_val == 0x40) { /* This pin supports Tristate change */ if (pinmux_mask_val & 0x10) { /* Change Tristate */ if (pinmux_val & 0x10) { pinmux_val &= 0xFFFFFFEF; } } /* This pin supports EInput change */ if (pinmux_mask_val & 0x40) { /* Change EInput */ if (!(pinmux_val & 0x40)) { pinmux_val |= 0x40; } } /* This pin supports EOd change */ if (pinmux_mask_val & 0x800) { /* Change EOd */ if (pinmux_val & 0x800) { pinmux_val &= 0xFFFFF7FF; } } } else if (eod_config_val == 0x60) { /* This pin supports Tristate change */ if (pinmux_mask_val & 0x10) { /* Change Tristate */ if (pinmux_val & 0x10) { pinmux_val &= 0xFFFFFFEF; } } /* This pin supports EInput change */ if (pinmux_mask_val & 0x40) { /* Change EInput */ if (!(pinmux_val & 0x40)) { pinmux_val |= 0x40; } } /* This pin supports EOd change */ if (pinmux_mask_val & 0x800) { /* Change EOd */ if (!(pinmux_val & 0x800)) { pinmux_val |= 0x800; } } } else { /* This pin supports Tristate change */ if (pinmux_mask_val & 0x10) { /* Change Tristate */ if (pinmux_val & 0x10) { pinmux_val &= 0xFFFFFFEF; } } /* This pin supports EInput change */ if (pinmux_mask_val & 0x40) { /* Change EInput */ if (pinmux_val & 0x40) { pinmux_val &= 0xFFFFFFBF; } } /* This pin supports EOd change */ if (pinmux_mask_val & 0x800) { /* Change EOd */ if (pinmux_val & 0x800) { pinmux_val &= 0xFFFFF7FF; } } } } u32 lock_config_val = (pinmux_config_val & 0x80); /* Adjust Lock */ if (pinmux_config_mask_val & 0x80) { /* This pin supports Lock change */ if (pinmux_mask_val & 0x80) { /* Change Lock */ if ((pinmux_val ^ pinmux_config_val) & 0x80) { pinmux_val &= 0xFFFFFF7F; pinmux_val |= lock_config_val; } } } u32 ioreset_config_val = ((pinmux_config_val >> 0x08) & 0x10000); /* Adjust IoReset */ if (pinmux_config_mask_val & 0x100) { /* This pin supports IoReset change */ if (pinmux_mask_val & 0x10000) { /* Change IoReset */ if (((pinmux_val >> 0x10) ^ (pinmux_config_val >> 0x08)) & 0x01) { pinmux_val |= ioreset_config_val; } } } u32 park_config_val = ((pinmux_config_val >> 0x0A) & 0x20); /* Adjust Park */ if (pinmux_config_mask_val & 0x400) { /* This pin supports Park change */ if (pinmux_mask_val & 0x20) { /* Change Park */ if (((pinmux_val >> 0x05) ^ (pinmux_config_val >> 0x0A)) & 0x01) { pinmux_val |= park_config_val; } } } u32 elpdr_config_val = ((pinmux_config_val >> 0x0B) & 0x100); /* Adjust ELpdr */ if (pinmux_config_mask_val & 0x800) { /* This pin supports ELpdr change */ if (pinmux_mask_val & 0x100) { /* Change ELpdr */ if (((pinmux_val >> 0x08) ^ (pinmux_config_val >> 0x0B)) & 0x01) { pinmux_val |= elpdr_config_val; } } } u32 ehsm_config_val = ((pinmux_config_val >> 0x0C) & 0x200); /* Adjust EHsm */ if (pinmux_config_mask_val & 0x1000) { /* This pin supports EHsm change */ if (pinmux_mask_val & 0x200) { /* Change EHsm */ if (((pinmux_val >> 0x09) ^ (pinmux_config_val >> 0x0C)) & 0x01) { pinmux_val |= ehsm_config_val; } } } u32 eiohv_config_val = ((pinmux_config_val >> 0x09) & 0x400); /* Adjust EIoHv */ if (pinmux_config_mask_val & 0x200) { /* This pin supports EIoHv change */ if (pinmux_mask_val & 0x400) { /* Change EIoHv */ if (((pinmux_val >> 0x0A) ^ (pinmux_config_val >> 0x09)) & 0x01) { pinmux_val |= eiohv_config_val; } } } u32 eschmt_config_val = ((pinmux_config_val >> 0x0D) & 0x1000); /* Adjust ESchmt */ if (pinmux_config_mask_val & 0x2000) { /* This pin supports ESchmt change */ if (pinmux_mask_val & 0x1000) { /* Change ESchmt */ if (((pinmux_val >> 0x0C) ^ (pinmux_config_val >> 0x0D)) & 0x01) { pinmux_val |= eschmt_config_val; } } } u32 preemp_config_val = ((pinmux_config_val >> 0x0D) & 0x8000); /* Adjust Preemp */ if (pinmux_config_mask_val & 0x10000) { /* This pin supports Preemp change */ if (pinmux_mask_val & 0x8000) { /* Change Preemp */ if (((pinmux_val >> 0x0F) ^ (pinmux_config_val >> 0x10)) & 0x01) { pinmux_val |= preemp_config_val; } } } u32 drvtype_config_val = ((pinmux_config_val >> 0x0E) & 0x6000); /* Adjust DrvType */ if (pinmux_config_mask_val & 0xC000) { /* This pin supports DrvType change */ if (pinmux_mask_val & 0x6000) { /* Change DrvType */ if (((pinmux_val >> 0x0D) ^ (pinmux_config_val >> 0x0E)) & 0x03) { pinmux_val |= drvtype_config_val; } } } /* 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; } static const std::tuple g_pinmux_drivepad_map[] = { {0x000008E4, 0x01F1F000}, /* AlsProxInt */ {0x000008E8, 0x01F1F000}, /* ApReady */ {0x000008EC, 0x01F1F000}, /* ApWakeBt */ {0x000008F0, 0x01F1F000}, /* ApWakeNfc */ {0x000008F4, 0x01F1F000}, /* AudMclk */ {0x000008F8, 0x01F1F000}, /* BattBcl */ {0x000008FC, 0x01F1F000}, /* BtRst */ {0x00000900, 0x01F1F000}, /* BtWakeAp */ {0x00000904, 0x01F1F000}, /* ButtonHome */ {0x00000908, 0x01F1F000}, /* ButtonPowerOn */ {0x0000090C, 0x01F1F000}, /* ButtonSlideSw */ {0x00000910, 0x01F1F000}, /* ButtonVolDown */ {0x00000914, 0x01F1F000}, /* ButtonVolUp */ {0x00000918, 0x01F1F000}, /* Cam1Mclk */ {0x0000091C, 0x01F1F000}, /* Cam1Pwdn */ {0x00000920, 0x01F1F000}, /* Cam1Strobe */ {0x00000924, 0x01F1F000}, /* Cam2Mclk */ {0x00000928, 0x01F1F000}, /* Cam2Pwdn */ {0x0000092C, 0x01F1F000}, /* CamAfEn */ {0x00000930, 0x01F1F000}, /* CamFlashEn */ {0x00000934, 0x01F1F000}, /* CamI2cScl */ {0x00000938, 0x01F1F000}, /* CamI2cSda */ {0x0000093C, 0x01F1F000}, /* CamRst */ {0x00000940, 0x01F1F000}, /* Clk32kIn */ {0x00000944, 0x01F1F000}, /* Clk32kOut */ {0x00000948, 0x01F1F000}, /* ClkReq */ {0x0000094C, 0x01F1F000}, /* CorePwrReq */ {0x00000950, 0x01F1F000}, /* CpuPwrReq */ {0x00000954, 0xF0000000}, /* Dap1Din */ {0x00000958, 0xF0000000}, /* Dap1Dout */ {0x0000095C, 0xF0000000}, /* Dap1Fs */ {0x00000960, 0xF0000000}, /* Dap1Sclk */ {0x00000964, 0xF0000000}, /* Dap2Din */ {0x00000968, 0xF0000000}, /* Dap2Dout */ {0x0000096C, 0xF0000000}, /* Dap2Fs */ {0x00000970, 0xF0000000}, /* Dap2Sclk */ {0x00000974, 0x01F1F000}, /* Dap4Din */ {0x00000978, 0x01F1F000}, /* Dap4Dout */ {0x0000097C, 0x01F1F000}, /* Dap4Fs */ {0x00000980, 0x01F1F000}, /* Dap4Sclk */ {0x00000984, 0x01F1F000}, /* Dmic1Clk */ {0x00000988, 0x01F1F000}, /* Dmic1Dat */ {0x0000098C, 0x01F1F000}, /* Dmic2Clk */ {0x00000990, 0x01F1F000}, /* Dmic2Dat */ {0x00000994, 0x01F1F000}, /* Dmic3Clk */ {0x00000998, 0x01F1F000}, /* Dmic3Dat */ {0x0000099C, 0x01F1F000}, /* DpHpd */ {0x000009A0, 0x01F1F000}, /* DvfsClk */ {0x000009A4, 0x01F1F000}, /* DvfsPwm */ {0x000009A8, 0x01F1F000}, /* Gen1I2cScl */ {0x000009AC, 0x01F1F000}, /* Gen1I2cSda */ {0x000009B0, 0x01F1F000}, /* Gen2I2cScl */ {0x000009B4, 0x01F1F000}, /* Gen2I2cSda */ {0x000009B8, 0x01F1F000}, /* Gen3I2cScl */ {0x000009BC, 0x01F1F000}, /* Gen3I2cSda */ {0x000009C0, 0x01F1F000}, /* GpioPa6 */ {0x000009C4, 0x01F1F000}, /* GpioPcc7 */ {0x000009C8, 0x01F1F000}, /* GpioPe6 */ {0x000009CC, 0x01F1F000}, /* GpioPe7 */ {0x000009D0, 0x01F1F000}, /* GpioPh6 */ {0x000009D4, 0xF0000000}, /* GpioPk0 */ {0x000009D8, 0xF0000000}, /* GpioPk1 */ {0x000009DC, 0xF0000000}, /* GpioPk2 */ {0x000009E0, 0xF0000000}, /* GpioPk3 */ {0x000009E4, 0xF0000000}, /* GpioPk4 */ {0x000009E8, 0xF0000000}, /* GpioPk5 */ {0x000009EC, 0xF0000000}, /* GpioPk6 */ {0x000009F0, 0xF0000000}, /* GpioPk7 */ {0x000009F4, 0xF0000000}, /* GpioPl0 */ {0x000009F8, 0xF0000000}, /* GpioPl1 */ {0x000009FC, 0x07F7F000}, /* GpioPz0 */ {0x00000A00, 0x07F7F000}, /* GpioPz1 */ {0x00000A04, 0x07F7F000}, /* GpioPz2 */ {0x00000A08, 0x07F7F000}, /* GpioPz3 */ {0x00000A0C, 0x07F7F000}, /* GpioPz4 */ {0x00000A10, 0x07F7F000}, /* GpioPz5 */ {0x00000A14, 0x01F1F000}, /* GpioX1Aud */ {0x00000A18, 0x01F1F000}, /* GpioX3Aud */ {0x00000A1C, 0x01F1F000}, /* GpsEn */ {0x00000A20, 0x01F1F000}, /* GpsRst */ {0x00000A24, 0x01F1F000}, /* HdmiCec */ {0x00000A28, 0x01F1F000}, /* HdmiIntDpHpd */ {0x00000A2C, 0x01F1F000}, /* JtagRtck */ {0x00000A30, 0x01F1F000}, /* LcdBlEn */ {0x00000A34, 0x01F1F000}, /* LcdBlPwm */ {0x00000A38, 0x01F1F000}, /* LcdGpio1 */ {0x00000A3C, 0x01F1F000}, /* LcdGpio2 */ {0x00000A40, 0x01F1F000}, /* LcdRst */ {0x00000A44, 0x01F1F000}, /* LcdTe */ {0x00000A48, 0x01F1F000}, /* ModemWakeAp */ {0x00000A4C, 0x01F1F000}, /* MotionInt */ {0x00000A50, 0x01F1F000}, /* NfcEn */ {0x00000A54, 0x01F1F000}, /* NfcInt */ {0x00000A58, 0x01F1F000}, /* PexL0ClkReqN */ {0x00000A5C, 0x01F1F000}, /* PexL0RstN */ {0x00000A60, 0x01F1F000}, /* PexL1ClkreqN */ {0x00000A64, 0x01F1F000}, /* PexL1RstN */ {0x00000A68, 0x01F1F000}, /* PexWakeN */ {0x00000A6C, 0x01F1F000}, /* PwrI2cScl */ {0x00000A70, 0x01F1F000}, /* PwrI2cSda */ {0x00000A74, 0x01F1F000}, /* PwrIntN */ {0x00000A78, 0x07F7F000}, /* QspiComp */ {0x00000A90, 0xF0000000}, /* QspiSck */ {0x00000A94, 0x01F1F000}, /* SataLedActive */ {0x00000A98, 0xF7F7F000}, /* Sdmmc1Pad */ {0x00000AB0, 0xF7F7F000}, /* Sdmmc3Pad */ {0x00000AC8, 0x01F1F000}, /* Shutdown */ {0x00000ACC, 0x01F1F000}, /* SpdifIn */ {0x00000AD0, 0x01F1F000}, /* SpdifOut */ {0x00000AD4, 0xF0000000}, /* Spi1Cs0 */ {0x00000AD8, 0xF0000000}, /* Spi1Cs1 */ {0x00000ADC, 0xF0000000}, /* Spi1Miso */ {0x00000AE0, 0xF0000000}, /* Spi1Mosi */ {0x00000AE4, 0xF0000000}, /* Spi1Sck */ {0x00000AE8, 0xF0000000}, /* Spi2Cs0 */ {0x00000AEC, 0xF0000000}, /* Spi2Cs1 */ {0x00000AF0, 0xF0000000}, /* Spi2Miso */ {0x00000AF4, 0xF0000000}, /* Spi2Mosi */ {0x00000AF8, 0xF0000000}, /* Spi2Sck */ {0x00000AFC, 0xF0000000}, /* Spi4Cs0 */ {0x00000B00, 0xF0000000}, /* Spi4Miso */ {0x00000B04, 0xF0000000}, /* Spi4Mosi */ {0x00000B08, 0xF0000000}, /* Spi4Sck */ {0x00000B0C, 0x01F1F000}, /* TempAlert */ {0x00000B10, 0x01F1F000}, /* TouchClk */ {0x00000B14, 0x01F1F000}, /* TouchInt */ {0x00000B18, 0x01F1F000}, /* TouchRst */ {0x00000B1C, 0x01F1F000}, /* Uart1Cts */ {0x00000B20, 0x01F1F000}, /* Uart1Rts */ {0x00000B24, 0x01F1F000}, /* Uart1Rx */ {0x00000B28, 0x01F1F000}, /* Uart1Tx */ {0x00000B2C, 0x01F1F000}, /* Uart2Cts */ {0x00000B30, 0x01F1F000}, /* Uart2Rts */ {0x00000B34, 0x01F1F000}, /* Uart2Rx */ {0x00000B38, 0x01F1F000}, /* Uart2Tx */ {0x00000B3C, 0x01F1F000}, /* Uart3Cts */ {0x00000B40, 0x01F1F000}, /* Uart3Rts */ {0x00000B44, 0x01F1F000}, /* Uart3Rx */ {0x00000B48, 0x01F1F000}, /* Uart3Tx */ {0x00000B4C, 0x01F1F000}, /* Uart4Cts */ {0x00000B50, 0x01F1F000}, /* Uart4Rts */ {0x00000B54, 0x01F1F000}, /* Uart4Rx */ {0x00000B58, 0x01F1F000}, /* Uart4Tx */ {0x00000B5C, 0x01F1F000}, /* UsbVbusEn0 */ {0x00000B60, 0x01F1F000}, /* UsbVbusEn1 */ {0x00000B64, 0x01F1F000}, /* WifiEn */ {0x00000B68, 0x01F1F000}, /* WifiRst */ {0x00000B6C, 0x01F1F000}, /* WifiWakeAp */ }; static const std::tuple g_pinmux_drivepad_config_map[] = { {0x04, 0x01010000, 0x01F1F000}, {0x0D, 0x01010000, 0x01F1F000}, {0x10, 0x01010000, 0x01F1F000}, {0x12, 0x01010000, 0x01F1F000}, {0x13, 0x01010000, 0x01F1F000}, {0x14, 0x0001F000, 0x01F1F000}, {0x15, 0x0001F000, 0x01F1F000}, {0x24, 0x01010000, 0x01F1F000}, {0x25, 0x01010000, 0x01F1F000}, {0x26, 0x01010000, 0x01F1F000}, {0x27, 0x01010000, 0x01F1F000}, {0x28, 0x01010000, 0x01F1F000}, {0x29, 0x01010000, 0x01F1F000}, {0x2A, 0x01010000, 0x01F1F000}, {0x2B, 0x01010000, 0x01F1F000}, {0x2C, 0x01F1F000, 0x01F1F000}, {0x2D, 0x01F1F000, 0x01F1F000}, {0x2F, 0x01F1F000, 0x01F1F000}, {0x30, 0x01404000, 0x01F1F000}, {0x31, 0x0001F000, 0x01F1F000}, {0x32, 0x0001F000, 0x01F1F000}, {0x33, 0x0001F000, 0x01F1F000}, {0x34, 0x0001F000, 0x01F1F000}, {0x35, 0x00007000, 0x01F1F000}, {0x36, 0x00007000, 0x01F1F000}, {0x46, 0x01010000, 0x01F1F000}, {0x47, 0x01010000, 0x01F1F000}, {0x4C, 0x01404000, 0x01F1F000}, {0x4D, 0x01404000, 0x01F1F000}, {0x62, 0x0001F000, 0x01F1F000}, {0x63, 0x0001F000, 0x01F1F000}, {0x7C, 0x01414000, 0x01F1F000}, {0x87, 0x01404000, 0x01F1F000}, {0x88, 0x01404000, 0x01F1F000}, {0x89, 0x01404000, 0x01F1F000}, {0x8A, 0x01404000, 0x01F1F000}, {0x6D, 0x00000000, 0xF0000000}, {0x6E, 0x00000000, 0xF0000000}, {0x6F, 0x00000000, 0xF0000000}, {0x70, 0x00000000, 0xF0000000}, {0x71, 0x00000000, 0xF0000000}, {0x72, 0x00000000, 0xF0000000}, {0x73, 0x00000000, 0xF0000000}, {0x74, 0x00000000, 0xF0000000}, {0x75, 0x00000000, 0xF0000000}, {0x76, 0x00000000, 0xF0000000}, {0x69, 0x51212000, 0xF1F1F000}, }; static int pinmux_update_drivepad(u64 pinmux_base_vaddr, unsigned int pinmux_drivepad_idx, unsigned int pinmux_drivepad_config_val, unsigned int pinmux_drivepad_config_mask_val) { /* Fetch this PINMUX drive group's register offset */ u32 pinmux_drivepad_reg_offset = std::get<0>(g_pinmux_drivepad_map[pinmux_drivepad_idx]); /* Fetch this PINMUX drive group's mask value */ u32 pinmux_drivepad_mask_val = std::get<1>(g_pinmux_drivepad_map[pinmux_drivepad_idx]); /* Read from the PINMUX drive group register */ u32 pinmux_drivepad_val = *((u32 *)pinmux_base_vaddr + pinmux_drivepad_reg_offset); /* Adjust DriveDownStrength */ if (pinmux_drivepad_config_mask_val & 0x1F000) { u32 mask_val = 0x7F000; /* Adjust mask value */ if ((pinmux_drivepad_mask_val & 0x7F000) != 0x7F000) mask_val = 0x1F000; /* This drive group supports DriveDownStrength change */ if (pinmux_drivepad_mask_val & mask_val) { /* Change DriveDownStrength */ if (((pinmux_drivepad_config_val & 0x7F000) & mask_val) != (pinmux_drivepad_val & mask_val)) { pinmux_drivepad_val &= ~(mask_val); pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F000) & mask_val); } } } /* Adjust DriveUpStrength */ if (pinmux_drivepad_config_mask_val & 0x1F00000) { u32 mask_val = 0x7F00000; /* Adjust mask value */ if ((pinmux_drivepad_mask_val & 0x7F00000) != 0x7F00000) mask_val = 0x1F00000; /* This drive group supports DriveUpStrength change */ if (pinmux_drivepad_mask_val & mask_val) { /* Change DriveUpStrength */ if (((pinmux_drivepad_config_val & 0x7F00000) & mask_val) != (pinmux_drivepad_val & mask_val)) { pinmux_drivepad_val &= ~(mask_val); pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F00000) & mask_val); } } } /* Adjust DriveDownSlew */ if (pinmux_drivepad_config_mask_val & 0x30000000) { /* This drive group supports DriveDownSlew change */ if (pinmux_drivepad_mask_val & 0x30000000) { /* Change DriveDownSlew */ if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0x30000000) { pinmux_drivepad_val &= 0xCFFFFFFF; pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0x30000000); } } } /* Adjust DriveUpSlew */ if (pinmux_drivepad_config_mask_val & 0xC0000000) { /* This drive group supports DriveUpSlew change */ if (pinmux_drivepad_mask_val & 0xC0000000) { /* Change DriveUpSlew */ if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0xC0000000) { pinmux_drivepad_val &= 0x3FFFFFFF; pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0xC0000000); } } } /* Write to the appropriate PINMUX drive group register */ *((u32 *)pinmux_base_vaddr + pinmux_drivepad_reg_offset) = pinmux_drivepad_val; /* Do a dummy read from the PINMUX drive group register */ pinmux_drivepad_val = *((u32 *)pinmux_base_vaddr + pinmux_drivepad_reg_offset); return pinmux_drivepad_val; } static const std::tuple g_pmc_control_map[] = { {0x000, 0x0800, 0x01}, {0x000, 0x0400, 0x00}, {0x000, 0x0200, 0x01}, {0x000, 0x0100, 0x00}, {0x000, 0x0040, 0x00}, {0x000, 0x0020, 0x00}, {0x440, 0x4000, 0x01}, {0x440, 0x0200, 0x00}, {0x440, 0x0001, 0x01}, }; static int pmc_init_wake_events(u64 pmc_base_vaddr, bool is_blink) { Result rc; u32 pmc_wake_debounce_val = 0; u32 pmc_blink_timer_val = 0x08008800; u32 pmc_cntrl_val = 0; u32 pmc_dpd_pads_oride_val = 0; if (kernelAbove200()) { /* Use svcReadWriteRegister to write APBDEV_PMC_WAKE_DEBOUNCE_EN_0 */ rc = svcReadWriteRegister(&pmc_wake_debounce_val, PMC_BASE + 0x4D8, 0xFFFFFFFF, pmc_wake_debounce_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from APBDEV_PMC_WAKE_DEBOUNCE_EN_0 */ rc = svcReadWriteRegister(&pmc_wake_debounce_val, PMC_BASE + 0x4D8, 0, 0); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to write APBDEV_PMC_BLINK_TIMER_0 */ rc = svcReadWriteRegister(&pmc_blink_timer_val, PMC_BASE + 0x40, 0xFFFFFFFF, pmc_blink_timer_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from APBDEV_PMC_BLINK_TIMER_0 */ rc = svcReadWriteRegister(&pmc_blink_timer_val, PMC_BASE + 0x40, 0, 0); if (R_FAILED(rc)) { return rc; } for (unsigned int i = 0; i < MAX_PMC_CONTROL; i++) { /* Fetch this PMC register offset */ u32 pmc_control_reg_offset = std::get<0>(g_pmc_control_map[i]); /* Fetch this PMC mask value */ u32 pmc_control_mask_val = std::get<1>(g_pmc_control_map[i]); /* Fetch this PMC flag value */ u32 pmc_control_flag_val = std::get<2>(g_pmc_control_map[i]); u32 pmc_control_val = 0; /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_control_val, PMC_BASE + pmc_control_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } pmc_control_val &= ~(pmc_control_mask_val); pmc_control_val |= ((pmc_control_flag_val & 0x01) ? pmc_control_mask_val : 0); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_control_val, PMC_BASE + pmc_control_reg_offset, 0xFFFFFFFF, pmc_control_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_control_val, PMC_BASE + pmc_control_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } } /* Use svcReadWriteRegister to read from APBDEV_PMC_CNTRL_0 */ rc = svcReadWriteRegister(&pmc_cntrl_val, PMC_BASE + 0, 0, 0); if (R_FAILED(rc)) { return rc; } pmc_cntrl_val &= ~(0x80); pmc_cntrl_val |= (is_blink ? 0x80 : 0); /* Use svcReadWriteRegister to write to APBDEV_PMC_CNTRL_0 */ rc = svcReadWriteRegister(&pmc_cntrl_val, PMC_BASE + 0, 0xFFFFFFFF, pmc_cntrl_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from APBDEV_PMC_CNTRL_0 */ rc = svcReadWriteRegister(&pmc_cntrl_val, PMC_BASE + 0, 0, 0); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to read from APBDEV_PMC_DPD_PADS_ORIDE_0 */ rc = svcReadWriteRegister(&pmc_dpd_pads_oride_val, PMC_BASE + 0x1C, 0, 0); if (R_FAILED(rc)) { return rc; } pmc_dpd_pads_oride_val &= ~(0x100000); pmc_dpd_pads_oride_val |= (is_blink ? 0x100000 : 0); /* Use svcReadWriteRegister to write to APBDEV_PMC_DPD_PADS_ORIDE_0 */ rc = svcReadWriteRegister(&pmc_dpd_pads_oride_val, PMC_BASE + 0x1C, 0xFFFFFFFF, pmc_dpd_pads_oride_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from APBDEV_PMC_DPD_PADS_ORIDE_0 */ rc = svcReadWriteRegister(&pmc_dpd_pads_oride_val, PMC_BASE + 0x1C, 0, 0); if (R_FAILED(rc)) { return rc; } } else { /* Write to APBDEV_PMC_WAKE_DEBOUNCE_EN_0 */ *((u32 *)pmc_base_vaddr + 0x4D8) = pmc_wake_debounce_val; /* Do a dummy read from APBDEV_PMC_WAKE_DEBOUNCE_EN_0 */ pmc_wake_debounce_val = *((u32 *)pmc_base_vaddr + 0x4D8); /* Write to APBDEV_PMC_BLINK_TIMER_0 */ *((u32 *)pmc_base_vaddr + 0x40) = pmc_blink_timer_val; /* Do a dummy read from APBDEV_PMC_BLINK_TIMER_0 */ pmc_blink_timer_val = *((u32 *)pmc_base_vaddr + 0x40); for (unsigned int i = 0; i < MAX_PMC_CONTROL; i++) { /* Fetch this PMC register offset */ u32 pmc_control_reg_offset = std::get<0>(g_pmc_control_map[i]); /* Fetch this PMC mask value */ u32 pmc_control_mask_val = std::get<1>(g_pmc_control_map[i]); /* Fetch this PMC flag value */ u32 pmc_control_flag_val = std::get<2>(g_pmc_control_map[i]); /* Read from the PMC register */ u32 pmc_control_val = *((u32 *)pmc_base_vaddr + pmc_control_reg_offset); pmc_control_val &= ~(pmc_control_mask_val); pmc_control_val |= ((pmc_control_flag_val & 0x01) ? pmc_control_mask_val : 0); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_control_reg_offset) = pmc_control_val; /* Do a dummy read from the PMC register */ pmc_control_val = *((u32 *)pmc_base_vaddr + pmc_control_reg_offset); } /* Read from APBDEV_PMC_CNTRL_0 */ pmc_cntrl_val = *((u32 *)pmc_base_vaddr + 0); pmc_cntrl_val &= ~(0x80); pmc_cntrl_val |= (is_blink ? 0x80 : 0); /* Write to APBDEV_PMC_CNTRL_0 */ *((u32 *)pmc_base_vaddr + 0) = pmc_cntrl_val; /* Do a dummy read from APBDEV_PMC_CNTRL_0 */ pmc_cntrl_val = *((u32 *)pmc_base_vaddr + 0); /* Read from APBDEV_PMC_DPD_PADS_ORIDE_0 */ pmc_dpd_pads_oride_val = *((u32 *)pmc_base_vaddr + 0x1C); pmc_dpd_pads_oride_val &= ~(0x100000); pmc_dpd_pads_oride_val |= (is_blink ? 0x100000 : 0); /* Write to APBDEV_PMC_DPD_PADS_ORIDE_0 */ *((u32 *)pmc_base_vaddr + 0x1C) = pmc_dpd_pads_oride_val; /* Do a dummy read from APBDEV_PMC_DPD_PADS_ORIDE_0 */ pmc_dpd_pads_oride_val = *((u32 *)pmc_base_vaddr + 0x1C); } rc = 0; return rc; } static const std::tuple g_pmc_wake_pin_map_icosa[] = { {0x00, 0x00, 0x02}, {0x01, 0x00, 0x02}, {0x02, 0x00, 0x02}, {0x03, 0x00, 0x02}, {0x04, 0x01, 0x02}, {0x05, 0x00, 0x02}, {0x06, 0x01, 0x02}, {0x07, 0x01, 0x02}, {0x08, 0x00, 0x02}, {0x0A, 0x01, 0x02}, {0x0B, 0x00, 0x02}, {0x0C, 0x00, 0x02}, {0x0D, 0x00, 0x02}, {0x0E, 0x01, 0x00}, {0x0F, 0x00, 0x02}, {0x11, 0x00, 0x02}, {0x12, 0x00, 0x02}, {0x13, 0x00, 0x02}, {0x14, 0x00, 0x02}, {0x15, 0x00, 0x02}, {0x16, 0x00, 0x02}, {0x17, 0x00, 0x02}, {0x18, 0x00, 0x02}, {0x19, 0x00, 0x02}, {0x1A, 0x00, 0x02}, {0x1B, 0x01, 0x00}, {0x1C, 0x00, 0x02}, {0x21, 0x00, 0x02}, {0x22, 0x01, 0x00}, {0x23, 0x01, 0x02}, {0x24, 0x00, 0x02}, {0x2D, 0x00, 0x02}, {0x2E, 0x00, 0x02}, {0x2F, 0x00, 0x02}, {0x30, 0x01, 0x02}, {0x31, 0x00, 0x02}, {0x32, 0x00, 0x02}, {0x33, 0x01, 0x00}, {0x34, 0x01, 0x00}, {0x35, 0x00, 0x02}, {0x36, 0x00, 0x02}, {0x37, 0x00, 0x02}, {0x38, 0x00, 0x02}, {0x39, 0x00, 0x02}, {0x3A, 0x00, 0x02}, {0x3B, 0x00, 0x02}, {0x3D, 0x00, 0x02}, {0x3E, 0x00, 0x02}, {0x3F, 0x00, 0x02}, }; static const std::tuple g_pmc_wake_pin_map_copper[] = { {0x00, 0x01, 0x02}, {0x01, 0x00, 0x02}, {0x02, 0x00, 0x02}, {0x03, 0x01, 0x02}, {0x04, 0x00, 0x02}, {0x05, 0x01, 0x02}, {0x06, 0x00, 0x02}, {0x07, 0x00, 0x02}, {0x08, 0x01, 0x02}, {0x0A, 0x00, 0x02}, {0x0B, 0x00, 0x02}, {0x0C, 0x00, 0x02}, {0x0D, 0x00, 0x02}, {0x0E, 0x01, 0x00}, {0x0F, 0x00, 0x02}, {0x11, 0x00, 0x02}, {0x12, 0x00, 0x02}, {0x13, 0x00, 0x02}, {0x14, 0x00, 0x02}, {0x15, 0x00, 0x02}, {0x16, 0x00, 0x02}, {0x17, 0x00, 0x02}, {0x18, 0x01, 0x02}, {0x19, 0x00, 0x02}, {0x1A, 0x00, 0x02}, {0x1B, 0x00, 0x00}, {0x1C, 0x00, 0x02}, {0x21, 0x00, 0x02}, {0x22, 0x00, 0x00}, {0x23, 0x00, 0x02}, {0x24, 0x00, 0x02}, {0x2D, 0x00, 0x02}, {0x2E, 0x00, 0x02}, {0x2F, 0x01, 0x02}, {0x30, 0x01, 0x02}, {0x31, 0x00, 0x02}, {0x32, 0x01, 0x02}, {0x33, 0x01, 0x00}, {0x34, 0x01, 0x00}, {0x35, 0x00, 0x02}, {0x36, 0x00, 0x02}, {0x37, 0x00, 0x02}, {0x38, 0x00, 0x02}, {0x39, 0x00, 0x02}, {0x3A, 0x00, 0x02}, {0x3B, 0x00, 0x02}, {0x3D, 0x00, 0x02}, {0x3E, 0x00, 0x02}, {0x3F, 0x00, 0x02}, }; static int pmc_set_wake_event_level(u64 pmc_base_vaddr, unsigned int wake_pin_idx, unsigned int wake_pin_mode) { Result rc; /* Invalid pin index */ if (wake_pin_idx > 0x3F) { return -1; } u32 pmc_wake_level_reg_offset = 0; u32 pmc_wake_level_mask_reg_offset = 0; u32 pmc_wake_level_val = 0; u32 pmc_wake_level_mask_val = 0; /* Pins up to 0x1F use APBDEV_PMC_WAKE_LVL_0 and APBDEV_PMC_AUTO_WAKE_LVL_MASK_0, */ /* while others use APBDEV_PMC_WAKE2_LVL_0 and APBDEV_PMC_AUTO_WAKE2_LVL_MASK_0 */ if (wake_pin_idx <= 0x1F) { pmc_wake_level_reg_offset = 0x10; pmc_wake_level_mask_reg_offset = 0xDC; } else { pmc_wake_level_reg_offset = 0x164; pmc_wake_level_mask_reg_offset = 0x170; } if (wake_pin_mode < 0x02) { if (kernelAbove200()) { /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Mask with the wake pin index */ pmc_wake_level_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0xFFFFFFFF, pmc_wake_level_mask_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Mask with the wake pin index */ pmc_wake_level_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set or clear the wake level */ pmc_wake_level_val |= (wake_pin_mode ? (0x01 << (wake_pin_idx & 0x1F)) : 0); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0xFFFFFFFF, pmc_wake_level_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } } else { /* Read from the PMC register */ pmc_wake_level_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset); /* Mask with the wake pin index */ pmc_wake_level_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset) = pmc_wake_level_mask_val; /* Do a dummy read from the PMC register */ pmc_wake_level_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset); /* Read from the PMC register */ pmc_wake_level_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset); /* Mask with the wake pin index */ pmc_wake_level_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set or clear the wake level */ pmc_wake_level_val |= (wake_pin_mode ? (0x01 << (wake_pin_idx & 0x1F)) : 0); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset) = pmc_wake_level_val; /* Do a dummy read from the PMC register */ pmc_wake_level_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset); } } else if (wake_pin_mode == 0x02) { if (kernelAbove200()) { /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Mask with the wake pin index */ pmc_wake_level_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0xFFFFFFFF, pmc_wake_level_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_val, PMC_BASE + pmc_wake_level_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Mask with the wake pin index */ pmc_wake_level_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set the wake level mask */ pmc_wake_level_mask_val |= (0x01 << (wake_pin_idx & 0x1F)); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0xFFFFFFFF, pmc_wake_level_mask_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_level_mask_val, PMC_BASE + pmc_wake_level_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } } else { /* Read from the PMC register */ pmc_wake_level_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset); /* Mask with the wake pin index */ pmc_wake_level_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset) = pmc_wake_level_val; /* Do a dummy read from the PMC register */ pmc_wake_level_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_reg_offset); /* Read from the PMC register */ pmc_wake_level_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset); /* Mask with the wake pin index */ pmc_wake_level_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set the wake level mask */ pmc_wake_level_mask_val |= (0x01 << (wake_pin_idx & 0x1F)); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset) = pmc_wake_level_mask_val; /* Do a dummy read from the PMC register */ pmc_wake_level_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_level_mask_reg_offset); } } else { /* Invalid */ } rc = 0; return rc; } static int pmc_set_wake_event_enabled(u64 pmc_base_vaddr, unsigned int wake_pin_idx, bool is_enabled) { Result rc; /* Invalid pin index */ if (wake_pin_idx > 0x3F) { return -1; } u32 pmc_wake_mask_reg_offset = 0; u32 pmc_wake_mask_val = 0; /* Pins up to 0x1F use APBDEV_PMC_WAKE_MASK_0, while others use APBDEV_PMC_WAKE2_MASK_0 */ if (wake_pin_idx <= 0x1F) pmc_wake_mask_reg_offset = 0x0C; else pmc_wake_mask_reg_offset = 0x160; if (kernelAbove200()) { /* Use svcReadWriteRegister to read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_mask_val, PMC_BASE + pmc_wake_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } /* Mask with the wake pin index */ pmc_wake_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set the wake mask */ pmc_wake_mask_val |= (is_enabled ? (0x01 << (wake_pin_idx & 0x1F)) : 0); /* Use svcReadWriteRegister to write to the PMC register */ rc = svcReadWriteRegister(&pmc_wake_mask_val, PMC_BASE + pmc_wake_mask_reg_offset, 0xFFFFFFFF, pmc_wake_mask_val); if (R_FAILED(rc)) { return rc; } /* Use svcReadWriteRegister to do a dummy read from the PMC register */ rc = svcReadWriteRegister(&pmc_wake_mask_val, PMC_BASE + pmc_wake_mask_reg_offset, 0, 0); if (R_FAILED(rc)) { return rc; } } else { /* Read from the PMC register */ pmc_wake_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_mask_reg_offset); /* Mask with the wake pin index */ pmc_wake_mask_val &= ~(0x01 << (wake_pin_idx & 0x1F)); /* Set the wake mask */ pmc_wake_mask_val |= (is_enabled ? (0x01 << (wake_pin_idx & 0x1F)) : 0); /* Write to the PMC register */ *((u32 *)pmc_base_vaddr + pmc_wake_mask_reg_offset) = pmc_wake_mask_val; /* Do a dummy read from the PMC register */ pmc_wake_mask_val = *((u32 *)pmc_base_vaddr + pmc_wake_mask_reg_offset); } rc = 0; return rc; } int main(int argc, char **argv) { consoleDebugInit(debugDevice_SVC); Result rc; u64 pinmux_base_vaddr = 0; u64 gpio_base_vaddr = 0; u64 pmc_base_vaddr = 0; /* Map the APB MISC registers for PINMUX */ rc = svcQueryIoMapping(&pinmux_base_vaddr, APB_MISC_BASE, 0x4000); if (R_FAILED(rc)) { return rc; } /* IO mapping failed */ if (!pinmux_base_vaddr) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_IoError)); /* Map the GPIO registers */ rc = svcQueryIoMapping(&gpio_base_vaddr, GPIO_BASE, 0x1000); if (R_FAILED(rc)) { return rc; } /* IO mapping failed */ if (!gpio_base_vaddr) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_IoError)); /* Change GPIO voltage to 1.8v */ if (kernelAbove200()) { 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); if (R_FAILED(rc)) { return rc; } /* IO mapping failed */ if (!pmc_base_vaddr) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_IoError)); /* Write to APBDEV_PMC_PWR_DET_0 */ *((u32 *)pmc_base_vaddr + 0x48) |= 0xA42000; /* Write to APBDEV_PMC_PWR_DET_VAL_0 */ *((u32 *)pmc_base_vaddr + 0xE4) &= ~(0xA42000); } /* Wait for changes to take effect */ svcSleepThread(100000); /* Default to invalid hardware type */ HardwareType hardware_type = HARDWARETYPE_INVALID; /* Get the hardware type from SPL */ rc = splGetConfig(SplConfigItem_HardwareType, (u64 *)&hardware_type); if (R_FAILED(rc)) { return rc; } /* The Icosa GPIO map was common to all hardware before 2.0.0 */ if (!kernelAbove200() || (hardware_type == HARDWARETYPE_ICOSA) || (hardware_type == HARDWARETYPE_HOAG)) { /* Setup all GPIOs for Icosa or Hoag hardware */ for (unsigned int i = 0; i < MAX_GPIO_ICOSA; i++) { /* Configure the GPIO */ gpio_configure(gpio_base_vaddr, std::get<0>(g_gpio_config_map_icosa[i])); /* Set the GPIO's direction */ gpio_set_direction(gpio_base_vaddr, std::get<0>(g_gpio_config_map_icosa[i]), std::get<1>(g_gpio_config_map_icosa[i])); /* Manually set GPIO 0x18 value which changed on 4.0.0+ */ if (kernelAbove400() && (std::get<0>(g_gpio_config_map_icosa[i]) == 0x18)) { /* Set the GPIO's value to high */ gpio_set_value(gpio_base_vaddr, std::get<0>(g_gpio_config_map_icosa[i]), true); } else { /* Set the GPIO's value */ gpio_set_value(gpio_base_vaddr, std::get<0>(g_gpio_config_map_icosa[i]), std::get<2>(g_gpio_config_map_icosa[i])); } } } else if (hardware_type == HARDWARETYPE_COPPER) { /* Setup all GPIOs for Copper hardware */ for (unsigned int i = 0; i < MAX_GPIO_COPPER; i++) { /* Configure the GPIO */ gpio_configure(gpio_base_vaddr, std::get<0>(g_gpio_config_map_copper[i])); /* Set the GPIO's direction */ gpio_set_direction(gpio_base_vaddr, std::get<0>(g_gpio_config_map_copper[i]), std::get<1>(g_gpio_config_map_copper[i])); /* Set the GPIO's value */ gpio_set_value(gpio_base_vaddr, std::get<0>(g_gpio_config_map_copper[i]), std::get<2>(g_gpio_config_map_copper[i])); } } else if (hardware_type == HARDWARETYPE_MARIKO) { /* Setup all GPIOs for Mariko hardware */ for (unsigned int i = 0; i < MAX_GPIO_MARIKO; i++) { /* Configure the GPIO */ gpio_configure(gpio_base_vaddr, std::get<0>(g_gpio_config_map_mariko[i])); /* Set the GPIO's direction */ gpio_set_direction(gpio_base_vaddr, std::get<0>(g_gpio_config_map_mariko[i]), std::get<1>(g_gpio_config_map_mariko[i])); /* Set the GPIO's value */ gpio_set_value(gpio_base_vaddr, std::get<0>(g_gpio_config_map_mariko[i]), std::get<2>(g_gpio_config_map_mariko[i])); } } /* TODO: Evaluate if this can be ignored */ if (kernelAbove500()) { u64 car_base_vaddr = 0; /* Map the Clock and Reset registers */ rc = svcQueryIoMapping(&car_base_vaddr, CAR_BASE, 0x1000); if (R_FAILED(rc)) { return rc; } /* Read from CLK_RST_CONTROLLER_PLLU_BASE_0 */ u32 pplu_base = *((u32 *)car_base_vaddr + 0xC0); /* Read from CLK_RST_CONTROLLER_UTMIP_PLL_CFG0_0 */ u32 utmip_pll_cfg0 = *((u32 *)car_base_vaddr + 0x480); if (((pplu_base & 0x1FFFFF) != 0x11902) || ((utmip_pll_cfg0 & 0xFFFF00) != 0x190100)) { /* svcSleepThread(1000000000); pmic_reset(); */ } } if (kernelAbove200()) { /* TODO: PMIC testing */ } /* This is ignored in Copper hardware */ if (hardware_type != HARDWARETYPE_COPPER) { if (kernelAbove200()) { /* TODO: Display configuration */ } /* TODO: Battery charge check */ } /* Update PINMUX park status */ for (unsigned int i = 0; i < MAX_PINMUX; i++) { pinmux_update_park(pinmux_base_vaddr, i); } if ((hardware_type == HARDWARETYPE_ICOSA) || (hardware_type == HARDWARETYPE_HOAG)) { /* Configure all PINMUX pads (minus BattBcl) for Icosa or Hoag */ for (unsigned int i = 0; i < (MAX_PINMUX - 1); i++) { pinmux_update_pad(pinmux_base_vaddr, std::get<0>(g_pinmux_config_map_icosa[i]), std::get<1>(g_pinmux_config_map_icosa[i]), std::get<2>(g_pinmux_config_map_icosa[i])); } } else if (hardware_type == HARDWARETYPE_COPPER) { /* Configure all PINMUX pads (minus BattBcl) for Copper */ for (unsigned int i = 0; i < (MAX_PINMUX - 1); i++) { pinmux_update_pad(pinmux_base_vaddr, std::get<0>(g_pinmux_config_map_copper[i]), std::get<1>(g_pinmux_config_map_copper[i]), std::get<2>(g_pinmux_config_map_copper[i])); } } else if (hardware_type == HARDWARETYPE_MARIKO) { /* Configure all PINMUX pads (minus BattBcl) for Mariko */ for (unsigned int i = 0; i < (MAX_PINMUX_MARIKO - 1); i++) { pinmux_update_pad(pinmux_base_vaddr, std::get<0>(g_pinmux_config_map_mariko[i]), std::get<1>(g_pinmux_config_map_mariko[i]), std::get<2>(g_pinmux_config_map_mariko[i])); } /* Configure additional values for SDMMC2 pins */ pinmux_update_pad(pinmux_base_vaddr, 0xAA, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xAC, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA2, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA3, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA4, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA5, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA6, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA7, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA8, 0x2000, 0x2000); pinmux_update_pad(pinmux_base_vaddr, 0xA9, 0x2000, 0x2000); } else { /* Invalid */ } /* Configure all PINMUX drive pads (common to all hardware types) */ for (unsigned int i = 0; i < MAX_PINMUX_DRIVEPAD; i++) { pinmux_update_drivepad(pinmux_base_vaddr, std::get<0>(g_pinmux_drivepad_config_map[i]), std::get<1>(g_pinmux_drivepad_config_map[i]), std::get<2>(g_pinmux_drivepad_config_map[i])); } /* Initialize PMC for configuring wake pin events */ pmc_init_wake_events(pmc_base_vaddr, false); /* Configure all wake pin events */ for (unsigned int i = 0; i < MAX_PMC_WAKE_PIN; i++) { if (kernelAbove200() && (hardware_type == HARDWARETYPE_COPPER)) { /* Set wake event levels for Copper hardware */ pmc_set_wake_event_level(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_copper[i]), std::get<2>(g_pmc_wake_pin_map_copper[i])); /* Enable or disable wake events for Copper hardware */ pmc_set_wake_event_enabled(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_copper[i]), std::get<1>(g_pmc_wake_pin_map_copper[i])); } else if (kernelAbove200() && (std::get<0>(g_pmc_wake_pin_map_icosa[i]) == 0x08)) { /* Manually set pin 8's wake event level for Icosa hardware on 2.0.0+ */ pmc_set_wake_event_level(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_icosa[i]), 1); /* Manually enable or disable pin 8's wake event for Icosa hardware on 2.0.0+ */ pmc_set_wake_event_enabled(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_icosa[i]), 1); } else { /* Set wake event levels for Icosa hardware */ pmc_set_wake_event_level(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_icosa[i]), std::get<2>(g_pmc_wake_pin_map_icosa[i])); /* Enable or disable wake events for Icosa hardware */ pmc_set_wake_event_enabled(pmc_base_vaddr, std::get<0>(g_pmc_wake_pin_map_icosa[i]), std::get<1>(g_pmc_wake_pin_map_icosa[i])); } } /* This is ignored in Copper hardware */ if (hardware_type != HARDWARETYPE_COPPER) { /* 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; } } /* Change GPIO 0x4B in Copper hardware only */ if (hardware_type == HARDWARETYPE_COPPER) { gpio_configure(gpio_base_vaddr, 0x4B); gpio_set_direction(gpio_base_vaddr, 0x4B, true); gpio_set_value(gpio_base_vaddr, 0x4B, true); } /* TODO: NAND repair */ /* pmshellNotifyBootFinished(); */ rc = 0; return rc; }