BPMP ABORT!
This commit is contained in:
1 parent
9428309ac3
commit
ab60e55303
87 files changed
+553
-3213
No files matched your search
@@ -8,4 +8,3 @@ build
|
||||
Source/hekate
|
||||
dist/*
|
||||
!dist/.gitignore
|
||||
bpmpfw.bin
|
||||
@@ -1,9 +0,0 @@
|
||||
160c160
|
||||
< /* Validate that the bpmp is appropriately halted. */
|
||||
---
|
||||
> /* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
|
||||
161a162,165
|
||||
> reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
> FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
|
||||
>
|
||||
> /* Validate that the bpmp is appropriately halted. */
|
||||
@@ -900,32 +900,6 @@ namespace ams::secmon {
|
||||
reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH39, REG_BITS_VALUE(0, 27, WarmbootCarveoutConfig));
|
||||
}
|
||||
|
||||
void EnableBpmpSmmu() {
|
||||
/* Define the ASID contents. */
|
||||
constexpr int BpmpAsid = 1;
|
||||
constexpr uintptr_t BpmpAsidPde = MemoryRegionPhysicalDeviceSecurityEngine.GetAddress();
|
||||
|
||||
/* Configure the ASID. */
|
||||
reg::Write(MC + MC_SMMU_PTB_ASID, MC_REG_BITS_VALUE(SMMU_PTB_ASID_CURRENT_ASID, BpmpAsid));
|
||||
|
||||
reg::Write(MC + MC_SMMU_PTB_DATA, MC_REG_BITS_VALUE(SMMU_PTB_DATA_ASID_PDE_BASE, BpmpAsidPde / 4_KB),
|
||||
MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_NONSECURE, DISABLE),
|
||||
MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_WRITABLE, DISABLE),
|
||||
MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_READABLE, DISABLE));
|
||||
|
||||
/* Configure the BPMP and PPCS1 to use the asid. */
|
||||
reg::Write(MC + MC_SMMU_AVPC_ASID, MC_REG_BITS_ENUM(SMMU_AVPC_ASID_AVPC_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_AVPC_ASID_AVPC_ASID, BpmpAsid));
|
||||
reg::Write(MC + MC_SMMU_PPCS1_ASID, MC_REG_BITS_ENUM(SMMU_PPCS1_ASID_PPCS1_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_PPCS1_ASID_PPCS1_ASID, BpmpAsid));
|
||||
|
||||
/* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
|
||||
reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0);
|
||||
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||
|
||||
/* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
|
||||
reg::Write(MC + MC_SMMU_TLB_FLUSH, 0);
|
||||
reg::Read (MC + MC_SMMU_TLB_CONFIG);
|
||||
}
|
||||
|
||||
void ValidateResetExpected() {
|
||||
/* We're coming out of reset, so check that we expected to come out of reset. */
|
||||
if (!IsResetExpected()) {
|
||||
@@ -935,11 +909,6 @@ namespace ams::secmon {
|
||||
SetResetExpected(false);
|
||||
}
|
||||
|
||||
void ActmonInterruptHandler() {
|
||||
SetError(pkg1::ErrorInfo_ActivityMonitorInterrupt);
|
||||
AMS_ABORT("actmon observed bpmp wakeup");
|
||||
}
|
||||
|
||||
void ExitChargerHiZMode() {
|
||||
/* Setup I2c-1. */
|
||||
pinmux::SetupI2c1();
|
||||
@@ -1182,39 +1151,6 @@ namespace ams::secmon {
|
||||
FinalizeCarveoutSecureScratchRegisters();
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_Carveout);
|
||||
|
||||
/* Clear all the BPMP exception vectors to a fixed value. */
|
||||
constexpr u32 BpmpExceptionVector = 0x7D000000;
|
||||
reg::Write(EVP + EVP_COP_RESET_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_UNDEF_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_SWI_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_RSVD_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_IRQ_VECTOR, BpmpExceptionVector);
|
||||
reg::Write(EVP + EVP_COP_FIQ_VECTOR, BpmpExceptionVector);
|
||||
|
||||
/* Disable arbitration for the bpmp. */
|
||||
reg::ReadWrite(SYSTEM + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE));
|
||||
|
||||
/* Turn on the SMMU for the BPMP. */
|
||||
EnableBpmpSmmu();
|
||||
|
||||
/* Wait until the flow controller reports that the BPMP is halted. */
|
||||
while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP))) {
|
||||
util::WaitMicroSeconds(1);
|
||||
}
|
||||
|
||||
/* Enable clock to the activity monitor. */
|
||||
clkrst::EnableActmonClock();
|
||||
|
||||
/* If JTAG is disabled, disable JTAG. */
|
||||
if (!secmon::IsJtagEnabled()) {
|
||||
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, DISABLED));
|
||||
|
||||
/* Turn on the activity monitor to prevent booting up the bpmp. */
|
||||
actmon::StartMonitoringBpmp(ActmonInterruptHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupPmcAndMcSecure() {
|
||||
|
||||
@@ -157,12 +157,8 @@ namespace ams::secmon::smc {
|
||||
/* Validate that all other cores are off. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
|
||||
|
||||
/* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
|
||||
const bool jtag = IsJtagEnabled();
|
||||
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
|
||||
|
||||
/* Validate that the bpmp is appropriately halted. */
|
||||
const bool jtag = IsJtagEnabled();
|
||||
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED)));
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
include $(DEVKITARM)/base_rules
|
||||
|
||||
TARGET := bpmpfw
|
||||
BUILDDIR := build
|
||||
OUTPUTDIR := out
|
||||
SOURCEDIR := source
|
||||
|
||||
LIBCDIR := $(SOURCEDIR)/libc
|
||||
|
||||
CPP_SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
|
||||
C_SOURCES := $(wildcard $(LIBCDIR)/src/*.c)
|
||||
S_SOURCES := $(wildcard $(SOURCEDIR)/*.s)
|
||||
|
||||
OBJS := $(patsubst $(SOURCEDIR)/%.cpp,$(BUILDDIR)/%.o,$(CPP_SOURCES)) \
|
||||
$(patsubst $(LIBCDIR)/src/%.c,$(BUILDDIR)/libc/%.o,$(C_SOURCES)) \
|
||||
$(patsubst $(SOURCEDIR)/%.s,$(BUILDDIR)/%.o,$(S_SOURCES))
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||
COMMONDIR := ../common/include
|
||||
INCLUDE := -I$(SOURCEDIR) -I$(LIBCDIR)/include -I$(LIBCDIR)/include/fslc -I$(COMMONDIR)
|
||||
CFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -ffunction-sections -fdata-sections \
|
||||
-fomit-frame-pointer -std=gnu11 -Wall -Wextra $(CUSTOMDEFINES)
|
||||
CXXFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -fno-exceptions -fno-rtti \
|
||||
-fno-unwind-tables -fno-threadsafe-statics -ffunction-sections -fdata-sections \
|
||||
-fomit-frame-pointer -std=gnu++20 -Wall -Wextra $(CUSTOMDEFINES)
|
||||
ASFLAGS := $(ARCH) -g
|
||||
LDFLAGS := $(ARCH) -nostartfiles -nodefaultlibs -Wl,--nmagic,--gc-sections \
|
||||
-T $(SOURCEDIR)/../bpmpfw.ld
|
||||
LDLIBS := -lgcc
|
||||
|
||||
BIN_TARGET := $(OUTPUTDIR)/$(TARGET).bin
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BIN_TARGET)
|
||||
|
||||
$(BIN_TARGET): $(BUILDDIR)/$(TARGET).elf
|
||||
@mkdir -p $(OUTPUTDIR)
|
||||
@echo "bpmpfw.bin"
|
||||
@$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(BUILDDIR)/$(TARGET).elf: $(OBJS)
|
||||
@echo "linking $(TARGET).elf"
|
||||
@$(CXX) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
|
||||
|
||||
$(BUILDDIR)/%.o: $(SOURCEDIR)/%.cpp | $(BUILDDIR)
|
||||
@echo "$(notdir $<)"
|
||||
@$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@
|
||||
|
||||
$(BUILDDIR)/libc/%.o: $(LIBCDIR)/src/%.c | $(BUILDDIR)/libc
|
||||
@echo "$(notdir $<)"
|
||||
@$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
|
||||
|
||||
$(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | $(BUILDDIR)
|
||||
@echo "$(notdir $<)"
|
||||
@$(CXX) $(ASFLAGS) $(INCLUDE) -c $< -o $@
|
||||
|
||||
$(BUILDDIR):
|
||||
@mkdir -p $(BUILDDIR)
|
||||
|
||||
$(BUILDDIR)/libc: | $(BUILDDIR)
|
||||
@mkdir -p $(BUILDDIR)/libc
|
||||
|
||||
clean:
|
||||
@rm -rf $(BUILDDIR) $(OUTPUTDIR)
|
||||
@@ -1,151 +0,0 @@
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(reset)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
bpmpfw : ORIGIN = 0x40004000, LENGTH = 32K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(__start__ = ORIGIN(bpmpfw));
|
||||
. = __start__;
|
||||
__code_start = . ;
|
||||
|
||||
.vectors :
|
||||
{
|
||||
KEEP (*(.vectors .vectors.*))
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
.init :
|
||||
{
|
||||
KEEP( *(.init) )
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
*(.iplt)
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP( *(.fini) )
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
. = ALIGN(8);
|
||||
__rodata_start = . ;
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
. = ALIGN(8);
|
||||
} >bpmpfw
|
||||
|
||||
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >bpmpfw
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >bpmpfw
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >bpmpfw
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >bpmpfw
|
||||
|
||||
.hash : { *(.hash) } >bpmpfw
|
||||
|
||||
. = ALIGN(8);
|
||||
__data_start = . ;
|
||||
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >bpmpfw
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >bpmpfw
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >bpmpfw
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >bpmpfw
|
||||
|
||||
.preinit_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
} >bpmpfw
|
||||
|
||||
.init_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE (__init_array_end = .);
|
||||
} >bpmpfw
|
||||
|
||||
.fini_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE (__fini_array_end = .);
|
||||
} >bpmpfw
|
||||
|
||||
.ctors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >bpmpfw
|
||||
|
||||
.dtors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >bpmpfw
|
||||
|
||||
__got_start__ = .;
|
||||
|
||||
.got : { *(.got) *(.igot) } >bpmpfw
|
||||
.got.plt : { *(.got.plt) *(.igot.plt) } >bpmpfw
|
||||
|
||||
__got_end__ = .;
|
||||
|
||||
.data ALIGN(8) :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
} >bpmpfw
|
||||
|
||||
__bss_start__ = .;
|
||||
.bss ALIGN(8) :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
} >bpmpfw
|
||||
__bss_end__ = .;
|
||||
|
||||
__end__ = ABSOLUTE(.) ;
|
||||
|
||||
__stack_top = ORIGIN(bpmpfw) + LENGTH(bpmpfw) - 0x10;
|
||||
|
||||
/DISCARD/ : { *(.group .comment .note .interp .ARM.attributes) }
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
}
|
||||
@@ -1,65 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "actmon.hpp"
|
||||
|
||||
namespace actmon {
|
||||
|
||||
u32 DevReg(ActmonDev dev, u32 off) {
|
||||
return ActmonDevBase + (static_cast<u32>(dev) * ActmonDevSize) + off;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Init() {
|
||||
const u32 emcFreqKhz = static_cast<u32>(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);
|
||||
}
|
||||
}
|
||||
|
||||
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<u32>((static_cast<u64>(avgAll) * 10 * 100) / (emcFreqKhz * ActmonPeriodMs));
|
||||
info.emcLoadCpu = static_cast<u32>((static_cast<u64>(avgCpu) * 10 * 100) / (emcFreqKhz * ActmonPeriodMs));
|
||||
|
||||
info.emcBwAll = static_cast<u32>((static_cast<u64>(emcFreqKhz) * 16 * info.emcLoadAll) / 1000000);
|
||||
info.emcBwCpu = static_cast<u32>((static_cast<u64>(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
|
||||
@@ -1,64 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "freq.hpp"
|
||||
#include "regs.hpp"
|
||||
|
||||
#include <hocclk/bpmp.h>
|
||||
|
||||
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;
|
||||
|
||||
u32 DevReg(ActmonDev dev, u32 off);
|
||||
|
||||
void EnableDev(ActmonDev dev, u32 freqKhz, u32 weight);
|
||||
|
||||
void Init();
|
||||
|
||||
void Update(HocClkBpmpSharedInfo &info);
|
||||
|
||||
} // namespace actmon
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 - 2017, NVIDIA CORPORATION. All rights reserved.
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "aotag.hpp"
|
||||
|
||||
namespace aotag {
|
||||
|
||||
void Update(HocClkBpmpSharedInfo &info) {
|
||||
const u32 regval = MMIO32(PmcBase + PmcTsensorStatus1);
|
||||
|
||||
if (!(regval & Status1ValidBit)) {
|
||||
info.tempAO = InvalidSentinel;
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 abs = (regval >> Status1AbsShift) & Status1AbsMask;
|
||||
const bool frac = (regval & Status1FracBit) != 0;
|
||||
const bool negative = (regval & Status1SignBit) != 0;
|
||||
|
||||
s32 temp = static_cast<s32>(abs) * 1000 + (frac ? 500 : 0);
|
||||
if (negative) {
|
||||
temp = -temp;
|
||||
}
|
||||
|
||||
info.tempAO = temp;
|
||||
}
|
||||
|
||||
} // namespace aotag
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 - 2017, NVIDIA CORPORATION. All rights reserved.
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "regs.hpp"
|
||||
|
||||
#include <hocclk/bpmp.h>
|
||||
|
||||
namespace aotag {
|
||||
|
||||
constexpr u32 PmcBase = 0x7000E400;
|
||||
constexpr u32 PmcTsensorStatus1 = 0x4AC;
|
||||
|
||||
constexpr u32 Status1ValidBit = (1u << 31);
|
||||
constexpr u32 Status1AbsShift = 8;
|
||||
constexpr u32 Status1AbsMask = 0xFF;
|
||||
constexpr u32 Status1FracBit = (1u << 7);
|
||||
constexpr u32 Status1SignBit = (1u << 0);
|
||||
|
||||
constexpr s32 InvalidSentinel = -125;
|
||||
|
||||
void Update(HocClkBpmpSharedInfo &info);
|
||||
|
||||
} // namespace aotag
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bpmp_mmu.hpp"
|
||||
|
||||
namespace bpmpMmu {
|
||||
|
||||
u32 AlignUp(u32 x, u32 a) {
|
||||
return (x + a - 1) & ~(a - 1);
|
||||
}
|
||||
|
||||
u32 AlignDown(u32 x, u32 a) {
|
||||
return x & ~(a - 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Disable() {
|
||||
if (!(MMIO32(CacheBase + CacheConfig) & CfgEnableCache)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean and invalidate cache.
|
||||
Maintenance(MaintCleanInvalidWay, false);
|
||||
|
||||
// Disable cache.
|
||||
MMIO32(CacheBase + CacheConfig) = 0;
|
||||
}
|
||||
|
||||
} // namespace bpmpMmu
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 },
|
||||
};
|
||||
|
||||
u32 AlignUp(u32 x, u32 a);
|
||||
u32 AlignDown(u32 x, u32 a);
|
||||
|
||||
void Maintenance(u32 op, bool force);
|
||||
|
||||
void SetEntry(u32 idx, const MmuEntry &entry);
|
||||
|
||||
void Enable();
|
||||
|
||||
void Disable();
|
||||
|
||||
} // namespace bpmpMmu
|
||||
@@ -1,28 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using s8 = std::int8_t;
|
||||
using s16 = std::int16_t;
|
||||
using s32 = std::int32_t;
|
||||
using s64 = std::int64_t;
|
||||
@@ -1,61 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "freq.hpp"
|
||||
|
||||
namespace freq {
|
||||
|
||||
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<u64>(cnt) * multiplier * osc) / win;
|
||||
}
|
||||
|
||||
void Update(HocClkBpmpSharedInfo &info) {
|
||||
info.freqMem = static_cast<u32>(MeasurePtoFreqHz(ClkPtoEmc, 1) / 1000);
|
||||
info.freqCpu = static_cast<u32>(MeasurePtoFreqHz(ClkPtoCclkGDiv2, 2) / 1000);
|
||||
}
|
||||
|
||||
} // namespace freq
|
||||
@@ -1,44 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "regs.hpp"
|
||||
|
||||
#include <hocclk/bpmp.h>
|
||||
|
||||
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;
|
||||
|
||||
u64 MeasurePtoFreqHz(u32 srcId, u32 multiplier);
|
||||
|
||||
void Update(HocClkBpmpSharedInfo &info);
|
||||
|
||||
} // namespace freq
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Jurģis Brigmanis <velko.x@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _STD_ASSERT_H
|
||||
#define _STD_ASSERT_H
|
||||
|
||||
#include "fslc/fslc_assert.h"
|
||||
|
||||
#endif /* _STD_ASSERT_H */
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef FSLC_ASSERT_H
|
||||
#define FSLC_ASSERT_H
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
|
||||
#define fslc_assert assert
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define fslc_assert(expr) ((void)0)
|
||||
|
||||
#else /* NDEBUG */
|
||||
|
||||
/* Note: __PRETTY_FUNCTION__ is GCC specific */
|
||||
#define fslc_assert(expr) ((expr) ? (void)0 : __fslc_assert_fail(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__))
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
void __fslc_assert_fail(const char *expr, const char *file, unsigned int line, const char *func);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* FSLC_ASSERT_H */
|
||||
@@ -1,74 +0,0 @@
|
||||
#ifndef FSLC_STDIO_H
|
||||
#define FSLC_STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
|
||||
#define FSLC_FILE FILE
|
||||
#define fslc_stdout stdout
|
||||
#define fslc_stdin stdin
|
||||
#define fslc_putchar putchar
|
||||
#define fslc_fputc fputc
|
||||
#define fslc_fputs fputs
|
||||
#define fslc_puts puts
|
||||
|
||||
#define fslc_vfprintf vfprintf
|
||||
#define fslc_vprintf vprintf
|
||||
#define fslc_fprintf fprintf
|
||||
#define fslc_printf printf
|
||||
|
||||
#define fslc_fwrite fwrite
|
||||
#define fslc_fread fread
|
||||
|
||||
#define fslc_getc getc
|
||||
#define fslc_getchar getchar
|
||||
#define fslc_ungetc ungetc
|
||||
#define fslc_fgets fgets
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
typedef struct _FSLC_FILE FSLC_FILE;
|
||||
|
||||
struct _FSLC_FILE
|
||||
{
|
||||
void *user_ptr;
|
||||
int (*putc)(int c, FSLC_FILE *stream);
|
||||
int (*getc)(FSLC_FILE *stream);
|
||||
void (*pre_output)(FSLC_FILE *stream);
|
||||
void (*post_output)(FSLC_FILE *stream);
|
||||
int ungetc_buf;
|
||||
};
|
||||
|
||||
extern FSLC_FILE *fslc_stdout;
|
||||
extern FSLC_FILE *fslc_stdin;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int fslc_putchar(int c);
|
||||
int fslc_fputc(int c, FSLC_FILE *stream);
|
||||
int fslc_fputs(const char *str, FSLC_FILE *stream);
|
||||
int fslc_puts(const char *str);
|
||||
|
||||
int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg);
|
||||
int fslc_vprintf(const char *format, va_list arg);
|
||||
int fslc_fprintf(FSLC_FILE *stream, const char *format, ...);
|
||||
int fslc_printf(const char *format, ...);
|
||||
|
||||
size_t fslc_fwrite(const void *ptr, size_t size, size_t count, FSLC_FILE *stream);
|
||||
size_t fslc_fread(void *ptr, size_t size, size_t count, FSLC_FILE *stream);
|
||||
|
||||
int fslc_getc(FSLC_FILE *stream);
|
||||
int fslc_getchar(void);
|
||||
int fslc_ungetc(int c, FSLC_FILE *stream);
|
||||
char *fslc_fgets(char *str, int num, FSLC_FILE *stream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* FSLC_STDIO_H */
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef FSLC_STDLIB_H
|
||||
#define FSLC_STDLIB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
|
||||
#define fslc_bsearch bsearch
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *));
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* FSLC_STDLIB_H */
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef FSLC_STRING_H
|
||||
#define FSLC_STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
#define fslc_memset memset
|
||||
#define fslc_memcpy memcpy
|
||||
#define fslc_memmove memmove
|
||||
#define fslc_memcmp memcmp
|
||||
|
||||
#define fslc_strlen strlen
|
||||
#define fslc_strcpy strcpy
|
||||
#define fslc_strncpy strncpy
|
||||
#define fslc_strcmp strcmp
|
||||
#define fslc_strncmp strncmp
|
||||
#define fslc_strchr strchr
|
||||
#define fslc_strstr strstr
|
||||
#define fslc_strpbrk strpbrk
|
||||
#define fslc_strspn strspn
|
||||
#define fslc_strtok_r strtok_r
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void *fslc_memset(void *ptr, int value, size_t num);
|
||||
void *fslc_memcpy(void *dest, const void *src, size_t len);
|
||||
void *fslc_memmove(void *dest, const void *src, size_t len);
|
||||
int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num);
|
||||
|
||||
size_t fslc_strlen(const char *str);
|
||||
char *fslc_strcpy(char *dest, const char *src);
|
||||
char *fslc_strncpy(char *dest, const char *src, size_t len);
|
||||
int fslc_strcmp(const char *str1, const char *str2);
|
||||
int fslc_strncmp(const char *str1, const char *str2, size_t num);
|
||||
char *fslc_strchr(const char *str, int c);
|
||||
char *fslc_strstr(const char *search_in, const char *search_for);
|
||||
char *fslc_strpbrk(const char *str, const char *delim);
|
||||
size_t fslc_strspn(const char *str, const char *delim);
|
||||
char *fslc_strtok_r(char *str, const char *delim, char **save_p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* FSLC_STRING_H */
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef FSLC_STDLIBX_H
|
||||
#define FSLC_STDLIBX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
|
||||
#define fslc_bsearch_i bsearch_i
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* FSLC_STDLIBX_H */
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef FSLC_STRINGX_H
|
||||
#define FSLC_STRINGX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef ALT_FSLC_NAMES
|
||||
|
||||
#define fslc_memset_l memset_l
|
||||
#define fslc_strcpy_e strcpy_e
|
||||
#define fslc_strncpy_e strncpy_e
|
||||
|
||||
#endif /* ALT_FSLC_NAMES */
|
||||
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
#define memset_32 memset_l
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
#define memset_32(A, V, S) memset_l(A, (((unsigned long)(V)<<32)|(V)), S)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void *fslc_memset_l(void *ptr, unsigned long value, size_t num);
|
||||
char *fslc_strcpy_e(char *dest, const char *src);
|
||||
char *fslc_strncpy_e(char *dest, const char *src, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* FSLC_STRINGX_H */
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _STD_STDIO_H
|
||||
#define _STD_STDIO_H
|
||||
|
||||
#include "fslc/fslc_stdio.h"
|
||||
|
||||
#endif /* _STD_STDIO_H */
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _STD_STDLIB_H
|
||||
#define _STD_STDLIB_H
|
||||
|
||||
#include "fslc/fslc_stdlib.h"
|
||||
|
||||
#endif /* _STD_STDLIB_H */
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef _STD_STRING_H
|
||||
#define _STD_STRING_H
|
||||
|
||||
#include "fslc/fslc_string.h"
|
||||
|
||||
#endif /* _STD_STRING_H */
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "fslc_stdlib.h"
|
||||
#include "stdlibx.h"
|
||||
|
||||
void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *))
|
||||
{
|
||||
int sidx = fslc_bsearch_i(key, base, num, size, cmp_proc);
|
||||
|
||||
if (sidx < 0)
|
||||
return NULL;
|
||||
|
||||
return (char *)base + (sidx * size);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include <stddef.h>
|
||||
|
||||
int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *))
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = num - 1;
|
||||
|
||||
char *cbase = (char *)base;
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
int i = lo + ((hi - lo) >> 1);
|
||||
|
||||
char *ptr = cbase + (i * size);
|
||||
int cmp = cmp_proc(key, ptr);
|
||||
|
||||
if (cmp == 0)
|
||||
return i;
|
||||
|
||||
if (cmp > 0)
|
||||
{
|
||||
lo = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~lo;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int fslc_fprintf(FSLC_FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int r = fslc_vfprintf(stream, format, args);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int fslc_fputc(int c, FSLC_FILE *stream)
|
||||
{
|
||||
if (stream->pre_output) stream->pre_output(stream);
|
||||
|
||||
int r = stream->putc(c, stream);
|
||||
|
||||
if (stream->post_output) stream->post_output(stream);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int _fslc_fputs_impl(const char *str, FSLC_FILE *stream);
|
||||
|
||||
int fslc_fputs(const char *str, FSLC_FILE *stream)
|
||||
{
|
||||
if (stream->pre_output) stream->pre_output(stream);
|
||||
|
||||
int r = _fslc_fputs_impl(str, stream);
|
||||
|
||||
if (stream->post_output) stream->post_output(stream);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int _fslc_fputs_impl(const char *str, FSLC_FILE *stream)
|
||||
{
|
||||
int res = 0;
|
||||
for (;*str; ++str)
|
||||
{
|
||||
int pr = stream->putc(*str, stream);
|
||||
if (pr < 0) return pr;
|
||||
++res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
#include <stdint.h>
|
||||
|
||||
int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num)
|
||||
{
|
||||
unsigned char *b_p1 = (unsigned char *)ptr1;
|
||||
unsigned char *b_p2 = (unsigned char *)ptr2;
|
||||
|
||||
for (;((uintptr_t)b_p1 & (sizeof(long)-1)) && num > 0; ++b_p1, ++b_p2, --num)
|
||||
{
|
||||
if (*b_p1 != *b_p2)
|
||||
{
|
||||
return *b_p1 > *b_p2 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long *w_p1 = (unsigned long *)b_p1;
|
||||
unsigned long *w_p2 = (unsigned long *)b_p2;
|
||||
for (;num >= sizeof(unsigned long); ++w_p1, ++w_p2, num -= sizeof(unsigned long))
|
||||
{
|
||||
if (*w_p1 != *w_p2)
|
||||
{
|
||||
return *w_p1 > *w_p2 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
b_p1 = (unsigned char *)w_p1;
|
||||
b_p2 = (unsigned char *)w_p2;
|
||||
for (; num > 0; ++b_p1, ++b_p2, --num)
|
||||
{
|
||||
if (*b_p1 != *b_p2)
|
||||
{
|
||||
return *b_p1 > *b_p2 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void *fslc_memcpy(void *dest, const void *src, size_t len)
|
||||
{
|
||||
/* Copy byte-by-byte up to word-aligned.
|
||||
*
|
||||
* There's a possibility, that src and dest have different offsets
|
||||
* to word boundary and can not both be used efficiently.
|
||||
*
|
||||
* In this case we use align to dest argument, because it then can be
|
||||
* written in one operation, instead of read-modify-write of 2 words.
|
||||
*
|
||||
* Most of the time both parameters should be word-aligned, however.
|
||||
*/
|
||||
unsigned char *b_src = (unsigned char *)src;
|
||||
unsigned char *b_dst = (unsigned char *)dest;
|
||||
for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
|
||||
/* Then all word-aligned */
|
||||
unsigned long *w_src = (unsigned long*)b_src;
|
||||
unsigned long *w_dst = (unsigned long*)b_dst;
|
||||
for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long))
|
||||
{
|
||||
*w_dst = *w_src;
|
||||
}
|
||||
|
||||
/* And byte-by-byte the rest */
|
||||
b_src = (unsigned char *)w_src;
|
||||
b_dst = (unsigned char *)w_dst;
|
||||
for (; len > 0; b_src++, b_dst++, len--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void *fslc_memmove(void *dest, const void *src, size_t len)
|
||||
{
|
||||
unsigned char *b_dst = (unsigned char *)dest;
|
||||
unsigned char *b_src = (unsigned char *)src;
|
||||
|
||||
/* Need to check if memory regions overlaps. Then if the dest address is
|
||||
* larger than source, we need to copy backwards (or else source regions
|
||||
* ending will be overwritten by writes to dest, before they are read).
|
||||
*
|
||||
* In other cases it works identically as memcpy(). Same considerations
|
||||
* about address alignment applies here.
|
||||
*/
|
||||
if ( b_dst < b_src + len && b_dst > b_src)
|
||||
{
|
||||
b_src += len;
|
||||
b_dst += len;
|
||||
|
||||
/* Byte-by-byte down to word-aligned. */
|
||||
for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; )
|
||||
{
|
||||
b_src--, b_dst--, len--;
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
|
||||
/* Then all word-aligned */
|
||||
unsigned long *w_src = (unsigned long*)b_src;
|
||||
unsigned long *w_dst = (unsigned long*)b_dst;
|
||||
for (;len >= sizeof(unsigned long); )
|
||||
{
|
||||
w_src--, w_dst--, len -= sizeof(unsigned long);
|
||||
*w_dst = *w_src;
|
||||
}
|
||||
|
||||
/* And byte-by-byte the rest */
|
||||
b_src = (unsigned char *)w_src;
|
||||
b_dst = (unsigned char *)w_dst;
|
||||
for (; len > 0; )
|
||||
{
|
||||
b_src--, b_dst--, len--;
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
} else {
|
||||
/* Byte-by-byte up to word-aligned. */
|
||||
for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
|
||||
/* Then all word-aligned */
|
||||
unsigned long *w_src = (unsigned long *)b_src;
|
||||
unsigned long *w_dst = (unsigned long *)b_dst;
|
||||
for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long))
|
||||
{
|
||||
*w_dst = *w_src;
|
||||
}
|
||||
|
||||
/* And byte-by-byte the rest */
|
||||
b_src = (unsigned char *)w_src;
|
||||
b_dst = (unsigned char *)w_dst;
|
||||
for (; len > 0; b_src++, b_dst++, len--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
#include "stringx.h"
|
||||
|
||||
void *fslc_memset(void *ptr, int value, size_t num)
|
||||
{
|
||||
/* Will use memset_l() to actually fill the memory region. If value is non-zero, we need
|
||||
* to replicate lowest byte to all the long's bytes.
|
||||
*/
|
||||
if (value)
|
||||
{
|
||||
unsigned char c_val = value;
|
||||
unsigned long l_val = (c_val << 0) | (c_val << 8) | (c_val << 16) | (c_val << 24);
|
||||
|
||||
#if __SIZEOF_LONG__ == 8
|
||||
l_val |= l_val << 32;
|
||||
#endif
|
||||
|
||||
return fslc_memset_l(ptr, l_val, num);
|
||||
}
|
||||
else
|
||||
return fslc_memset_l(ptr, value, num);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#include "stringx.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void *fslc_memset_l(void *ptr, unsigned long value, size_t num)
|
||||
{
|
||||
unsigned char *b_src = (unsigned char *)&value;
|
||||
unsigned char *b_dst = (unsigned char *)ptr;
|
||||
|
||||
/* Byte by byte - to aligned word address */
|
||||
b_src += ((uintptr_t)b_dst & (sizeof(unsigned long)-1));
|
||||
for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && num > 0; b_dst++,b_src++,num--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
|
||||
/* All aligned */
|
||||
unsigned long *w_dst = (unsigned long *)b_dst;
|
||||
for (;num >= sizeof(unsigned long); w_dst++,num -= sizeof(unsigned long))
|
||||
{
|
||||
*w_dst= value;
|
||||
}
|
||||
|
||||
/* Unaligned ending */
|
||||
b_src = (unsigned char *)&value;
|
||||
b_dst = (unsigned char *)w_dst;
|
||||
for (; num > 0; b_dst++,b_src++,num--)
|
||||
{
|
||||
*b_dst = *b_src;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int fslc_printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int r = fslc_vfprintf(fslc_stdout, format, args);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int fslc_putchar(int c)
|
||||
{
|
||||
return fslc_fputc(c, fslc_stdout);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int _fslc_fputs_impl(const char *str, FSLC_FILE *stream);
|
||||
|
||||
int fslc_puts(const char *str)
|
||||
{
|
||||
if (fslc_stdout->pre_output) fslc_stdout->pre_output(fslc_stdout);
|
||||
|
||||
int r = _fslc_fputs_impl(str, fslc_stdout);
|
||||
|
||||
if (r >= 0)
|
||||
{
|
||||
int nlr = fslc_stdout->putc('\n', fslc_stdout);
|
||||
if (nlr < 0)
|
||||
r = nlr;
|
||||
}
|
||||
|
||||
if (fslc_stdout->post_output) fslc_stdout->post_output(fslc_stdout);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
FSLC_FILE *fslc_stdout;
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
char *fslc_strchr(const char *str, int c)
|
||||
{
|
||||
for (;*str; ++str)
|
||||
if (*str == c)
|
||||
return (char *)str;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
int fslc_strcmp(const char *str1, const char *str2)
|
||||
{
|
||||
for( ; *str1 && *str1 == *str2; ++str1, ++str2);
|
||||
|
||||
return *((unsigned char *)str1) - *((unsigned char *)str2);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
#include "stringx.h"
|
||||
|
||||
char *fslc_strcpy(char *dest, const char *src)
|
||||
{
|
||||
fslc_strcpy_e(dest, src);
|
||||
return dest;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "stringx.h"
|
||||
|
||||
char *fslc_strcpy_e(char *dest, const char *src)
|
||||
{
|
||||
for(; *src; ++src, ++dest)
|
||||
*dest = *src;
|
||||
|
||||
*dest = 0;
|
||||
return dest;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
size_t fslc_strlen(const char *str)
|
||||
{
|
||||
size_t res = 0;
|
||||
for(; *str; ++str) ++res;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
int fslc_strncmp(const char *str1, const char *str2, size_t num)
|
||||
{
|
||||
for( ; *str1 && *str1 == *str2 && num > 1; ++str1, ++str2, --num);
|
||||
|
||||
return *((unsigned char *)str1) - *((unsigned char *)str2);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
char *_fslc_strncpy_impl(char *dest, const char *src, size_t len);
|
||||
|
||||
char *fslc_strncpy(char *dest, const char *src, size_t len)
|
||||
{
|
||||
_fslc_strncpy_impl(dest, src, len);
|
||||
return dest;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "stringx.h"
|
||||
|
||||
char *_fslc_strncpy_impl(char *dest, const char *src, size_t len);
|
||||
|
||||
char *fslc_strncpy_e(char *dest, const char *src, size_t len)
|
||||
{
|
||||
char *r = _fslc_strncpy_impl(dest, src, len);
|
||||
return *r ? r + 1: r;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <stddef.h>
|
||||
|
||||
char *_fslc_strncpy_impl(char *dest, const char *src, size_t len)
|
||||
{
|
||||
for(; *src && len > 1; ++src, ++dest, --len)
|
||||
*dest = *src;
|
||||
|
||||
*dest = *src;
|
||||
return dest;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
char *fslc_strpbrk(const char *str, const char *delim)
|
||||
{
|
||||
for (; *str; ++str)
|
||||
{
|
||||
const char *d;
|
||||
for (d = delim; *d; ++d)
|
||||
if (*str == *d)
|
||||
return (char *)str;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
size_t fslc_strspn(const char *str, const char *delim)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
for (r = 0; *str; ++str, ++r)
|
||||
{
|
||||
const char *d;
|
||||
for (d = delim; *d; ++d)
|
||||
if (*str == *d) // skip to next if found
|
||||
break;
|
||||
|
||||
if (*d == 0) // inner loop exited on \0 - char was not there
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
char *fslc_strstr(const char *search_in, const char *search_for)
|
||||
{
|
||||
while (*search_in)
|
||||
{
|
||||
char *rc = fslc_strchr(search_in, search_for[0]); // find first char
|
||||
|
||||
if (rc)
|
||||
{
|
||||
const char *si = rc + 1, *sf = search_for + 1; // search strcmp-style from second char
|
||||
for( ; *si && *si == *sf; ++si, ++sf);
|
||||
|
||||
if (*sf == 0) return rc; // end of search-for - found result
|
||||
|
||||
search_in = rc + 1; // not this one, continue from next char
|
||||
}
|
||||
else
|
||||
return NULL; // did not find first char - exit
|
||||
}
|
||||
|
||||
return NULL; // reached end of source - did not find
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "fslc_string.h"
|
||||
|
||||
char *fslc_strtok_r(char *str, const char *delim, char **save_p)
|
||||
{
|
||||
if (str)
|
||||
*save_p = str;
|
||||
|
||||
if (*save_p == NULL)
|
||||
return NULL;
|
||||
|
||||
char *r = *save_p + fslc_strspn(*save_p, delim);
|
||||
|
||||
char *p = fslc_strpbrk(r, delim);
|
||||
|
||||
if (p)
|
||||
{
|
||||
*(p++) = 0;
|
||||
*save_p = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*r == 0) r = NULL;
|
||||
*save_p = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
/* There'a a funny behaviour of va_list and va_arg() macros:
|
||||
* - on x86_64 compiler generates a branch of some sort for each va_arg() macro. Normally it is not a problem,
|
||||
* however it kinda screws up branch coverage analysis. Therefore I decided to move va_arg() accesses into
|
||||
* dedicated functions, minimizing the issue to one untaken branch per access function.
|
||||
* - passing va_list by value works fine on x86_64, but makes some tests to fail on i386. It seems that modifications
|
||||
* done by va_arg() is not passed back to caller. Subsequent calls to va_arg() or access functions returns wrong
|
||||
* values on that platform.
|
||||
* - OK, then. Let's pass pointer to va_list instead. Not so fast. Works fine on i386, but fails to compile on
|
||||
* x86_64. Fine! Wrapping va_list into a dedicated struct and passing around pointer to it.
|
||||
*
|
||||
* Why such a fuss about a few untaken branches in tests? Well, just because! Also, if I ever decide to refactor
|
||||
* _fslc_vfprintf_impl() - the case statement is getting a bit long and messy, it should make things easier if
|
||||
* argument list can be passed around freely (as opposed to using it from single function).
|
||||
*/
|
||||
|
||||
struct va_list_w
|
||||
{
|
||||
va_list arg;
|
||||
};
|
||||
|
||||
/* Prototype for printf's internal implementation */
|
||||
static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *args);
|
||||
|
||||
|
||||
/* Main exported function */
|
||||
int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg)
|
||||
{
|
||||
if (stream->pre_output) stream->pre_output(stream);
|
||||
|
||||
struct va_list_w argw;
|
||||
va_copy(argw.arg, arg); // can not assign directly, should make a copy
|
||||
|
||||
int res = _fslc_vfprintf_impl(stream, format, &argw);
|
||||
|
||||
va_end(argw.arg); // and free it after use
|
||||
|
||||
if (stream->post_output) stream->post_output(stream);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Prototype to private FSLIBC function - implemented elsewhere */
|
||||
int _fslc_fputs_impl(const char *str, FSLC_FILE *stream);
|
||||
|
||||
|
||||
/* Prototypes for internal functions */
|
||||
static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream);
|
||||
static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream);
|
||||
static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha);
|
||||
|
||||
static int _get_sint_arg(struct va_list_w *arg);
|
||||
static unsigned _get_uint_arg(struct va_list_w *arg);
|
||||
static long long _get_slonglong_arg(struct va_list_w *arg);
|
||||
static unsigned long long _get_ulonglong_arg(struct va_list_w *arg);
|
||||
static void *_get_ptr_arg(struct va_list_w *arg);
|
||||
|
||||
/* There are some considerations when formatting Integers for output:
|
||||
* - on 32-bit systems integers will mostly be 32 bits long, except when one REALLY
|
||||
* wants to print long long. It should be more optimal to use 32-bit calculations
|
||||
* when possible and invoke 64-bit only when needed. To support that we provide 2
|
||||
* separate implementations.
|
||||
* - on 64-bit systems may be 32 or 64 bits, but there is no real benefit from
|
||||
* using shorter bit size. Hence common implementation.
|
||||
* - this library does not aim to support systems with shorter integer sizes (like 16-bit)
|
||||
* but it it did, it would probably make sense to provide optimized ports for these cases
|
||||
* as well.
|
||||
*
|
||||
* Buffer size calculations:
|
||||
* Max UInt32 fits in 10 bytes (+1 for zero terminator) decimal
|
||||
* 2**32 - 1 == 4294967295z
|
||||
* FFFFFFFFz
|
||||
* 01234567890
|
||||
*
|
||||
* Max UInt64 fits in 10 bytes (and +1 for \0)
|
||||
* 2**64 -1 == 18446744073709551615z
|
||||
* FFFFFFFFFFFFFFFFz
|
||||
* 012345678901234567890
|
||||
*/
|
||||
|
||||
#define BUFSIZE_LONG_LONG_DECIMAL 20
|
||||
#define BUFSIZE_LONG_HEX (__SIZEOF_LONG__ * 2)
|
||||
#define BUFSIZE_LONG_LONG_HEX (__SIZEOF_LONG_LONG__ * 2)
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
|
||||
#define BUFSIZE_LONG_DECIMAL 10
|
||||
static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream);
|
||||
static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream);
|
||||
static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha);
|
||||
|
||||
#define _get_slong_arg _get_sint_arg
|
||||
#define _get_ulong_arg _get_uint_arg
|
||||
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
|
||||
#define BUFSIZE_LONG_DECIMAL BUFSIZE_LONG_LONG_DECIMAL
|
||||
#define _fslc_put_sint_ll _fslc_put_sint_l
|
||||
#define _fslc_put_uint_ll _fslc_put_uint_l
|
||||
#define _fslc_put_hex_ll _fslc_put_hex_l
|
||||
|
||||
#define _get_slong_arg _get_slonglong_arg
|
||||
#define _get_ulong_arg _get_ulonglong_arg
|
||||
|
||||
#endif
|
||||
|
||||
#define FLAG_LONG 1
|
||||
#define FLAG_VERYLONG 3
|
||||
|
||||
static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *arg)
|
||||
{
|
||||
int res = 0;
|
||||
int pr;
|
||||
const char *c;
|
||||
|
||||
for (c = format; *c; ++c)
|
||||
{
|
||||
if (*c == '%')
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
++c;
|
||||
switch (*c)
|
||||
{
|
||||
case 's':
|
||||
pr = _fslc_fputs_impl((const char *)_get_ptr_arg(arg), stream);
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
pr = stream->putc(_get_sint_arg(arg), stream);
|
||||
if (pr < 0) return pr;
|
||||
++res;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
pr = stream->putc('%', stream);
|
||||
if (pr < 0) return pr;
|
||||
++res;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'd':
|
||||
if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG)
|
||||
pr = _fslc_put_sint_ll(_get_slonglong_arg(arg), stream);
|
||||
else if (flags & FLAG_LONG)
|
||||
pr = _fslc_put_sint_l(_get_slong_arg(arg), stream);
|
||||
else
|
||||
pr = _fslc_put_sint_l(_get_sint_arg(arg), stream);
|
||||
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG)
|
||||
pr = _fslc_put_uint_ll(_get_ulonglong_arg(arg), stream);
|
||||
else if (flags & FLAG_LONG)
|
||||
pr = _fslc_put_uint_l(_get_ulong_arg(arg), stream);
|
||||
else
|
||||
pr = _fslc_put_uint_l(_get_uint_arg(arg), stream);
|
||||
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG)
|
||||
pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'a');
|
||||
else if (flags & FLAG_LONG)
|
||||
pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a');
|
||||
else
|
||||
pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'a');
|
||||
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG)
|
||||
pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'A');
|
||||
else if (flags & FLAG_LONG)
|
||||
pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'A');
|
||||
else
|
||||
pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'A');
|
||||
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pr = _fslc_fputs_impl("0x", stream);
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
|
||||
pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a');
|
||||
|
||||
if (pr < 0) return pr;
|
||||
res += pr;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (flags & FLAG_LONG)
|
||||
flags |= FLAG_VERYLONG;
|
||||
else
|
||||
flags |= FLAG_LONG;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
pr = stream->putc(*c, stream);
|
||||
if (pr < 0) return pr;
|
||||
++res;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _get_sint_arg(struct va_list_w *arg)
|
||||
{
|
||||
return va_arg(arg->arg, signed int);
|
||||
}
|
||||
|
||||
static unsigned _get_uint_arg(struct va_list_w *arg)
|
||||
{
|
||||
return va_arg(arg->arg, unsigned int);
|
||||
}
|
||||
|
||||
static long long _get_slonglong_arg(struct va_list_w *arg)
|
||||
{
|
||||
return va_arg(arg->arg, signed long long);
|
||||
}
|
||||
|
||||
static unsigned long long _get_ulonglong_arg(struct va_list_w *arg)
|
||||
{
|
||||
return va_arg(arg->arg, unsigned long long);
|
||||
}
|
||||
|
||||
static void *_get_ptr_arg(struct va_list_w *arg)
|
||||
{
|
||||
return va_arg(arg->arg, void *);
|
||||
}
|
||||
|
||||
static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream)
|
||||
{
|
||||
if (v < 0)
|
||||
{
|
||||
int pr = stream->putc('-', stream);
|
||||
if (pr < 0) return pr;
|
||||
|
||||
pr = _fslc_put_uint_l(-v, stream);
|
||||
if (pr < 0) return pr;
|
||||
|
||||
return pr+1;
|
||||
} else
|
||||
return _fslc_put_uint_l(v, stream);
|
||||
}
|
||||
|
||||
static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream)
|
||||
{
|
||||
char dbuff[BUFSIZE_LONG_DECIMAL+1], *p;
|
||||
|
||||
dbuff[BUFSIZE_LONG_DECIMAL] = 0;
|
||||
|
||||
for (p = dbuff + BUFSIZE_LONG_DECIMAL; v ; v /= 10)
|
||||
{
|
||||
*(--p) = (v % 10) + '0';
|
||||
}
|
||||
|
||||
if (*p == 0) *(--p) = '0';
|
||||
|
||||
return _fslc_fputs_impl(p, stream);
|
||||
}
|
||||
|
||||
static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha)
|
||||
{
|
||||
char dbuff[BUFSIZE_LONG_HEX+1], *p;
|
||||
|
||||
dbuff[BUFSIZE_LONG_HEX] = 0;
|
||||
|
||||
for (p = dbuff + BUFSIZE_LONG_HEX; v ; v >>= 4)
|
||||
{
|
||||
char digit = (v & 0xF);
|
||||
*(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha;
|
||||
}
|
||||
|
||||
if (*p == 0) *(--p) = '0';
|
||||
|
||||
return _fslc_fputs_impl(p, stream);
|
||||
}
|
||||
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
|
||||
static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream)
|
||||
{
|
||||
if (v < 0)
|
||||
{
|
||||
int pr = stream->putc('-', stream);
|
||||
if (pr < 0) return pr;
|
||||
|
||||
pr = _fslc_put_uint_ll(-v, stream);
|
||||
if (pr < 0) return pr;
|
||||
|
||||
return pr+1;
|
||||
} else
|
||||
return _fslc_put_uint_ll(v, stream);
|
||||
}
|
||||
|
||||
static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream)
|
||||
{
|
||||
char dbuff[BUFSIZE_LONG_LONG_DECIMAL+1], *p;
|
||||
|
||||
dbuff[BUFSIZE_LONG_LONG_DECIMAL] = 0;
|
||||
|
||||
for (p = dbuff + BUFSIZE_LONG_LONG_DECIMAL; v ; v /= 10)
|
||||
{
|
||||
*(--p) = (v % 10) + '0';
|
||||
}
|
||||
|
||||
if (*p == 0) *(--p) = '0';
|
||||
|
||||
return _fslc_fputs_impl(p, stream);
|
||||
}
|
||||
|
||||
static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha)
|
||||
{
|
||||
char dbuff[BUFSIZE_LONG_LONG_HEX+1], *p;
|
||||
|
||||
dbuff[BUFSIZE_LONG_LONG_HEX] = 0;
|
||||
|
||||
for (p = dbuff + BUFSIZE_LONG_LONG_HEX; v ; v >>= 4)
|
||||
{
|
||||
char digit = (v & 0xF);
|
||||
*(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha;
|
||||
}
|
||||
|
||||
if (*p == 0) *(--p) = '0';
|
||||
|
||||
return _fslc_fputs_impl(p, stream);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "fslc_stdio.h"
|
||||
|
||||
int fslc_vprintf(const char *format, va_list arg)
|
||||
{
|
||||
return fslc_vfprintf(fslc_stdout, format, arg);
|
||||
}
|
||||
@@ -1,39 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "regs.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
int UartStreamPutc(int c, FILE *) {
|
||||
UartPutc(static_cast<char>(c));
|
||||
return c;
|
||||
}
|
||||
|
||||
void UartStreamPostOutput(FILE *) {
|
||||
UartFlush();
|
||||
}
|
||||
|
||||
FILE g_uartStdout = { nullptr, UartStreamPutc, nullptr, nullptr, UartStreamPostOutput, -1 };
|
||||
|
||||
} // namespace
|
||||
|
||||
void InitializeLibc() {
|
||||
stdout = &g_uartStdout;
|
||||
}
|
||||
@@ -1,111 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "actmon.hpp"
|
||||
#include "aotag.hpp"
|
||||
#include "bpmp_mmu.hpp"
|
||||
#include "freq.hpp"
|
||||
#include "libc_platform.hpp"
|
||||
#include "pllmb.hpp"
|
||||
#include "regs.hpp"
|
||||
#include "sensors.hpp"
|
||||
|
||||
#include <hocclk/bpmp.h>
|
||||
|
||||
extern "C" [[noreturn]] void _panic_reboot();
|
||||
|
||||
namespace {
|
||||
|
||||
HocClkBpmpSharedInfo &SharedInfo() {
|
||||
return *reinterpret_cast<HocClkBpmpSharedInfo *>(WorkRamStart);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
[[noreturn]] void HandleShutdown(HocClkBpmpSharedInfo &info) {
|
||||
/* Deinit MMU otherwise sleep will fatal. */
|
||||
bpmpMmu::Disable();
|
||||
info.magic = 0x0;
|
||||
UartPutsForce("[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 (;;) {
|
||||
HandleCommand(info);
|
||||
|
||||
const u32 temp1 = MMIO32(SocthermBase + SocthermSensorTemp1);
|
||||
const u32 temp2 = MMIO32(SocthermBase + SocthermSensorTemp2);
|
||||
|
||||
info.tempCpu = TranslateSocthermTemp(static_cast<u16>(temp1 >> 16));
|
||||
info.tempGpu = TranslateSocthermTemp(static_cast<u16>(temp1));
|
||||
info.tempMem = TranslateSocthermTemp(static_cast<u16>(temp2 >> 16));
|
||||
info.tempPllx = TranslateSocthermTemp(static_cast<u16>(temp2));
|
||||
|
||||
freq::Update(info);
|
||||
actmon::Update(info);
|
||||
aotag::Update(info);
|
||||
info.freqMemPll = static_cast<u32>(pllmb::MeasureRamClockHz() / 1000);
|
||||
|
||||
msleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void main() {
|
||||
bpmpMmu::Enable();
|
||||
|
||||
InitializeLibc();
|
||||
|
||||
UartPutsForce("[hoc-bpmpfw]: Starting bpmpfw\n");
|
||||
|
||||
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 */
|
||||
MainLoop(info);
|
||||
|
||||
UartPutsForce("[hoc-bpmpfw]: PANIC\n");
|
||||
|
||||
/* Kill execution */
|
||||
_panic_reboot();
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer
|
||||
* Copyright (c) KazushiMe
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pllmb.hpp"
|
||||
|
||||
namespace pllmb {
|
||||
|
||||
u64 MeasurePtoHz(u32 ptoId, u32 divider, u32 preselReg, u32 preselMask) {
|
||||
u32 preselOrigBit = 0;
|
||||
|
||||
if (preselReg) {
|
||||
u32 val = MMIO32(freq::CarBase + preselReg);
|
||||
usleep(10);
|
||||
preselOrigBit = val & preselMask;
|
||||
val &= ~preselMask;
|
||||
val |= preselMask;
|
||||
MMIO32(freq::CarBase + preselReg) = val;
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
constexpr u32 cycleCount = 16;
|
||||
const u32 savedCntl = MMIO32(freq::CarBase + freq::CarPtoClkCntCntl);
|
||||
|
||||
u32 val = freq::PtoDivSelDiv1 | freq::PtoClkEnable | (cycleCount - 1);
|
||||
val |= ptoId << freq::PtoSrcSelShift;
|
||||
|
||||
MMIO32(freq::CarBase + freq::CarPtoClkCntCntl) = val;
|
||||
usleep(10);
|
||||
MMIO32(freq::CarBase + freq::CarPtoClkCntCntl) = val | freq::PtoCntRst;
|
||||
usleep(10);
|
||||
MMIO32(freq::CarBase + freq::CarPtoClkCntCntl) = val;
|
||||
usleep(10);
|
||||
MMIO32(freq::CarBase + freq::CarPtoClkCntCntl) = val | freq::PtoCntEn;
|
||||
usleep(500);
|
||||
|
||||
while (MMIO32(freq::CarBase + freq::CarPtoClkCntStatus) & PtoCyclePeriod)
|
||||
;
|
||||
|
||||
u32 cnt = MMIO32(freq::CarBase + freq::CarPtoClkCntStatus) & freq::PtoClkCntMask;
|
||||
cnt *= divider;
|
||||
|
||||
const u64 rateHz = (static_cast<u64>(cnt) * 32768) / cycleCount;
|
||||
|
||||
usleep(10);
|
||||
MMIO32(freq::CarBase + freq::CarPtoClkCntCntl) = savedCntl;
|
||||
usleep(10);
|
||||
|
||||
if (preselReg) {
|
||||
u32 val2 = MMIO32(freq::CarBase + preselReg);
|
||||
usleep(10);
|
||||
val2 &= ~preselMask;
|
||||
val2 |= preselOrigBit;
|
||||
MMIO32(freq::CarBase + preselReg) = val2;
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
return rateHz;
|
||||
}
|
||||
|
||||
u64 MeasureRamClockHz() {
|
||||
const u64 pllmbHz = MeasurePtoHz(PtoPllmb, 2, PllmMisc2, PllmMisc2PllmbBit);
|
||||
if (pllmbHz != 0) {
|
||||
return pllmbHz;
|
||||
}
|
||||
return MeasurePtoHz(PtoPllm, 2, PllmMisc2, PllmMisc2PllmBit);
|
||||
}
|
||||
|
||||
} // namespace pllmb
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer
|
||||
* Copyright (c) KazushiMe
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "freq.hpp"
|
||||
#include "regs.hpp"
|
||||
|
||||
namespace pllmb {
|
||||
|
||||
constexpr u32 PtoPllm = 2;
|
||||
constexpr u32 PtoPllmb = 37;
|
||||
|
||||
constexpr u32 PllmMisc2 = 0x9C;
|
||||
constexpr u32 PllmMisc2PllmBit = (1u << 8);
|
||||
constexpr u32 PllmMisc2PllmbBit = (1u << 9);
|
||||
|
||||
constexpr u32 PtoCyclePeriod = (1u << 31); // PTO_CLK_CNT_STATUS busy bit
|
||||
|
||||
u64 MeasurePtoHz(u32 ptoId, u32 divider, u32 preselReg, u32 preselMask);
|
||||
|
||||
u64 MeasureRamClockHz();
|
||||
|
||||
} // namespace pllmb
|
||||
@@ -1,77 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "regs.hpp"
|
||||
|
||||
[[maybe_unused]] void usleep(u32 us) {
|
||||
while (us) {
|
||||
const u32 delay = (us > HaltMaxCnt) ? HaltMaxCnt : us;
|
||||
us -= delay;
|
||||
MMIO32(FlowCtlrBase + FlowCtlrHaltCopEvents) = HaltModeWaitEvent | HaltUsec | delay;
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] void msleep(u32 ms) {
|
||||
while (ms) {
|
||||
const u32 delay = (ms > HaltMaxCnt) ? HaltMaxCnt : ms;
|
||||
ms -= delay;
|
||||
MMIO32(FlowCtlrBase + FlowCtlrHaltCopEvents) = HaltModeWaitEvent | HaltMsec | delay;
|
||||
}
|
||||
}
|
||||
|
||||
bool g_uartLoggingEnabled = false;
|
||||
|
||||
void UartPutc(char c) {
|
||||
if (!g_uartLoggingEnabled) {
|
||||
return;
|
||||
}
|
||||
while (!(MMIO32(UartBBase + UartLsr) & UartLsrThre))
|
||||
;
|
||||
MMIO32(UartBBase + UartThr) = static_cast<u32>(static_cast<u8>(c));
|
||||
}
|
||||
|
||||
void UartFlush() {
|
||||
if (!g_uartLoggingEnabled) {
|
||||
return;
|
||||
}
|
||||
while (!(MMIO32(UartBBase + UartLsr) & UartLsrTmty))
|
||||
;
|
||||
}
|
||||
|
||||
void UartPuts(const char *s) {
|
||||
while (*s) {
|
||||
UartPutc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
void UartPutHex32(u32 v) {
|
||||
static const char digits[] = "0123456789ABCDEF";
|
||||
for (int i = 28; i >= 0; i -= 4) {
|
||||
UartPutc(digits[(v >> i) & 0xF]);
|
||||
}
|
||||
}
|
||||
|
||||
void UartPutsForce(const char *s) {
|
||||
while (*s) {
|
||||
while (!(MMIO32(UartBBase + UartLsr) & UartLsrThre))
|
||||
;
|
||||
MMIO32(UartBBase + UartThr) = static_cast<u32>(static_cast<u8>(*s++));
|
||||
}
|
||||
|
||||
while (!(MMIO32(UartBBase + UartLsr) & UartLsrTmty))
|
||||
;
|
||||
}
|
||||
@@ -1,58 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "defs.hpp"
|
||||
|
||||
#define MMIO32(addr) (*reinterpret_cast<volatile u32 *>(addr))
|
||||
|
||||
constexpr u32 FwRamStart = 0x40004000;
|
||||
constexpr u32 FwRamEnd = 0x4000C000;
|
||||
constexpr u32 WorkRamStart = FwRamEnd;
|
||||
constexpr u32 WorkRamEnd = 0x40010000;
|
||||
|
||||
constexpr u32 FlowCtlrBase = 0x60007000;
|
||||
constexpr u32 FlowCtlrHaltCopEvents = 0x004;
|
||||
|
||||
constexpr u32 HaltModeWaitEvent = (2u << 29);
|
||||
constexpr u32 HaltMsec = (1u << 24);
|
||||
constexpr u32 HaltUsec = (1u << 25);
|
||||
constexpr u32 HaltMaxCnt = 0xFF;
|
||||
|
||||
[[maybe_unused]] void usleep(u32 us);
|
||||
[[maybe_unused]] void msleep(u32 ms);
|
||||
|
||||
constexpr u32 TmrBase = 0x60005000;
|
||||
constexpr u32 TimerUsCntr1Us = 0x10;
|
||||
|
||||
constexpr u32 UartBBase = 0x70006040;
|
||||
constexpr u32 UartThr = 0x00;
|
||||
constexpr u32 UartLsr = 0x14;
|
||||
constexpr u32 UartLsrThre = (1u << 5);
|
||||
constexpr u32 UartLsrTmty = (1u << 6);
|
||||
|
||||
extern bool g_uartLoggingEnabled;
|
||||
|
||||
void UartPutc(char c);
|
||||
|
||||
void UartFlush();
|
||||
|
||||
void UartPuts(const char *s);
|
||||
|
||||
void UartPutHex32(u32 v);
|
||||
|
||||
void UartPutsForce(const char *s);
|
||||
@@ -1,29 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sensors.hpp"
|
||||
|
||||
s32 TranslateSocthermTemp(u16 val) {
|
||||
s32 t = ((val >> 8) & 0xFF) * 1000;
|
||||
if (val & (1u << 7)) {
|
||||
t += 500;
|
||||
}
|
||||
if (val & (1u << 0)) {
|
||||
t = -t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -1,25 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "regs.hpp"
|
||||
|
||||
constexpr u32 SocthermBase = 0x700E2000;
|
||||
constexpr u32 SocthermSensorTemp1 = 0x1C8;
|
||||
constexpr u32 SocthermSensorTemp2 = 0x1CC;
|
||||
|
||||
s32 TranslateSocthermTemp(u16 val);
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphere-NX
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
.section .vectors, "ax", %progbits
|
||||
.align 3
|
||||
.global reset
|
||||
reset:
|
||||
b _start
|
||||
b _panic
|
||||
|
||||
.section .text.start, "ax", %progbits
|
||||
.align 3
|
||||
.global _start
|
||||
.extern main
|
||||
_start:
|
||||
/* Mask IRQ + FIQ, enter SVC mode. */
|
||||
msr cpsr_f, #0xC0
|
||||
msr cpsr_cf, #0xD3
|
||||
|
||||
/* Set the stack pointer. */
|
||||
ldr sp, =__stack_top
|
||||
|
||||
/* Zero .bss. */
|
||||
ldr r0, =__bss_start__
|
||||
ldr r1, =__bss_end__
|
||||
mov r2, #0
|
||||
1:
|
||||
cmp r0, r1
|
||||
bge 2f
|
||||
str r2, [r0], #4
|
||||
b 1b
|
||||
2:
|
||||
|
||||
/* Run global constructors. */
|
||||
ldr r4, =__init_array_start
|
||||
ldr r5, =__init_array_end
|
||||
3:
|
||||
cmp r4, r5
|
||||
bge 4f
|
||||
ldr r0, [r4], #4
|
||||
mov lr, pc
|
||||
bx r0
|
||||
b 3b
|
||||
4:
|
||||
|
||||
bl main
|
||||
|
||||
.global _panic
|
||||
_panic:
|
||||
ldr r0, =0x70006040 /* UART_B_BASE */
|
||||
adr r3, _panic_msg
|
||||
7:
|
||||
ldrb r1, [r3], #1
|
||||
cmp r1, #0
|
||||
beq 9f
|
||||
8:
|
||||
ldr r2, [r0, #0x14] /* UART_LSR */
|
||||
tst r2, #0x20 /* UART_LSR_THRE */
|
||||
beq 8b
|
||||
str r1, [r0]
|
||||
b 7b
|
||||
9:
|
||||
ldr r2, [r0, #0x14] /* UART_LSR */
|
||||
tst r2, #0x40 /* UART_LSR_TMTY */
|
||||
beq 9b
|
||||
b _panic_reboot
|
||||
|
||||
_panic_msg:
|
||||
.asciz "[bpmpfw] PANIC\n"
|
||||
.align 2
|
||||
|
||||
.global _panic_reboot
|
||||
_panic_reboot:
|
||||
ldr r0, =0x7000EC40 /* PMC_BASE + APBDEV_PMC_SCRATCH200 */
|
||||
ldr r1, =0xF8F00000 /* Panic code. */
|
||||
str r1, [r0]
|
||||
|
||||
ldr r4, =0x60005000 /* TMR_BASE */
|
||||
|
||||
/* Write the magic */
|
||||
ldr r1, =0xC45A
|
||||
str r1, [r4, #0x18C]
|
||||
|
||||
/* Disable the counters */
|
||||
mov r1, #0x2
|
||||
str r1, [r4, #0x188]
|
||||
|
||||
/* Start periodic timer */
|
||||
ldr r1, =0xC0000000
|
||||
str r1, [r4, #0x080]
|
||||
|
||||
/* Set reboot source to the timer we started */
|
||||
ldr r1, =0x8019
|
||||
str r1, [r4, #0x180]
|
||||
|
||||
/* Enable the counters */
|
||||
mov r1, #0x1
|
||||
str r1, [r4, #0x188]
|
||||
|
||||
_panic_hang:
|
||||
b _panic_hang
|
||||
@@ -19,16 +19,6 @@ for arg in "$@"; do
|
||||
esac
|
||||
done
|
||||
|
||||
echo
|
||||
echo "*** Compiling bpmpfw ***"
|
||||
pushd "$ROOT_DIR/bpmpfw"
|
||||
make -j$CORES
|
||||
popd > /dev/null
|
||||
|
||||
mkdir -p "$ROOT_DIR/sysmodule/data"
|
||||
cp -vf "$ROOT_DIR/bpmpfw/out/bpmpfw.bin" "$ROOT_DIR/sysmodule/data/bpmpfw.bin"
|
||||
echo
|
||||
|
||||
echo "*** Compiling hoc-clk ***"
|
||||
TITLE_ID="$(grep -oP '"title_id":\s*"0x\K(\w+)' "$ROOT_DIR/sysmodule/perms.json")"
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#ifdef __SWITCH__ // Wont be defined in BPMP-FW
|
||||
#include <switch/types.h>
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
@@ -1,58 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "board.h"
|
||||
|
||||
#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.
|
||||
*/
|
||||
typedef struct {
|
||||
u32 magic; // should be HOCCLK_BPMP_MAGIC once bpmpfw is running
|
||||
u32 status; // Reserved for error codes and such
|
||||
s32 tempCpu;
|
||||
s32 tempGpu;
|
||||
s32 tempMem;
|
||||
s32 tempPllx;
|
||||
u32 freqCpu; // kHz
|
||||
u32 freqMem; // kHz
|
||||
u32 freqMemPll; // kHz
|
||||
u32 emcLoadAll;
|
||||
u32 emcLoadCpu;
|
||||
u32 emcBwAll;
|
||||
u32 emcBwCpu;
|
||||
u32 emcBwGpu;
|
||||
u32 cmd; // HocClkBpmpCmd; 0 = no command pending
|
||||
u32 cmdArg1;
|
||||
u32 cmdArg2;
|
||||
u32 cmdArg3;
|
||||
u32 cmdArg4;
|
||||
s32 tempAO;
|
||||
} HocClkBpmpSharedInfo;
|
||||
|
||||
static_assert(sizeof(HocClkBpmpSharedInfo) == 0x50);
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "board.h"
|
||||
#include "bpmp.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -85,11 +84,8 @@ typedef struct {
|
||||
bool rebootRequired;
|
||||
bool isFirstLoad;
|
||||
|
||||
// Populated from bpmpfw's work-RAM via SmcCopyFromIram (see HocClkBpmpSharedInfo above).
|
||||
HocClkBpmpSharedInfo bpmpInfo;
|
||||
|
||||
// Reserved for future use
|
||||
u8 reserved[0x308];
|
||||
u8 reserved[0x358];
|
||||
} HocClkContext;
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -44,7 +44,6 @@ tsl::elm::ListItem* aotagTempItem = NULL;
|
||||
tsl::elm::ListItem* dramTempItem = NULL;
|
||||
tsl::elm::ListItem* cTypeItem = NULL;
|
||||
tsl::elm::ListItem* creditsItem = NULL;
|
||||
tsl::elm::ListItem* bpmpStatusItem = NULL;
|
||||
|
||||
#define R_ARROW "\u2192"
|
||||
|
||||
@@ -153,8 +152,6 @@ void AboutGui::listUI()
|
||||
// custRevItem = new tsl::elm::ListItem("CUST revision:");
|
||||
// this->listElement->addItem(custRevItem);
|
||||
|
||||
bpmpStatusItem = new tsl::elm::ListItem("BPMP Status:");
|
||||
this->listElement->addItem(bpmpStatusItem);
|
||||
|
||||
kipVersionItem = new tsl::elm::ListItem("KIP version:");
|
||||
this->listElement->addItem(kipVersionItem);
|
||||
@@ -285,7 +282,6 @@ void AboutGui::refresh()
|
||||
dramTempItem->setValue(strings[12]);
|
||||
|
||||
cTypeItem->setValue(hocClkFormatConsoleType(this->context->consoleType, true));
|
||||
bpmpStatusItem->setValue(this->context->bpmpInfo.magic == HOCCLK_BPMP_MAGIC ? "Enabled" : "Halted");
|
||||
}
|
||||
|
||||
class CreditsSubMenu : public AboutGui {
|
||||
|
||||
@@ -22,7 +22,7 @@ CONFIG_DIR := horizon-oc
|
||||
BUILD := build
|
||||
OUTDIR := out
|
||||
RESOURCES := res
|
||||
SOURCES := src src/hos src/i2c src/ipc src/board src/bpmp src/display src/tsensor src/mgr src/file src/soc src/mapping src/pwr src/util
|
||||
SOURCES := src src/hos src/i2c src/ipc src/board src/display src/tsensor src/mgr src/file src/soc src/mapping src/pwr src/util
|
||||
DATA := data
|
||||
INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
|
||||
EXEFS_SRC := exefs_src
|
||||
@@ -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 sync-bpmpfw
|
||||
.PHONY: $(BUILD) clean clean-libs clean-build all libs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
@@ -116,11 +116,7 @@ libs:
|
||||
$(LIBNAMES):
|
||||
@echo $@
|
||||
|
||||
sync-bpmpfw:
|
||||
@$(MAKE) --no-print-directory -C $(TOPDIR)/../bpmpfw
|
||||
@cp -f $(TOPDIR)/../bpmpfw/out/bpmpfw.bin $(TOPDIR)/data/bpmpfw.bin
|
||||
|
||||
$(BUILD): libs sync-bpmpfw
|
||||
$(BUILD): libs
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"title_id": "0x00FF0000636C6BFF",
|
||||
"title_id_range_min": "0x00FF0000636C6BFF",
|
||||
"title_id_range_max": "0x00FF0000636C6BFF",
|
||||
"main_thread_stack_size": "0x0000F000",
|
||||
"main_thread_stack_size": "0x0000C000",
|
||||
"main_thread_priority": 16,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 1,
|
||||
@@ -46,14 +46,7 @@
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
"address": "0x60005000",
|
||||
"is_ro": false,
|
||||
"size": "0x00001000",
|
||||
"is_io": true
|
||||
}
|
||||
|
||||
}, {
|
||||
"type": "map",
|
||||
"value": {
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <switch.h>
|
||||
#include <tmp451.h>
|
||||
|
||||
#include "../bpmp/bpmp.hpp"
|
||||
#include "../display/display_refresh_rate.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
#include "../hos/apm_ext.h"
|
||||
@@ -53,13 +52,7 @@
|
||||
#include "../soc/dram_mrr.hpp"
|
||||
namespace board {
|
||||
|
||||
u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr, sysVirtAddr, actmonVirtAddr, gpuVirtAddr, tmrVirtAddr;
|
||||
consteval inline u32 PackCode(u32 r, u32 g, u32 b) {
|
||||
return ((r & 0xF) << 8) | ((g & 0xF) << 4) | ((b & 0xF) << 0);
|
||||
}
|
||||
const u32 GpuPanic = PackCode(0xF, 0x7, 0x0);
|
||||
const u32 CpuPanic = PackCode(0xF, 0x0, 0x0);
|
||||
const u32 RamPanic = PackCode(0x0, 0xF, 0xF);
|
||||
u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr;
|
||||
|
||||
HocClkSocType gSocType;
|
||||
u8 gDramID;
|
||||
@@ -160,16 +153,6 @@ namespace board {
|
||||
rc = QueryMemoryMapping(&fuseVirtAddr, 0x7000F000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "QueryMemoryMapping (fuse)");
|
||||
|
||||
rc = QueryMemoryMapping(&sysVirtAddr, 0x6000C000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "QueryMemoryMapping (sys)");
|
||||
actmonVirtAddr = sysVirtAddr + 0x800;
|
||||
|
||||
rc = QueryMemoryMapping(&gpuVirtAddr, 0x57000000, 0x1000000);
|
||||
ASSERT_RESULT_OK(rc, "QueryMemoryMapping (gpu)");
|
||||
|
||||
rc = QueryMemoryMapping(&tmrVirtAddr, 0x60005000, 0x1000);
|
||||
ASSERT_RESULT_OK(rc, "QueryMemoryMapping (tmr)");
|
||||
|
||||
FetchHardwareInfos();
|
||||
|
||||
Result nvCheck = 1;
|
||||
@@ -190,12 +173,6 @@ namespace board {
|
||||
|
||||
tsensor::InitializeSoctherm(); // SOCTHERM must be init before AOTAG
|
||||
|
||||
Result bpmpfwRc = bpmp::StartBpmfwExecution();
|
||||
if (R_FAILED(bpmpfwRc)) {
|
||||
file::utils::LogLine("[bpmp] StartBpmfwExecution failed: 0x%x", bpmpfwRc);
|
||||
}
|
||||
bpmp::StartSleepMonitorThread();
|
||||
|
||||
// PMC exosphere check
|
||||
SecmonArgs args = {};
|
||||
args.X[0] = 0xF0000002;
|
||||
@@ -224,7 +201,6 @@ namespace board {
|
||||
}
|
||||
|
||||
void Exit() {
|
||||
bpmp::StopSleepMonitorThread();
|
||||
|
||||
if (HOSSVC_HAS_CLKRST) {
|
||||
clkrstExit();
|
||||
@@ -254,30 +230,6 @@ namespace board {
|
||||
nvExit();
|
||||
}
|
||||
|
||||
#define MMIO32(addr) (*reinterpret_cast<volatile u32 *>(addr))
|
||||
NX_NORETURN void Panic(u32 c) {
|
||||
SmcReadWriteRegister(0x7000EC40 /* PMC_BASE + APBDEV_PMC_SCRATCH200 */, ~0, c);
|
||||
|
||||
/* Write timer magic */
|
||||
MMIO32(tmrVirtAddr + 0x18C) = 0xC45A;
|
||||
|
||||
/* Disable counters */
|
||||
MMIO32(tmrVirtAddr + 0x188) = 0x2;
|
||||
|
||||
/* Start periodic timer */
|
||||
MMIO32(tmrVirtAddr + 0x80) = 0xC0000000;
|
||||
|
||||
/* Set the reboot source to the timer */
|
||||
MMIO32(tmrVirtAddr + 0x180) = 0x8019;
|
||||
|
||||
/* Enable counter */
|
||||
MMIO32(tmrVirtAddr + 0x188) = 0x1;
|
||||
|
||||
/* Hang. */
|
||||
for(;;)
|
||||
;
|
||||
}
|
||||
|
||||
HocClkSocType GetSocType() {
|
||||
return gSocType;
|
||||
}
|
||||
|
||||
@@ -42,15 +42,12 @@
|
||||
#define HOSSVC_HAS_TC (hosversionAtLeast(5, 0, 0))
|
||||
|
||||
namespace board {
|
||||
extern u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr, sysVirtAddr, actmonVirtAddr, gpuVirtAddr;
|
||||
extern u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr;
|
||||
extern HocClkSocType gSocType;
|
||||
extern u8 gDramID;
|
||||
extern HocClkConsoleType gConsoleType;
|
||||
extern FuseData fuseData;
|
||||
extern u8 speedoBracket;
|
||||
extern const u32 GpuPanic;
|
||||
extern const u32 CpuPanic;
|
||||
extern const u32 RamPanic;
|
||||
|
||||
void Initialize();
|
||||
void Exit();
|
||||
@@ -62,6 +59,5 @@ namespace board {
|
||||
bool IsDram8GB();
|
||||
void SetDisplayRefreshDockedState(bool docked);
|
||||
FuseData *GetFuseData();
|
||||
NX_NORETURN void Panic(u32 c);
|
||||
|
||||
} // namespace board
|
||||
@@ -28,15 +28,16 @@
|
||||
#include <i2c.h>
|
||||
#include <max17050.h>
|
||||
#include <switch.h>
|
||||
#include <t210.h>
|
||||
#include <tmp451.h>
|
||||
|
||||
#include "../bpmp/bpmp.hpp"
|
||||
#include "../display/display_refresh_rate.hpp"
|
||||
#include "../file/config.hpp"
|
||||
#include "../file/errors.hpp"
|
||||
#include "../hos/apm_ext.h"
|
||||
#include "../i2c/i2cDrv.h"
|
||||
#include "../soc/gm20b.hpp"
|
||||
#include "../soc/pllmb.hpp"
|
||||
#include "board.hpp"
|
||||
#include "board_name.hpp"
|
||||
#include <ipc_server.h>
|
||||
@@ -183,30 +184,13 @@ namespace board {
|
||||
u32 hz = 0;
|
||||
switch (module) {
|
||||
case HocClkModule_CPU:
|
||||
return bpmp::GetSharedInfo()->freqCpu * 1000;
|
||||
case HocClkModule_GPU: {
|
||||
constexpr u32 ClkOutEnbX = 0x280;
|
||||
constexpr u32 RstDevicesX = 0x28C;
|
||||
constexpr u32 GpuBit = (1u << 24);
|
||||
|
||||
const bool gpuEnabled = (*reinterpret_cast<volatile u32 *>(clkVirtAddr + ClkOutEnbX) & GpuBit) &&
|
||||
!(*reinterpret_cast<volatile u32 *>(clkVirtAddr + RstDevicesX) & GpuBit);
|
||||
if (!gpuEnabled) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 coeff = *reinterpret_cast<volatile u32 *>(gpuVirtAddr + 0x137004);
|
||||
const u32 divm = coeff & 0xFF;
|
||||
const u32 divn = (coeff >> 8) & 0xFF;
|
||||
const u32 divp = (coeff >> 16) & 0x3F;
|
||||
if (divm == 0 || divp == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<u32>((static_cast<u64>(38400000) * divn) / (divm * divp) / 2);
|
||||
}
|
||||
return t210ClkCpuFreq();
|
||||
case HocClkModule_GPU:
|
||||
return t210ClkGpuFreq();
|
||||
case HocClkModule_MEM:
|
||||
return bpmp::GetSharedInfo()->freqMemPll * 1000;
|
||||
return file::config::GetConfigValue(HocClkConfigValue_MemoryFrequencyMeasurementMode) == MemoryFrequencyMeasurementMode_PLL
|
||||
? pllmb::getRamClockRatePLLMB()
|
||||
: t210ClkMemFreq();
|
||||
case HocClkModule_Display:
|
||||
return GetDisplayRate(hz);
|
||||
default:
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
#include <minIni.h>
|
||||
#include <numeric>
|
||||
#include <switch.h>
|
||||
#include <t210.h>
|
||||
#include <tmp451.h>
|
||||
|
||||
#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 bpmp::GetSharedInfo()->emcLoadAll;
|
||||
return t210EmcLoadAll();
|
||||
case HocClkPartLoad_EMCCpu:
|
||||
return bpmp::GetSharedInfo()->emcLoadCpu;
|
||||
return t210EmcLoadCpu();
|
||||
case HocClkPartLoad_GPU:
|
||||
return gpuLoad;
|
||||
case HocClkPartLoad_CPUMax:
|
||||
@@ -130,13 +130,13 @@ namespace board {
|
||||
case HocClkPartLoad_FAN:
|
||||
return GetFanLevel();
|
||||
case HocClkPartLoad_RamBWAll:
|
||||
return bpmp::GetSharedInfo()->emcBwAll;
|
||||
return t210EmcBwAll();
|
||||
case HocClkPartLoad_RamBWCpu:
|
||||
return bpmp::GetSharedInfo()->emcBwCpu;
|
||||
return t210EmcBwCpu();
|
||||
case HocClkPartLoad_RamBWGpu:
|
||||
return bpmp::GetSharedInfo()->emcBwGpu;
|
||||
return t210EmcBwGpu();
|
||||
case HocClkPartLoad_RamBWPeak:
|
||||
return static_cast<u32>((static_cast<u64>(bpmp::GetSharedInfo()->freqMem) * 16) / 1000);
|
||||
return t210EmcBwPeak();
|
||||
default:
|
||||
ASSERT_ENUM_VALID(HocClkPartLoad, loadSource);
|
||||
}
|
||||
|
||||
@@ -1,406 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <switch.h>
|
||||
|
||||
#include "../board/board.hpp"
|
||||
#include "../file/config.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
#include "../mapping/mem_map.hpp"
|
||||
#include "../tsensor/soctherm.hpp"
|
||||
#include "bpmp.hpp"
|
||||
|
||||
#include "bpmpfw_bin.h"
|
||||
|
||||
namespace bpmp {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u64 FlowCtlrPhysBase = 0x60007000;
|
||||
constexpr u64 EvpPhysBase = 0x6000F000;
|
||||
|
||||
constexpr u32 ClkRstRstDevLSet = 0x300;
|
||||
constexpr u32 ClkRstRstDevLClr = 0x304;
|
||||
constexpr u32 RstDevLCopRstBit = (1u << 1); /* SWR_COP_RST */
|
||||
|
||||
constexpr u32 ApbMiscSlaveSecurityReg0 = 0xC00;
|
||||
constexpr u32 ApbMiscSlaveSecurityReg1 = 0xC04;
|
||||
constexpr u32 ApbMiscSlaveSecurityReg2 = 0xC08;
|
||||
|
||||
/* Relative to actmonVirtAddr */
|
||||
constexpr u32 ActmonGlbPeriodCtrl = 0x004;
|
||||
constexpr u32 ActmonCopCtrl = 0xC0;
|
||||
constexpr u32 ActmonCopUpperWmark = 0xC4;
|
||||
constexpr u32 ActmonCopIntrStatus = 0xE4;
|
||||
|
||||
constexpr u32 ActmonGlbPeriodCtrlUsec = (1u << 8);
|
||||
constexpr u32 ActmonCopCtrlStockArmed = (1u << 31) | (1u << 30) | (1u << 18);
|
||||
|
||||
/* MC SMMU handling for the BPMP. */
|
||||
constexpr u64 McPhysBase = 0x70019000;
|
||||
|
||||
constexpr u32 McSmmuTlbConfig = 0x014;
|
||||
constexpr u32 McSmmuPtbAsid = 0x01C;
|
||||
constexpr u32 McSmmuPtbData = 0x020;
|
||||
constexpr u32 McSmmuTlbFlush = 0x030;
|
||||
constexpr u32 McSmmuPtcFlush = 0x034;
|
||||
constexpr u32 McSmmuAvpcAsid = 0x23C;
|
||||
constexpr u32 McSmmuPpcs1Asid = 0x298;
|
||||
|
||||
/* Page table is backed by the security engine's MMIO aperture. */
|
||||
constexpr u64 BpmpSmmuPdeBase = 0x70012000;
|
||||
constexpr u32 BpmpSmmuAsid = 1;
|
||||
|
||||
/* MC_SMMU_PTB_ASID */
|
||||
constexpr u32 SmmuPtbAsidCurrentAsid = BpmpSmmuAsid; /* [0:7] */
|
||||
|
||||
/* MC_SMMU_PTB_DATA */
|
||||
constexpr u32 SmmuPtbDataPdeMask = 0x7FFFFF; /* [0:22] */
|
||||
|
||||
/* MC_SMMU_AVPC_ASID / MC_SMMU_PPCS1_ASID */
|
||||
constexpr u32 SmmuClientSmmuEnableBit = (1u << 31);
|
||||
constexpr u32 SmmuAvpcAsidValue = (SmmuClientSmmuEnableBit | BpmpSmmuAsid);
|
||||
constexpr u32 SmmuPpcs1AsidValue = (SmmuClientSmmuEnableBit | BpmpSmmuAsid);
|
||||
|
||||
constexpr u32 EvpCopResetVector = 0x200;
|
||||
constexpr u32 EvpCopUndefVector = 0x204;
|
||||
constexpr u32 EvpCopSwiVector = 0x208;
|
||||
constexpr u32 EvpCopPrefetchAbortVector = 0x20C;
|
||||
constexpr u32 EvpCopDataAbortVector = 0x210;
|
||||
constexpr u32 EvpCopRsvdVector = 0x214;
|
||||
constexpr u32 EvpCopIrqVector = 0x218;
|
||||
constexpr u32 EvpCopFiqVector = 0x21C;
|
||||
|
||||
constexpr u32 StockBpmpExceptionVector = 0x7D000000;
|
||||
|
||||
constexpr u32 FlowCtlrHaltCopEvents = 0x004;
|
||||
constexpr u32 FlowModeNone = 0x00000000;
|
||||
constexpr u32 FlowModeStop = (2u << 29);
|
||||
|
||||
constexpr u64 FwIramPhysBase = 0x40004000;
|
||||
constexpr u32 FwStagingSize = 0x8000;
|
||||
constexpr u64 WorkRamPhysBase = FwIramPhysBase + FwStagingSize; // matches bpmpfw's WorkRamStart
|
||||
|
||||
/* secmon will return error unless we apply thiss workaround */
|
||||
alignas(4096) u8 s_fwStageBuf[FwStagingSize];
|
||||
|
||||
HocClkBpmpSharedInfo s_sharedInfo = {};
|
||||
|
||||
inline volatile u32 &Mmio(u64 base_va, u32 offset) {
|
||||
return *reinterpret_cast<volatile u32 *>(base_va + offset);
|
||||
}
|
||||
|
||||
// Late in the boot chain, otherwise a fatal will occur from invalid boot state
|
||||
constexpr u32 pscDependencies[] = { PscPmModuleId_Olsc };
|
||||
constexpr PscPmModuleId PscModuleId = (PscPmModuleId)705;
|
||||
|
||||
PscPmModule s_pscModule;
|
||||
bool s_pscPrepared = false;
|
||||
Thread s_pscThread;
|
||||
bool s_pscExit = false;
|
||||
|
||||
std::atomic_bool s_isAwake = true;
|
||||
|
||||
|
||||
/* Must be called to prevent secmon/erpt panic on wake */
|
||||
void RequestBpmpExitAndWait() {
|
||||
if (!IsPatchedExosphere()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 cmd = HocClkBpmpCmd_RequestShutdown;
|
||||
Result rc = SmcCopyToIram(WorkRamPhysBase + offsetof(HocClkBpmpSharedInfo, cmd), &cmd, sizeof(cmd));
|
||||
if (R_FAILED(rc)) {
|
||||
file::utils::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;
|
||||
}
|
||||
}
|
||||
|
||||
file::utils::LogLine("[bpmp] RequestBpmpExitAndWait: BPMP timeout (cannot sleep)");
|
||||
board::Panic(board::CpuPanic);
|
||||
}
|
||||
|
||||
void EnableBpmpSmmu() {
|
||||
/* Point the ASID page table at the security engine aperture. */
|
||||
const u32 pde_base = static_cast<u32>(BpmpSmmuPdeBase / 0x1000);
|
||||
|
||||
/* Select the ASID and configure its page table entry. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtbAsid, 0xFFFFFFFF, SmmuPtbAsidCurrentAsid);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtbData, 0xFFFFFFFF, pde_base & SmmuPtbDataPdeMask);
|
||||
|
||||
/* Route BPMP (AVPC) and PPCS1 through the SMMU. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuAvpcAsid, 0xFFFFFFFF, SmmuAvpcAsidValue);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPpcs1Asid, 0xFFFFFFFF, SmmuPpcs1AsidValue);
|
||||
|
||||
/* Flush the page table cache. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtcFlush, 0xFFFFFFFF, 0);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
|
||||
|
||||
/* Flush the translation lookaside buffer. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuTlbFlush, 0xFFFFFFFF, 0);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
|
||||
}
|
||||
|
||||
void DisableBpmpSmmu() {
|
||||
/* Clear the ASID page table. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtbAsid, 0xFFFFFFFF, SmmuPtbAsidCurrentAsid);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtbData, 0xFFFFFFFF, 0);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuAvpcAsid, 0xFFFFFFFF, 0);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPpcs1Asid, 0xFFFFFFFF, 0);
|
||||
|
||||
/* Flush the page table cache. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuPtcFlush, 0xFFFFFFFF, 0);
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuTlbConfig, 0, 0);
|
||||
|
||||
/* Flush the translation lookaside buffer. */
|
||||
SmcReadWriteRegister(McPhysBase + McSmmuTlbFlush, 0xFFFFFFFF, 0);
|
||||
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()) {
|
||||
file::utils::LogLine("[bpmp] SendBpmpCommand: BPMP never signaled ready (cmd=%u)", static_cast<u32>(cmd));
|
||||
return;
|
||||
}
|
||||
|
||||
struct {
|
||||
u32 cmd;
|
||||
u32 cmdArg1;
|
||||
u32 cmdArg2;
|
||||
u32 cmdArg3;
|
||||
u32 cmdArg4;
|
||||
} req = { static_cast<u32>(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)) {
|
||||
file::utils::LogLine("[bpmp] SendBpmpCommand: SmcCopyToIram failed: 0x%x (cmd=%u)", rc, static_cast<u32>(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreStockState() {
|
||||
RequestBpmpExitAndWait();
|
||||
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopResetVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopUndefVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopSwiVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopPrefetchAbortVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopDataAbortVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopRsvdVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopIrqVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopFiqVector, 0xFFFFFFFF, StockBpmpExceptionVector);
|
||||
|
||||
SmcReadWriteRegister(FlowCtlrPhysBase + FlowCtlrHaltCopEvents, 0xFFFFFFFF, FlowModeStop);
|
||||
|
||||
Mmio(board::actmonVirtAddr, ActmonGlbPeriodCtrl) = ActmonGlbPeriodCtrlUsec;
|
||||
Mmio(board::actmonVirtAddr, ActmonCopUpperWmark) = 0;
|
||||
Mmio(board::actmonVirtAddr, ActmonCopIntrStatus) = Mmio(board::actmonVirtAddr, ActmonCopIntrStatus);
|
||||
Mmio(board::actmonVirtAddr, ActmonCopCtrl) = ActmonCopCtrlStockArmed;
|
||||
|
||||
EnableBpmpSmmu();
|
||||
}
|
||||
|
||||
void PscThreadFunc(void *) {
|
||||
while (!s_pscExit) {
|
||||
Result rc = eventWait(&s_pscModule.event, 1'000'000'000ULL);
|
||||
if (R_FAILED(rc)) {
|
||||
continue; // Timeout
|
||||
}
|
||||
|
||||
PscPmState state;
|
||||
u32 flags;
|
||||
rc = pscPmModuleGetRequest(&s_pscModule, &state, &flags);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (state == PscPmState_Awake) {
|
||||
svcSleepThread(500'000'000); // 500ms
|
||||
|
||||
/* I have no clue why this is needed as it wasn't needed before ¯\(ツ)/¯ */
|
||||
tsensor::InitializeSoctherm();
|
||||
|
||||
Result wrc = StartBpmfwExecution();
|
||||
if (R_FAILED(wrc)) {
|
||||
file::utils::LogLine("[bpmp] restart after wake failed: 0x%x", wrc);
|
||||
}
|
||||
|
||||
s_isAwake = true;
|
||||
} else if (state == PscPmState_ReadySleep || state == PscPmState_ReadyShutdown) {
|
||||
RestoreStockState();
|
||||
s_isAwake = false;
|
||||
}
|
||||
|
||||
pscPmModuleAcknowledge(&s_pscModule, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result StartBpmfwExecution() {
|
||||
if (!IsPatchedExosphere()) {
|
||||
file::utils::LogLine("[bpmp] Cannot start without patched exosphere");
|
||||
return (Result)1;
|
||||
}
|
||||
|
||||
const size_t fw_size = bpmpfw_bin_size;
|
||||
if (fw_size == 0 || fw_size > FwStagingSize) {
|
||||
file::utils::LogLine("[bpmp] StartBpmfwExecution: bpmpfw of %zu bytes is invalid (should not happen)!", fw_size);
|
||||
return (Result)1;
|
||||
}
|
||||
|
||||
std::memcpy(s_fwStageBuf, bpmpfw_bin, fw_size);
|
||||
|
||||
file::utils::LogLine("[bpmp] StartBpmfwExecution: loading %zu bytes at 0x%llx",
|
||||
fw_size, static_cast<unsigned long long>(FwIramPhysBase));
|
||||
|
||||
/* Disable the SMMU so DRAM can be accessed */
|
||||
DisableBpmpSmmu();
|
||||
|
||||
/* Set BPMP reset */
|
||||
Mmio(board::clkVirtAddr, ClkRstRstDevLSet) = RstDevLCopRstBit;
|
||||
|
||||
/* Grant BPMP access to all a bunch of registers that are useful */
|
||||
Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg0) = 0;
|
||||
Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg1) = 0;
|
||||
Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg2) = 0;
|
||||
|
||||
/* Set up exeption vectors for bpmp */
|
||||
const u32 fw_reset_vector = static_cast<u32>(FwIramPhysBase + 0x0);
|
||||
const u32 fw_panic_vector = static_cast<u32>(FwIramPhysBase + 0x4);
|
||||
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopResetVector, 0xFFFFFFFF, fw_reset_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopUndefVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopSwiVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopPrefetchAbortVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopDataAbortVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopRsvdVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopIrqVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
SmcReadWriteRegister(EvpPhysBase + EvpCopFiqVector, 0xFFFFFFFF, fw_panic_vector);
|
||||
|
||||
/* Disable actmon monitoring to avoid hang on FW >4.0.0 */
|
||||
Mmio(board::actmonVirtAddr, ActmonCopCtrl) = 0;
|
||||
Mmio(board::actmonVirtAddr, ActmonCopIntrStatus) = Mmio(board::actmonVirtAddr, ActmonCopIntrStatus);
|
||||
|
||||
/* Load the BPMPFW into iram per page. TODO: determine if this is nessesary */
|
||||
constexpr size_t PageSize = 4096;
|
||||
for (size_t ofs = 0; ofs < fw_size; ofs += PageSize) {
|
||||
const size_t chunk = (fw_size - ofs) < PageSize ? (fw_size - ofs) : PageSize;
|
||||
|
||||
Result copy_rc = SmcCopyToIram(FwIramPhysBase + ofs, s_fwStageBuf + ofs, static_cast<u32>(chunk));
|
||||
if (R_FAILED(copy_rc)) {
|
||||
file::utils::LogLine("[bpmp] SmcCopyToIram failed at +0x%zx: 0x%x", ofs, copy_rc);
|
||||
return copy_rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear BPMP reset. */
|
||||
Mmio(board::clkVirtAddr, ClkRstRstDevLClr) = RstDevLCopRstBit;
|
||||
|
||||
/* Clear the halt written by bootloader. */
|
||||
SmcReadWriteRegister(FlowCtlrPhysBase + FlowCtlrHaltCopEvents, 0xFFFFFFFF, FlowModeNone);
|
||||
|
||||
SendBpmpCommand(HocClkBpmpCmd_SetUartEnabled, file::utils::IsUartEnabled() ? 1u : 0u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StartSleepMonitorThread() {
|
||||
if (!IsPatchedExosphere()) {
|
||||
file::utils::LogLine("[bpmp] Cant start BPMP without exosphere patch");
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = pscmInitialize();
|
||||
if (R_FAILED(rc)) {
|
||||
file::utils::LogLine("[bpmp] pscmInitialize failed: 0x%x", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = pscmGetPmModule(&s_pscModule, PscModuleId, pscDependencies, sizeof(pscDependencies) / sizeof(u32), true);
|
||||
if (R_FAILED(rc)) {
|
||||
file::utils::LogLine("[bpmp] pscmGetPmModule failed: 0x%x", rc);
|
||||
pscmExit();
|
||||
return;
|
||||
}
|
||||
s_pscPrepared = true;
|
||||
|
||||
rc = threadCreate(&s_pscThread, PscThreadFunc, nullptr, NULL, 0x1000, 0x10, 3);
|
||||
if (R_FAILED(rc)) {
|
||||
file::utils::LogLine("[bpmp] failed to create psc thread: 0x%x", rc);
|
||||
return;
|
||||
}
|
||||
threadStart(&s_pscThread);
|
||||
}
|
||||
|
||||
void StopSleepMonitorThread() {
|
||||
if (!s_pscPrepared) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_pscExit = true;
|
||||
eventFire(&s_pscModule.event);
|
||||
threadWaitForExit(&s_pscThread);
|
||||
threadClose(&s_pscThread);
|
||||
|
||||
pscPmModuleFinalize(&s_pscModule);
|
||||
pscPmModuleClose(&s_pscModule);
|
||||
pscmExit();
|
||||
s_pscPrepared = false;
|
||||
}
|
||||
|
||||
const HocClkBpmpSharedInfo *GetSharedInfo() {
|
||||
if (!IsPatchedExosphere()) {
|
||||
s_sharedInfo = {};
|
||||
return &s_sharedInfo;
|
||||
}
|
||||
|
||||
SmcCopyFromIram(&s_sharedInfo, WorkRamPhysBase, sizeof(s_sharedInfo));
|
||||
return &s_sharedInfo;
|
||||
}
|
||||
|
||||
bool IsAwake() {
|
||||
return s_isAwake;
|
||||
}
|
||||
|
||||
} // namespace bpmp
|
||||
@@ -1,33 +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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include <hocclk/bpmp.h>
|
||||
|
||||
namespace bpmp {
|
||||
Result StartBpmfwExecution();
|
||||
|
||||
void StartSleepMonitorThread();
|
||||
void StopSleepMonitorThread();
|
||||
|
||||
const HocClkBpmpSharedInfo *GetSharedInfo();
|
||||
|
||||
// Always true on stock exosphere
|
||||
bool IsAwake();
|
||||
}
|
||||
@@ -66,35 +66,3 @@ Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size) {
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool IsPatchedExosphere() {
|
||||
static bool checked = false;
|
||||
static bool patched = false;
|
||||
|
||||
if (!checked) {
|
||||
constexpr u64 EvpPhysBase = 0x6000F000;
|
||||
constexpr u64 EvpCopResetVector = 0x200;
|
||||
|
||||
SecmonArgs args = {};
|
||||
args.X[0] = 0xF0000002;
|
||||
args.X[1] = EvpPhysBase + EvpCopResetVector;
|
||||
args.X[2] = 0;
|
||||
args.X[3] = 0;
|
||||
svcCallSecureMonitor(&args);
|
||||
|
||||
patched = (args.X[0] == 0);
|
||||
checked = true;
|
||||
}
|
||||
|
||||
return patched;
|
||||
}
|
||||
|
||||
u32 SmcReadWriteRegister(u64 phys_addr, u32 mask, u32 value) {
|
||||
SecmonArgs args = {};
|
||||
args.X[0] = 0xF0000002;
|
||||
args.X[1] = phys_addr;
|
||||
args.X[2] = mask;
|
||||
args.X[3] = value;
|
||||
svcCallSecureMonitor(&args);
|
||||
return (u32)args.X[1];
|
||||
}
|
||||
@@ -22,5 +22,3 @@ Result QueryMemoryMapping(u64 *virtaddr, u64 physaddr, u64 size);
|
||||
Result MapAddress(u64 &va, const u64 &physAddr, const char *name);
|
||||
Result SmcCopyFromIram(void *dest, uintptr_t src, u32 size);
|
||||
Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size);
|
||||
bool IsPatchedExosphere();
|
||||
u32 SmcReadWriteRegister(u64 phys_addr, u32 mask, u32 value);
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <i2c.h>
|
||||
|
||||
#include "../board/board.hpp"
|
||||
#include "../bpmp/bpmp.hpp"
|
||||
#include "../display/aula.hpp"
|
||||
#include "../display/display_refresh_rate.hpp"
|
||||
#include "../file/config.hpp"
|
||||
@@ -630,8 +629,6 @@ namespace mgr {
|
||||
bool RefreshContext() {
|
||||
bool hasChanged = false;
|
||||
|
||||
gContext.bpmpInfo = *bpmp::GetSharedInfo();
|
||||
|
||||
std::uint32_t mode = 0;
|
||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||
@@ -882,10 +879,6 @@ namespace mgr {
|
||||
}
|
||||
|
||||
void WaitForNextTick() {
|
||||
if (!bpmp::IsAwake()) {
|
||||
svcSleepThread(250 * 1000000ULL); // 250ms
|
||||
return;
|
||||
}
|
||||
|
||||
if (board::GetHz(HocClkModule_MEM) > 665000000)
|
||||
svcSleepThread(file::config::GetConfigValue(HocClkConfigValue_PollingIntervalMs) * 1000000ULL);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer
|
||||
*
|
||||
* Copyright (c) KazushiMe
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pllmb.hpp"
|
||||
|
||||
namespace pllmb {
|
||||
#define GET_BITS(VAL, HIGH, LOW) ((VAL & ((1UL << (HIGH + 1UL)) - 1UL)) >> LOW)
|
||||
#define GET_BIT(VAL, BIT) GET_BITS(VAL, BIT, BIT)
|
||||
|
||||
static inline volatile u32 ®(uintptr_t addr) {
|
||||
return *reinterpret_cast<volatile u32 *>(addr);
|
||||
}
|
||||
|
||||
// From jetson nano kernel
|
||||
typedef enum {
|
||||
/* divider = 2 */
|
||||
CLK_PLLX = 5,
|
||||
CLK_PLLM = 2,
|
||||
CLK_PLLMB = 37,
|
||||
/* PLLX & PLLG are backup PLLs for CPU & GPU */
|
||||
/* divider = 1 */
|
||||
CLK_CCLK_G = 18, // A57 CPU cluster
|
||||
CLK_EMC = 36,
|
||||
} PTO_ID; // PLL Test Output Register ID
|
||||
|
||||
/* See if GM20B clock GPC PLL regs are accessible. */
|
||||
|
||||
#define PLLX_MISC0 0xE4
|
||||
#define PLLM_MISC2 0x9C
|
||||
|
||||
double ptoGetMHz(PTO_ID pto_id, u32 divider = 1, u32 presel_reg = 0, u32 presel_mask = 0) {
|
||||
u32 pre_val, val, presel_val;
|
||||
|
||||
if (presel_reg) {
|
||||
val = REG(board::clkVirtAddr + presel_reg);
|
||||
usleep(10);
|
||||
presel_val = val & presel_mask;
|
||||
val &= ~presel_mask;
|
||||
val |= presel_mask;
|
||||
REG(board::clkVirtAddr + presel_reg) = val;
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
constexpr u32 cycle_count = 16;
|
||||
pre_val = REG(board::clkVirtAddr + 0x60);
|
||||
val = BIT(23) | BIT(13) | (cycle_count - 1);
|
||||
val |= pto_id << 14;
|
||||
|
||||
REG(board::clkVirtAddr + 0x60) = val;
|
||||
usleep(10);
|
||||
REG(board::clkVirtAddr + 0x60) = val | BIT(10);
|
||||
usleep(10);
|
||||
REG(board::clkVirtAddr + 0x60) = val;
|
||||
usleep(10);
|
||||
REG(board::clkVirtAddr + 0x60) = val | BIT(9);
|
||||
usleep(500);
|
||||
|
||||
while (REG(board::clkVirtAddr + 0x64) & BIT(31))
|
||||
;
|
||||
|
||||
val = REG(board::clkVirtAddr + 0x64);
|
||||
val &= 0xFFFFFF;
|
||||
val *= divider;
|
||||
|
||||
double rate_hz = (u64)val * 32768. / cycle_count;
|
||||
usleep(10);
|
||||
REG(board::clkVirtAddr + 0x60) = pre_val;
|
||||
usleep(10);
|
||||
|
||||
if (presel_reg) {
|
||||
val = REG(board::clkVirtAddr + presel_reg);
|
||||
usleep(10);
|
||||
val &= ~presel_mask;
|
||||
val |= presel_val;
|
||||
REG(board::clkVirtAddr + presel_reg) = val;
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
return rate_hz;
|
||||
}
|
||||
|
||||
u64 getRamClockRatePLLMB() {
|
||||
// printf("\n"
|
||||
// "EMC: %6.1f MHz\n"
|
||||
// "CCLK_G: %6.1f MHz\n"
|
||||
// "PLLX: %6.1f MHz\n"
|
||||
// "PLLM: %6.1f MHz\n"
|
||||
// "PLLMB: %6.1f MHz\n",
|
||||
// ptoGetMHz(CLK_EMC),
|
||||
// ptoGetMHz(CLK_CCLK_G),
|
||||
// ptoGetMHz(CLK_PLLX, 2, PLLX_MISC0, BIT(22)),
|
||||
// ptoGetMHz(CLK_PLLM, 2, PLLM_MISC2, BIT(8)),
|
||||
// ptoGetMHz(CLK_PLLMB, 2, PLLM_MISC2, BIT(9))
|
||||
// );
|
||||
|
||||
u32 pllmb = ptoGetMHz(CLK_PLLMB, 2, PLLM_MISC2, BIT(9));
|
||||
u32 pllm = ptoGetMHz(CLK_PLLM, 2, PLLM_MISC2, BIT(8));
|
||||
return pllmb == 0 ? pllm : pllmb; // pllmb is zeroed out at times, fallback to pllm
|
||||
}
|
||||
} // namespace pllmb
|
||||
+13
-2
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos and Horizon OC Contributors
|
||||
* Copyright (c) Souldbminer
|
||||
*
|
||||
* Copyright (c) KazushiMe
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -16,5 +18,14 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <hocclk.h>
|
||||
#include <registers.h>
|
||||
#include <switch.h>
|
||||
|
||||
void InitializeLibc();
|
||||
#include "../board/board.hpp"
|
||||
|
||||
namespace pllmb {
|
||||
|
||||
u64 getRamClockRatePLLMB();
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
||||
* 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 <switch.h>
|
||||
|
||||
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
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <notification.h>
|
||||
|
||||
#include "../bpmp/bpmp.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
#include "../mapping/mem_map.hpp"
|
||||
#include "aotag.hpp"
|
||||
@@ -215,7 +214,24 @@ namespace tsensor {
|
||||
return -126;
|
||||
}
|
||||
|
||||
return bpmp::GetSharedInfo()->tempAO;
|
||||
u32 regval = 0, abs = 0, fraction = 0, valid = 0, sign = 0;
|
||||
s32 temp = 0;
|
||||
regval = ReadPmcReg(PMC_TSENSOR_STATUS1);
|
||||
valid = REG_GET(regval, STATUS1_TEMP_VALID);
|
||||
|
||||
if (!valid) {
|
||||
return -125;
|
||||
}
|
||||
|
||||
abs = REG_GET(regval, STATUS1_TEMP_ABS);
|
||||
fraction = REG_GET(regval, STATUS1_TEMP_FRAC);
|
||||
sign = REG_GET(regval, STATUS1_TEMP_SIGN);
|
||||
temp = (abs * 1000) + (fraction * 500);
|
||||
if (sign) {
|
||||
temp = (-1) * (temp);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool IsInitialized() {
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <switch.h>
|
||||
|
||||
#include "../board/board.hpp"
|
||||
#include "../bpmp/bpmp.hpp"
|
||||
#include "../file/file_utils.hpp"
|
||||
#include "../mapping/mem_map.hpp"
|
||||
#include "soctherm.hpp"
|
||||
@@ -414,6 +413,15 @@ namespace tsensor {
|
||||
bool isMariko;
|
||||
} // namespace
|
||||
|
||||
bool IsDisabledThroughSleep() {
|
||||
return (ReadReg(carVa, CLK_RST_CONTROLLER_RST_DEVICES) & SWR_SOC_THERM_RST) ||
|
||||
!(ReadReg(carVa, CLK_RST_CONTROLLER_CLK_OUT_ENB) & CLK_ENB_SOC_THERM);
|
||||
}
|
||||
|
||||
bool IsSensorEnabled() {
|
||||
return ReadReg(socthermVa, TSENSOR_TSENSOR_CLKEN);
|
||||
}
|
||||
|
||||
void EnableSensor(const TSensor *sensor, u32 sensorIdx) {
|
||||
u32 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
|
||||
WriteReg(socthermVa, sensor->base + SENSOR_CONFIG0, val);
|
||||
@@ -426,6 +434,21 @@ namespace tsensor {
|
||||
WriteReg(socthermVa, sensor->base + SENSOR_CONFIG2, calib[sensorIdx]);
|
||||
}
|
||||
|
||||
s32 TranslateTemp(u16 val) {
|
||||
s32 t;
|
||||
|
||||
t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
|
||||
if (val & READBACK_ADD_HALF) {
|
||||
t += 500;
|
||||
}
|
||||
|
||||
if (val & READBACK_NEGATE) {
|
||||
t *= -1;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void StartSensors() {
|
||||
u32 pdiv, hotspot;
|
||||
|
||||
@@ -451,15 +474,23 @@ namespace tsensor {
|
||||
}
|
||||
|
||||
void ReadTSensors(TSensorTemps &temps) {
|
||||
const HocClkBpmpSharedInfo *bpmpInfo = bpmp::GetSharedInfo();
|
||||
if (bpmpInfo->magic != HOCCLK_BPMP_MAGIC) {
|
||||
if (IsDisabledThroughSleep()) {
|
||||
return;
|
||||
}
|
||||
|
||||
temps.cpu = bpmpInfo->tempCpu;
|
||||
temps.gpu = bpmpInfo->tempGpu;
|
||||
temps.pllx = bpmpInfo->tempPllx;
|
||||
temps.mem = (board::GetSocType() == HocClkSocType_Erista) ? bpmpInfo->tempMem : bpmpInfo->tempPllx;
|
||||
if (!IsSensorEnabled()) {
|
||||
StartSensors();
|
||||
}
|
||||
|
||||
temps.cpu = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP1) >> 16);
|
||||
temps.gpu = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP1) & SENSOR_TEMP1_GPU_TEMP_MASK);
|
||||
temps.pllx = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP2) & SENSOR_TEMP2_PLLX_TEMP_MASK);
|
||||
|
||||
if (board::GetSocType() == HocClkSocType_Erista) {
|
||||
temps.mem = TranslateTemp(ReadReg(socthermVa, SENSOR_TEMP2) >> 16);
|
||||
} else {
|
||||
temps.mem = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeSoctherm() {
|
||||
|
||||
Reference in new issue
Block a user