From 6b88b43cb9ac0a756591f9f54cf262adedf2db30 Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Fri, 28 Aug 2026 13:43:50 -0400 Subject: [PATCH] add bpmp-fw cmd interface --- Source/hoc-clk/bpmpfw/source/main.cpp | 37 ++++++++++++----- Source/hoc-clk/bpmpfw/source/regs.cpp | 8 ++++ Source/hoc-clk/bpmpfw/source/regs.hpp | 2 + Source/hoc-clk/common/include/hocclk/bpmp.h | 14 ++++++- .../common/include/hocclk/clock_manager.h | 2 +- Source/hoc-clk/sysmodule/Makefile | 8 +++- Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp | 40 ++++++++++++++++++- 7 files changed, 94 insertions(+), 17 deletions(-) diff --git a/Source/hoc-clk/bpmpfw/source/main.cpp b/Source/hoc-clk/bpmpfw/source/main.cpp index b3f49cea..e5c13d36 100644 --- a/Source/hoc-clk/bpmpfw/source/main.cpp +++ b/Source/hoc-clk/bpmpfw/source/main.cpp @@ -39,11 +39,35 @@ namespace { } // namespace +[[noreturn]] void HandleShutdown(HocClkBpmpSharedInfo &info) { + /* Deinit MMU otherwise sleep will fatal. */ + bpmpMmu::Disable(); + info.magic = 0x0; + printf("[hoc-bpmpfw]: Halting...\n"); + for (;;) + ; +} + +void HandleCommand(HocClkBpmpSharedInfo &info) { + switch (info.cmd) { + case HocClkBpmpCmd_None: + break; + case HocClkBpmpCmd_RequestShutdown: + HandleShutdown(info); + break; + case HocClkBpmpCmd_SetUartEnabled: + g_uartLoggingEnabled = (info.cmdArg1 != 0); + info.cmd = HocClkBpmpCmd_None; + break; + default: + info.cmd = HocClkBpmpCmd_None; + break; + } +} + void MainLoop(HocClkBpmpSharedInfo &info) { for (;;) { - if (info.exitRequested) { - break; - } + HandleCommand(info); const u32 temp1 = MMIO32(SocthermBase + SocthermSensorTemp1); const u32 temp2 = MMIO32(SocthermBase + SocthermSensorTemp2); @@ -60,13 +84,6 @@ void MainLoop(HocClkBpmpSharedInfo &info) { msleep(250); } - - /* Deinit MMU otherwise sleep will fatal. */ - bpmpMmu::Disable(); - info.magic = 0x0; - - for (;;) - ; } extern "C" void main() { diff --git a/Source/hoc-clk/bpmpfw/source/regs.cpp b/Source/hoc-clk/bpmpfw/source/regs.cpp index 3b80f9af..0a6084b6 100644 --- a/Source/hoc-clk/bpmpfw/source/regs.cpp +++ b/Source/hoc-clk/bpmpfw/source/regs.cpp @@ -33,13 +33,21 @@ } } +bool g_uartLoggingEnabled = true; + void UartPutc(char c) { + if (!g_uartLoggingEnabled) { + return; + } while (!(MMIO32(UartBBase + UartLsr) & UartLsrThre)) ; MMIO32(UartBBase + UartThr) = static_cast(static_cast(c)); } void UartFlush() { + if (!g_uartLoggingEnabled) { + return; + } while (!(MMIO32(UartBBase + UartLsr) & UartLsrTmty)) ; } diff --git a/Source/hoc-clk/bpmpfw/source/regs.hpp b/Source/hoc-clk/bpmpfw/source/regs.hpp index 9e0b1d9c..512b305c 100644 --- a/Source/hoc-clk/bpmpfw/source/regs.hpp +++ b/Source/hoc-clk/bpmpfw/source/regs.hpp @@ -45,6 +45,8 @@ constexpr u32 UartLsr = 0x14; constexpr u32 UartLsrThre = (1u << 5); constexpr u32 UartLsrTmty = (1u << 6); +extern bool g_uartLoggingEnabled; + void UartPutc(char c); void UartFlush(); diff --git a/Source/hoc-clk/common/include/hocclk/bpmp.h b/Source/hoc-clk/common/include/hocclk/bpmp.h index 016719c6..d9c6ffba 100644 --- a/Source/hoc-clk/common/include/hocclk/bpmp.h +++ b/Source/hoc-clk/common/include/hocclk/bpmp.h @@ -22,6 +22,12 @@ #define HOCCLK_BPMP_MAGIC 0x42504D50 // 'BPMP' +typedef enum { + HocClkBpmpCmd_None = 0, + HocClkBpmpCmd_RequestShutdown = 1, // Request BPMP-FW to shut down for sleep mode. + HocClkBpmpCmd_SetUartEnabled = 2, // cmdArg1: 0/1. +} HocClkBpmpCmd; + /* * Shared with BPMP-FW * Any 64 bit data type is not permitted. @@ -41,8 +47,12 @@ typedef struct { u32 emcBwAll; u32 emcBwCpu; u32 emcBwGpu; - u32 exitRequested; // Request BPMP-FW to shutdown for sleep mode + u32 cmd; // HocClkBpmpCmd; 0 = no command pending + u32 cmdArg1; + u32 cmdArg2; + u32 cmdArg3; + u32 cmdArg4; s32 tempAO; } HocClkBpmpSharedInfo; -static_assert(sizeof(HocClkBpmpSharedInfo) == 0x40); +static_assert(sizeof(HocClkBpmpSharedInfo) == 0x50); diff --git a/Source/hoc-clk/common/include/hocclk/clock_manager.h b/Source/hoc-clk/common/include/hocclk/clock_manager.h index 766412cb..9b6830e5 100644 --- a/Source/hoc-clk/common/include/hocclk/clock_manager.h +++ b/Source/hoc-clk/common/include/hocclk/clock_manager.h @@ -89,7 +89,7 @@ typedef struct { HocClkBpmpSharedInfo bpmpInfo; // Reserved for future use - u8 reserved[0x33C]; + u8 reserved[0x32C]; } HocClkContext; typedef struct diff --git a/Source/hoc-clk/sysmodule/Makefile b/Source/hoc-clk/sysmodule/Makefile index 01693f80..7c2eb292 100644 --- a/Source/hoc-clk/sysmodule/Makefile +++ b/Source/hoc-clk/sysmodule/Makefile @@ -105,7 +105,7 @@ export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) export APP_JSON := $(TOPDIR)/perms.json -.PHONY: $(BUILD) clean clean-libs clean-build all libs +.PHONY: $(BUILD) clean clean-libs clean-build all libs sync-bpmpfw #--------------------------------------------------------------------------------- all: $(BUILD) @@ -116,7 +116,11 @@ libs: $(LIBNAMES): @echo $@ -$(BUILD): libs +sync-bpmpfw: + @$(MAKE) --no-print-directory -C $(TOPDIR)/../bpmpfw + @cp -f $(TOPDIR)/../bpmpfw/out/bpmpfw.bin $(TOPDIR)/data/bpmpfw.bin + +$(BUILD): libs sync-bpmpfw @[ -d $@ ] || mkdir -p $@ @[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR) @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp index 23b5dd35..ee5e8d6e 100644 --- a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp @@ -125,8 +125,8 @@ namespace bpmp { return; } - const u32 one = 1; - Result rc = SmcCopyToIram(WorkRamPhysBase + offsetof(HocClkBpmpSharedInfo, exitRequested), &one, sizeof(one)); + const u32 cmd = HocClkBpmpCmd_RequestShutdown; + Result rc = SmcCopyToIram(WorkRamPhysBase + offsetof(HocClkBpmpSharedInfo, cmd), &cmd, sizeof(cmd)); if (R_FAILED(rc)) { fileUtils::LogLine("[bpmp] RequestBpmpExitAndWait: SmcCopyToIram failed: 0x%x", rc); return; @@ -186,6 +186,40 @@ namespace bpmp { SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0); } + bool WaitForBpmpReady(int maxAttempts = 50, u64 pollIntervalNs = 20'000'000) { + HocClkBpmpSharedInfo info = {}; + for (int i = 0; i < maxAttempts; i++) { + Result rc = SmcCopyFromIram(&info, WorkRamPhysBase, sizeof(info)); + if (R_SUCCEEDED(rc) && info.magic == HOCCLK_BPMP_MAGIC) { + return true; + } + svcSleepThread(pollIntervalNs); + } + return false; + } + + void SendBpmpCommand(HocClkBpmpCmd cmd, u32 arg1 = 0, u32 arg2 = 0, u32 arg3 = 0, u32 arg4 = 0) { + if (!WaitForBpmpReady()) { + fileUtils::LogLine("[bpmp] SendBpmpCommand: BPMP never signaled ready (cmd=%u)", static_cast(cmd)); + return; + } + + struct { + u32 cmd; + u32 cmdArg1; + u32 cmdArg2; + u32 cmdArg3; + u32 cmdArg4; + } req = { static_cast(cmd), arg1, arg2, arg3, arg4 }; + static_assert(offsetof(HocClkBpmpSharedInfo, cmdArg1) == offsetof(HocClkBpmpSharedInfo, cmd) + 1 * sizeof(u32)); + static_assert(offsetof(HocClkBpmpSharedInfo, cmdArg4) == offsetof(HocClkBpmpSharedInfo, cmd) + 4 * sizeof(u32)); + + const Result rc = SmcCopyToIram(WorkRamPhysBase + offsetof(HocClkBpmpSharedInfo, cmd), &req, sizeof(req)); + if (R_FAILED(rc)) { + fileUtils::LogLine("[bpmp] SendBpmpCommand: SmcCopyToIram failed: 0x%x (cmd=%u)", rc, static_cast(cmd)); + } + } + void RestoreStockState() { RequestBpmpExitAndWait(); @@ -306,6 +340,8 @@ namespace bpmp { /* Clear the halt written by bootloader. */ SmcReadWriteRegister(FlowCtlrPhysBase + FlowCtlrHaltCopEvents, 0xFFFFFFFF, FlowModeNone); + SendBpmpCommand(HocClkBpmpCmd_SetUartEnabled, fileUtils::IsUartEnabled() ? 1u : 0u); + return 0; }