diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp index 6f16f37f1..308bb435c 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_clkrst_registers.hpp @@ -16,3 +16,5 @@ #pragma once #define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 +#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300 +#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304 diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_evp_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_evp_registers.hpp new file mode 100644 index 000000000..5f7bdf084 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_evp_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 EVP_COP_RESET_VECTOR 0x200 diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_flow_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_flow_registers.hpp index 373454499..42e329887 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_flow_registers.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_flow_registers.hpp @@ -15,6 +15,7 @@ */ #pragma once +#define FLOW_CTLR_HALT_COP_EVENTS 0x004 #define FLOW_CTLR_CC4_HVC_CONTROL 0x060 #define FLOW_CTLR_CC4_RETENTION_CONTROL 0x064 #define FLOW_CTLR_CC4_HVC_RETRY 0x08C 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 f1b0f1d19..da7f1f6ad 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 @@ -605,6 +605,11 @@ namespace ams::kern::board::nintendo::nx { /* If on core 0, wake up the device page tables. */ if (core_id == 0) { KDevicePageTable::Wakeup(); + + /* If we're using the legacy driver, resume the bpmp firmware. */ + if (use_legacy_lps_driver) { + lps::ResumeBpmpFirmware(); + } } /* Ensure that all cores get to this point before continuing. */ 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 51b8b133d..b6c232a05 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp @@ -20,6 +20,7 @@ #include "kern_bpmp_api.hpp" #include "kern_atomics_registers.hpp" #include "kern_clkrst_registers.hpp" +#include "kern_evp_registers.hpp" #include "kern_flow_registers.hpp" #include "kern_ictlr_registers.hpp" #include "kern_pmc_registers.hpp" @@ -31,7 +32,7 @@ namespace ams::kern::board::nintendo::nx::lps { constexpr inline int ChannelCount = 12; - constexpr inline TimeSpan ChannelTimeout = TimeSpan::FromMicroSeconds(1); + constexpr inline TimeSpan ChannelTimeout = TimeSpan::FromSeconds(1); constinit bool g_lps_init_done = false; constinit bool g_bpmp_connected = false; @@ -434,4 +435,33 @@ namespace ams::kern::board::nintendo::nx::lps { ConfigureCc3AndCc4(); } + void ResumeBpmpFirmware() { + /* Halt the bpmp. */ + Write(g_flow_address + FLOW_CTLR_HALT_COP_EVENTS, (0x2 << 29)); + + /* Hold the bpmp in reset. */ + Write(g_clkrst_address + CLK_RST_CONTROLLER_RST_DEV_L_SET, 0x2); + + /* Read the saved bpmp entrypoint, and write it to the relevant exception vector. */ + const u32 bpmp_entry = Read(g_pmc_address + APBDEV_PMC_SCRATCH39); + Write(g_evp_address + EVP_COP_RESET_VECTOR, bpmp_entry); + + /* Verify that we can read back the address we wrote. */ + while (Read(g_evp_address + EVP_COP_RESET_VECTOR) != bpmp_entry) { + /* ... */ + } + + /* Spin for 40 ticks, to give enough time for the bpmp to be reset. */ + const auto start_tick = KHardwareTimer::GetTick(); + do { + __asm__ __volatile__("" ::: "memory"); + } while ((KHardwareTimer::GetTick() - start_tick) < 40); + + /* Take the bpmp out of reset. */ + Write(g_clkrst_address + CLK_RST_CONTROLLER_RST_DEV_L_CLR, 0x2); + + /* Resume the bpmp. */ + Write(g_flow_address + FLOW_CTLR_HALT_COP_EVENTS, (0x0 << 29)); + } + } \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp index 49ff4b3d3..45139f7b2 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp @@ -23,6 +23,7 @@ namespace ams::kern::board::nintendo::nx { void Initialize(); Result EnableSuspend(bool enable); void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry); + void ResumeBpmpFirmware(); } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp index 756d287d9..2ed4d670f 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_pmc_registers.hpp @@ -18,3 +18,4 @@ #define APBDEV_PMC_DPD_ENABLE 0x024 #define APBDEV_PMC_SCRATCH0 0x050 #define APBDEV_PMC_SCRATCH4 0x060 +#define APBDEV_PMC_SCRATCH39 0x138