diff --git a/stratosphere/boot/source/boot_functions.hpp b/stratosphere/boot/source/boot_functions.hpp index a7be01861..9c150c39a 100644 --- a/stratosphere/boot/source/boot_functions.hpp +++ b/stratosphere/boot/source/boot_functions.hpp @@ -84,4 +84,8 @@ class Boot { static u16 GetCrc16(const void *data, size_t size); static u32 GetBatteryVersion(); static u32 GetBatteryVendor(); + + /* Wake pin utiliies. */ + static void SetWakeEventLevel(u32 index, u32 level); + static void SetWakeEventEnabled(u32 index, bool enabled); }; diff --git a/stratosphere/boot/source/boot_registers_pmc.hpp b/stratosphere/boot/source/boot_registers_pmc.hpp index 46cf89454..d543f360b 100644 --- a/stratosphere/boot/source/boot_registers_pmc.hpp +++ b/stratosphere/boot/source/boot_registers_pmc.hpp @@ -24,6 +24,8 @@ static constexpr uintptr_t PmcBase = 0x7000E400ul; static constexpr size_t APBDEV_PMC_CNTRL = 0x0; static constexpr u32 PMC_CNTRL_MAIN_RST = (1 << 4); static constexpr size_t APBDEV_PMC_SEC_DISABLE = 0x4; +static constexpr size_t APBDEV_PMC_WAKE_MASK = 0xC; +static constexpr size_t APBDEV_PMC_WAKE_LVL = 0x10; static constexpr size_t APBDEV_PMC_DPD_PADS_ORIDE = 0x1C; static constexpr size_t APBDEV_PMC_PWRGATE_TOGGLE = 0x30; static constexpr size_t APBDEV_PMC_PWRGATE_STATUS = 0x38; @@ -32,6 +34,7 @@ static constexpr size_t APBDEV_PMC_NO_IOPOWER = 0x44; static constexpr size_t APBDEV_PMC_SCRATCH0 = 0x50; static constexpr size_t APBDEV_PMC_SCRATCH1 = 0x54; static constexpr size_t APBDEV_PMC_SCRATCH20 = 0xA0; +static constexpr size_t APBDEV_PMC_AUTO_WAKE_LVL_MASK = 0xDC; static constexpr size_t APBDEV_PMC_PWR_DET_VAL = 0xE4; static constexpr u32 PMC_PWR_DET_SDMMC1_IO_EN = (1 << 12); static constexpr size_t APBDEV_PMC_DDR_PWR = 0xE8; @@ -40,6 +43,9 @@ static constexpr u32 PMC_CRYPTO_OP_SE_ENABLE = 0; static constexpr u32 PMC_CRYPTO_OP_SE_DISABLE = 1; static constexpr size_t APBDEV_PMC_SCRATCH33 = 0x120; static constexpr size_t APBDEV_PMC_SCRATCH40 = 0x13C; +static constexpr size_t APBDEV_PMC_WAKE2_MASK = 0x164; +static constexpr size_t APBDEV_PMC_WAKE2_LVL = 0x164; +static constexpr size_t APBDEV_PMC_AUTO_WAKE2_LVL_MASK = 0x170; static constexpr size_t APBDEV_PMC_OSC_EDPD_OVER = 0x1A4; static constexpr size_t APBDEV_PMC_CLK_OUT_CNTRL = 0x1A8; static constexpr size_t APBDEV_PMC_RST_STATUS = 0x1B4; diff --git a/stratosphere/boot/source/boot_types.hpp b/stratosphere/boot/source/boot_types.hpp index b62f22add..03e2ad4cc 100644 --- a/stratosphere/boot/source/boot_types.hpp +++ b/stratosphere/boot/source/boot_types.hpp @@ -35,4 +35,10 @@ struct PinmuxInitialConfig { u32 name; u32 val; u32 mask; +}; + +struct WakePinConfig { + u32 index; + bool enabled; + u32 level; }; \ No newline at end of file diff --git a/stratosphere/boot/source/boot_wake_pin_configuration.hpp b/stratosphere/boot/source/boot_wake_pin_configuration.hpp new file mode 100644 index 000000000..0ef5dd8ba --- /dev/null +++ b/stratosphere/boot/source/boot_wake_pin_configuration.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018-2019 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 . + */ + +#pragma once +#include + +#include "boot_types.hpp" + +static constexpr WakePinConfig WakePinConfigs[] = { + {0x00, false, 0x02}, + {0x01, false, 0x02}, + {0x02, false, 0x02}, + {0x03, false, 0x02}, + {0x04, true, 0x02}, + {0x05, false, 0x02}, + {0x06, true, 0x02}, + {0x07, true, 0x02}, + {0x08, false, 0x02}, + {0x0A, true, 0x02}, + {0x0B, false, 0x02}, + {0x0C, false, 0x02}, + {0x0D, false, 0x02}, + {0x0E, true, 0x00}, + {0x0F, false, 0x02}, + {0x11, false, 0x02}, + {0x12, false, 0x02}, + {0x13, false, 0x02}, + {0x14, false, 0x02}, + {0x15, false, 0x02}, + {0x16, false, 0x02}, + {0x17, false, 0x02}, + {0x18, false, 0x02}, + {0x19, false, 0x02}, + {0x1A, false, 0x02}, + {0x1B, true, 0x00}, + {0x1C, false, 0x02}, + {0x21, false, 0x02}, + {0x22, true, 0x00}, + {0x23, true, 0x02}, + {0x24, false, 0x02}, + {0x2D, false, 0x02}, + {0x2E, false, 0x02}, + {0x2F, false, 0x02}, + {0x30, true, 0x02}, + {0x31, false, 0x02}, + {0x32, false, 0x02}, + {0x33, true, 0x00}, + {0x34, true, 0x00}, + {0x35, false, 0x02}, + {0x36, false, 0x02}, + {0x37, false, 0x02}, + {0x38, false, 0x02}, + {0x39, false, 0x02}, + {0x3A, false, 0x02}, + {0x3B, false, 0x02}, + {0x3D, false, 0x02}, + {0x3E, false, 0x02}, + {0x3F, false, 0x02}, +}; + +static constexpr size_t NumWakePinConfigs = sizeof(WakePinConfigs) / sizeof(WakePinConfigs[0]); diff --git a/stratosphere/boot/source/boot_wake_pin_configuration_copper.hpp b/stratosphere/boot/source/boot_wake_pin_configuration_copper.hpp new file mode 100644 index 000000000..e053988ec --- /dev/null +++ b/stratosphere/boot/source/boot_wake_pin_configuration_copper.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018-2019 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 . + */ + +#pragma once +#include + +#include "boot_types.hpp" + +static constexpr WakePinConfig WakePinConfigsCopper[] = { + {0x00, true, 0x02}, + {0x01, false, 0x02}, + {0x02, false, 0x02}, + {0x03, true, 0x02}, + {0x04, false, 0x02}, + {0x05, true, 0x02}, + {0x06, false, 0x02}, + {0x07, false, 0x02}, + {0x08, true, 0x02}, + {0x0A, false, 0x02}, + {0x0B, false, 0x02}, + {0x0C, false, 0x02}, + {0x0D, false, 0x02}, + {0x0E, true, 0x00}, + {0x0F, false, 0x02}, + {0x11, false, 0x02}, + {0x12, false, 0x02}, + {0x13, false, 0x02}, + {0x14, false, 0x02}, + {0x15, false, 0x02}, + {0x16, false, 0x02}, + {0x17, false, 0x02}, + {0x18, true, 0x02}, + {0x19, false, 0x02}, + {0x1A, false, 0x02}, + {0x1B, false, 0x00}, + {0x1C, false, 0x02}, + {0x21, false, 0x02}, + {0x22, false, 0x00}, + {0x23, false, 0x02}, + {0x24, false, 0x02}, + {0x2D, false, 0x02}, + {0x2E, false, 0x02}, + {0x2F, true, 0x02}, + {0x30, true, 0x02}, + {0x31, false, 0x02}, + {0x32, true, 0x02}, + {0x33, true, 0x00}, + {0x34, true, 0x00}, + {0x35, false, 0x02}, + {0x36, false, 0x02}, + {0x37, false, 0x02}, + {0x38, false, 0x02}, + {0x39, false, 0x02}, + {0x3A, false, 0x02}, + {0x3B, false, 0x02}, + {0x3D, false, 0x02}, + {0x3E, false, 0x02}, + {0x3F, false, 0x02}, +}; + +static constexpr size_t NumWakePinConfigsCopper = sizeof(WakePinConfigsCopper) / sizeof(WakePinConfigsCopper[0]); diff --git a/stratosphere/boot/source/boot_wake_pins.cpp b/stratosphere/boot/source/boot_wake_pins.cpp index 667ad711e..21dc3cbb4 100644 --- a/stratosphere/boot/source/boot_wake_pins.cpp +++ b/stratosphere/boot/source/boot_wake_pins.cpp @@ -17,6 +17,8 @@ #include "boot_functions.hpp" #include "boot_registers_pmc.hpp" #include "boot_wake_control_configs.hpp" +#include "boot_wake_pin_configuration.hpp" +#include "boot_wake_pin_configuration_copper.hpp" static void UpdatePmcControlBit(const u32 reg_offset, const u32 mask_val, const bool flag) { Boot::WritePmcRegister(PmcBase + reg_offset, flag ? UINT32_MAX : 0, mask_val); @@ -44,8 +46,43 @@ static void InitializePmcWakeConfiguration(const bool is_blink) { UpdatePmcControlBit(APBDEV_PMC_DPD_PADS_ORIDE, 0x100000, is_blink); } +void Boot::SetWakeEventLevel(u32 index, u32 level) { + u32 pmc_wake_level_reg_offset = index <= 0x1F ? APBDEV_PMC_WAKE_LVL : APBDEV_PMC_WAKE2_LVL; + u32 pmc_wake_level_mask_reg_offset = index <= 0x1F ? APBDEV_PMC_AUTO_WAKE_LVL_MASK : APBDEV_PMC_AUTO_WAKE2_LVL_MASK; + if (level == 2) { + std::swap(pmc_wake_level_reg_offset, pmc_wake_level_mask_reg_offset); + } + + const u32 mask_val = (1 << (index & 0x1F)); + + /* Clear level reg bit. */ + UpdatePmcControlBit(pmc_wake_level_reg_offset, mask_val, false); + + /* Set or clear mask reg bit. */ + UpdatePmcControlBit(pmc_wake_level_mask_reg_offset, mask_val, level > 0); +} + +void Boot::SetWakeEventEnabled(u32 index, bool enabled) { + /* Set or clear enabled bit. */ + UpdatePmcControlBit(index <= 0x1F ? APBDEV_PMC_WAKE_MASK : APBDEV_PMC_WAKE2_MASK, (1 << (index & 0x1F)), enabled); +} + void Boot::SetInitialWakePinConfiguration() { InitializePmcWakeConfiguration(false); - /* TODO: Wake event levels, wake event enables. */ + /* Set wake event levels, wake event enables. */ + const WakePinConfig *configs; + size_t num_configs; + if (Boot::GetHardwareType() == HardwareType_Copper) { + configs = WakePinConfigsCopper; + num_configs = NumWakePinConfigsCopper; + } else { + configs = WakePinConfigs; + num_configs = NumWakePinConfigs; + } + + for (size_t i = 0; i < num_configs; i++) { + Boot::SetWakeEventLevel(configs[i].index, configs[i].level); + Boot::SetWakeEventEnabled(configs[i].index, configs[i].enabled); + } }