hocclk: major code refactor

move everything into its own directory, clean codebase up a lot
This commit is contained in:
souldbminersmwc
2026-05-08 22:43:14 -04:00
parent 65dfa8f48a
commit 3ca1f17e4d
78 changed files with 138 additions and 263 deletions

View File

@@ -0,0 +1,483 @@
/*
* 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
* --------------------------------------------------------------------------
*/
#include "config.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <ctime>
#include <map>
#include <string>
#include <atomic>
#include <initializer_list>
#include <minIni.h>
#include "../hos/apm_ext.h"
#include <i2c.h>
#include <t210.h>
#include <max17050.h>
#include <tmp451.h>
#include <ipc_server.h>
#include <lockable_mutex.h>
#include "../board/board.hpp"
#include "errors.hpp"
#include "file_utils.hpp"
namespace config {
uint64_t configValues[HocClkConfigValue_EnumMax];
namespace {
bool gLoaded = false;
std::string gPath;
time_t gMtime = 0;
std::atomic_bool gEnabled{false};
std::uint32_t gOverrideFreqs[HocClkModule_EnumMax];
std::map<std::tuple<std::uint64_t, HocClkProfile, HocClkModule>, std::uint32_t> gProfileMHzMap;
std::map<std::uint64_t, std::uint8_t> gProfileCountMap;
LockableMutex gConfigMutex;
LockableMutex gOverrideMutex;
time_t CheckModificationTime() {
time_t mtime = 0;
struct stat st;
if (stat(gPath.c_str(), &st) == 0) {
mtime = st.st_mtime;
}
return mtime;
}
std::uint32_t FindClockMHz(std::uint64_t tid, HocClkModule module, HocClkProfile profile) {
if (gLoaded) {
auto it = gProfileMHzMap.find(std::make_tuple(tid, profile, module));
if (it != gProfileMHzMap.end()) {
return it->second;
}
}
return 0;
}
std::uint32_t FindClockHzFromProfiles(std::uint64_t tid, HocClkModule module, std::initializer_list<HocClkProfile> profiles, u32 mhzMultiplier = 1000000) {
std::uint32_t mhz = 0;
if (gLoaded) {
for (auto profile: profiles) {
mhz = FindClockMHz(tid, module, profile);
if (mhz) {
break;
}
}
}
return std::max((std::uint32_t)0, mhz * mhzMultiplier);
}
int BrowseIniFunc(const char* section, const char* key, const char* value, void* userdata) {
(void)userdata;
std::uint64_t input;
if (!strcmp(section, CONFIG_VAL_SECTION)) {
for (unsigned int kval = 0; kval < HocClkConfigValue_EnumMax; kval++) {
if (!strcmp(key, hocclkFormatConfigValue((HocClkConfigValue)kval, false))) {
input = strtoul(value, NULL, 0);
if (!hocclkValidConfigValue((HocClkConfigValue)kval, input)) {
input = hocclkDefaultConfigValue((HocClkConfigValue)kval);
fileUtils::LogLine("[cfg] Invalid value for key '%s' in section '%s': using default %d", key, section, input);
}
configValues[kval] = input;
return 1;
}
}
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Unrecognized config value", key, section);
return 1;
}
std::uint64_t tid = strtoul(section, NULL, 16);
if (!tid || strlen(section) != 16) {
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Invalid TitleID", key, section);
return 1;
}
HocClkProfile parsedProfile = HocClkProfile_EnumMax;
HocClkModule parsedModule = HocClkModule_EnumMax;
for (unsigned int profile = 0; profile < HocClkProfile_EnumMax; profile++) {
const char* profileCode = board::GetProfileName((HocClkProfile)profile, false);
size_t profileCodeLen = strlen(profileCode);
if (!strncmp(key, profileCode, profileCodeLen) && key[profileCodeLen] == '_') {
const char* subkey = key + profileCodeLen + 1;
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
const char* moduleCode = board::GetModuleName((HocClkModule)module, false);
size_t moduleCodeLen = strlen(moduleCode);
if (!strncmp(subkey, moduleCode, moduleCodeLen) && subkey[moduleCodeLen] == '\0') {
parsedProfile = (HocClkProfile)profile;
parsedModule = (HocClkModule)module;
}
}
}
}
if (parsedModule == HocClkModule_EnumMax || parsedProfile == HocClkProfile_EnumMax) {
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Unrecognized key", key, section);
return 1;
}
std::uint32_t mhz = strtoul(value, NULL, 10);
if (!mhz) {
fileUtils::LogLine("[cfg] Skipping key '%s' in section '%s': Invalid value", key, section);
return 1;
}
gProfileMHzMap[std::make_tuple(tid, parsedProfile, parsedModule)] = mhz;
auto it = gProfileCountMap.find(tid);
if (it == gProfileCountMap.end()) {
gProfileCountMap[tid] = 1;
} else {
it->second++;
}
return 1;
}
void Close() {
gLoaded = false;
gProfileMHzMap.clear();
gProfileCountMap.clear();
for (unsigned int i = 0; i < HocClkConfigValue_EnumMax; i++) {
configValues[i] = hocclkDefaultConfigValue((HocClkConfigValue)i);
}
}
void Load() {
fileUtils::LogLine("[cfg] Reading %s", gPath.c_str());
Close();
gMtime = CheckModificationTime();
if (!gMtime) {
fileUtils::LogLine("[cfg] Error finding file");
} else if (!ini_browse(&BrowseIniFunc, nullptr, gPath.c_str())) {
fileUtils::LogLine("[cfg] Error loading file");
}
gLoaded = true;
}
}
void Initialize() {
gPath = FILE_CONFIG_DIR "/config.ini";
gLoaded = false;
gProfileMHzMap.clear();
gProfileCountMap.clear();
gMtime = 0;
gEnabled = false;
for (unsigned int i = 0; i < HocClkModule_EnumMax; i++) {
gOverrideFreqs[i] = 0;
}
for (unsigned int i = 0; i < HocClkConfigValue_EnumMax; i++) {
configValues[i] = hocclkDefaultConfigValue((HocClkConfigValue)i);
}
}
void Exit() {
std::scoped_lock lock{gConfigMutex};
Close();
}
bool Refresh() {
std::scoped_lock lock{gConfigMutex};
if (!gLoaded || gMtime != CheckModificationTime()) {
Load();
return true;
}
return false;
}
bool HasProfilesLoaded() {
std::scoped_lock lock{gConfigMutex};
return gLoaded;
}
std::uint32_t GetAutoClockHz(std::uint64_t tid, HocClkModule module, HocClkProfile profile, bool returnRaw) {
std::scoped_lock lock{gConfigMutex};
switch (profile) {
case HocClkProfile_Handheld:
return FindClockHzFromProfiles(tid, module, {HocClkProfile_Handheld}, returnRaw ? 1 : 1000000);
case HocClkProfile_HandheldCharging:
case HocClkProfile_HandheldChargingUSB:
return FindClockHzFromProfiles(tid, module, {HocClkProfile_HandheldChargingUSB, HocClkProfile_HandheldCharging, HocClkProfile_Handheld}, returnRaw ? 1 : 1000000);
case HocClkProfile_HandheldChargingOfficial:
return FindClockHzFromProfiles(tid, module, {HocClkProfile_HandheldChargingOfficial, HocClkProfile_HandheldCharging, HocClkProfile_Handheld}, returnRaw ? 1 : 1000000);
case HocClkProfile_Docked:
return FindClockHzFromProfiles(tid, module, {HocClkProfile_Docked}, returnRaw ? 1 : 1000000);
default:
ERROR_THROW("Unhandled HocClkProfile: %u", profile);
}
return 0;
}
void GetProfiles(std::uint64_t tid, HocClkTitleProfileList* out_profiles) {
std::scoped_lock lock{gConfigMutex};
for (unsigned int profile = 0; profile < HocClkProfile_EnumMax; profile++) {
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
out_profiles->mhzMap[profile][module] = FindClockMHz(tid, (HocClkModule)module, (HocClkProfile)profile);
}
}
}
bool SetProfiles(std::uint64_t tid, HocClkTitleProfileList* profiles, bool immediate) {
std::scoped_lock lock{gConfigMutex};
uint8_t numProfiles = 0;
char section[17] = {0};
snprintf(section, sizeof(section), "%016lX", tid);
std::vector<std::string> keys;
std::vector<std::string> values;
keys.reserve(+HocClkProfile_EnumMax * +HocClkModule_EnumMax);
values.reserve(+HocClkProfile_EnumMax * +HocClkModule_EnumMax);
std::uint32_t* mhz = &profiles->mhz[0];
for (unsigned int profile = 0; profile < HocClkProfile_EnumMax; profile++) {
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
if (*mhz) {
numProfiles++;
std::string key = std::string(board::GetProfileName((HocClkProfile)profile, false)) +
"_" +
board::GetModuleName((HocClkModule)module, false);
std::string value = std::to_string(*mhz);
keys.push_back(key);
values.push_back(value);
}
mhz++;
}
}
std::vector<const char*> keyPointers;
std::vector<const char*> valuePointers;
keyPointers.reserve(keys.size() + 1);
valuePointers.reserve(values.size() + 1);
for (size_t i = 0; i < keys.size(); i++) {
keyPointers.push_back(keys[i].c_str());
valuePointers.push_back(values[i].c_str());
}
keyPointers.push_back(NULL);
valuePointers.push_back(NULL);
if (!ini_putsection(section, keyPointers.data(), valuePointers.data(), gPath.c_str())) {
return false;
}
if (immediate) {
mhz = &profiles->mhz[0];
gProfileCountMap[tid] = numProfiles;
for (unsigned int profile = 0; profile < HocClkProfile_EnumMax; profile++) {
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
if (*mhz) {
gProfileMHzMap[std::make_tuple(tid, (HocClkProfile)profile, (HocClkModule)module)] = *mhz;
} else {
gProfileMHzMap.erase(std::make_tuple(tid, (HocClkProfile)profile, (HocClkModule)module));
}
mhz++;
}
}
}
return true;
}
std::uint8_t GetProfileCount(std::uint64_t tid) {
auto it = gProfileCountMap.find(tid);
if (it == gProfileCountMap.end()) {
return 0;
}
return it->second;
}
void SetEnabled(bool enabled) {
gEnabled = enabled;
}
bool Enabled() {
return gEnabled;
}
void SetOverrideHz(HocClkModule module, std::uint32_t hz) {
ASSERT_ENUM_VALID(HocClkModule, module);
std::scoped_lock lock{gOverrideMutex};
gOverrideFreqs[module] = hz;
}
std::uint32_t GetOverrideHz(HocClkModule module) {
ASSERT_ENUM_VALID(HocClkModule, module);
std::scoped_lock lock{gOverrideMutex};
return gOverrideFreqs[module];
}
std::uint64_t GetConfigValue(HocClkConfigValue kval) {
ASSERT_ENUM_VALID(HocClkConfigValue, kval);
std::scoped_lock lock{gConfigMutex};
return configValues[kval];
}
const char* GetConfigValueName(HocClkConfigValue kval, bool pretty) {
ASSERT_ENUM_VALID(HocClkConfigValue, kval);
return hocclkFormatConfigValue(kval, pretty);
}
void GetConfigValues(HocClkConfigValueList* out_configValues) {
std::scoped_lock lock{gConfigMutex};
for (unsigned int kval = 0; kval < HocClkConfigValue_EnumMax; kval++) {
out_configValues->values[kval] = configValues[kval];
}
}
bool SetConfigValues(HocClkConfigValueList* configValues, bool immediate) {
std::scoped_lock lock{gConfigMutex};
std::vector<const char*> iniKeys;
std::vector<std::string> iniValues;
iniKeys.reserve(HocClkConfigValue_EnumMax + 1);
iniValues.reserve(HocClkConfigValue_EnumMax);
for (unsigned int kval = 0; kval < HocClkConfigValue_EnumMax; kval++) {
if (!hocclkValidConfigValue((HocClkConfigValue)kval, configValues->values[kval]) ||
configValues->values[kval] == hocclkDefaultConfigValue((HocClkConfigValue)kval)) {
continue;
}
iniValues.push_back(std::to_string(configValues->values[kval]));
iniKeys.push_back(hocclkFormatConfigValue((HocClkConfigValue)kval, false));
}
iniKeys.push_back(NULL);
std::vector<const char*> valuePointers;
valuePointers.reserve(iniValues.size() + 1);
for (const auto& val : iniValues) {
valuePointers.push_back(val.c_str());
}
valuePointers.push_back(NULL);
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
return false;
}
if (immediate) {
for (unsigned int kval = 0; kval < HocClkConfigValue_EnumMax; kval++) {
if (hocclkValidConfigValue((HocClkConfigValue)kval, configValues->values[kval])) {
config::configValues[kval] = configValues->values[kval];
} else {
config::configValues[kval] = hocclkDefaultConfigValue((HocClkConfigValue)kval);
}
}
}
return true;
}
bool ResetConfigValue(HocClkConfigValue kval) {
if (!HOCCLK_ENUM_VALID(HocClkConfigValue, kval)) {
fileUtils::LogLine("[cfg] Invalid HocClkConfigValue: %u", kval);
return false;
}
std::scoped_lock lock{gConfigMutex};
std::uint64_t defaultValue = hocclkDefaultConfigValue(kval);
std::vector<const char*> iniKeys;
std::vector<std::string> iniValues;
iniKeys.reserve(2);
iniValues.reserve(1);
iniKeys.push_back(hocclkFormatConfigValue(kval, false));
iniValues.push_back("");
iniKeys.push_back(NULL);
std::vector<const char*> valuePointers;
valuePointers.reserve(iniValues.size() + 1);
for (const auto& val : iniValues) {
valuePointers.push_back(val.c_str());
}
valuePointers.push_back(NULL);
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
fileUtils::LogLine("[cfg] Failed to reset config value %u in INI", kval);
return false;
}
configValues[kval] = defaultValue;
fileUtils::LogLine("[cfg] Reset config value %u to default: %llu", kval, defaultValue);
return true;
}
bool SetConfigValue(HocClkConfigValue kval, std::uint64_t value, bool immediate) {
if (!HOCCLK_ENUM_VALID(HocClkConfigValue, kval)) {
return false;
}
if (!hocclkValidConfigValue(kval, value)) {
return false;
}
std::scoped_lock lock{gConfigMutex};
std::vector<const char*> iniKeys;
std::vector<std::string> iniValues;
iniKeys.reserve(2);
iniValues.reserve(1);
iniKeys.push_back(hocclkFormatConfigValue(kval, false));
iniValues.push_back(std::to_string(value));
iniKeys.push_back(NULL);
std::vector<const char*> valuePointers;
valuePointers.reserve(2);
valuePointers.push_back(iniValues[0].c_str());
valuePointers.push_back(NULL);
if (!ini_putsection(CONFIG_VAL_SECTION, iniKeys.data(), valuePointers.data(), gPath.c_str())) {
return false;
}
if (immediate) {
configValues[kval] = value;
}
return true;
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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
#include <hocclk.h>
#include <switch.h>
#define CONFIG_VAL_SECTION "values"
namespace config {
void Initialize();
void Exit();
bool Refresh();
bool HasProfilesLoaded();
std::uint8_t GetProfileCount(std::uint64_t tid);
void GetProfiles(std::uint64_t tid, HocClkTitleProfileList* out_profiles);
bool SetProfiles(std::uint64_t tid, HocClkTitleProfileList* profiles, bool immediate);
std::uint32_t GetAutoClockHz(std::uint64_t tid, HocClkModule module, HocClkProfile profile, bool returnRaw);
void SetEnabled(bool enabled);
bool Enabled();
void SetOverrideHz(HocClkModule module, std::uint32_t hz);
std::uint32_t GetOverrideHz(HocClkModule module);
std::uint64_t GetConfigValue(HocClkConfigValue val);
const char* GetConfigValueName(HocClkConfigValue val, bool pretty);
void GetConfigValues(HocClkConfigValueList* out_configValues);
bool SetConfigValues(HocClkConfigValueList* configValues, bool immediate);
bool ResetConfigValue(HocClkConfigValue kval);
bool SetConfigValue(HocClkConfigValue kval, std::uint64_t value, bool immediate = true);
extern uint64_t configValues[HocClkConfigValue_EnumMax];
}

View File

@@ -0,0 +1,41 @@
/*
* 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
* --------------------------------------------------------------------------
*/
#include "errors.hpp"
#include "file_utils.hpp"
#include <cstdarg>
#include <cstring>
namespace errors {
void ThrowException(const char* format, ...) {
va_list args;
va_start(args, format);
fileUtils::LogLine(format, args);
va_end(args);
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen));
// throw std::runtime_error(msg);
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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
#include <switch.h>
#include <stdexcept>
#define ERROR_THROW(format, ...) errors::ThrowException(format "\n in %s:%u", ##__VA_ARGS__, __FILE__, __LINE__)
#define ERROR_RESULT_THROW(rc, format, ...) ERROR_THROW(format "\n RC: [0x%x] %04d-%04d", ##__VA_ARGS__, rc, R_MODULE(rc), R_DESCRIPTION(rc))
#define ASSERT_RESULT_OK(rc, format, ...) \
if (R_FAILED(rc)) \
{ \
ERROR_RESULT_THROW(rc, "ASSERT_RESULT_OK: " format, ##__VA_ARGS__); \
}
#define ASSERT_ENUM_VALID(n, v) \
if (!HOCCLK_ENUM_VALID(n, v)) { \
ERROR_THROW("No such %s: %u", #n, v); \
}
namespace errors {
void ThrowException(const char* format, ...);
}

View File

@@ -0,0 +1,213 @@
/*
* 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 <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
* --------------------------------------------------------------------------
*/
#include "file_utils.hpp"
#include "../hos/apm_ext.h"
#include <i2c.h>
#include <t210.h>
#include <max17050.h>
#include <tmp451.h>
#include <ipc_server.h>
#include <lockable_mutex.h>
extern "C" void __libnx_init_time(void);
namespace fileUtils {
namespace {
u64 bootTimeS;
LockableMutex g_log_mutex;
LockableMutex g_csv_mutex;
std::atomic_bool g_has_initialized = false;
bool g_log_enabled = false;
std::uint64_t g_last_flag_check = 0;
void RefreshFlags(bool force) {
std::uint64_t now = armTicksToNs(armGetSystemTick());
if (!force && (now - g_last_flag_check) < FILE_FLAG_CHECK_INTERVAL_NS) {
return;
}
FILE* file = fopen(FILE_LOG_FLAG_PATH, "r");
if (file) {
g_log_enabled = true;
fclose(file);
} else {
g_log_enabled = false;
}
g_last_flag_check = now;
}
void InitializeThreadFunc(void* args) {
Initialize();
}
}
bool IsInitialized() {
return g_has_initialized;
}
bool IsLogEnabled() {
return g_log_enabled;
}
void LogLine(const char* format, ...) {
std::scoped_lock lock{g_log_mutex};
va_list args;
va_start(args, format);
if (g_has_initialized) {
RefreshFlags(false);
if (g_log_enabled) {
FILE* file = fopen(FILE_LOG_FILE_PATH, "a");
if (file) {
timespec now = {};
clock_gettime(CLOCK_REALTIME, &now);
fprintf(file, "[%luls] ", now.tv_sec - bootTimeS);
vfprintf(file, format, args);
fprintf(file, "\n");
fclose(file);
}
}
}
va_end(args);
}
void WriteContextToCsv(const HocClkContext* context) {
std::scoped_lock lock{g_csv_mutex};
FILE* file = fopen(FILE_CONTEXT_CSV_PATH, "a");
if (file) {
// Print header
if (!ftell(file)) {
fprintf(file, "timestamp,profile,app_tid");
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
fprintf(file, ",%s_hz", hocclkFormatModule((HocClkModule)module, false));
}
for (unsigned int sensor = 0; sensor < HocClkThermalSensor_EnumMax; sensor++) {
fprintf(file, ",%s_milliC", hocclkFormatThermalSensor((HocClkThermalSensor)sensor, false));
}
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
fprintf(file, ",%s_real_hz", hocclkFormatModule((HocClkModule)module, false));
}
for (unsigned int sensor = 0; sensor < HocClkPowerSensor_EnumMax; sensor++) {
fprintf(file, ",%s_mw", hocclkFormatPowerSensor((HocClkPowerSensor)sensor, false));
}
fprintf(file, "\n");
}
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
fprintf(file, "%ld%03ld,%s,%016lx", now.tv_sec, now.tv_nsec / 1000000UL, hocclkFormatProfile(context->profile, false), context->applicationId);
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
fprintf(file, ",%d", context->freqs[module]);
}
for (unsigned int sensor = 0; sensor < HocClkThermalSensor_EnumMax; sensor++) {
fprintf(file, ",%d", context->temps[sensor]);
}
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
fprintf(file, ",%d", context->realFreqs[module]);
}
for (unsigned int sensor = 0; sensor < HocClkPowerSensor_EnumMax; sensor++) {
fprintf(file, ",%d", context->power[sensor]);
}
fprintf(file, "\n");
fclose(file);
}
}
void SetBootTime() {
timespec bootTime = {};
clock_gettime(CLOCK_REALTIME, &bootTime);
bootTimeS = bootTime.tv_sec;
}
void InitializeAsync() {
Thread initThread = {0};
threadCreate(&initThread, InitializeThreadFunc, NULL, NULL, 0x4000, 0x15, 0);
threadStart(&initThread);
}
Result Initialize() {
Result rc = 0;
if (R_SUCCEEDED(rc)) {
rc = timeInitialize();
}
__libnx_init_time();
timeExit();
SetBootTime();
if (R_SUCCEEDED(rc)) {
rc = fsInitialize();
}
if (R_SUCCEEDED(rc)) {
rc = fsdevMountSdmc();
}
if (R_SUCCEEDED(rc)) {
RefreshFlags(true);
g_has_initialized = true;
LogLine("=== hoc-clk " TARGET_VERSION " ===");
LogLine("by m4xw, natinusala, p-sam, Souldbminer, Lightos_ and Dominatorul");
}
return rc;
}
void Exit() {
if (!g_has_initialized) {
return;
}
g_has_initialized = false;
g_log_enabled = false;
fsdevUnmountAll();
fsExit();
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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
#include <switch.h>
#include <time.h>
#include <vector>
#include <string>
#include <atomic>
#include <cstdarg>
#include <hocclk.h>
#define FILE_CONFIG_DIR "/config/" CONFIG_DIR
#define FILE_FLAG_CHECK_INTERVAL_NS (10000ULL * 1000000000ULL)
#define FILE_CONTEXT_CSV_PATH FILE_CONFIG_DIR "/context.csv"
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
namespace fileUtils {
void Exit();
Result Initialize();
bool IsInitialized();
bool IsLogEnabled();
void InitializeAsync();
void LogLine(const char* format, ...);
void WriteContextToCsv(const HocClkContext* context);
}

View File

@@ -0,0 +1,308 @@
/*
* 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 "kip.hpp"
#include "../i2c/i2cDrv.h"
#include "../board/board.hpp"
#include "file_utils.hpp"
#include "../mgr/clock_manager.hpp"
namespace kip {
bool kipAvailable = false;
void SetKipData()
{
// TODO: figure out if this REALLY causes issues (i doubt it)
// if(board::GetSocType() == HocClkSocType_Mariko) {
// if(R_FAILED(I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt) / 1000))) {
// fileUtils::LogLine("[clock_manager] Failed set i2c vddq");
// notification::writeNotification("Horizon OC\nFailed to write I2C\nwhile setting vddq");
// }
// }
CustomizeTable table;
FILE* fp;
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) {
notification::writeNotification("Horizon OC\nKip opening failed");
kipAvailable = false;
return;
} else {
kipAvailable = true;
fclose(fp);
}
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to read KIP file");
notification::writeNotification("Horizon OC\nKip read failed");
return;
}
// if(cust_get_cust_rev(&table) != CUST_REV) {
// fileUtils::LogLine("Revision: %u", cust_get_cust_rev(&table));
// notification::writeNotification("Horizon OC\nKip version mismatch\nPlease reinstall Horizon OC");
// return;
// }
// CUST_WRITE_FIELD_BATCH(&table, mtcConf, config::GetConfigValue(KipConfigValue_mtcConf));
CUST_WRITE_FIELD_BATCH(&table, hpMode, config::GetConfigValue(KipConfigValue_hpMode));
CUST_WRITE_FIELD_BATCH(&table, commonEmcMemVolt, config::GetConfigValue(KipConfigValue_commonEmcMemVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock1, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock1));
CUST_WRITE_FIELD_BATCH(&table, eristaEmcMaxClock2, config::GetConfigValue(KipConfigValue_eristaEmcMaxClock2));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcMaxClock, config::GetConfigValue(KipConfigValue_marikoEmcMaxClock));
CUST_WRITE_FIELD_BATCH(&table, marikoEmcVddqVolt, config::GetConfigValue(KipConfigValue_marikoEmcVddqVolt));
CUST_WRITE_FIELD_BATCH(&table, emcDvbShift, config::GetConfigValue(KipConfigValue_emcDvbShift));
CUST_WRITE_FIELD_BATCH(&table, marikoSocVmax, config::GetConfigValue(KipConfigValue_marikoSocVmax));
CUST_WRITE_FIELD_BATCH(&table, t1_tRCD, config::GetConfigValue(KipConfigValue_t1_tRCD));
CUST_WRITE_FIELD_BATCH(&table, t2_tRP, config::GetConfigValue(KipConfigValue_t2_tRP));
CUST_WRITE_FIELD_BATCH(&table, t3_tRAS, config::GetConfigValue(KipConfigValue_t3_tRAS));
CUST_WRITE_FIELD_BATCH(&table, t4_tRRD, config::GetConfigValue(KipConfigValue_t4_tRRD));
CUST_WRITE_FIELD_BATCH(&table, t5_tRFC, config::GetConfigValue(KipConfigValue_t5_tRFC));
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW, config::GetConfigValue(KipConfigValue_t6_tRTW));
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR, config::GetConfigValue(KipConfigValue_t7_tWTR));
CUST_WRITE_FIELD_BATCH(&table, t8_tREFI, config::GetConfigValue(KipConfigValue_t8_tREFI));
CUST_WRITE_FIELD_BATCH(&table, stepMode, config::GetConfigValue(KipConfigValue_stepMode));
CUST_WRITE_FIELD_BATCH(&table, timingEmcTbreak, config::GetConfigValue(KipConfigValue_timingEmcTbreak));
CUST_WRITE_FIELD_BATCH(&table, low_t6_tRTW, config::GetConfigValue(KipConfigValue_low_t6_tRTW));
CUST_WRITE_FIELD_BATCH(&table, low_t7_tWTR, config::GetConfigValue(KipConfigValue_low_t7_tWTR));
CUST_WRITE_FIELD_BATCH(&table, t2_tRP_cap, config::GetConfigValue(KipConfigValue_t2_tRP_cap));
CUST_WRITE_FIELD_BATCH(&table, readLatency1333, config::GetConfigValue(KipConfigValue_read_latency_1333));
CUST_WRITE_FIELD_BATCH(&table, readLatency1600, config::GetConfigValue(KipConfigValue_read_latency_1600));
CUST_WRITE_FIELD_BATCH(&table, readLatency1866, config::GetConfigValue(KipConfigValue_read_latency_1866));
CUST_WRITE_FIELD_BATCH(&table, readLatency2133, config::GetConfigValue(KipConfigValue_read_latency_2133));
CUST_WRITE_FIELD_BATCH(&table, writeLatency1333, config::GetConfigValue(KipConfigValue_write_latency_1333));
CUST_WRITE_FIELD_BATCH(&table, writeLatency1600, config::GetConfigValue(KipConfigValue_write_latency_1600));
CUST_WRITE_FIELD_BATCH(&table, writeLatency1866, config::GetConfigValue(KipConfigValue_write_latency_1866));
CUST_WRITE_FIELD_BATCH(&table, writeLatency2133, config::GetConfigValue(KipConfigValue_write_latency_2133));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_read_latency, config::GetConfigValue(KipConfigValue_mem_burst_read_latency));
CUST_WRITE_FIELD_BATCH(&table, mem_burst_write_latency, config::GetConfigValue(KipConfigValue_mem_burst_write_latency));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUV, config::GetConfigValue(KipConfigValue_eristaCpuUV));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuVmin, config::GetConfigValue(KipConfigValue_eristaCpuVmin));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuMaxVolt, config::GetConfigValue(KipConfigValue_eristaCpuMaxVolt));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuUnlock, config::GetConfigValue(KipConfigValue_eristaCpuUnlock));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVLow, config::GetConfigValue(KipConfigValue_marikoCpuUVLow));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuUVHigh, config::GetConfigValue(KipConfigValue_marikoCpuUVHigh));
CUST_WRITE_FIELD_BATCH(&table, tableConf, config::GetConfigValue(KipConfigValue_tableConf));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuLowVmin, config::GetConfigValue(KipConfigValue_marikoCpuLowVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuHighVmin, config::GetConfigValue(KipConfigValue_marikoCpuHighVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxVolt, config::GetConfigValue(KipConfigValue_marikoCpuMaxVolt));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuMaxClock, config::GetConfigValue(KipConfigValue_marikoCpuMaxClock));
CUST_WRITE_FIELD_BATCH(&table, eristaCpuBoostClock, config::GetConfigValue(KipConfigValue_eristaCpuBoostClock));
CUST_WRITE_FIELD_BATCH(&table, marikoCpuBoostClock, config::GetConfigValue(KipConfigValue_marikoCpuBoostClock));
CUST_WRITE_FIELD_BATCH(&table, eristaGpuUV, config::GetConfigValue(KipConfigValue_eristaGpuUV));
CUST_WRITE_FIELD_BATCH(&table, eristaGpuVmin, config::GetConfigValue(KipConfigValue_eristaGpuVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuUV, config::GetConfigValue(KipConfigValue_marikoGpuUV));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmin, config::GetConfigValue(KipConfigValue_marikoGpuVmin));
CUST_WRITE_FIELD_BATCH(&table, marikoGpuVmax, config::GetConfigValue(KipConfigValue_marikoGpuVmax));
CUST_WRITE_FIELD_BATCH(&table, commonGpuVoltOffset, config::GetConfigValue(KipConfigValue_commonGpuVoltOffset));
CUST_WRITE_FIELD_BATCH(&table, gpuSpeedo, config::GetConfigValue(KipConfigValue_gpuSpeedo));
for (int i = 0; i < 24; i++) {
table.marikoGpuVoltArray[i] = config::GetConfigValue((HocClkConfigValue)(KipConfigValue_g_volt_76800 + i));
}
for (int i = 0; i < 27; i++) {
table.eristaGpuVoltArray[i] = config::GetConfigValue((HocClkConfigValue)(KipConfigValue_g_volt_e_76800 + i));
}
CUST_WRITE_FIELD_BATCH(&table, t6_tRTW_fine_tune, config::GetConfigValue(KipConfigValue_t6_tRTW_fine_tune));
CUST_WRITE_FIELD_BATCH(&table, t7_tWTR_fine_tune, config::GetConfigValue(KipConfigValue_t7_tWTR_fine_tune));
if (!cust_write_table("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to write KIP file");
notification::writeNotification("Horizon OC\nKip write failed");
}
HocClkConfigValueList configValues;
config::GetConfigValues(&configValues);
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
if (config::SetConfigValues(&configValues, false)) {
fileUtils::LogLine("[kip] KIP data set. CRC32: %ld (Cust Rev %ld)", configValues.values[KipCrc32], configValues.values[KipConfigValue_custRev]);
for (u64 i = KipConfigValue_hpMode; i < HocClkConfigValue_EnumMax; i++) {
fileUtils::LogLine("%s: %ld", hocclkFormatConfigValue((HocClkConfigValue)i, false), configValues.values[i]);
}
} else {
fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP");
notification::writeNotification("Horizon OC\nKip config set failed");
}
}
// I know this is very hacky, but the config system in the sysmodule doesn't really support writing
void GetKipData()
{
FILE* fp;
if (config::Refresh()) {
fp = fopen("sdmc:/atmosphere/kips/hoc.kip", "r");
if (fp == NULL) {
notification::writeNotification("Horizon OC\nKip opening failed");
kipAvailable = false;
return;
} else {
kipAvailable = true;
fclose(fp);
}
HocClkConfigValueList configValues;
config::GetConfigValues(&configValues);
CustomizeTable table;
if (!cust_read_and_cache("sdmc:/atmosphere/kips/hoc.kip", &table)) {
fileUtils::LogLine("[kip] Failed to read KIP file for GetKipData");
notification::writeNotification("Horizon OC\nKip read failed");
return;
}
// if(cust_get_cust_rev(&table) != CUST_REV) {
// notification::writeNotification("Horizon OC\nKip version mismatch\nPlease reinstall Horizon OC");
// return;
// }
if ((u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip") != config::GetConfigValue(KipCrc32) && !config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
SetKipData();
notification::writeNotification("Horizon OC\nKIP has been updated\nPlease reboot your console");
return;
}
if (config::GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) {
configValues.values[HocClkConfigValue_IsFirstLoad] = (u64)false;
notification::writeNotification("Horizon OC has been installed");
}
configValues.values[KipCrc32] = (u64)crc32::checksum_file("sdmc:/atmosphere/kips/hoc.kip"); // write checksum
// configValues.values[KipConfigValue_mtcConf] = cust_get_mtc_conf(&table);
clockManager::gContext.custRev = cust_get_cust_rev(&table);
u16 kipVersion = cust_get_kip_version(&table);
if (kipVersion != KIP_VERSION) {
notification::writeNotification("Horizon OC\nKip version mismatch detected!");
}
clockManager::gContext.kipVersion = kipVersion;
configValues.values[KipConfigValue_hpMode] = cust_get_hp_mode(&table);
configValues.values[KipConfigValue_commonEmcMemVolt] = cust_get_common_emc_volt(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock] = cust_get_erista_emc_max(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock1] = cust_get_erista_emc_max1(&table);
configValues.values[KipConfigValue_eristaEmcMaxClock2] = cust_get_erista_emc_max2(&table);
configValues.values[KipConfigValue_marikoEmcMaxClock] = cust_get_mariko_emc_max(&table);
configValues.values[KipConfigValue_marikoEmcVddqVolt] = cust_get_mariko_emc_vddq(&table);
configValues.values[KipConfigValue_emcDvbShift] = cust_get_emc_dvb_shift(&table);
configValues.values[KipConfigValue_marikoSocVmax] = cust_get_marikoSocVmax(&table);
configValues.values[KipConfigValue_t1_tRCD] = cust_get_tRCD(&table);
configValues.values[KipConfigValue_t2_tRP] = cust_get_tRP(&table);
configValues.values[KipConfigValue_t3_tRAS] = cust_get_tRAS(&table);
configValues.values[KipConfigValue_t4_tRRD] = cust_get_tRRD(&table);
configValues.values[KipConfigValue_t5_tRFC] = cust_get_tRFC(&table);
configValues.values[KipConfigValue_t6_tRTW] = cust_get_tRTW(&table);
configValues.values[KipConfigValue_t7_tWTR] = cust_get_tWTR(&table);
configValues.values[KipConfigValue_t8_tREFI] = cust_get_tREFI(&table);
configValues.values[KipConfigValue_stepMode] = cust_get_step_mode(&table);
configValues.values[KipConfigValue_timingEmcTbreak] = cust_get_timing_emc_tbreak(&table);
configValues.values[KipConfigValue_low_t6_tRTW] = cust_get_low_t6_tRTW(&table);
configValues.values[KipConfigValue_low_t7_tWTR] = cust_get_low_t7_tWTR(&table);
configValues.values[KipConfigValue_t2_tRP_cap] = cust_get_tRP_cap(&table);
configValues.values[KipConfigValue_read_latency_1333] = cust_get_read_latency_1333(&table);
configValues.values[KipConfigValue_read_latency_1600] = cust_get_read_latency_1600(&table);
configValues.values[KipConfigValue_read_latency_1866] = cust_get_read_latency_1866(&table);
configValues.values[KipConfigValue_read_latency_2133] = cust_get_read_latency_2133(&table);
configValues.values[KipConfigValue_write_latency_1333] = cust_get_write_latency_1333(&table);
configValues.values[KipConfigValue_write_latency_1600] = cust_get_write_latency_1600(&table);
configValues.values[KipConfigValue_write_latency_1866] = cust_get_write_latency_1866(&table);
configValues.values[KipConfigValue_write_latency_2133] = cust_get_write_latency_2133(&table);
configValues.values[KipConfigValue_mem_burst_read_latency] = cust_get_burst_read_lat(&table);
configValues.values[KipConfigValue_mem_burst_write_latency] = cust_get_burst_write_lat(&table);
configValues.values[KipConfigValue_eristaCpuUV] = cust_get_erista_cpu_uv(&table);
configValues.values[KipConfigValue_eristaCpuVmin] = cust_get_eristaCpuVmin(&table);
configValues.values[KipConfigValue_eristaCpuMaxVolt] = cust_get_erista_cpu_max_volt(&table);
configValues.values[KipConfigValue_eristaCpuUnlock] = cust_get_eristaCpuUnlock(&table);
configValues.values[KipConfigValue_marikoCpuUVLow] = cust_get_mariko_cpu_uv_low(&table);
configValues.values[KipConfigValue_marikoCpuUVHigh] = cust_get_mariko_cpu_uv_high(&table);
configValues.values[KipConfigValue_tableConf] = cust_get_table_conf(&table);
configValues.values[KipConfigValue_marikoCpuLowVmin] = cust_get_mariko_cpu_low_vmin(&table);
configValues.values[KipConfigValue_marikoCpuHighVmin] = cust_get_mariko_cpu_high_vmin(&table);
configValues.values[KipConfigValue_marikoCpuMaxVolt] = cust_get_mariko_cpu_max_volt(&table);
configValues.values[KipConfigValue_marikoCpuMaxClock] = cust_get_marikoCpuMaxClock(&table);
configValues.values[KipConfigValue_eristaCpuBoostClock] = cust_get_erista_cpu_boost(&table);
configValues.values[KipConfigValue_marikoCpuBoostClock] = cust_get_mariko_cpu_boost(&table);
configValues.values[KipConfigValue_eristaGpuUV] = cust_get_erista_gpu_uv(&table);
configValues.values[KipConfigValue_eristaGpuVmin] = cust_get_erista_gpu_vmin(&table);
configValues.values[KipConfigValue_marikoGpuUV] = cust_get_mariko_gpu_uv(&table);
configValues.values[KipConfigValue_marikoGpuVmin] = cust_get_mariko_gpu_vmin(&table);
configValues.values[KipConfigValue_marikoGpuVmax] = cust_get_mariko_gpu_vmax(&table);
configValues.values[KipConfigValue_commonGpuVoltOffset] = cust_get_common_gpu_offset(&table);
configValues.values[KipConfigValue_gpuSpeedo] = board::GetFuseData()->gpuSpeedo; // cust_get_gpu_speedo(&table);
for (int i = 0; i < 24; i++) {
configValues.values[KipConfigValue_g_volt_76800 + i] = cust_get_mariko_gpu_volt(&table, i);
}
for (int i = 0; i < 27; i++) {
configValues.values[KipConfigValue_g_volt_e_76800 + i] = cust_get_erista_gpu_volt(&table, i);
}
configValues.values[KipConfigValue_t7_tWTR_fine_tune] = cust_get_tWTR_fine_tune(&table);
configValues.values[KipConfigValue_t6_tRTW_fine_tune] = cust_get_tRTW_fine_tune(&table);
// if(cust_get_cust_rev(&table) == KIP_CUST_REV)
// return;
if (sizeof(HocClkConfigValueList) <= sizeof(configValues)) {
if (config::SetConfigValues(&configValues, false)) {
fileUtils::LogLine("[kip] KIP loaded. CRC32: %ld (Cust Rev %ld)", configValues.values[KipCrc32], configValues.values[KipConfigValue_custRev]);
for (u64 i = KipConfigValue_hpMode; i < HocClkConfigValue_EnumMax; i++) {
fileUtils::LogLine("%s: %ld", hocclkFormatConfigValue((HocClkConfigValue)i, false), configValues.values[i]);
}
} else {
fileUtils::LogLine("[kip] Warning: Failed to set config values from KIP");
notification::writeNotification("Horizon OC\nKip config set failed");
}
} else {
fileUtils::LogLine("[kip] Error: Config value list buffer size mismatch");
notification::writeNotification("Horizon OC\nConfig Buffer Mismatch");
}
} else {
fileUtils::LogLine("[kip] Config refresh error in GetKipData!");
notification::writeNotification("Horizon OC\nConfig refresh failed");
}
}
}

View File

@@ -0,0 +1,506 @@
/*
* 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 <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "config.hpp"
#include "file_utils.hpp"
#include <notification.h>
#include <crc32.h>
#pragma pack(push, 1)
namespace kip {
extern bool kipAvailable;
typedef struct {
u8 cust[4];
u32 custRev;
u32 kipVersion;
u32 hpMode;
u32 commonEmcMemVolt;
u32 eristaEmcMaxClock;
u32 eristaEmcMaxClock1;
u32 eristaEmcMaxClock2;
u32 stepMode;
u32 marikoEmcMaxClock;
u32 marikoEmcVddqVolt;
u32 emcDvbShift;
u32 marikoSocVmax;
// advanced config
u32 t1_tRCD;
u32 t2_tRP;
u32 t3_tRAS;
u32 t4_tRRD;
u32 t5_tRFC;
u32 t6_tRTW;
u32 t7_tWTR;
u32 t8_tREFI;
u32 t2_tRP_cap;
u32 timingEmcTbreak;
u32 low_t6_tRTW;
u32 low_t7_tWTR;
/* These latencies are arrays in loader, but it's easier to handle it this way in the configurator. */
u32 readLatency1333, readLatency1600, readLatency1866, readLatency2133;
u32 writeLatency1333, writeLatency1600, writeLatency1866, writeLatency2133;
u32 mem_burst_read_latency;
u32 mem_burst_write_latency;
u32 eristaCpuUV;
u32 eristaCpuVmin;
u32 eristaCpuMaxVolt;
u32 eristaCpuUnlock;
u32 marikoCpuUVLow;
u32 marikoCpuUVHigh;
u32 tableConf;
u32 marikoCpuLowVmin;
u32 marikoCpuHighVmin;
u32 marikoCpuMaxVolt;
u32 marikoCpuMaxClock;
u32 eristaCpuBoostClock;
u32 marikoCpuBoostClock;
u32 eristaGpuUV;
u32 eristaGpuVmin;
u32 marikoGpuUV;
u32 marikoGpuVmin;
u32 marikoGpuVmax;
u32 commonGpuVoltOffset;
u32 gpuSpeedo;
u32 eristaGpuVoltArray[27];
u32 marikoGpuVoltArray[24];
u32 t6_tRTW_fine_tune;
u32 t7_tWTR_fine_tune;
u32 reserved[60];
} CustomizeTable;
#pragma pack(pop)
#define CUST_MAGIC "CUST"
#define CUST_MAGIC_LEN 4
typedef struct {
FILE* file;
long offset;
CustomizeTable cached_table;
bool has_cache;
} CustHandle;
static inline bool cust_find_offset(FILE* f, long* out_offset) {
u8 buf[512];
long pos = 0;
fseek(f, 0, SEEK_SET);
while (1) {
size_t r = fread(buf, 1, sizeof(buf), f);
if (r < CUST_MAGIC_LEN) break;
for (size_t i = 0; i <= r - CUST_MAGIC_LEN; i++) {
if (memcmp(&buf[i], CUST_MAGIC, CUST_MAGIC_LEN) == 0) {
*out_offset = pos + (long)i;
return true;
}
}
pos += (long)(r - (CUST_MAGIC_LEN - 1));
fseek(f, pos, SEEK_SET);
}
return false;
}
static inline bool cust_read_table(const char* path, CustomizeTable* out) {
FILE* f = fopen(path, "rb");
if (!f) return false;
long off;
if (!cust_find_offset(f, &off)) {
fclose(f);
return false;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
if (off + (long)sizeof(CustomizeTable) > size) {
fclose(f);
return false;
}
fseek(f, off, SEEK_SET);
bool ok = fread(out, 1, sizeof(CustomizeTable), f) == sizeof(CustomizeTable);
fclose(f);
return ok && memcmp(out->cust, CUST_MAGIC, CUST_MAGIC_LEN) == 0;
}
static inline bool cust_write_table(const char* path, const CustomizeTable* in) {
FILE* f = fopen(path, "r+b");
if (!f) return false;
long off;
if (!cust_find_offset(f, &off)) {
fclose(f);
return false;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
if (off + (long)sizeof(CustomizeTable) > size) {
fclose(f);
return false;
}
fseek(f, off, SEEK_SET);
bool ok = fwrite(in, 1, sizeof(CustomizeTable), f) == sizeof(CustomizeTable);
fflush(f);
fclose(f);
return ok;
}
static inline bool cust_read_and_cache(const char* path, CustomizeTable* out) {
return cust_read_table(path, out);
}
#define CUST_WRITE_FIELD_BATCH(table, field, val) \
do { \
(table)->field = (val); \
} while (0)
#define CUST_WRITE_FIELD(path, field, val) \
do { \
CustomizeTable t; \
if (!cust_read_table(path, &t)) return false; \
t.field = (val); \
return cust_write_table(path, &t); \
} while (0)
// static inline bool cust_set_cust_rev(const char* p, u32 v) { CUST_WRITE_FIELD(p, custRev, v); }
// static inline bool cust_set_mtc_conf(const char* p, u32 v) { CUST_WRITE_FIELD(p, mtcConf, v); }
static inline bool cust_set_hp_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, hpMode, v); }
static inline bool cust_set_common_emc_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonEmcMemVolt, v); }
static inline bool cust_set_erista_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock, v); }
static inline bool cust_set_erista_emc_max1(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock1, v); }
static inline bool cust_set_erista_emc_max2(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaEmcMaxClock2, v); }
static inline bool cust_set_step_mode(const char* p, u32 v) { CUST_WRITE_FIELD(p, stepMode, v); }
static inline bool cust_set_mariko_emc_max(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcMaxClock, v); }
static inline bool cust_set_mariko_emc_vddq(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoEmcVddqVolt, v); }
static inline bool cust_set_emc_dvb_shift(const char* p, u32 v) { CUST_WRITE_FIELD(p, emcDvbShift, v); }
static inline bool cust_set_tRCD(const char* p, u32 v) { CUST_WRITE_FIELD(p, t1_tRCD, v); }
static inline bool cust_set_tRP(const char* p, u32 v) { CUST_WRITE_FIELD(p, t2_tRP, v); }
static inline bool cust_set_tRAS(const char* p, u32 v) { CUST_WRITE_FIELD(p, t3_tRAS, v); }
static inline bool cust_set_tRRD(const char* p, u32 v) { CUST_WRITE_FIELD(p, t4_tRRD, v); }
static inline bool cust_set_tRFC(const char* p, u32 v) { CUST_WRITE_FIELD(p, t5_tRFC, v); }
static inline bool cust_set_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW, v); }
static inline bool cust_set_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR, v); }
static inline bool cust_set_tREFI(const char* p, u32 v) { CUST_WRITE_FIELD(p, t8_tREFI, v); }
static inline bool cust_set_tRP_cap(const char* p, u32 v) { CUST_WRITE_FIELD(p, t2_tRP_cap, v); }
static inline bool cust_set_timing_emc_tbreak(const char* p, u32 v) { CUST_WRITE_FIELD(p, timingEmcTbreak, v); }
static inline bool cust_set_low_tRTW(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t6_tRTW, v); }
static inline bool cust_set_low_tWTR(const char* p, u32 v) { CUST_WRITE_FIELD(p, low_t7_tWTR, v); }
static inline bool cust_set_tRTW_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t6_tRTW_fine_tune, v); }
static inline bool cust_set_tWTR_fine_tune(const char* p, u32 v) { CUST_WRITE_FIELD(p, t7_tWTR_fine_tune, v); }
static inline bool cust_set_read_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1333, v); }
static inline bool cust_set_read_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1600, v); }
static inline bool cust_set_read_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency1866, v); }
static inline bool cust_set_read_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, readLatency2133, v); }
static inline bool cust_set_write_latency_1333(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1333, v); }
static inline bool cust_set_write_latency_1600(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1600, v); }
static inline bool cust_set_write_latency_1866(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency1866, v); }
static inline bool cust_set_write_latency_2133(const char* p, u32 v) { CUST_WRITE_FIELD(p, writeLatency2133, v); }
static inline bool cust_set_burst_read_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_read_latency, v); }
static inline bool cust_set_burst_write_lat(const char* p, u32 v) { CUST_WRITE_FIELD(p, mem_burst_write_latency, v); }
static inline bool cust_set_erista_cpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuUV, v); }
static inline bool cust_set_eristaCpuVmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuVmin, v); }
static inline bool cust_set_erista_cpu_max_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuMaxVolt, v); }
static inline bool cust_set_eristaCpuUnlock(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuUnlock, v); }
static inline bool cust_set_mariko_cpu_uv_low(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuUVLow, v); }
static inline bool cust_set_mariko_cpu_uv_high(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuUVHigh, v); }
static inline bool cust_set_mariko_cpu_low_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuLowVmin, v); }
static inline bool cust_set_mariko_cpu_high_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuHighVmin, v); }
static inline bool cust_set_mariko_cpu_max_volt(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuMaxVolt, v); }
static inline bool cust_set_erista_cpu_boost(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaCpuBoostClock, v); }
static inline bool cust_set_mariko_cpu_boost(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuBoostClock, v); }
static inline bool cust_set_erista_gpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaGpuUV, v); }
static inline bool cust_set_erista_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, eristaGpuVmin, v); }
static inline bool cust_set_mariko_gpu_uv(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuUV, v); }
static inline bool cust_set_mariko_gpu_vmin(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmin, v); }
static inline bool cust_set_mariko_gpu_vmax(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoGpuVmax, v); }
static inline bool cust_set_common_gpu_offset(const char* p, u32 v) { CUST_WRITE_FIELD(p, commonGpuVoltOffset, v); }
static inline bool cust_set_gpu_speedo(const char* p, u32 v) { CUST_WRITE_FIELD(p, gpuSpeedo, v); }
static inline bool cust_set_marikoCpuMaxClock(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoCpuMaxClock, v); }
static inline bool cust_set_marikoSocVmax(const char* p, u32 v) { CUST_WRITE_FIELD(p, marikoSocVmax, v); }
/* GPU VOLT ARRAY HELPERS */
static inline bool cust_set_erista_gpu_volt(const char* p, int idx, u32 v) {
if (idx < 0 || idx >= 27) return false;
CustomizeTable t;
if (!cust_read_table(p, &t)) return false;
t.eristaGpuVoltArray[idx] = v;
return cust_write_table(p, &t);
}
static inline bool cust_set_mariko_gpu_volt(const char* p, int idx, u32 v) {
if (idx < 0 || idx >= 24) return false;
CustomizeTable t;
if (!cust_read_table(p, &t)) return false;
t.marikoGpuVoltArray[idx] = v;
return cust_write_table(p, &t);
}
static inline u32 cust_get_field(const CustomizeTable* t, u32 offset) {
if (!t) return 0;
return *(u32*)((u8*)t + offset);
}
#define CUST_GET_FIELD(table, field) ((table) ? (table)->field : 0)
static inline u32 cust_get_cust_rev(const CustomizeTable* t) { return CUST_GET_FIELD(t, custRev); }
static inline u32 cust_get_kip_version(const CustomizeTable* t) { return CUST_GET_FIELD(t, kipVersion); }
// static inline u32 cust_get_mtc_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, mtcConf); }
static inline u32 cust_get_hp_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, hpMode); }
static inline u32 cust_get_common_emc_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonEmcMemVolt); }
static inline u32 cust_get_erista_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock); }
static inline u32 cust_get_erista_emc_max1(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock1); }
static inline u32 cust_get_erista_emc_max2(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaEmcMaxClock2); }
static inline u32 cust_get_step_mode(const CustomizeTable* t) { return CUST_GET_FIELD(t, stepMode); }
static inline u32 cust_get_mariko_emc_max(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcMaxClock); }
static inline u32 cust_get_mariko_emc_vddq(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoEmcVddqVolt); }
static inline u32 cust_get_emc_dvb_shift(const CustomizeTable* t) { return CUST_GET_FIELD(t, emcDvbShift); }
static inline u32 cust_get_tRCD(const CustomizeTable* t) { return CUST_GET_FIELD(t, t1_tRCD); }
static inline u32 cust_get_tRP(const CustomizeTable* t) { return CUST_GET_FIELD(t, t2_tRP); }
static inline u32 cust_get_tRAS(const CustomizeTable* t) { return CUST_GET_FIELD(t, t3_tRAS); }
static inline u32 cust_get_tRRD(const CustomizeTable* t) { return CUST_GET_FIELD(t, t4_tRRD); }
static inline u32 cust_get_tRFC(const CustomizeTable* t) { return CUST_GET_FIELD(t, t5_tRFC); }
static inline u32 cust_get_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW); }
static inline u32 cust_get_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR); }
static inline u32 cust_get_tREFI(const CustomizeTable* t) { return CUST_GET_FIELD(t, t8_tREFI); }
static inline u32 cust_get_tRP_cap(const CustomizeTable* t) { return CUST_GET_FIELD(t, t2_tRP_cap); }
static inline u32 cust_get_timing_emc_tbreak(const CustomizeTable* t) { return CUST_GET_FIELD(t, timingEmcTbreak); }
static inline u32 cust_get_low_t6_tRTW(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t6_tRTW); }
static inline u32 cust_get_low_t7_tWTR(const CustomizeTable* t) { return CUST_GET_FIELD(t, low_t7_tWTR); }
static inline u32 cust_get_tRTW_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t6_tRTW_fine_tune); }
static inline u32 cust_get_tWTR_fine_tune(const CustomizeTable* t) { return CUST_GET_FIELD(t, t7_tWTR_fine_tune); }
static inline u32 cust_get_read_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1333); }
static inline u32 cust_get_read_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1600); }
static inline u32 cust_get_read_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency1866); }
static inline u32 cust_get_read_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, readLatency2133); }
static inline u32 cust_get_write_latency_1333(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1333); }
static inline u32 cust_get_write_latency_1600(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1600); }
static inline u32 cust_get_write_latency_1866(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency1866); }
static inline u32 cust_get_write_latency_2133(const CustomizeTable* t) { return CUST_GET_FIELD(t, writeLatency2133); }
static inline u32 cust_get_burst_read_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_read_latency); }
static inline u32 cust_get_burst_write_lat(const CustomizeTable* t) { return CUST_GET_FIELD(t, mem_burst_write_latency); }
static inline u32 cust_get_erista_cpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuUV); }
static inline u32 cust_get_eristaCpuVmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuVmin); }
static inline u32 cust_get_erista_cpu_max_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuMaxVolt); }
static inline u32 cust_get_eristaCpuUnlock(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuUnlock); }
static inline u32 cust_get_mariko_cpu_uv_low(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuUVLow); }
static inline u32 cust_get_mariko_cpu_uv_high(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuUVHigh); }
static inline u32 cust_get_mariko_cpu_low_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuLowVmin); }
static inline u32 cust_get_mariko_cpu_high_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuHighVmin); }
static inline u32 cust_get_mariko_cpu_max_volt(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxVolt); }
static inline u32 cust_get_erista_cpu_boost(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaCpuBoostClock); }
static inline u32 cust_get_mariko_cpu_boost(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuBoostClock); }
static inline u32 cust_get_table_conf(const CustomizeTable* t) { return CUST_GET_FIELD(t, tableConf); }
static inline u32 cust_get_erista_gpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaGpuUV); }
static inline u32 cust_get_erista_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, eristaGpuVmin); }
static inline u32 cust_get_mariko_gpu_uv(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuUV); }
static inline u32 cust_get_mariko_gpu_vmin(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmin); }
static inline u32 cust_get_mariko_gpu_vmax(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoGpuVmax); }
static inline u32 cust_get_common_gpu_offset(const CustomizeTable* t) { return CUST_GET_FIELD(t, commonGpuVoltOffset); }
static inline u32 cust_get_gpu_speedo(const CustomizeTable* t) { return CUST_GET_FIELD(t, gpuSpeedo); }
static inline u32 cust_get_marikoCpuMaxClock(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoCpuMaxClock); }
static inline u32 cust_get_marikoSocVmax(const CustomizeTable* t) { return CUST_GET_FIELD(t, marikoSocVmax); }
static inline u32 cust_get_erista_gpu_volt(const CustomizeTable* t, int idx) {
if (!t || idx < 0 || idx >= 27) return 0;
return t->eristaGpuVoltArray[idx];
}
static inline u32 cust_get_mariko_gpu_volt(const CustomizeTable* t, int idx) {
if (!t || idx < 0 || idx >= 24) return 0;
return t->marikoGpuVoltArray[idx];
}
#define DECL_ERISTA_GPU_VOLT_HELPER(freq, idx) \
static inline bool cust_set_erista_gpu_volt_##freq( \
const char* p, u32 v) { \
return cust_set_erista_gpu_volt(p, idx, v); \
}
#define DECL_MARIKO_GPU_VOLT_HELPER(freq, idx) \
static inline bool cust_set_mariko_gpu_volt_##freq( \
const char* p, u32 v) { \
return cust_set_mariko_gpu_volt(p, idx, v); \
}
DECL_ERISTA_GPU_VOLT_HELPER(76800, 0)
DECL_ERISTA_GPU_VOLT_HELPER(115200, 1)
DECL_ERISTA_GPU_VOLT_HELPER(153600, 2)
DECL_ERISTA_GPU_VOLT_HELPER(192000, 3)
DECL_ERISTA_GPU_VOLT_HELPER(230400, 4)
DECL_ERISTA_GPU_VOLT_HELPER(268800, 5)
DECL_ERISTA_GPU_VOLT_HELPER(307200, 6)
DECL_ERISTA_GPU_VOLT_HELPER(345600, 7)
DECL_ERISTA_GPU_VOLT_HELPER(384000, 8)
DECL_ERISTA_GPU_VOLT_HELPER(422400, 9)
DECL_ERISTA_GPU_VOLT_HELPER(460800, 10)
DECL_ERISTA_GPU_VOLT_HELPER(499200, 11)
DECL_ERISTA_GPU_VOLT_HELPER(537600, 12)
DECL_ERISTA_GPU_VOLT_HELPER(576000, 13)
DECL_ERISTA_GPU_VOLT_HELPER(614400, 14)
DECL_ERISTA_GPU_VOLT_HELPER(652800, 15)
DECL_ERISTA_GPU_VOLT_HELPER(691200, 16)
DECL_ERISTA_GPU_VOLT_HELPER(729600, 17)
DECL_ERISTA_GPU_VOLT_HELPER(768000, 18)
DECL_ERISTA_GPU_VOLT_HELPER(806400, 19)
DECL_ERISTA_GPU_VOLT_HELPER(844800, 20)
DECL_ERISTA_GPU_VOLT_HELPER(883200, 21)
DECL_ERISTA_GPU_VOLT_HELPER(921600, 22)
DECL_ERISTA_GPU_VOLT_HELPER(960000, 23)
DECL_ERISTA_GPU_VOLT_HELPER(998400, 24)
DECL_ERISTA_GPU_VOLT_HELPER(1036800, 25)
DECL_ERISTA_GPU_VOLT_HELPER(1075200, 26)
DECL_MARIKO_GPU_VOLT_HELPER(76800, 0)
DECL_MARIKO_GPU_VOLT_HELPER(153600, 1)
DECL_MARIKO_GPU_VOLT_HELPER(230400, 2)
DECL_MARIKO_GPU_VOLT_HELPER(307200, 3)
DECL_MARIKO_GPU_VOLT_HELPER(384000, 4)
DECL_MARIKO_GPU_VOLT_HELPER(460800, 5)
DECL_MARIKO_GPU_VOLT_HELPER(537600, 6)
DECL_MARIKO_GPU_VOLT_HELPER(614400, 7)
DECL_MARIKO_GPU_VOLT_HELPER(691200, 8)
DECL_MARIKO_GPU_VOLT_HELPER(768000, 9)
DECL_MARIKO_GPU_VOLT_HELPER(844800, 10)
DECL_MARIKO_GPU_VOLT_HELPER(921600, 11)
DECL_MARIKO_GPU_VOLT_HELPER(998400, 12)
DECL_MARIKO_GPU_VOLT_HELPER(1075200, 13)
DECL_MARIKO_GPU_VOLT_HELPER(1152000, 14)
DECL_MARIKO_GPU_VOLT_HELPER(1228800, 15)
DECL_MARIKO_GPU_VOLT_HELPER(1267200, 16)
DECL_MARIKO_GPU_VOLT_HELPER(1305600, 17)
DECL_MARIKO_GPU_VOLT_HELPER(1344000, 18)
DECL_MARIKO_GPU_VOLT_HELPER(1382400, 19)
DECL_MARIKO_GPU_VOLT_HELPER(1420800, 20)
DECL_MARIKO_GPU_VOLT_HELPER(1459200, 21)
DECL_MARIKO_GPU_VOLT_HELPER(1497600, 22)
DECL_MARIKO_GPU_VOLT_HELPER(1536000, 23)
#define DECL_ERISTA_GPU_VOLT_GET(freq, idx) \
static inline u32 cust_get_erista_gpu_volt_##freq##_val(const char* p) { \
CustomizeTable t; \
if (!cust_read_table(p, &t)) return 0; \
return cust_get_erista_gpu_volt(&t, idx); \
}
#define DECL_MARIKO_GPU_VOLT_GET(freq, idx) \
static inline u32 cust_get_mariko_gpu_volt_##freq##_val(const char* p) { \
CustomizeTable t; \
if (!cust_read_table(p, &t)) return 0; \
return cust_get_mariko_gpu_volt(&t, idx); \
}
DECL_ERISTA_GPU_VOLT_GET(76800, 0)
DECL_ERISTA_GPU_VOLT_GET(115200, 1)
DECL_ERISTA_GPU_VOLT_GET(153600, 2)
DECL_ERISTA_GPU_VOLT_GET(192000, 3)
DECL_ERISTA_GPU_VOLT_GET(230400, 4)
DECL_ERISTA_GPU_VOLT_GET(268800, 5)
DECL_ERISTA_GPU_VOLT_GET(307200, 6)
DECL_ERISTA_GPU_VOLT_GET(345600, 7)
DECL_ERISTA_GPU_VOLT_GET(384000, 8)
DECL_ERISTA_GPU_VOLT_GET(422400, 9)
DECL_ERISTA_GPU_VOLT_GET(460800, 10)
DECL_ERISTA_GPU_VOLT_GET(499200, 11)
DECL_ERISTA_GPU_VOLT_GET(537600, 12)
DECL_ERISTA_GPU_VOLT_GET(576000, 13)
DECL_ERISTA_GPU_VOLT_GET(614400, 14)
DECL_ERISTA_GPU_VOLT_GET(652800, 15)
DECL_ERISTA_GPU_VOLT_GET(691200, 16)
DECL_ERISTA_GPU_VOLT_GET(729600, 17)
DECL_ERISTA_GPU_VOLT_GET(768000, 18)
DECL_ERISTA_GPU_VOLT_GET(806400, 19)
DECL_ERISTA_GPU_VOLT_GET(844800, 20)
DECL_ERISTA_GPU_VOLT_GET(883200, 21)
DECL_ERISTA_GPU_VOLT_GET(921600, 22)
DECL_ERISTA_GPU_VOLT_GET(960000, 23)
DECL_ERISTA_GPU_VOLT_GET(998400, 24)
DECL_ERISTA_GPU_VOLT_GET(1036800, 25)
DECL_ERISTA_GPU_VOLT_GET(1075200, 26)
DECL_MARIKO_GPU_VOLT_GET(76800, 0)
DECL_MARIKO_GPU_VOLT_GET(153600, 1)
DECL_MARIKO_GPU_VOLT_GET(230400, 2)
DECL_MARIKO_GPU_VOLT_GET(307200, 3)
DECL_MARIKO_GPU_VOLT_GET(384000, 4)
DECL_MARIKO_GPU_VOLT_GET(460800, 5)
DECL_MARIKO_GPU_VOLT_GET(537600, 6)
DECL_MARIKO_GPU_VOLT_GET(614400, 7)
DECL_MARIKO_GPU_VOLT_GET(691200, 8)
DECL_MARIKO_GPU_VOLT_GET(768000, 9)
DECL_MARIKO_GPU_VOLT_GET(844800, 10)
DECL_MARIKO_GPU_VOLT_GET(921600, 11)
DECL_MARIKO_GPU_VOLT_GET(998400, 12)
DECL_MARIKO_GPU_VOLT_GET(1075200, 13)
DECL_MARIKO_GPU_VOLT_GET(1152000, 14)
DECL_MARIKO_GPU_VOLT_GET(1228800, 15)
DECL_MARIKO_GPU_VOLT_GET(1267200, 16)
DECL_MARIKO_GPU_VOLT_GET(1305600, 17)
DECL_MARIKO_GPU_VOLT_GET(1344000, 18)
DECL_MARIKO_GPU_VOLT_GET(1382400, 19)
DECL_MARIKO_GPU_VOLT_GET(1420800, 20)
DECL_MARIKO_GPU_VOLT_GET(1459200, 21)
DECL_MARIKO_GPU_VOLT_GET(1497600, 22)
DECL_MARIKO_GPU_VOLT_GET(1536000, 23)
void SetKipData();
void GetKipData();
}