EMC voltage for Mariko; Fix #60; Show battery & voltage info in overlay on Erista
- From previous analysis, EMC voltage is set before AMS loads on Mariko, and will not be set again or changed afterwards. - sys-clk-OC will take care of setting emc voltage on Mariko once it loads. - OS will not hang at boot as it always boots with EMC @ 1600 MHz.
This commit is contained in:
36
Source/sys-clk-OC/common/include/cpp_util.hpp
Normal file
36
Source/sys-clk-OC/common/include/cpp_util.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
template<typename F>
|
||||
class ScopeGuard {
|
||||
public:
|
||||
ScopeGuard(F&& f)
|
||||
: f(f), engaged(true) {};
|
||||
|
||||
~ScopeGuard() {
|
||||
if (engaged)
|
||||
f();
|
||||
};
|
||||
|
||||
ScopeGuard(ScopeGuard&& rhs)
|
||||
: f(std::move(rhs.f)) {};
|
||||
|
||||
void dismiss() { engaged = false; }
|
||||
|
||||
private:
|
||||
F f;
|
||||
bool engaged;
|
||||
};
|
||||
|
||||
struct MakeScopeExit {
|
||||
template<typename F>
|
||||
ScopeGuard<F> operator+=(F&& f) {
|
||||
return ScopeGuard<F>(std::move(f));
|
||||
};
|
||||
};
|
||||
|
||||
#define STRING_CAT2(x, y) x##y
|
||||
#define STRING_CAT(x, y) STRING_CAT2(x, y)
|
||||
#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline))
|
||||
#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD
|
||||
@@ -11,6 +11,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "cpp_util.hpp"
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,14 +14,34 @@ float I2c_Max17050_GetBatteryCurrent();
|
||||
|
||||
const u8 MAX17050_CURRENT_REG = 0x0A;
|
||||
|
||||
// Max77812 Mariko-specific buck converter
|
||||
typedef enum I2c_Max77812_Volt_Type {
|
||||
// Buck Converter
|
||||
typedef enum I2c_BuckConverter_Reg {
|
||||
I2c_Max77620_SD1VOLT_REG = 0x16,
|
||||
I2c_Max77621_VOLT_REG = 0x00,
|
||||
I2c_Max77812_CPUVOLT_REG = 0x26,
|
||||
I2c_Max77812_GPUVOLT_REG = 0x23,
|
||||
I2c_Max77812_MEMVOLT_REG = 0x25,
|
||||
} I2c_Max77812_Volt_Type;
|
||||
I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4)
|
||||
} I2c_BuckConverter_Reg;
|
||||
|
||||
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type);
|
||||
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 = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 650000, 0x78 };
|
||||
|
||||
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);
|
||||
|
||||
@@ -83,24 +83,58 @@ float I2c_Max17050_GetBatteryCurrent() {
|
||||
return (s16)val * (1.5625 / (SenseResistor * CGain));
|
||||
}
|
||||
|
||||
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type) {
|
||||
u8 reg = (u8)type;
|
||||
u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
|
||||
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
|
||||
}
|
||||
|
||||
const u32 MIN_MV = 250;
|
||||
const u32 MV_STEP = 5;
|
||||
const u8 RESET_VAL = 0x78;
|
||||
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;
|
||||
|
||||
u8 val = RESET_VAL;
|
||||
// Retry 3 times if received RESET_VAL
|
||||
return (uvolt - domain->uv_min) / domain->uv_step;
|
||||
}
|
||||
|
||||
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
|
||||
u8 val;
|
||||
Result res;
|
||||
// Retry 3 times if failed or received POR value
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (I2cRead_OutU8(I2cDevice_Max77812_2, reg, &val))
|
||||
return 0u;
|
||||
if (val != RESET_VAL)
|
||||
break;
|
||||
svcSleepThread(10);
|
||||
res = I2cRead_OutU8(domain->device, domain->reg, &val);
|
||||
if (R_FAILED(res) || (domain->por_val && val == domain->por_val)) {
|
||||
svcSleepThread(1000);
|
||||
continue;
|
||||
}
|
||||
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
return val * MV_STEP + MIN_MV;
|
||||
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;
|
||||
|
||||
svcSleepThread(1000);
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user