/* * Copyright (c) Souldbminer and Horizon OC Contributors * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* -------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * , , * wrote this file. As long as you retain this notice you can do whatever you * want with this stuff. If you meet any of us some day, and you think this * stuff is worth it, you can buy us a beer in return. - The sys-clk authors * -------------------------------------------------------------------------- */ #include #include "board.h" #include "errors.h" #define HOSSVC_HAS_CLKRST (hosversionAtLeast(8,0,0)) #define HOSSVC_HAS_TC (hosversionAtLeast(5,0,0)) #define NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD 0x80044715 Result nvCheck = 1; u32 fd = 0; static SysClkSocType g_socType = SysClkSocType_Erista; const char* Board::GetModuleName(SysClkModule module, bool pretty) { ASSERT_ENUM_VALID(SysClkModule, module); return sysclkFormatModule(module, pretty); } const char* Board::GetProfileName(SysClkProfile profile, bool pretty) { ASSERT_ENUM_VALID(SysClkProfile, profile); return sysclkFormatProfile(profile, pretty); } const char* Board::GetThermalSensorName(SysClkThermalSensor sensor, bool pretty) { ASSERT_ENUM_VALID(SysClkThermalSensor, sensor); return sysclkFormatThermalSensor(sensor, pretty); } const char* Board::GetPowerSensorName(SysClkPowerSensor sensor, bool pretty) { ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); return sysclkFormatPowerSensor(sensor, pretty); } PcvModule Board::GetPcvModule(SysClkModule sysclkModule) { switch(sysclkModule) { case SysClkModule_CPU: return PcvModule_CpuBus; case SysClkModule_GPU: return PcvModule_GPU; case SysClkModule_MEM: return PcvModule_EMC; default: ASSERT_ENUM_VALID(SysClkModule, sysclkModule); } return (PcvModule)0; } PcvModuleId Board::GetPcvModuleId(SysClkModule sysclkModule) { PcvModuleId pcvModuleId; Result rc = pcvGetModuleId(&pcvModuleId, GetPcvModule(sysclkModule)); ASSERT_RESULT_OK(rc, "pcvGetModuleId"); return pcvModuleId; } void Board::Initialize() { Result rc = 0; if(HOSSVC_HAS_CLKRST) { rc = clkrstInitialize(); ASSERT_RESULT_OK(rc, "clkrstInitialize"); } else { rc = pcvInitialize(); ASSERT_RESULT_OK(rc, "pcvInitialize"); } rc = apmExtInitialize(); ASSERT_RESULT_OK(rc, "apmExtInitialize"); rc = psmInitialize(); ASSERT_RESULT_OK(rc, "psmInitialize"); if(HOSSVC_HAS_TC) { rc = tcInitialize(); ASSERT_RESULT_OK(rc, "tcInitialize"); } rc = max17050Initialize(); ASSERT_RESULT_OK(rc, "max17050Initialize"); rc = tmp451Initialize(); ASSERT_RESULT_OK(rc, "tmp451Initialize"); // u32 fd = 0; // if (R_SUCCEEDED(nvInitialize())) nvCheck = nvOpen(&fd, "/dev/nvhost-ctrl-gpu"); FetchHardwareInfos(); } void Board::Exit() { if(HOSSVC_HAS_CLKRST) { clkrstExit(); } else { pcvExit(); } apmExtExit(); psmExit(); if(HOSSVC_HAS_TC) { tcExit(); } max17050Exit(); tmp451Exit(); nvExit(); } SysClkProfile Board::GetProfile() { std::uint32_t mode = 0; Result rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); if(mode) { return SysClkProfile_Docked; } PsmChargerType chargerType; rc = psmGetChargerType(&chargerType); ASSERT_RESULT_OK(rc, "psmGetChargerType"); if(chargerType == PsmChargerType_EnoughPower) { return SysClkProfile_HandheldChargingOfficial; } else if(chargerType == PsmChargerType_LowPower) { return SysClkProfile_HandheldChargingUSB; } return SysClkProfile_Handheld; } void Board::SetHz(SysClkModule module, std::uint32_t hz) { Result rc = 0; if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); rc = clkrstSetClockRate(&session, hz); ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); clkrstCloseSession(&session); } else { rc = pcvSetClockRate(Board::GetPcvModule(module), hz); ASSERT_RESULT_OK(rc, "pcvSetClockRate"); } } std::uint32_t Board::GetHz(SysClkModule module) { Result rc = 0; std::uint32_t hz = 0; if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); rc = clkrstGetClockRate(&session, &hz); ASSERT_RESULT_OK(rc, "clkrstSetClockRate"); clkrstCloseSession(&session); } else { rc = pcvGetClockRate(Board::GetPcvModule(module), &hz); ASSERT_RESULT_OK(rc, "pcvGetClockRate"); } return hz; } std::uint32_t Board::GetRealHz(SysClkModule module) { switch(module) { case SysClkModule_CPU: return t210ClkCpuFreq(); case SysClkModule_GPU: return t210ClkGpuFreq(); case SysClkModule_MEM: return t210ClkMemFreq(); default: ASSERT_ENUM_VALID(SysClkModule, module); } return 0; } void Board::GetFreqList(SysClkModule module, std::uint32_t* outList, std::uint32_t maxCount, std::uint32_t* outCount) { Result rc = 0; PcvClockRatesListType type; s32 tmpInMaxCount = maxCount; s32 tmpOutCount = 0; if(HOSSVC_HAS_CLKRST) { ClkrstSession session = {0}; rc = clkrstOpenSession(&session, Board::GetPcvModuleId(module), 3); ASSERT_RESULT_OK(rc, "clkrstOpenSession"); rc = clkrstGetPossibleClockRates(&session, outList, tmpInMaxCount, &type, &tmpOutCount); ASSERT_RESULT_OK(rc, "clkrstGetPossibleClockRates"); clkrstCloseSession(&session); } else { rc = pcvGetPossibleClockRates(Board::GetPcvModule(module), outList, tmpInMaxCount, &type, &tmpOutCount); ASSERT_RESULT_OK(rc, "pcvGetPossibleClockRates"); } if(type != PcvClockRatesListType_Discrete) { ERROR_THROW("Unexpected PcvClockRatesListType: %u (module = %s)", type, Board::GetModuleName(module, false)); } *outCount = tmpOutCount; } void Board::ResetToStock() { Result rc = 0; if(hosversionAtLeast(9,0,0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); SysClkApmConfiguration* apmConfiguration = NULL; for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { if(sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } if(!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz); Board::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz); Board::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz); } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); rc = apmExtSysRequestPerformanceMode(mode); ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } void Board::ResetToStockCpu() { Result rc = 0; if(hosversionAtLeast(9,0,0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); SysClkApmConfiguration* apmConfiguration = NULL; for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { if(sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } if(!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz); } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); rc = apmExtSysRequestPerformanceMode(mode); ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } void Board::ResetToStockMem() { Result rc = 0; if(hosversionAtLeast(9,0,0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); SysClkApmConfiguration* apmConfiguration = NULL; for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { if(sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } if(!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz); } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); rc = apmExtSysRequestPerformanceMode(mode); ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } void Board::ResetToStockGpu() { Result rc = 0; if(hosversionAtLeast(9,0,0)) { std::uint32_t confId = 0; rc = apmExtGetCurrentPerformanceConfiguration(&confId); ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration"); SysClkApmConfiguration* apmConfiguration = NULL; for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++) { if(sysclk_g_apm_configurations[i].id == confId) { apmConfiguration = &sysclk_g_apm_configurations[i]; break; } } if(!apmConfiguration) { ERROR_THROW("Unknown apm configuration: %x", confId); } Board::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz); } else { std::uint32_t mode = 0; rc = apmExtGetPerformanceMode(&mode); ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode"); rc = apmExtSysRequestPerformanceMode(mode); ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode"); } } std::uint32_t Board::GetTemperatureMilli(SysClkThermalSensor sensor) { std::int32_t millis = 0; if(sensor == SysClkThermalSensor_SOC) { millis = tmp451TempSoc(); } else if(sensor == SysClkThermalSensor_PCB) { millis = tmp451TempPcb(); } else if(sensor == SysClkThermalSensor_Skin) { if(HOSSVC_HAS_TC) { Result rc; rc = tcGetSkinTemperatureMilliC(&millis); ASSERT_RESULT_OK(rc, "tcGetSkinTemperatureMilliC"); } } else { ASSERT_ENUM_VALID(SysClkThermalSensor, sensor); } return std::max(0, millis); } std::int32_t Board::GetPowerMw(SysClkPowerSensor sensor) { switch(sensor) { case SysClkPowerSensor_Now: return max17050PowerNow(); case SysClkPowerSensor_Avg: return max17050PowerAvg(); default: ASSERT_ENUM_VALID(SysClkPowerSensor, sensor); } return 0; } std::uint32_t Board::GetPartLoad(SysClkPartLoad loadSource) { // u32 temp, GPU_Load_u = 0; switch(loadSource) { case SysClkPartLoad_EMC: return t210EmcLoadAll(); case SysClkPartLoad_EMCCpu: return t210EmcLoadCpu(); // case HocClkPartLoad_GPU: // #define gpu_samples_average 10 // // nvIoctl(fd, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &temp); // GPU_Load_u = ((GPU_Load_u * (gpu_samples_average-1)) + temp) / gpu_samples_average; // return GPU_Load_u / 10; default: ASSERT_ENUM_VALID(SysClkPartLoad, loadSource); } return 0; } SysClkSocType Board::GetSocType() { return g_socType; } void Board::FetchHardwareInfos() { u64 sku = 0; Result rc = splInitialize(); ASSERT_RESULT_OK(rc, "splInitialize"); rc = splGetConfig(SplConfigItem_HardwareType, &sku); ASSERT_RESULT_OK(rc, "splGetConfig"); splExit(); switch(sku) { case 2 ... 5: g_socType = SysClkSocType_Mariko; break; default: g_socType = SysClkSocType_Erista; } }