From d8c6a86bb0052b021918274daa097ea4cdcc92bd Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Wed, 26 Aug 2026 11:56:56 -0400 Subject: [PATCH] real freqs + ram load on bpmp gpu freq is excluded due to smmu issue (carveout?) --- Source/hoc-clk/bpmpfw/Makefile | 5 +- Source/hoc-clk/bpmpfw/out/bpmpfw.bin | Bin 2968 -> 5008 bytes Source/hoc-clk/bpmpfw/source/actmon.hpp | 99 ++++++ Source/hoc-clk/bpmpfw/source/bpmp_mmu.hpp | 152 +++++++++ Source/hoc-clk/bpmpfw/source/freq.hpp | 79 +++++ Source/hoc-clk/bpmpfw/source/main.cpp | 24 +- Source/hoc-clk/common/include/hocclk/bpmp.h | 12 +- .../common/include/hocclk/clock_manager.h | 2 +- Source/hoc-clk/sysmodule/src/board/board.cpp | 1 - .../sysmodule/src/board/board_freq.cpp | 8 +- .../sysmodule/src/board/board_freq.hpp | 1 - .../sysmodule/src/board/board_load.cpp | 14 +- .../sysmodule/src/board/board_profile.cpp | 1 - .../sysmodule/src/board/board_sensor.cpp | 1 - Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp | 33 ++ Source/hoc-clk/sysmodule/src/file/config.cpp | 1 - .../hoc-clk/sysmodule/src/file/file_utils.cpp | 1 - .../hoc-clk/sysmodule/src/ipc/ipc_service.cpp | 1 - Source/hoc-clk/sysmodule/src/soc/t210.c | 297 ------------------ Source/hoc-clk/sysmodule/src/soc/t210.h | 47 --- 20 files changed, 411 insertions(+), 368 deletions(-) create mode 100644 Source/hoc-clk/bpmpfw/source/actmon.hpp create mode 100644 Source/hoc-clk/bpmpfw/source/bpmp_mmu.hpp create mode 100644 Source/hoc-clk/bpmpfw/source/freq.hpp delete mode 100644 Source/hoc-clk/sysmodule/src/soc/t210.c delete mode 100644 Source/hoc-clk/sysmodule/src/soc/t210.h diff --git a/Source/hoc-clk/bpmpfw/Makefile b/Source/hoc-clk/bpmpfw/Makefile index 4cd0257a..ddfe3882 100644 --- a/Source/hoc-clk/bpmpfw/Makefile +++ b/Source/hoc-clk/bpmpfw/Makefile @@ -28,7 +28,8 @@ CXXFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -fno-exceptions -fno-rtti \ -fomit-frame-pointer -std=gnu++20 -Wall -Wextra $(CUSTOMDEFINES) ASFLAGS := $(ARCH) -g LDFLAGS := $(ARCH) -nostartfiles -nodefaultlibs -Wl,--nmagic,--gc-sections \ - -T $(SOURCEDIR)/../bpmpfw.ld -lgcc + -T $(SOURCEDIR)/../bpmpfw.ld +LDLIBS := -lgcc BIN_TARGET := $(OUTPUTDIR)/$(TARGET).bin @@ -41,7 +42,7 @@ $(BIN_TARGET): $(BUILDDIR)/$(TARGET).elf $(OBJCOPY) -S -O binary $< $@ $(BUILDDIR)/$(TARGET).elf: $(OBJS) - @$(CXX) $(LDFLAGS) $(OBJS) -o $@ + @$(CXX) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ $(BUILDDIR)/%.o: $(SOURCEDIR)/%.cpp | $(BUILDDIR) @$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/Source/hoc-clk/bpmpfw/out/bpmpfw.bin b/Source/hoc-clk/bpmpfw/out/bpmpfw.bin index 61766ba1ec27f24d8e81d98268537af1a9222190..4681bab6323048e8d6d6b4642ca5e57ede0e4405 100644 GIT binary patch delta 2545 zcmah~ZD?E98Gi4FQ`r&Gjij}X2+fh4QWs)!-MT}|+)eg88q>5@qmZnuW3roM8KkWj z0?VIruXLSwftG2xHtR~$d$OfaN`HiQzrx0p(89WUkQE9UIjo8I!#~C-X*caT zSN58YhRIy(J$k>M`+hvUZAPXK}a010!fqL5y)Oi*tIvyzdV4zaAK8LD25g}evYMrw$Q2D7q z4X)|frATdJO)pVi5P_OPu;F%~c54unjX&>p2X;H5`kY0Hj&y=GT|d!)0bti0=qOOj zuo;H`Zubm)b3I?kQ*KjzmuTg86sb=QS|RxS){WG7HdJHqTV!6OSUXfM4$KV|tp!M} zC3p$OQ`A($2=rCKkLX~fP?^Qc@puU_0C0RVRNq6wYe;B2Tvj3f6>^2~m{8FvoFfg! z<#G9uN~COeUX_5-MKGJVB%GhanaHk+u2soqi25r;VlP#wWz6MprW#d-YrmM>>$M=A zz>_aVD!(~WPG#hVgJ#y9rb-);N~6$qaRym@Rc|-HkfAr1_jKyc7rN^}P-kaUmuj)a z_-L2$p~-wRHr<-A9bbLg?H1ldED=8JG4aXzl}ny81z& z+FSH+z^{xZr*rXLdO|<+;AHq>3{Eu4OC203vl&E@iFsQk-yLC#Dz4Uj2kLHS0{eh5KI z+CJmMJ{vbmGs4sX5s#>z9fHp6%f(iCJ!Uo@+5up+pql2apkh-rQ6*0Y*M>tdbdcc1 zoz3i64vU99AU2!Lvjxn;N%VC|u^~*De+qK%oXBgs)NMM#n`-;7o`X}#92|6)bhSJ^ z1Q)5TXJ82fcCy#|_L9^c?8^e+|87c!Tq1q|TR+gaE`@`Y))(2YZPVU|I(d ziR_+KM<<~}(k|_bZ5PAoVmP;ZL2Om_37dTh)g3`;K*>M?6m8(L2vDmgtqcN`|KO4` z>|DGR%m31vyah901Jq~Ra;nQVcMO+Xh>jmAMFNh+Ze)CU&TYwaUh+1!akiFn+GjV5JmKs=re5^_F|SPU0H!p-=;ou9GB z1r3~BZ$bUL+r9a}Nss=&qzpt18-1(%UHjMZ2VO|{fo+=8T%kE4Q|j?VM$A*@I-brv zb-mmHTAemEcT{qd8M;L@p~*TSW)SqduNiZO*{Z#}$=ZL{z>^^7KQAvY@2Q2)59~ER z`YgOWFqzOcU!!hK-xZx6RV3PL+4}A1Dacie9FYU{=bj+CnF1+MedLCP%fS|BRqD#i zoiz0bPT$#99h^Z`xxxL5po-=Z{*X~cJLk?S+&rUSC)#DAts5NfNz>x6>(zIZ$J)OJ9;V6!F2EP%=K@d;*TLFUala}+b(1CTpJ_Iz-J`)@0Y~j+qw;`?S z`@#YF5j_**Ee6u{9+d|>n+ZE7F?{c1agRm=N9|x&7DZq64PjIkJ5+t6W7PL|{(;NJ zrj{7n1KxOIUOqfMFZ-Nx;^Aj-2Dm(c<(Ih}1F$qzh2>lVumdp$ba3_2URBoP-b9P_ zHJ~p?U0KsZiGdzul=EW3bhaj80XhTl1 zpLd8p`kO(%&-~k=eQD<_`b#2fJA9_{_26KYsp4Y&NWJOg;8x z<;4E#cYZigo1S8`hYr7R?9e0biTh3r=qPuxn>l>^(6OFbcwpmw?ApJ&-g@TuCa97i Lz`yH|yZHPEv``-I delta 464 zcmX|;ze~eV5XUbuYAqs<7_>--SFM=AV&deWm^umVP%Ma0gkn(~6oWs&rC1XcMvK7;C9Ry)b70j_AKA<+lv&WR8=_Nah{w|# z(azq87-4}zS@4XAvuMpc3*7OFFPpCKnk5W8eSb_!1;I&<$1k2WotfUWhb8|9}yQ;Ba-3ab+0+zY8L` z+^g|uK^p53R06Hb(~uEDk@rw$hLlZYHHXVa(O1a1_zc6bhcJ8t8XvO3hH?Tg(7f)q zCApq!_6@A|$4gjwYPZ{KId6-s$b~PjMV8FyS_~CkERt0QyL7NuIo#gd-(9DNo4dBT eFnQcHvuNVpi#p-uhtv2&Kasb<`tv*JLyT_>)~-PS diff --git a/Source/hoc-clk/bpmpfw/source/actmon.hpp b/Source/hoc-clk/bpmpfw/source/actmon.hpp new file mode 100644 index 00000000..9a607c4e --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/actmon.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) Souldbminer, Lightos and Horizon OC Contributors + * + * 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 "freq.hpp" +#include "regs.hpp" + +#include + +namespace actmon { + + constexpr u32 ActmonBase = 0x6000C800; + constexpr u32 ActmonDevBase = ActmonBase + 0x80; + constexpr u32 ActmonDevSize = 0x40; + + constexpr u32 ActmonGlbStatus = 0x0; + constexpr u32 ActmonGlbPeriodCtrl = 0x4; + constexpr u32 ActmonMccpuMonAct = (1u << 8); + constexpr u32 ActmonMcallMonAct = (1u << 9); + + constexpr u32 ActmonDevCtrlKVal3 = (3u << 10); + constexpr u32 ActmonDevCtrlEnbPeriodic = (1u << 18); + constexpr u32 ActmonDevCtrlEnb = (1u << 31); + + constexpr u32 ActmonPeriodMs = 20; + + enum ActmonDev : u32 { + DevCpu = 0, + DevBpmp, + DevAhb, + DevApb, + DevCpuFreq, + DevMcAll, + DevMcCpu, + }; + + constexpr u32 DevCtrl = 0x00; + constexpr u32 DevInitAvg = 0x0C; + constexpr u32 DevCountWeight = 0x18; + constexpr u32 DevAvgCount = 0x20; + + inline u32 DevReg(ActmonDev dev, u32 off) { + return ActmonDevBase + (static_cast(dev) * ActmonDevSize) + off; + } + + inline void EnableDev(ActmonDev dev, u32 freqKhz, u32 weight) { + MMIO32(DevReg(dev, DevInitAvg)) = freqKhz * ActmonPeriodMs / 2; + MMIO32(DevReg(dev, DevCountWeight)) = weight; + MMIO32(DevReg(dev, DevCtrl)) = ActmonDevCtrlEnb | ActmonDevCtrlEnbPeriodic | ActmonDevCtrlKVal3; + } + + inline void Init() { + const u32 emcFreqKhz = static_cast(freq::MeasurePtoFreqHz(freq::ClkPtoEmc, 1) / 1000); + + if (!(MMIO32(ActmonBase + ActmonGlbStatus) & ActmonMcallMonAct)) { + MMIO32(ActmonBase + ActmonGlbPeriodCtrl) = (ActmonPeriodMs - 1) & 0xFF; + EnableDev(DevMcAll, emcFreqKhz, 256 * 4); + } + + if (!(MMIO32(ActmonBase + ActmonGlbStatus) & ActmonMccpuMonAct)) { + EnableDev(DevMcCpu, emcFreqKhz, 256 * 4); + } + } + + inline void Update(HocClkBpmpSharedInfo &info) { + const u32 emcFreqKhz = info.freqMem; + if (emcFreqKhz == 0) { + return; + } + + const u32 avgAll = MMIO32(DevReg(DevMcAll, DevAvgCount)); + const u32 avgCpu = MMIO32(DevReg(DevMcCpu, DevAvgCount)); + + // Get 1000 -> 100.0. + info.emcLoadAll = static_cast((static_cast(avgAll) * 10 * 100) / (emcFreqKhz * ActmonPeriodMs)); + info.emcLoadCpu = static_cast((static_cast(avgCpu) * 10 * 100) / (emcFreqKhz * ActmonPeriodMs)); + + info.emcBwAll = static_cast((static_cast(emcFreqKhz) * 16 * info.emcLoadAll) / 1000000); + info.emcBwCpu = static_cast((static_cast(emcFreqKhz) * 16 * info.emcLoadCpu) / 1000000); + + // Not 100% accurate but should be enough. + info.emcBwGpu = (info.emcBwAll > info.emcBwCpu) ? (info.emcBwAll - info.emcBwCpu) : 0; + } + +} // namespace actmon diff --git a/Source/hoc-clk/bpmpfw/source/bpmp_mmu.hpp b/Source/hoc-clk/bpmpfw/source/bpmp_mmu.hpp new file mode 100644 index 00000000..ca106eb8 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/bpmp_mmu.hpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2019-2025 CTCaer + * Copyright (c) Souldbminer, Lightos and Horizon OC Contributors + * + * 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 "regs.hpp" + +// NOTE: MMU won't allow access to gpu address space (smmu carveout issue?) +namespace bpmpMmu { + + constexpr u32 CacheBase = 0x50040000; + + constexpr u32 CacheConfig = 0x000; + constexpr u32 CfgEnableCache = (1u << 0); + constexpr u32 CfgForceWriteThrough = (1u << 3); + constexpr u32 CfgMmuTagModeShift = 8; + constexpr u32 TagModeParallel = 0; + constexpr u32 CfgTagChkAbrtOnErr = (1u << 14); + + constexpr u32 MaintReq = 0x028; + constexpr u32 MaintReqWayBitmapAll = (0xFu << 8); + + constexpr u32 IntClear = 0x044; + constexpr u32 IntRawEvent = 0x048; + constexpr u32 IntMaintDone = (1u << 0); + + constexpr u32 MmuFallbackEntry = 0x0A0; + constexpr u32 MmuShadowCopyMask = 0x0A4; + + constexpr u32 MmuCfg = 0x0AC; + constexpr u32 MmuCfgSeqEn = (1u << 1); + constexpr u32 MmuCfgTlbEn = (1u << 2); + constexpr u32 MmuCfgAbortStoreLast = (1u << 4); + + constexpr u32 MmuCmd = 0x0B0; + constexpr u32 MmuCmdInit = 1; + constexpr u32 MmuCmdCopyShadow = 2; + + constexpr u32 ShadowEntryBase = CacheBase + 0x400; + + constexpr u32 MmuEnCached = (1u << 0); + constexpr u32 MmuEnExec = (1u << 1); + constexpr u32 MmuEnRead = (1u << 2); + constexpr u32 MmuEnWrite = (1u << 3); + + constexpr u32 MaintCleanInvalidWay = 19; + constexpr u32 MaintInvalidWay = 18; + + constexpr u32 CacheLineSize = 0x20; + + constexpr u32 DramStart = 0x80000000; + constexpr u32 IramBase = 0x40000000; + constexpr u32 IramEnd = 0x4003FFFF; + + struct MmuEntry { + u32 startAddr; + u32 endAddr; + u32 attr; + }; + + constexpr MmuEntry Entries[] = { + { DramStart, 0xFFFFFFFF, MmuEnRead | MmuEnWrite | MmuEnExec | MmuEnCached }, + { IramBase, IramEnd, MmuEnRead | MmuEnWrite | MmuEnExec | MmuEnCached }, + }; + + inline u32 AlignUp(u32 x, u32 a) { + return (x + a - 1) & ~(a - 1); + } + inline u32 AlignDown(u32 x, u32 a) { + return x & ~(a - 1); + } + + inline void Maintenance(u32 op, bool force) { + if (!force && !(MMIO32(CacheBase + CacheConfig) & CfgEnableCache)) { + return; + } + + MMIO32(CacheBase + IntClear) = IntMaintDone; + + // Blocking operation. + MMIO32(CacheBase + MaintReq) = MaintReqWayBitmapAll | op; + + while (!(MMIO32(CacheBase + IntRawEvent) & IntMaintDone)) + ; + + MMIO32(CacheBase + IntClear) = MMIO32(CacheBase + IntRawEvent); + } + + inline void SetEntry(u32 idx, const MmuEntry &entry) { + MMIO32(ShadowEntryBase + sizeof(u32) * 4 * idx + 0x0) = AlignUp(entry.startAddr, CacheLineSize); + MMIO32(ShadowEntryBase + sizeof(u32) * 4 * idx + 0x4) = AlignDown(entry.endAddr, CacheLineSize); + MMIO32(ShadowEntryBase + sizeof(u32) * 4 * idx + 0x8) = entry.attr; + + MMIO32(CacheBase + MmuShadowCopyMask) |= (1u << idx); + } + + inline void Enable() { + if (MMIO32(CacheBase + CacheConfig) & CfgEnableCache) { + return; + } + + // Init BPMP MMU. + MMIO32(CacheBase + MmuCmd) = MmuCmdInit; + MMIO32(CacheBase + MmuFallbackEntry) = MmuEnRead | MmuEnWrite | MmuEnExec; // RWX for non-defined regions. + MMIO32(CacheBase + MmuCfg) = MmuCfgSeqEn | MmuCfgTlbEn | MmuCfgAbortStoreLast; + + // Init BPMP MMU entries. + MMIO32(CacheBase + MmuShadowCopyMask) = 0; + for (u32 idx = 0; idx < sizeof(Entries) / sizeof(Entries[0]); idx++) { + SetEntry(idx, Entries[idx]); + } + + MMIO32(CacheBase + MmuCmd) = MmuCmdCopyShadow; + + // Invalidate cache. + Maintenance(MaintInvalidWay, true); + + // Enable cache. + MMIO32(CacheBase + CacheConfig) = CfgEnableCache | CfgForceWriteThrough | + (TagModeParallel << CfgMmuTagModeShift) | CfgTagChkAbrtOnErr; + + // HW bug. Invalidate cache again. + Maintenance(MaintInvalidWay, false); + } + + inline void Disable() { + if (!(MMIO32(CacheBase + CacheConfig) & CfgEnableCache)) { + return; + } + + // Clean and invalidate cache. + Maintenance(MaintCleanInvalidWay, false); + + // Disable cache. + MMIO32(CacheBase + CacheConfig) = 0; + } + +} // namespace bpmpMmu diff --git a/Source/hoc-clk/bpmpfw/source/freq.hpp b/Source/hoc-clk/bpmpfw/source/freq.hpp new file mode 100644 index 00000000..eea8e9a4 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/freq.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) Souldbminer, Lightos and Horizon OC Contributors + * + * 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 "regs.hpp" + +#include + +namespace freq { + + constexpr u32 CarBase = 0x60006000; + constexpr u32 CarPtoClkCntCntl = 0x60; + constexpr u32 CarPtoClkCntStatus = 0x64; + + constexpr u32 PtoCntEn = (1u << 9); + constexpr u32 PtoCntRst = (1u << 10); + constexpr u32 PtoClkEnable = (1u << 13); + constexpr u32 PtoSrcSelShift = 14; + constexpr u32 PtoDivSelDiv1 = (1u << 23); + constexpr u32 PtoClkCntBusy = (1u << 31); + constexpr u32 PtoClkCntMask = 0xFFFFFF; + + constexpr u32 ClkPtoCclkGDiv2 = 0x13; + constexpr u32 ClkPtoEmc = 0x24; + + inline u64 MeasurePtoFreqHz(u32 srcId, u32 multiplier) { + constexpr u32 win = 16; + constexpr u32 osc = 32768; + + const u32 val = (srcId << PtoSrcSelShift) | PtoDivSelDiv1 | PtoClkEnable | (win - 1); + + MMIO32(CarBase + CarPtoClkCntCntl) = val; + (void)MMIO32(CarBase + CarPtoClkCntCntl); + usleep(2); + + MMIO32(CarBase + CarPtoClkCntCntl) = val | PtoCntRst; + (void)MMIO32(CarBase + CarPtoClkCntCntl); + usleep(2); + + MMIO32(CarBase + CarPtoClkCntCntl) = val; + (void)MMIO32(CarBase + CarPtoClkCntCntl); + usleep(2); + + MMIO32(CarBase + CarPtoClkCntCntl) = val | PtoCntEn; + (void)MMIO32(CarBase + CarPtoClkCntCntl); + usleep((1000000u * win / osc) + 12 + 2); // 502us + + while (MMIO32(CarBase + CarPtoClkCntStatus) & PtoClkCntBusy) + ; + + const u32 cnt = MMIO32(CarBase + CarPtoClkCntStatus) & PtoClkCntMask; + + MMIO32(CarBase + CarPtoClkCntCntl) = 0; + (void)MMIO32(CarBase + CarPtoClkCntCntl); + usleep(2); + + return (static_cast(cnt) * multiplier * osc) / win; + } + + inline void Update(HocClkBpmpSharedInfo &info) { + info.freqMem = static_cast(MeasurePtoFreqHz(ClkPtoEmc, 1) / 1000); + info.freqCpu = static_cast(MeasurePtoFreqHz(ClkPtoCclkGDiv2, 2) / 1000); + } + +} // namespace freq diff --git a/Source/hoc-clk/bpmpfw/source/main.cpp b/Source/hoc-clk/bpmpfw/source/main.cpp index 2da95075..43e74416 100644 --- a/Source/hoc-clk/bpmpfw/source/main.cpp +++ b/Source/hoc-clk/bpmpfw/source/main.cpp @@ -18,6 +18,9 @@ #include #include +#include "actmon.hpp" +#include "bpmp_mmu.hpp" +#include "freq.hpp" #include "libc_platform.hpp" #include "regs.hpp" #include "sensors.hpp" @@ -34,6 +37,10 @@ namespace { void MainLoop(HocClkBpmpSharedInfo &info) { for (;;) { + if (info.exitRequested) { + break; + } + const u32 temp1 = MMIO32(SocthermBase + SocthermSensorTemp1); const u32 temp2 = MMIO32(SocthermBase + SocthermSensorTemp2); @@ -42,11 +49,23 @@ void MainLoop(HocClkBpmpSharedInfo &info) { info.tempMem = TranslateSocthermTemp(static_cast(temp2 >> 16)); info.tempPllx = TranslateSocthermTemp(static_cast(temp2)); - msleep(500); + freq::Update(info); + actmon::Update(info); + + msleep(250); } + + /* Deinit MMU otherwise sleep will fatal. */ + bpmpMmu::Disable(); + info.magic = 0x0; + + for (;;) + ; } extern "C" void main() { + bpmpMmu::Enable(); + InitializeLibc(); printf("[hoc-bpmpfw]: Starting bpmpfw\n"); @@ -54,6 +73,9 @@ extern "C" void main() { HocClkBpmpSharedInfo &info = SharedInfo(); memset(&info, 0, sizeof(info)); info.status = 0; + + actmon::Init(); + info.magic = HOCCLK_BPMP_MAGIC; // written last /* If the main loop exits then it is a panic or invalid state */ diff --git a/Source/hoc-clk/common/include/hocclk/bpmp.h b/Source/hoc-clk/common/include/hocclk/bpmp.h index d2b5f862..c064f835 100644 --- a/Source/hoc-clk/common/include/hocclk/bpmp.h +++ b/Source/hoc-clk/common/include/hocclk/bpmp.h @@ -33,7 +33,15 @@ typedef struct { s32 tempGpu; s32 tempMem; s32 tempPllx; - u32 reserved[2]; + u32 freqCpu; // kHz + u32 freqMem; // kHz + u32 emcLoadAll; + u32 emcLoadCpu; + u32 emcBwAll; + u32 emcBwCpu; + u32 emcBwGpu; + u32 exitRequested; // Request BPMP-FW to shutdown for sleep mode + u32 reserved[1]; } HocClkBpmpSharedInfo; -static_assert(sizeof(HocClkBpmpSharedInfo) == 0x20); +static_assert(sizeof(HocClkBpmpSharedInfo) == 0x3C); diff --git a/Source/hoc-clk/common/include/hocclk/clock_manager.h b/Source/hoc-clk/common/include/hocclk/clock_manager.h index f2338354..766412cb 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[0x358]; + u8 reserved[0x33C]; } HocClkContext; typedef struct diff --git a/Source/hoc-clk/sysmodule/src/board/board.cpp b/Source/hoc-clk/sysmodule/src/board/board.cpp index da191e6d..049ec75a 100644 --- a/Source/hoc-clk/sysmodule/src/board/board.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "../bpmp/bpmp.hpp" diff --git a/Source/hoc-clk/sysmodule/src/board/board_freq.cpp b/Source/hoc-clk/sysmodule/src/board/board_freq.cpp index 8386d8ef..81128498 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_freq.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_freq.cpp @@ -28,9 +28,9 @@ #include #include #include -#include #include +#include "../bpmp/bpmp.hpp" #include "../display/display_refresh_rate.hpp" #include "../file/config.hpp" #include "../file/errors.hpp" @@ -179,13 +179,13 @@ namespace board { u32 hz = 0; switch (module) { case HocClkModule_CPU: - return t210ClkCpuFreq(); + return bpmp::GetSharedInfo()->freqCpu * 1000; case HocClkModule_GPU: - return t210ClkGpuFreq(); + return bpmp::GetSharedInfo()->freqGpu * 1000; case HocClkModule_MEM: return config::GetConfigValue(HocClkConfigValue_MemoryFrequencyMeasurementMode) == MemoryFrequencyMeasurementMode_PLL ? pllmb::getRamClockRatePLLMB() - : t210ClkMemFreq(); + : bpmp::GetSharedInfo()->freqMem * 1000; case HocClkModule_Display: return GetDisplayRate(hz); default: diff --git a/Source/hoc-clk/sysmodule/src/board/board_freq.hpp b/Source/hoc-clk/sysmodule/src/board/board_freq.hpp index fa774cbe..b0a91b6f 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_freq.hpp +++ b/Source/hoc-clk/sysmodule/src/board/board_freq.hpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "../file/errors.hpp" diff --git a/Source/hoc-clk/sysmodule/src/board/board_load.cpp b/Source/hoc-clk/sysmodule/src/board/board_load.cpp index bf814453..669f46d2 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_load.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_load.cpp @@ -33,9 +33,9 @@ #include #include #include -#include #include +#include "../bpmp/bpmp.hpp" #include "../hos/apm_ext.h" #include "board.hpp" #include "board_misc.hpp" @@ -116,9 +116,9 @@ namespace board { u32 GetPartLoad(HocClkPartLoad loadSource) { switch (loadSource) { case HocClkPartLoad_EMC: - return t210EmcLoadAll(); + return bpmp::GetSharedInfo()->emcLoadAll; case HocClkPartLoad_EMCCpu: - return t210EmcLoadCpu(); + return bpmp::GetSharedInfo()->emcLoadCpu; case HocClkPartLoad_GPU: return gpuLoad; case HocClkPartLoad_CPUMax: @@ -130,13 +130,13 @@ namespace board { case HocClkPartLoad_FAN: return GetFanLevel(); case HocClkPartLoad_RamBWAll: - return t210EmcBwAll(); + return bpmp::GetSharedInfo()->emcBwAll; case HocClkPartLoad_RamBWCpu: - return t210EmcBwCpu(); + return bpmp::GetSharedInfo()->emcBwCpu; case HocClkPartLoad_RamBWGpu: - return t210EmcBwGpu(); + return bpmp::GetSharedInfo()->emcBwGpu; case HocClkPartLoad_RamBWPeak: - return t210EmcBwPeak(); + return static_cast((static_cast(bpmp::GetSharedInfo()->freqMem) * 16) / 1000); default: ASSERT_ENUM_VALID(HocClkPartLoad, loadSource); } diff --git a/Source/hoc-clk/sysmodule/src/board/board_profile.cpp b/Source/hoc-clk/sysmodule/src/board/board_profile.cpp index 6d7da57e..eadeba8a 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_profile.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_profile.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "../hos/apm_ext.h" diff --git a/Source/hoc-clk/sysmodule/src/board/board_sensor.cpp b/Source/hoc-clk/sysmodule/src/board/board_sensor.cpp index b451075a..1a274050 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_sensor.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_sensor.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "../file/config.hpp" diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp index bf1824cf..7c626409 100644 --- a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -91,7 +92,39 @@ namespace bpmp { std::atomic_bool s_isAwake = true; + + /* Must be called to prevent secmon/erpt panic on wake */ + void RequestBpmpExitAndWait() { + if (!IsPatchedExosphere()) { + return; + } + + const u32 one = 1; + Result rc = SmcCopyToIram(WorkRamPhysBase + offsetof(HocClkBpmpSharedInfo, exitRequested), &one, sizeof(one)); + if (R_FAILED(rc)) { + fileUtils::LogLine("[bpmp] RequestBpmpExitAndWait: SmcCopyToIram failed: 0x%x", rc); + return; + } + + constexpr int MaxAttempts = 20; + constexpr u64 PollIntervalNs = 20'000'000; // 20ms + + HocClkBpmpSharedInfo info = {}; + for (int i = 0; i < MaxAttempts; i++) { + svcSleepThread(PollIntervalNs); + + rc = SmcCopyFromIram(&info, WorkRamPhysBase, sizeof(info)); + if (R_SUCCEEDED(rc) && info.magic != HOCCLK_BPMP_MAGIC) { + return; + } + } + + fileUtils::LogLine("[bpmp] RequestBpmpExitAndWait: BPMP timeout (cannot sleep)"); + } + void RestoreStockState() { + RequestBpmpExitAndWait(); + SmcReadWriteRegister(EvpPhysBase + EvpCopResetVector, 0xFFFFFFFF, StockBpmpExceptionVector); SmcReadWriteRegister(EvpPhysBase + EvpCopUndefVector, 0xFFFFFFFF, StockBpmpExceptionVector); SmcReadWriteRegister(EvpPhysBase + EvpCopSwiVector, 0xFFFFFFFF, StockBpmpExceptionVector); diff --git a/Source/hoc-clk/sysmodule/src/file/config.cpp b/Source/hoc-clk/sysmodule/src/file/config.cpp index d911cebb..018571a5 100644 --- a/Source/hoc-clk/sysmodule/src/file/config.cpp +++ b/Source/hoc-clk/sysmodule/src/file/config.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/Source/hoc-clk/sysmodule/src/file/file_utils.cpp b/Source/hoc-clk/sysmodule/src/file/file_utils.cpp index 107a2b73..169eb87b 100644 --- a/Source/hoc-clk/sysmodule/src/file/file_utils.cpp +++ b/Source/hoc-clk/sysmodule/src/file/file_utils.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include "../hos/apm_ext.h" diff --git a/Source/hoc-clk/sysmodule/src/ipc/ipc_service.cpp b/Source/hoc-clk/sysmodule/src/ipc/ipc_service.cpp index f6230f69..f1e01d9b 100644 --- a/Source/hoc-clk/sysmodule/src/ipc/ipc_service.cpp +++ b/Source/hoc-clk/sysmodule/src/ipc/ipc_service.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "../file/config.hpp" diff --git a/Source/hoc-clk/sysmodule/src/soc/t210.c b/Source/hoc-clk/sysmodule/src/soc/t210.c deleted file mode 100644 index d787976f..00000000 --- a/Source/hoc-clk/sysmodule/src/soc/t210.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2020-2023 CTCaer - * Copyright (c) 2023 p-sam - * Copyright (c) 2023 Lineon - * Copyright (c) 2026 Souldbminer - * - * 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 "t210.h" - -#define WAIT_NS 1000000000UL - -#define usleep(x) svcSleepThread(1000UL * x) - -#define GPU_TRIM_SYS_GPCPLL_COEFF 0x4 -#define GPU_TRIM_SYS_GPCPLL(x) (*(volatile u32 *)(g_gpu_base + 0x137000ul + (x))) - -#define CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL 0x60 -#define CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS 0x64 -#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 -#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C - -/*! PTO_CLK_CNT */ -#define PTO_REF_CLK_WIN_CFG_MASK 0xF -#define PTO_REF_CLK_WIN_CFG_16P 0xF -#define PTO_CNT_EN BIT(9) -#define PTO_CNT_RST BIT(10) -#define PTO_CLK_ENABLE BIT(13) -#define PTO_SRC_SEL_SHIFT 14 -#define PTO_SRC_SEL_MASK 0x1FF -#define PTO_DIV_SEL_MASK (3 << 23) -#define PTO_DIV_SEL_GATED (0 << 23) -#define PTO_DIV_SEL_DIV1 (1 << 23) -#define PTO_DIV_SEL_DIV2_RISING (2 << 23) -#define PTO_DIV_SEL_DIV2_FALLING (3 << 23) -#define PTO_DIV_SEL_CPU_EARLY (0 << 23) -#define PTO_DIV_SEL_CPU_LATE (1 << 23) - -#define PTO_CLK_CNT_BUSY BIT(31) -#define PTO_CLK_CNT 0xFFFFFF -#define CLK_PTO_CCLK_G_DIV2 0x13 -#define CLK_PTO_EMC 0x24 - -#define CLOCK(x) (*(volatile u32 *)(g_clk_base + (x))) - -/* Actmon Global registers */ -#define ACTMON_GLB_STATUS 0x0 -#define ACTMON_MCCPU_MON_ACT BIT(8) -#define ACTMON_MCALL_MON_ACT BIT(9) -#define ACTMON_CPU_FREQ_MON_ACT BIT(10) -#define ACTMON_BPMP_MON_ACT BIT(14) -#define ACTMON_CPU_MON_ACT BIT(15) - -#define ACTMON_GLB_PERIOD_CTRL 0x4 -#define ACTMON_GLB_PERIOD_USEC BIT(8) -#define ACTMON_GLB_PERIOD_SAMPLE(n) (((n) - 1) & 0xFF) - -/* Actmon Device Registers */ -#define ACTMON_DEV_SIZE 0x40 -/* Actmon CTRL */ -#define ACTMON_DEV_CTRL_K_VAL(k) (((k) & 7) << 10) -#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18) -#define ACTMON_DEV_CTRL_ENB BIT(31) - -#define ACTMON_PERIOD_MS 20 -#define DEV_COUNT_WEIGHT 1024 - -#define ACTMON_BASE (g_act_base + 0x800) -#define ACTMON_DEV_BASE (ACTMON_BASE + 0x80) -#define ACTMON(x) (*(volatile u32 *)(ACTMON_BASE + (x))) - -typedef enum _actmon_dev_t { - ACTMON_DEV_CPU, - ACTMON_DEV_BPMP, - ACTMON_DEV_AHB, - ACTMON_DEV_APB, - ACTMON_DEV_CPU_FREQ, - ACTMON_DEV_MC_ALL, - ACTMON_DEV_MC_CPU, - - ACTMON_DEV_NUM, -} actmon_dev_t; - -typedef struct _actmon_dev_reg_t { - vu32 ctrl; - vu32 upper_wnark; - vu32 lower_wmark; - vu32 init_avg; - vu32 avg_upper_wmark; - vu32 avg_lower_wmark; - vu32 count_weight; - vu32 count; - vu32 avg_count; - vu32 intr_status; - vu32 ctrl2; - vu32 rsvd[5]; -} actmon_dev_reg_t; - -static uintptr_t g_clk_base = 0; -static uintptr_t g_gpu_base = 0; -static uintptr_t g_act_base = 0; -static u64 g_update_ticks = 0; -static u32 g_cpu_freq = 0; -static u32 g_gpu_freq = 0; -static u32 g_mem_freq = 0; -static u32 g_emc_lall = 0; -static u32 g_emc_lcpu = 0; -static u32 g_emc_bw_all = 0; -static u32 g_emc_bw_cpu = 0; -static u32 g_emc_bw_gpu = 0; - -static u32 _clock_get_dev_freq(u32 id, u32 multiplier) { - const u32 pto_win = 16; - const u32 pto_osc = 32768; - - u32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (pto_win - 1); - CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; - (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); - usleep(2); - - CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST; - (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); - usleep(2); - - CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val; - (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); - usleep(2); - - CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN; - (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); - usleep((1000000ULL * pto_win / pto_osc) + 12 + 2); // 502 us. - - while (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY) - ; - - u32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT; - - CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0; - (void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL); - usleep(2); - - u32 freq_khz = (u64)cnt * multiplier * pto_osc / pto_win; - - return freq_khz; -} - -static void _actmon_dev_enable(actmon_dev_t dev, u32 freq, u32 weight) { - actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); - - regs->init_avg = (u32)freq * ACTMON_PERIOD_MS / 2; - regs->count_weight = weight; - - regs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC | ACTMON_DEV_CTRL_K_VAL(3); // 8 samples average. -} - -static u32 _actmon_dev_get_count_avg(actmon_dev_t dev) { - actmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE)); - - return regs->avg_count; -} - -static inline Result _svcQueryMemoryMappingFallback(u64 *virtaddr, u64 physaddr, u64 size) { - if (hosversionAtLeast(10, 0, 0)) { - u64 out_size; - return svcQueryMemoryMapping(virtaddr, &out_size, physaddr, size); - } else { - return svcLegacyQueryIoMapping(virtaddr, physaddr, size); - } -} - -static void _clock_update_freqs(void) { - u64 ticks = armGetSystemTick(); - if (armTicksToNs(ticks - g_update_ticks) <= WAIT_NS) { - return; - } - - g_update_ticks = ticks; - - if (!g_clk_base) { - _svcQueryMemoryMappingFallback(&g_clk_base, 0x60006000ul, 0x1000); - } - - if (!g_clk_base) { - return; - } - - g_mem_freq = _clock_get_dev_freq(CLK_PTO_EMC, 1); - g_cpu_freq = _clock_get_dev_freq(CLK_PTO_CCLK_G_DIV2, 2); - - if (!g_gpu_base) { - _svcQueryMemoryMappingFallback(&g_gpu_base, 0x57000000ul, 0x1000000); - } - - if (!g_gpu_base) { - return; - } - - bool gpu_enabled = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) & BIT(24)) && !(CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_X) & BIT(24)); - if (!gpu_enabled) { - return; - } - - if (!g_act_base) { - _svcQueryMemoryMappingFallback(&g_act_base, 0x6000C000ul, 0x1000); - } - - if (!g_act_base) { - return; - } - - const u32 osc = 38400000; - u32 coeff = GPU_TRIM_SYS_GPCPLL(GPU_TRIM_SYS_GPCPLL_COEFF); - u32 divm = coeff & 0xFF; - u32 divn = (coeff >> 8) & 0xFF; - u32 divp = (coeff >> 16) & 0x3F; - g_gpu_freq = osc * divn / (divm * divp) / 2; - - u32 emc_freq = g_mem_freq / 1000; - - // Check if actmon is disabled - if (!(ACTMON(ACTMON_GLB_STATUS) & ACTMON_MCALL_MON_ACT)) { - ACTMON(ACTMON_GLB_PERIOD_CTRL) = ACTMON_GLB_PERIOD_SAMPLE(ACTMON_PERIOD_MS); - _actmon_dev_enable(ACTMON_DEV_MC_ALL, emc_freq, 256 * 4); - } - - // Check if actmon is disabled - if (!(ACTMON(ACTMON_GLB_STATUS) & ACTMON_MCCPU_MON_ACT)) - _actmon_dev_enable(ACTMON_DEV_MC_CPU, emc_freq, 256 * 4); - - // Get 1000 -> 100.0. - g_emc_lall = (u64)_actmon_dev_get_count_avg(ACTMON_DEV_MC_ALL) * 10 * 100 / (emc_freq * ACTMON_PERIOD_MS); - g_emc_lcpu = (u64)_actmon_dev_get_count_avg(ACTMON_DEV_MC_CPU) * 10 * 100 / (emc_freq * ACTMON_PERIOD_MS); - - // TODO: use PLL instead of actmon - // Avoid floating point arithematic - g_emc_bw_all = (u64)emc_freq * 16 * g_emc_lall / 1000000; - g_emc_bw_cpu = (u64)emc_freq * 16 * g_emc_lcpu / 1000000; - - // Not 100% accurate but should be enough - g_emc_bw_gpu = g_emc_bw_all - g_emc_bw_cpu; -} - -u32 t210ClkCpuFreq(void) { - _clock_update_freqs(); - return g_cpu_freq; -} - -u32 t210ClkMemFreq(void) { - _clock_update_freqs(); - return g_mem_freq; -} - -u32 t210ClkGpuFreq(void) { - _clock_update_freqs(); - return g_gpu_freq; -} - -u32 t210EmcLoadAll() { - _clock_update_freqs(); - return g_emc_lall; -} - -u32 t210EmcLoadCpu() { - _clock_update_freqs(); - return g_emc_lcpu; -} - -u32 t210EmcBwAll() { - _clock_update_freqs(); - return g_emc_bw_all; -} - -u32 t210EmcBwCpu() { - _clock_update_freqs(); - return g_emc_bw_cpu; -} - -u32 t210EmcBwGpu() { - _clock_update_freqs(); - return g_emc_bw_gpu; -} - -u32 t210EmcBwPeak() { - _clock_update_freqs(); - return ((u64)g_mem_freq * 16) / 1000000; -} \ No newline at end of file diff --git a/Source/hoc-clk/sysmodule/src/soc/t210.h b/Source/hoc-clk/sysmodule/src/soc/t210.h deleted file mode 100644 index 2ad618f6..00000000 --- a/Source/hoc-clk/sysmodule/src/soc/t210.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors - * - * 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 . - * - */ - -/* -------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * , , - * wrote this file. As long as you retain this notice you can do whatever you - * want with this stuff. If you meet any of us some day, and you think this - * stuff is worth it, you can buy us a beer in return. - The sys-clk authors - * -------------------------------------------------------------------------- - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -u32 t210ClkCpuFreq(void); -u32 t210ClkMemFreq(void); -u32 t210ClkGpuFreq(void); -u32 t210EmcLoadAll(void); -u32 t210EmcLoadCpu(void); -u32 t210EmcBwAll(void); -u32 t210EmcBwCpu(void); -u32 t210EmcBwGpu(void); -u32 t210EmcBwPeak(void); - -#ifdef __cplusplus -} -#endif