sysclk: add charge current override
This commit is contained in:
@@ -63,6 +63,8 @@ typedef enum {
|
|||||||
HocClkConfigValue_KipEditing,
|
HocClkConfigValue_KipEditing,
|
||||||
HocClkConfigValue_KipFileName,
|
HocClkConfigValue_KipFileName,
|
||||||
|
|
||||||
|
HorizonOCConfigValue_BatteryChargeCurrent,
|
||||||
|
|
||||||
KipConfigValue_custRev,
|
KipConfigValue_custRev,
|
||||||
KipConfigValue_mtcConf,
|
KipConfigValue_mtcConf,
|
||||||
KipConfigValue_hpMode,
|
KipConfigValue_hpMode,
|
||||||
@@ -231,6 +233,9 @@ static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pr
|
|||||||
case HocClkConfigValue_KipFileName:
|
case HocClkConfigValue_KipFileName:
|
||||||
return pretty ? "KIP File Name" : "kip_file_name";
|
return pretty ? "KIP File Name" : "kip_file_name";
|
||||||
|
|
||||||
|
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||||
|
return pretty ? "Battery Charge Current" : "bat_charge_current";
|
||||||
|
|
||||||
// KIP config values
|
// KIP config values
|
||||||
case KipConfigValue_custRev:
|
case KipConfigValue_custRev:
|
||||||
return pretty ? "Custom Revision" : "kip_cust_rev";
|
return pretty ? "Custom Revision" : "kip_cust_rev";
|
||||||
@@ -423,6 +428,8 @@ static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
|
|||||||
return 8600ULL;
|
return 8600ULL;
|
||||||
case HocClkConfigValue_LiteTDPLimit:
|
case HocClkConfigValue_LiteTDPLimit:
|
||||||
return 6400ULL;
|
return 6400ULL;
|
||||||
|
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||||
|
return 0ULL;
|
||||||
default:
|
default:
|
||||||
return 0ULL;
|
return 0ULL;
|
||||||
}
|
}
|
||||||
@@ -548,7 +555,8 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
|||||||
case KipConfigValue_g_volt_e_1036800:
|
case KipConfigValue_g_volt_e_1036800:
|
||||||
case KipConfigValue_g_volt_e_1075200:
|
case KipConfigValue_g_volt_e_1075200:
|
||||||
return true;
|
return true;
|
||||||
|
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||||
|
return ((input >= 1024) && (input <= 3072)) || !input;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -995,9 +995,35 @@ void MiscGui::listUI()
|
|||||||
addConfigButton(KipConfigValue_g_volt_e_1075200, "GPU Voltage (1075.2MHz)", ValueRange(0, 0, 0, "0", 1), "Voltage", &EgpuVmaxThresholds, {}, eGpuVolts, false);
|
addConfigButton(KipConfigValue_g_volt_e_1075200, "GPU Voltage (1075.2MHz)", ValueRange(0, 0, 0, "0", 1), "Voltage", &EgpuVmaxThresholds, {}, eGpuVolts, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<NamedValue> chargerCurrents = {
|
||||||
|
NamedValue("Disabled", 0),
|
||||||
|
NamedValue("1024mA", 1024),
|
||||||
|
NamedValue("1280mA", 1280),
|
||||||
|
NamedValue("1536mA", 1536),
|
||||||
|
NamedValue("1792mA", 1792),
|
||||||
|
NamedValue("2048mA", 2048),
|
||||||
|
NamedValue("2304mA", 2304),
|
||||||
|
NamedValue("2560mA", 2560),
|
||||||
|
NamedValue("2816mA", 2816),
|
||||||
|
NamedValue("3072mA", 3072),
|
||||||
|
};
|
||||||
|
|
||||||
|
ValueThresholds chargerThresholds(2048, 2560);
|
||||||
|
|
||||||
// ========== EXPERIMENTAL CATEGORY (BOTTOM) ==========
|
// ========== EXPERIMENTAL CATEGORY (BOTTOM) ==========
|
||||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
|
this->listElement->addItem(new tsl::elm::CategoryHeader("Experimental"));
|
||||||
|
|
||||||
|
addConfigButton(
|
||||||
|
HorizonOCConfigValue_BatteryChargeCurrent,
|
||||||
|
"Charge Current Override",
|
||||||
|
ValueRange(0, 0, 1, "", 0),
|
||||||
|
"Charge Current Override",
|
||||||
|
&chargerThresholds,
|
||||||
|
{},
|
||||||
|
chargerCurrents,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
addConfigToggle(HocClkConfigValue_HandheldGovernor, nullptr);
|
addConfigToggle(HocClkConfigValue_HandheldGovernor, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "ipc_service.h"
|
#include "ipc_service.h"
|
||||||
#include "kip.h"
|
#include "kip.h"
|
||||||
|
#include "i2c_reg.h"
|
||||||
|
|
||||||
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
#define HOSPPC_HAS_BOOST (hosversionAtLeast(7,0,0))
|
||||||
|
|
||||||
ClockManager *ClockManager::instance = NULL;
|
ClockManager *ClockManager::instance = NULL;
|
||||||
@@ -254,6 +256,10 @@ void ClockManager::Tick()
|
|||||||
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
Result rc = apmExtGetCurrentPerformanceConfiguration(&mode);
|
||||||
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
|
||||||
|
|
||||||
|
if(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent)) {
|
||||||
|
I2c_Bq24193_SetFastChargeCurrentLimit(this->config->GetConfigValue(HorizonOCConfigValue_BatteryChargeCurrent));
|
||||||
|
}
|
||||||
|
|
||||||
if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) {
|
if(this->config->GetConfigValue(HocClkConfigValue_HandheldTDP) && opMode == AppletOperationMode_Handheld) {
|
||||||
if(Board::GetConsoleType() == HorizonOCConsoleType_Lite) {
|
if(Board::GetConsoleType() == HorizonOCConsoleType_Lite) {
|
||||||
if(Board::GetPowerMw(SysClkPowerSensor_Now) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
|
if(Board::GetPowerMw(SysClkPowerSensor_Now) < -(int)this->config->GetConfigValue(HocClkConfigValue_LiteTDPLimit)) {
|
||||||
|
|||||||
186
Source/sys-clk/sysmodule/src/i2c_reg.cpp
Normal file
186
Source/sys-clk/sysmodule/src/i2c_reg.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include "i2c_reg.h"
|
||||||
|
|
||||||
|
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val) {
|
||||||
|
// ams::fatal::srv::StopSoundTask::StopSound()
|
||||||
|
// I2C Bus Communication Reference: https://www.ti.com/lit/an/slva704/slva704.pdf
|
||||||
|
struct {
|
||||||
|
u8 reg;
|
||||||
|
u8 val;
|
||||||
|
} __attribute__((packed)) cmd;
|
||||||
|
|
||||||
|
I2cSession _session;
|
||||||
|
Result res = i2cOpenSession(&_session, dev);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
cmd.reg = reg;
|
||||||
|
cmd.val = val;
|
||||||
|
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||||
|
i2csessionClose(&_session);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out) {
|
||||||
|
struct { u8 reg; } __attribute__((packed)) cmd;
|
||||||
|
struct { u8 val; } __attribute__((packed)) rec;
|
||||||
|
|
||||||
|
I2cSession _session;
|
||||||
|
Result res = i2cOpenSession(&_session, dev);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
cmd.reg = reg;
|
||||||
|
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||||
|
if (res) {
|
||||||
|
i2csessionClose(&_session);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
|
||||||
|
i2csessionClose(&_session);
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = rec.val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out) {
|
||||||
|
struct { u8 reg; } __attribute__((packed)) cmd;
|
||||||
|
struct { u16 val; } __attribute__((packed)) rec;
|
||||||
|
|
||||||
|
I2cSession _session;
|
||||||
|
Result res = i2cOpenSession(&_session, dev);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
cmd.reg = reg;
|
||||||
|
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||||
|
if (res) {
|
||||||
|
i2csessionClose(&_session);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
|
||||||
|
i2csessionClose(&_session);
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = rec.val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float I2c_Max17050_GetBatteryCurrent() {
|
||||||
|
u16 val;
|
||||||
|
Result res = I2cRead_OutU16(I2cDevice_Max17050, MAX17050_CURRENT_REG, &val);
|
||||||
|
if (res)
|
||||||
|
return 0.f;
|
||||||
|
|
||||||
|
const float SenseResistor = 5.; // in uOhm
|
||||||
|
const float CGain = 1.99993;
|
||||||
|
return (s16)val * (1.5625 / (SenseResistor * CGain));
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
|
||||||
|
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||||
|
u32 uvolt = mvolt * 1000;
|
||||||
|
if (uvolt < domain->uv_min)
|
||||||
|
uvolt = domain->uv_min;
|
||||||
|
if (uvolt > domain->uv_max)
|
||||||
|
uvolt = domain->uv_max;
|
||||||
|
|
||||||
|
return (uvolt - domain->uv_min) / domain->uv_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
|
||||||
|
u8 val;
|
||||||
|
// Retry 5 times if received POR value
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
if (R_FAILED(I2cRead_OutU8(domain->device, domain->reg, &val)))
|
||||||
|
return 0u;
|
||||||
|
|
||||||
|
// Wait 1us
|
||||||
|
svcSleepThread(1E3);
|
||||||
|
|
||||||
|
if (!domain->por_val || val != domain->por_val)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||||
|
u8 val;
|
||||||
|
Result res = I2cRead_OutU8(domain->device, domain->reg, &val);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
u8 multiplier = I2c_BuckConverter_MvOutToMultiplier(domain, mvolt);
|
||||||
|
val &= ~domain->volt_mask;
|
||||||
|
val |= multiplier & domain->volt_mask;
|
||||||
|
|
||||||
|
res = I2cSet_U8(domain->device, domain->reg, val);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
// 5ms Ramp delay
|
||||||
|
svcSleepThread(5E6);
|
||||||
|
u8 new_val;
|
||||||
|
res = I2cRead_OutU8(domain->device, domain->reg, &new_val);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
return res;
|
||||||
|
if (new_val != val)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) {
|
||||||
|
// Adjustment is required
|
||||||
|
u8 raw = 0;
|
||||||
|
|
||||||
|
if (ma > MA_RANGE_MAX) // capping
|
||||||
|
ma = MA_RANGE_MAX;
|
||||||
|
|
||||||
|
bool pct20 = ma <= (MA_RANGE_MIN - 64);
|
||||||
|
if (pct20) {
|
||||||
|
ma = ma * 5;
|
||||||
|
raw |= 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma -= ma % 100; // round to 100
|
||||||
|
ma -= (MA_RANGE_MIN - 64); // ceiling
|
||||||
|
raw |= (ma >> 6) << 2;
|
||||||
|
|
||||||
|
return raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw) {
|
||||||
|
// No adjustment is allowed
|
||||||
|
u32 ma = (((raw >> 2)) << 6) + MA_RANGE_MIN;
|
||||||
|
|
||||||
|
bool pct20 = raw & 1;
|
||||||
|
if (pct20)
|
||||||
|
ma = ma * 20 / 100;
|
||||||
|
|
||||||
|
return ma;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma) {
|
||||||
|
u8 raw;
|
||||||
|
Result res = I2cRead_OutU8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, &raw);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
*ma = I2c_Bq24193_Convert_Raw_mA(raw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma) {
|
||||||
|
u8 raw = I2c_Bq24193_Convert_mA_Raw(ma);
|
||||||
|
return I2cSet_U8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, raw);
|
||||||
|
}
|
||||||
57
Source/sys-clk/sysmodule/src/i2c_reg.h
Normal file
57
Source/sys-clk/sysmodule/src/i2c_reg.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
// To use i2c service, sm and i2c should be intialized via smInitialize() and i2cInitialize().
|
||||||
|
|
||||||
|
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val);
|
||||||
|
|
||||||
|
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out);
|
||||||
|
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out);
|
||||||
|
|
||||||
|
// Max17050 fuel gauge
|
||||||
|
float I2c_Max17050_GetBatteryCurrent();
|
||||||
|
|
||||||
|
const u8 MAX17050_CURRENT_REG = 0x0A;
|
||||||
|
|
||||||
|
// Buck Converter
|
||||||
|
typedef enum I2c_BuckConverter_Reg {
|
||||||
|
I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
|
||||||
|
I2c_Max77621_VOLT_REG = 0x00,
|
||||||
|
I2c_Max77812_CPUVOLT_REG = 0x26,
|
||||||
|
I2c_Max77812_GPUVOLT_REG = 0x23,
|
||||||
|
I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4), used for Mariko VDDQ
|
||||||
|
} I2c_BuckConverter_Reg;
|
||||||
|
|
||||||
|
typedef struct I2c_BuckConverter_Domain {
|
||||||
|
I2cDevice device;
|
||||||
|
I2c_BuckConverter_Reg reg;
|
||||||
|
u8 volt_mask;
|
||||||
|
u32 uv_step;
|
||||||
|
u32 uv_min;
|
||||||
|
u32 uv_max;
|
||||||
|
u8 por_val;
|
||||||
|
} I2c_BuckConverter_Domain;
|
||||||
|
|
||||||
|
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 650000, 0x78 };
|
||||||
|
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
|
||||||
|
|
||||||
|
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
|
||||||
|
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
|
||||||
|
|
||||||
|
// Bq24193 Battery management
|
||||||
|
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw);
|
||||||
|
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma);
|
||||||
|
|
||||||
|
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma);
|
||||||
|
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma);
|
||||||
|
|
||||||
|
const u32 MA_RANGE_MIN = 512;
|
||||||
|
const u32 MA_RANGE_MAX = 4544;
|
||||||
|
|
||||||
|
const u8 BQ24193_CHARGE_CURRENT_CONTROL_REG = 0x2;
|
||||||
Reference in New Issue
Block a user