From 7ee1e3060978f863473ff21cac074195728f0a3b Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Thu, 30 Aug 2012 00:46:29 +0200 Subject: imx233: add regulator api Remove the old debug stuff about VDDx and add a clean api to get/set the regulator (VDDD, VDDA, VDDIO, VDDMEM). This is useful for proper frequency scaling. Change-Id: Ia5a1a712fd66652a8ad9601ed00db31aba5a7561 --- firmware/target/arm/imx233/debug-imx233.c | 46 +++++---- firmware/target/arm/imx233/power-imx233.c | 149 +++++++++++++++++++++++++----- firmware/target/arm/imx233/power-imx233.h | 45 ++++++--- 3 files changed, 184 insertions(+), 56 deletions(-) diff --git a/firmware/target/arm/imx233/debug-imx233.c b/firmware/target/arm/imx233/debug-imx233.c index 8553fd8509..fdad03ea78 100644 --- a/firmware/target/arm/imx233/debug-imx233.c +++ b/firmware/target/arm/imx233/debug-imx233.c @@ -34,6 +34,7 @@ #include "pinctrl-imx233.h" #include "ocotp-imx233.h" #include "string.h" +#include "stdio.h" #define DEBUG_CANCEL BUTTON_BACK @@ -150,21 +151,33 @@ bool dbg_hw_info_power(void) lcd_clear_display(); struct imx233_power_info_t info = imx233_power_get_info(POWER_INFO_ALL); - lcd_putsf(0, 0, "VDDD: %d mV linreg: %d offset: %d", info.vddd, info.vddd_linreg, - info.vddd_linreg_offset); - lcd_putsf(0, 1, "VDDA: %d mV linreg: %d offset: %d", info.vdda, info.vdda_linreg, - info.vdda_linreg_offset); - lcd_putsf(0, 2, "VDDIO: %d mV offset: %d", info.vddio, info.vddio_linreg_offset); - lcd_putsf(0, 3, "VDDMEM: %d mV linreg: %d", info.vddmem, info.vddmem_linreg); - lcd_putsf(0, 4, "DC-DC: pll: %d freq: %d", info.dcdc_sel_pllclk, info.dcdc_freqsel); - lcd_putsf(0, 5, "charge: %d mA stop: %d mA", info.charge_current, info.stop_current); - lcd_putsf(0, 6, "charging: %d bat_adj: %d", info.charging, info.batt_adj); - lcd_putsf(0, 7, "4.2: en: %d dcdc: %d", info._4p2_enable, info._4p2_dcdc); - lcd_putsf(0, 8, "4.2: cmptrip: %d dropout: %d", info._4p2_cmptrip, info._4p2_dropout); - lcd_putsf(0, 9, "5V: pwd_4.2_charge: %d", info._5v_pwd_charge_4p2); - lcd_putsf(0, 10, "5V: chargelim: %d mA", info._5v_charge_4p2_limit); - lcd_putsf(0, 11, "5V: dcdc: %d xfer: %d", info._5v_enable_dcdc, info._5v_dcdc_xfer); - lcd_putsf(0, 12, "5V: thr: %d mV use: %d cmps: %d", info._5v_vbusvalid_thr, + int line = 0; + unsigned trg, bo; + bool en; + int linreg; + char buf[16]; + + lcd_putsf(0, line++, "name value bo linreg"); +#define DISP_REGULATOR(name) \ + imx233_power_get_regulator(REGULATOR_##name, &trg, &bo); \ + imx233_power_get_regulator_linreg(REGULATOR_##name, &en, &linreg); \ + if(en) snprintf(buf, sizeof(buf), "%d", linreg); \ + else snprintf(buf, sizeof(buf), " "); \ + lcd_putsf(0, line++, "%6s %4d %4d %s", #name, trg, bo, buf); \ + + DISP_REGULATOR(VDDD); + DISP_REGULATOR(VDDA); + DISP_REGULATOR(VDDIO); + DISP_REGULATOR(VDDMEM); + lcd_putsf(0, line++, "DC-DC: pll: %d freq: %d", info.dcdc_sel_pllclk, info.dcdc_freqsel); + lcd_putsf(0, line++, "charge: %d mA stop: %d mA", info.charge_current, info.stop_current); + lcd_putsf(0, line++, "charging: %d bat_adj: %d", info.charging, info.batt_adj); + lcd_putsf(0, line++, "4.2: en: %d dcdc: %d", info._4p2_enable, info._4p2_dcdc); + lcd_putsf(0, line++, "4.2: cmptrip: %d dropout: %d", info._4p2_cmptrip, info._4p2_dropout); + lcd_putsf(0, line++, "5V: pwd_4.2_charge: %d", info._5v_pwd_charge_4p2); + lcd_putsf(0, line++, "5V: chargelim: %d mA", info._5v_charge_4p2_limit); + lcd_putsf(0, line++, "5V: dcdc: %d xfer: %d", info._5v_enable_dcdc, info._5v_dcdc_xfer); + lcd_putsf(0, line++, "5V: thr: %d mV use: %d cmps: %d", info._5v_vbusvalid_thr, info._5v_vbusvalid_detect, info._5v_vbus_cmps); lcd_update(); @@ -286,7 +299,8 @@ bool dbg_hw_info_clkctrl(void) #undef c } int line = ARRAYLEN(dbg_clk) + 1; - lcd_putsf(0, line, "auto slow: %d", imx233_clkctrl_is_auto_slow_enabled()); + lcd_putsf(0, line, "auto slow: %d emi sync: %d", imx233_clkctrl_is_auto_slow_enabled(), + imx233_clkctrl_is_emi_sync_enabled()); line++; lcd_putsf(0, line, "as monitor: "); int x_off = 12; diff --git a/firmware/target/arm/imx233/power-imx233.c b/firmware/target/arm/imx233/power-imx233.c index 6ba08ae394..c02d6ddb77 100644 --- a/firmware/target/arm/imx233/power-imx233.c +++ b/firmware/target/arm/imx233/power-imx233.c @@ -165,6 +165,130 @@ void imx233_power_set_stop_current(unsigned current) } } +/* regulator info */ +#define HAS_BO (1 << 0) +#define HAS_LINREG (1 << 1) +#define HAS_LINREG_OFFSET (1 << 2) + +static struct +{ + unsigned min, step; + volatile uint32_t *reg; + uint32_t trg_bm, trg_bp; // bitmask and bitpos + unsigned flags; + uint32_t bo_bm, bo_bp; // bitmask and bitpos + uint32_t linreg_bm; + uint32_t linreg_offset_bm, linreg_offset_bp; // bitmask and bitpos +} regulator_info[] = +{ +#define ADD_REGULATOR(name, mask) \ + .min = HW_POWER_##name##CTRL__TRG_MIN, \ + .step = HW_POWER_##name##CTRL__TRG_STEP, \ + .reg = &HW_POWER_##name##CTRL, \ + .trg_bm = HW_POWER_##name##CTRL__TRG_BM, \ + .trg_bp = HW_POWER_##name##CTRL__TRG_BP, \ + .flags = mask +#define ADD_REGULATOR_BO(name) \ + .bo_bm = HW_POWER_##name##CTRL__BO_OFFSET_BM, \ + .bo_bp = HW_POWER_##name##CTRL__BO_OFFSET_BP +#define ADD_REGULATOR_LINREG(name) \ + .linreg_bm = HW_POWER_##name##CTRL__ENABLE_LINREG +#define ADD_REGULATOR_LINREG_OFFSET(name) \ + .linreg_offset_bm = HW_POWER_##name##CTRL__LINREG_OFFSET_BM, \ + .linreg_offset_bp = HW_POWER_##name##CTRL__LINREG_OFFSET_BP + [REGULATOR_VDDD] = + { + ADD_REGULATOR(VDDD, HAS_BO|HAS_LINREG|HAS_LINREG_OFFSET), + ADD_REGULATOR_BO(VDDD), + ADD_REGULATOR_LINREG(VDDD), + ADD_REGULATOR_LINREG_OFFSET(VDDD) + }, + [REGULATOR_VDDA] = + { + ADD_REGULATOR(VDDA, HAS_BO|HAS_LINREG|HAS_LINREG_OFFSET), + ADD_REGULATOR_BO(VDDA), + ADD_REGULATOR_LINREG(VDDA), + ADD_REGULATOR_LINREG_OFFSET(VDDA) + }, + [REGULATOR_VDDIO] = + { + ADD_REGULATOR(VDDIO, HAS_BO|HAS_LINREG_OFFSET), + ADD_REGULATOR_BO(VDDIO), + ADD_REGULATOR_LINREG_OFFSET(VDDIO) + }, + [REGULATOR_VDDMEM] = + { + ADD_REGULATOR(VDDMEM, HAS_LINREG), + ADD_REGULATOR_LINREG(VDDMEM), + }, +}; + +void imx233_power_get_regulator(enum imx233_regulator_t reg, unsigned *value_mv, + unsigned *brownout_mv) +{ + uint32_t reg_val = *regulator_info[reg].reg; + /* read target value */ + unsigned raw_val = (reg_val & regulator_info[reg].trg_bm) >> regulator_info[reg].trg_bp; + /* convert it to mv */ + if(value_mv) + *value_mv = regulator_info[reg].min + regulator_info[reg].step * raw_val; + if(regulator_info[reg].flags & HAS_BO) + { + /* read brownout offset */ + unsigned raw_bo = (reg_val & regulator_info[reg].bo_bm) >> regulator_info[reg].bo_bp; + /* convert it to mv */ + if(brownout_mv) + *brownout_mv = regulator_info[reg].min + regulator_info[reg].step * (raw_val - raw_bo); + } + else if(brownout_mv) + *brownout_mv = 0; +} + +void imx233_power_set_regulator(enum imx233_regulator_t reg, unsigned value_mv, + unsigned brownout_mv) +{ + // compute raw values + unsigned raw_val = (value_mv - regulator_info[reg].min) / regulator_info[reg].step; + unsigned raw_bo_offset = (value_mv - brownout_mv) / regulator_info[reg].step; + // update + uint32_t reg_val = (*regulator_info[reg].reg) & ~regulator_info[reg].trg_bm; + reg_val |= raw_val << regulator_info[reg].trg_bp; + if(regulator_info[reg].flags & HAS_BO) + { + reg_val &= ~regulator_info[reg].bo_bm; + reg_val |= raw_bo_offset << regulator_info[reg].bo_bp; + } + *regulator_info[reg].reg = reg_val; +} + +// offset is -1,0 or 1 +void imx233_power_get_regulator_linreg(enum imx233_regulator_t reg, + bool *enabled, int *linreg_offset) +{ + if(enabled && regulator_info[reg].flags & HAS_LINREG) + *enabled = !!(*regulator_info[reg].reg & regulator_info[reg].linreg_bm); + else if(enabled) + *enabled = true; + if(regulator_info[reg].flags & HAS_LINREG_OFFSET) + { + unsigned v = (*regulator_info[reg].reg & regulator_info[reg].linreg_offset_bm); + v >>= regulator_info[reg].linreg_offset_bp; + if(linreg_offset) + *linreg_offset = (v == 0) ? 0 : (v == 1) ? 1 : -1; + } + else if(linreg_offset) + *linreg_offset = 0; +} + +// offset is -1,0 or 1 +/* +void imx233_power_set_regulator_linreg(enum imx233_regulator_t reg, + bool enabled, int linreg_offset) +{ +} +*/ + + struct imx233_power_info_t imx233_power_get_info(unsigned flags) { static int dcdc_freqsel[8] = { @@ -180,31 +304,6 @@ struct imx233_power_info_t imx233_power_get_info(unsigned flags) struct imx233_power_info_t s; memset(&s, 0, sizeof(s)); - if(flags & POWER_INFO_VDDD) - { - s.vddd = HW_POWER_VDDDCTRL__TRG_MIN + HW_POWER_VDDDCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDDCTRL, TRG); - s.vddd_linreg = HW_POWER_VDDDCTRL & HW_POWER_VDDDCTRL__ENABLE_LINREG; - s.vddd_linreg_offset = __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 0 ? 0 : - __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 1 ? 25 : -25; - } - if(flags & POWER_INFO_VDDA) - { - s.vdda = HW_POWER_VDDACTRL__TRG_MIN + HW_POWER_VDDACTRL__TRG_STEP * __XTRACT(HW_POWER_VDDACTRL, TRG); - s.vdda_linreg = HW_POWER_VDDACTRL & HW_POWER_VDDACTRL__ENABLE_LINREG; - s.vdda_linreg_offset = __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 0 ? 0 : - __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 1 ? 25 : -25; - } - if(flags & POWER_INFO_VDDIO) - { - s.vddio = HW_POWER_VDDIOCTRL__TRG_MIN + HW_POWER_VDDIOCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDIOCTRL, TRG); - s.vddio_linreg_offset = __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 0 ? 0 : - __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 1 ? 25 : -25; - } - if(flags & POWER_INFO_VDDMEM) - { - s.vddmem = HW_POWER_VDDMEMCTRL__TRG_MIN + HW_POWER_VDDMEMCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDMEMCTRL, TRG); - s.vddmem_linreg = HW_POWER_VDDMEMCTRL & HW_POWER_VDDMEMCTRL__ENABLE_LINREG; - } if(flags & POWER_INFO_DCDC) { s.dcdc_sel_pllclk = HW_POWER_MISC & HW_POWER_MISC__SEL_PLLCLK; diff --git a/firmware/target/arm/imx233/power-imx233.h b/firmware/target/arm/imx233/power-imx233.h index b38f9e576b..6991fde7b2 100644 --- a/firmware/target/arm/imx233/power-imx233.h +++ b/firmware/target/arm/imx233/power-imx233.h @@ -77,6 +77,8 @@ #define HW_POWER_VDDDCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x40)) #define HW_POWER_VDDDCTRL__TRG_BP 0 #define HW_POWER_VDDDCTRL__TRG_BM 0x1f +#define HW_POWER_VDDDCTRL__BO_OFFSET_BP 8 +#define HW_POWER_VDDDCTRL__BO_OFFSET_BM (0x7 << 8) #define HW_POWER_VDDDCTRL__TRG_STEP 25 /* mV */ #define HW_POWER_VDDDCTRL__TRG_MIN 800 /* mV */ #define HW_POWER_VDDDCTRL__LINREG_OFFSET_BP 16 @@ -86,6 +88,8 @@ #define HW_POWER_VDDACTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x50)) #define HW_POWER_VDDACTRL__TRG_BP 0 #define HW_POWER_VDDACTRL__TRG_BM 0x1f +#define HW_POWER_VDDACTRL__BO_OFFSET_BP 8 +#define HW_POWER_VDDACTRL__BO_OFFSET_BM (0x7 << 8) #define HW_POWER_VDDACTRL__TRG_STEP 25 /* mV */ #define HW_POWER_VDDACTRL__TRG_MIN 1500 /* mV */ #define HW_POWER_VDDACTRL__LINREG_OFFSET_BP 12 @@ -95,6 +99,8 @@ #define HW_POWER_VDDIOCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x60)) #define HW_POWER_VDDIOCTRL__TRG_BP 0 #define HW_POWER_VDDIOCTRL__TRG_BM 0x1f +#define HW_POWER_VDDIOCTRL__BO_OFFSET_BP 8 +#define HW_POWER_VDDIOCTRL__BO_OFFSET_BM (0x7 << 8) #define HW_POWER_VDDIOCTRL__TRG_STEP 25 /* mV */ #define HW_POWER_VDDIOCTRL__TRG_MIN 2800 /* mV */ #define HW_POWER_VDDIOCTRL__LINREG_OFFSET_BP 12 @@ -173,10 +179,33 @@ void imx233_power_set_charge_current(unsigned current); /* in mA */ void imx233_power_set_stop_current(unsigned current); /* in mA */ void imx233_power_enable_batadj(bool enable); +enum imx233_regulator_t +{ + REGULATOR_VDDD, /* target, brownout, linreg, linreg offset */ + REGULATOR_VDDA, /* target, brownout, linreg, linreg offset */ + REGULATOR_VDDIO, /* target, brownout, linreg offset */ + REGULATOR_VDDMEM, /* target, linreg */ + REGULATOR_COUNT, +}; + +void imx233_power_get_regulator(enum imx233_regulator_t reg, unsigned *target_mv, + unsigned *brownout_mv); + +void imx233_power_set_regulator(enum imx233_regulator_t reg, unsigned target_mv, + unsigned brownout_mv); + +// offset is -1,0 or 1 +void imx233_power_get_regulator_linreg(enum imx233_regulator_t reg, + bool *enabled, int *linreg_offset); + +// offset is -1,0 or 1 +void imx233_power_set_regulator_linreg(enum imx233_regulator_t reg, + bool enabled, int linreg_offset); + static inline void imx233_power_set_dcdc_freq(bool pll, unsigned freq) { HW_POWER_MISC &= ~(HW_POWER_MISC__SEL_PLLCLK | HW_POWER_MISC__FREQSEL_BM); - /* WARNING: HW_POWER_MISC does have a SET/CLR variant ! */ + /* WARNING: HW_POWER_MISC does not have a SET/CLR variant ! */ if(pll) { HW_POWER_MISC |= freq << HW_POWER_MISC__FREQSEL_BP; @@ -186,16 +215,6 @@ static inline void imx233_power_set_dcdc_freq(bool pll, unsigned freq) struct imx233_power_info_t { - int vddd; /* in mV */ - bool vddd_linreg; /* VDDD source: linreg from VDDA or DC-DC */ - int vddd_linreg_offset; - int vdda; /* in mV */ - bool vdda_linreg; /* VDDA source: linreg from VDDIO or DC-DC */ - int vdda_linreg_offset; - int vddio; /* in mV */ - int vddio_linreg_offset; - int vddmem; /* in mV */ - bool vddmem_linreg; /* VDDMEM source: linreg from VDDIO or off */ bool dcdc_sel_pllclk; /* clock source of DC-DC: pll or 24MHz xtal */ int dcdc_freqsel; int charge_current; @@ -215,10 +234,6 @@ struct imx233_power_info_t bool _5v_vbus_cmps; }; -#define POWER_INFO_VDDD (1 << 0) -#define POWER_INFO_VDDA (1 << 1) -#define POWER_INFO_VDDIO (1 << 2) -#define POWER_INFO_VDDMEM (1 << 3) #define POWER_INFO_DCDC (1 << 4) #define POWER_INFO_CHARGE (1 << 5) #define POWER_INFO_4P2 (1 << 6) -- cgit v1.2.3