diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_bpmp_api.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_bpmp_api.hpp index 38c5b0796..d06c35a8a 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_bpmp_api.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_bpmp_api.hpp @@ -17,31 +17,31 @@ #include /* Message Flags */ -#define BPMP_MSG_DO_ACK (1 << 0) +#define BPMP_MSG_DO_ACK (1 << 0) #define BPMP_MSG_RING_DOORBELL (1 << 1) /* Messages */ -#define MRQ_PING 0 -#define MRQ_ENABLE_SUSPEND 17 +#define MRQ_PING 0 +#define MRQ_ENABLE_SUSPEND 17 #define MRQ_CPU_PMIC_SELECT 28 /* BPMP Power states. */ -#define TEGRA_BPMP_PM_CC1 9 -#define TEGRA_BPMP_PM_CC4 12 -#define TEGRA_BPMP_PM_CC6 14 -#define TEGRA_BPMP_PM_CC7 15 -#define TEGRA_BPMP_PM_SC1 17 -#define TEGRA_BPMP_PM_SC2 18 -#define TEGRA_BPMP_PM_SC3 19 -#define TEGRA_BPMP_PM_SC4 20 -#define TEGRA_BPMP_PM_SC7 23 +#define TEGRA_BPMP_PM_CC1 9 +#define TEGRA_BPMP_PM_CC4 12 +#define TEGRA_BPMP_PM_CC6 14 +#define TEGRA_BPMP_PM_CC7 15 +#define TEGRA_BPMP_PM_SC1 17 +#define TEGRA_BPMP_PM_SC2 18 +#define TEGRA_BPMP_PM_SC3 19 +#define TEGRA_BPMP_PM_SC4 20 +#define TEGRA_BPMP_PM_SC7 23 /* Channel states. */ -#define CH_MASK(ch) (0x3u << ((ch) * 2)) -#define SL_SIGL(ch) (0x0u << ((ch) * 2)) -#define SL_QUED(ch) (0x1u << ((ch) * 2)) -#define MA_FREE(ch) (0x2u << ((ch) * 2)) -#define MA_ACKD(ch) (0x3u << ((ch) * 2)) +#define CH_MASK(ch) (0x3u << ((ch) * 2)) +#define SL_SIGL(ch) (0x0u << ((ch) * 2)) +#define SL_QUED(ch) (0x1u << ((ch) * 2)) +#define MA_FREE(ch) (0x2u << ((ch) * 2)) +#define MA_ACKD(ch) (0x3u << ((ch) * 2)) constexpr inline int MessageSize = 0x80; constexpr inline int MessageDataSizeMax = 0x78; diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp new file mode 100644 index 000000000..6f16f37f1 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018-2020 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 + +#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_ictlr_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_ictlr_registers.hpp index 35623ea45..3e63d8692 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_ictlr_registers.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_ictlr_registers.hpp @@ -15,11 +15,11 @@ */ #pragma once -#define ICTLR_REG_BASE(irq) ((((irq) - 32) >> 5) * 0x100) -#define ICTLR_FIR_SET(irq) (ICTLR_REG_BASE(irq) + 0x18) -#define ICTLR_FIR_CLR(irq) (ICTLR_REG_BASE(irq) + 0x1c) -#define FIR_BIT(irq) (1 << ((irq) & 0x1f)) +#define ICTLR_REG_BASE(irq) ((((irq) - 32) >> 5) * 0x100) +#define ICTLR_FIR_SET(irq) (ICTLR_REG_BASE(irq) + 0x18) +#define ICTLR_FIR_CLR(irq) (ICTLR_REG_BASE(irq) + 0x1c) +#define FIR_BIT(irq) (1 << ((irq) & 0x1f)) -#define INT_GIC_BASE (0) -#define INT_PRI_BASE (INT_GIC_BASE + 32) +#define INT_GIC_BASE (0) +#define INT_PRI_BASE (INT_GIC_BASE + 32) #define INT_SHR_SEM_OUTBOX_IBF (INT_PRI_BASE + 6) diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp index 96817b1a4..f1b0f1d19 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp @@ -561,7 +561,7 @@ namespace ams::kern::board::nintendo::nx { /* If we're using the legacy lps driver, enable suspend. */ if (use_legacy_lps_driver) { - MESOSPHERE_R_ABORT_UNLESS(lps::EnableSuspend()); + MESOSPHERE_R_ABORT_UNLESS(lps::EnableSuspend(true)); } /* Log that we're about to enter SC7. */ diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp index 9981771ae..51b8b133d 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp @@ -19,8 +19,10 @@ #include "kern_bpmp_api.hpp" #include "kern_atomics_registers.hpp" -#include "kern_ictlr_registers.hpp" +#include "kern_clkrst_registers.hpp" #include "kern_flow_registers.hpp" +#include "kern_ictlr_registers.hpp" +#include "kern_pmc_registers.hpp" #include "kern_sema_registers.hpp" namespace ams::kern::board::nintendo::nx::lps { @@ -43,9 +45,12 @@ namespace ams::kern::board::nintendo::nx::lps { constinit KVirtualAddress g_sema_address = Null; constinit KVirtualAddress g_atomics_address = Null; constinit KVirtualAddress g_clkrst_address = Null; + constinit KVirtualAddress g_pmc_address = Null; constinit ChannelData g_channel_area[ChannelCount] = {}; + constinit u32 g_csite_clk_source = 0; + ALWAYS_INLINE u32 Read(KVirtualAddress address) { return *GetPointer(address); } @@ -62,6 +67,7 @@ namespace ams::kern::board::nintendo::nx::lps { g_sema_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsSemaphore); g_atomics_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsAtomics); g_clkrst_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsClkRst); + g_pmc_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_PowerManagementController); } /* NOTE: linux "do_cc4_init" */ @@ -393,15 +399,36 @@ namespace ams::kern::board::nintendo::nx::lps { } void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry) { + /* Verify that we're allowed to perform suspension. */ MESOSPHERE_ABORT_UNLESS(g_lps_init_done); MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0); - MESOSPHERE_UNIMPLEMENTED(); + /* Save the CSITE clock source. */ + g_csite_clk_source = Read(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE); + + /* Configure CSITE clock source as CLK_M. */ + Write(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, (0x6 << 29)); + + /* Clear the top bit of PMC_SCRATCH4. */ + Write(g_pmc_address + APBDEV_PMC_SCRATCH4, Read(g_pmc_address + APBDEV_PMC_SCRATCH4) & 0x7FFFFFFF); + + /* Write 1 to PMC_SCRATCH0. This will cause the bootrom to use the warmboot code-path. */ + Write(g_pmc_address + APBDEV_PMC_SCRATCH0, 1); + + /* Read PMC_SCRATCH0 to be sure our write takes. */ + Read(g_pmc_address + APBDEV_PMC_SCRATCH0); /* Invoke the sleep hander. */ KSleepManager::CpuSleepHandler(arg, entry); - /* TODO: restore saved clkrst reg */ + /* Disable deep power down. */ + Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0); + + /* Restore the saved CSITE clock source. */ + Write(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, g_csite_clk_source); + + /* Read the CSITE clock source to ensure our configuration takes. */ + Read(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE); /* Configure CC3/CC4. */ ConfigureCc3AndCc4(); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp new file mode 100644 index 000000000..756d287d9 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2020 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 + +#define APBDEV_PMC_DPD_ENABLE 0x024 +#define APBDEV_PMC_SCRATCH0 0x050 +#define APBDEV_PMC_SCRATCH4 0x060 diff --git a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp index 91f86486b..5112c9ac0 100644 --- a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -41,10 +41,11 @@ namespace ams::kern { ALWAYS_INLINE bool SetupPowerManagementControllerMemoryRegion() { /* For backwards compatibility, the PMC must remain mappable on < 2.0.0. */ - const auto restrict_attr = GetTargetFirmware() >= TargetFirmware_2_0_0 ? KMemoryRegionAttr_NoUserMap : static_cast(0); + const auto rtc_restrict_attr = GetTargetFirmware() >= TargetFirmware_2_0_0 ? KMemoryRegionAttr_NoUserMap : static_cast(0); + const auto pmc_restrict_attr = GetTargetFirmware() >= TargetFirmware_2_0_0 ? KMemoryRegionAttr_NoUserMap : KMemoryRegionAttr_ShouldKernelMap; - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E000, 0x400, KMemoryRegionType_None | restrict_attr) && - KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E400, 0xC00, KMemoryRegionType_PowerManagementController | restrict_attr); + return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E000, 0x400, KMemoryRegionType_None | rtc_restrict_attr) && + KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E400, 0xC00, KMemoryRegionType_PowerManagementController | pmc_restrict_attr); } void InsertPoolPartitionRegionIntoBothTrees(size_t start, size_t size, KMemoryRegionType phys_type, KMemoryRegionType virt_type, u32 &cur_attr) {