Files
99_7018_lmx/cpu/br28/power/power_trim.c

293 lines
7.3 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
#include "asm/power_interface.h"
#include "asm/adc_api.h"
#include "app_config.h"
#include "includes.h"
#include "stdlib.h"
__attribute__((noinline))
AT(.volatile_ram_code)
static u8 wiovdd_trim(u8 trim, s16 *adc_wiovdd_voltage)
{
u32 wiovdd_lev = 7;
u32 miovdd_lev = 0;
P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
delay(215);//延时50us
P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
delay(430);
if (trim) {
for (; wiovdd_lev > 3; wiovdd_lev--) {
P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
delay(700);//延时50us
adc_wiovdd_voltage[wiovdd_lev] = get_vddio_voltage();;
}
for (int i = 3; i >= 0; i--) {
adc_wiovdd_voltage[i] = adc_wiovdd_voltage[i + 1] - 200;
}
}
return 0;
}
__attribute__((noinline))
AT(.volatile_ram_code)
u8 miovdd_trim(u8 trim, s16 *adc_miovdd_voltage)
{
u32 wiovdd_lev = 0;
u32 miovdd_lev = 7;
P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
delay(430);
P33_CON_SET(P3_ANA_CON5, 3, 3, wiovdd_lev);
delay(215);//延时50us
if (trim) {
for (; miovdd_lev > 3; miovdd_lev--) {
P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
delay(700);//延时50us
adc_miovdd_voltage[miovdd_lev] = get_vddio_voltage();;
}
for (int i = 3; i >= 0; i--) {
adc_miovdd_voltage[i] = adc_miovdd_voltage[i + 1] - 200;
}
}
return 0;
}
__attribute__((noinline))
AT(.volatile_ram_code)
u32 iovdd_trim(u8 trim, u8 *miovdd_lev, u8 *wiovdd_lev)
{
const u32 m_iovdd_lev = P3_ANA_CON5 & 0xf;
if (trim == 0) {
return 1;
}
u32 check_vbat = get_vdd_voltage(AD_CH_VBAT) * 4;
printf("check_vbat = %d\n", check_vbat);
if (check_vbat < 3700) {
printf("%s %d\n", __func__, __LINE__);
*miovdd_lev = m_iovdd_lev | BIT(7);
*wiovdd_lev = m_iovdd_lev | BIT(7);
return 0;
}
local_irq_disable();
const u32 lvd_con = P3_VLVD_CON;
P3_VLVD_CON &= ~BIT(2);
delay(100);
P3_VLVD_CON &= ~BIT(0); //关闭lvd
s16 adc_wiovdd_voltage[8];
s16 adc_miovdd_voltage[8];
miovdd_trim(trim, adc_miovdd_voltage);
wiovdd_trim(trim, adc_wiovdd_voltage);
if (lvd_con & BIT(0)) {
P3_VLVD_CON |= BIT(0);//en
delay(3);
P3_VLVD_CON |= BIT(2);//oe
}
local_irq_enable();
int miovdd_voltage = m_iovdd_lev * 200 + 2000;
u32 min_diff = -1;
int mlev = 0;
for (int i = 7; i >= 0; i--) {
u32 diff = abs(miovdd_voltage - adc_miovdd_voltage[i]);
if (diff < min_diff) {
mlev = i;
min_diff = diff;
}
}
*miovdd_lev = mlev;
u32 wlev = 0;
min_diff = -1;
for (int i = 7; i >= 0; i--) {
u32 diff = abs(adc_miovdd_voltage[mlev] - adc_wiovdd_voltage[i]);
if (diff < min_diff) {
wlev = i;
min_diff = diff;
}
}
*wiovdd_lev = wlev;
for (u8 i = 0; i < 8; i++) {
printf("adc_wiovdd_voltage[%d] = %d\n", i, adc_wiovdd_voltage[i]);
printf("adc_miovdd_voltage[%d] = %d\n", i, adc_miovdd_voltage[i]);
}
return 0;
}
static u8 wvdd_trim(u8 trim)
{
u8 wvdd_lev = 0;
wvdd_lev = 0;
int v = 0;
u8 err = 0;
if (trim) {
v = get_wvdd_level_trim();
if (v == 0) {
//0.65v
wvdd_lev = 0b0011;
} else if (v == 1) {
//0.7v
wvdd_lev = 0b0100;
} else if (v == 2) {
//0.75v
wvdd_lev = 0b0101;
} else {
//0.8v
//wvdd_lev = 0b0110;
WVDD_VOL_SEL(wvdd_lev);
WVDD_LOAD_EN(1);
WLDO06_EN(1);
delay(2000);//1ms
do {
WVDD_VOL_SEL(wvdd_lev);
delay(2000);//1ms * n
v = get_vdd_voltage(AD_CH_WVDD);
if (v > WVDD_VOL_TRIM) {
break;
}
wvdd_lev ++;
} while (wvdd_lev < WVDD_LEVEL_MAX);
WVDD_LOAD_EN(0);
WLDO06_EN(0);
u8 min = (WVDD_VOL_TRIM - WVDD_VOL_MIN) / WVDD_VOL_STEP - 2;
u8 max = (WVDD_VOL_TRIM - WVDD_VOL_MIN) / WVDD_VOL_STEP + 2;
if (!(wvdd_lev >= min && wvdd_lev <= max)) {
wvdd_lev = WVDD_LEVEL_DEFAULT;
err = 1;
}
}
//update_wvdd_trim_level(wvdd_lev);
} else {
wvdd_lev = get_wvdd_trim_level();
}
printf("trim: %d, wvdd_lev: %d, v: %d, err: %d\n", trim, wvdd_lev, v, err);
M2P_WDVDD = wvdd_lev;
if (err) {
return WVDD_LEVEL_ERR;
}
return wvdd_lev;
}
static u8 pvdd_trim(u8 trim)
{
/* return 0; */
u32 v = 0;
u8 lev_high_now = PVDD_LEVEL_DEFAULT;
u8 err = 0;
if (trim) {
PVDD_LEVEL_HIGH_NOW(PVDD_LEVEL_REF);
delay(2000);//1ms
v = get_vdd_voltage(AD_CH_PVDD);//adc_get_voltage_preemption(AD_CH_PVDD);
if ((v < (PVDD_VOL_REF - 2 * PVDD_VOL_STEP)) || (v > (PVDD_VOL_REF + 2 * PVDD_VOL_STEP))) {
lev_high_now = PVDD_LEVEL_DEFAULT;
M2P_PVDD_LEVEL_SLEEP_TRIM = PVDD_LEVEL_SLEEP;
err = 1;
} else {
M2P_PVDD_LEVEL_SLEEP_TRIM = (PVDD_LEVEL_REF - (v - PVDD_VOL_SLEEP) / PVDD_VOL_STEP);
lev_high_now = M2P_PVDD_LEVEL_SLEEP_TRIM + (PVDD_VOL_HIGH_NOW - PVDD_VOL_SLEEP) / PVDD_VOL_STEP;
}
} else {
lev_high_now = get_pvdd_trim_level();
M2P_PVDD_LEVEL_SLEEP_TRIM = get_pvdd_level() - (PVDD_VOL_HIGH_NOW - PVDD_VOL_SLEEP) / PVDD_VOL_STEP;
}
#if (!PMU_NEW_FLOW)
if (get_pvdd_dcdc_cfg()) {
//外接dcdcpvdd配置为3档
lev_high_now = 3;
}
#endif
PVDD_LEVEL_HIGH_NOW(lev_high_now);
delay(2000);
PVDD_AUTO_PRD(0x3);
PVDD_LEVEL_AUTO(0x1);
PVDD_LEVEL_LOW(M2P_WDVDD);
#if PMU_NEW_FLOW
if (get_pvdd_dcdc_cfg()) {
power_set_pvdd_mode(PWR_PVDD_DCDC);
}
#endif
printf("trim: %d, pvdd_vol_ref: %d, pvdd_level_high_now_trim: %d, pvdd_level_sleep_trim: %d, pvdd_level_lev_l_trim: %d, err: %d\n", \
trim, v, lev_high_now, M2P_PVDD_LEVEL_SLEEP_TRIM, M2P_WDVDD, err);
cap_rch_enable();
if (err) {
return PVDD_LEVEL_ERR;
}
return lev_high_now;
}
void volatage_trim_init()
{
/* trim wvdd */
printf("lvd_con = 0x%x\n", P3_VLVD_CON);
u8 trim = load_pmu_trim_value_from_vm();
u8 wvdd_lev = 0;
u8 pvdd_lev = 0;
extern bool vm_need_recover(void);
if (vm_need_recover()) { // 升级完后重新trim
trim = 0xff;
}
printf("trim = 0x%x\n", trim);
wvdd_lev = wvdd_trim((trim & TRIM_WVDD) ? 1 : 0);
pvdd_lev = pvdd_trim((trim & TRIM_PVDD) ? 1 : 0);
u8 miovdd_lev = 0;
u8 wiovdd_lev = 0;
if (trim & TRIM_IOVDD) {
u8 trim_succ = iovdd_trim(trim, &miovdd_lev, &wiovdd_lev);
} else {
miovdd_lev = get_miovdd_trim_level();
wiovdd_lev = get_wiovdd_trim_level();
}
if (trim) {
if ((wvdd_lev != WVDD_LEVEL_ERR) && (pvdd_lev != PVDD_LEVEL_ERR)) {
store_pmu_trim_value_to_vm(wvdd_lev, pvdd_lev, miovdd_lev, wiovdd_lev);
}
}
printf("miovdd_lev = %x\n", miovdd_lev);
printf("wiovdd_lev = %x\n", wiovdd_lev);
P33_CON_SET(P3_ANA_CON5, 0, 3, miovdd_lev);
P33_CON_SET(P3_ANA_CON5, 3, 3, 0);
}