summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/power-imx233.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/power-imx233.c')
-rw-r--r--firmware/target/arm/imx233/power-imx233.c149
1 files changed, 124 insertions, 25 deletions
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)
165 } 165 }
166} 166}
167 167
168/* regulator info */
169#define HAS_BO (1 << 0)
170#define HAS_LINREG (1 << 1)
171#define HAS_LINREG_OFFSET (1 << 2)
172
173static struct
174{
175 unsigned min, step;
176 volatile uint32_t *reg;
177 uint32_t trg_bm, trg_bp; // bitmask and bitpos
178 unsigned flags;
179 uint32_t bo_bm, bo_bp; // bitmask and bitpos
180 uint32_t linreg_bm;
181 uint32_t linreg_offset_bm, linreg_offset_bp; // bitmask and bitpos
182} regulator_info[] =
183{
184#define ADD_REGULATOR(name, mask) \
185 .min = HW_POWER_##name##CTRL__TRG_MIN, \
186 .step = HW_POWER_##name##CTRL__TRG_STEP, \
187 .reg = &HW_POWER_##name##CTRL, \
188 .trg_bm = HW_POWER_##name##CTRL__TRG_BM, \
189 .trg_bp = HW_POWER_##name##CTRL__TRG_BP, \
190 .flags = mask
191#define ADD_REGULATOR_BO(name) \
192 .bo_bm = HW_POWER_##name##CTRL__BO_OFFSET_BM, \
193 .bo_bp = HW_POWER_##name##CTRL__BO_OFFSET_BP
194#define ADD_REGULATOR_LINREG(name) \
195 .linreg_bm = HW_POWER_##name##CTRL__ENABLE_LINREG
196#define ADD_REGULATOR_LINREG_OFFSET(name) \
197 .linreg_offset_bm = HW_POWER_##name##CTRL__LINREG_OFFSET_BM, \
198 .linreg_offset_bp = HW_POWER_##name##CTRL__LINREG_OFFSET_BP
199 [REGULATOR_VDDD] =
200 {
201 ADD_REGULATOR(VDDD, HAS_BO|HAS_LINREG|HAS_LINREG_OFFSET),
202 ADD_REGULATOR_BO(VDDD),
203 ADD_REGULATOR_LINREG(VDDD),
204 ADD_REGULATOR_LINREG_OFFSET(VDDD)
205 },
206 [REGULATOR_VDDA] =
207 {
208 ADD_REGULATOR(VDDA, HAS_BO|HAS_LINREG|HAS_LINREG_OFFSET),
209 ADD_REGULATOR_BO(VDDA),
210 ADD_REGULATOR_LINREG(VDDA),
211 ADD_REGULATOR_LINREG_OFFSET(VDDA)
212 },
213 [REGULATOR_VDDIO] =
214 {
215 ADD_REGULATOR(VDDIO, HAS_BO|HAS_LINREG_OFFSET),
216 ADD_REGULATOR_BO(VDDIO),
217 ADD_REGULATOR_LINREG_OFFSET(VDDIO)
218 },
219 [REGULATOR_VDDMEM] =
220 {
221 ADD_REGULATOR(VDDMEM, HAS_LINREG),
222 ADD_REGULATOR_LINREG(VDDMEM),
223 },
224};
225
226void imx233_power_get_regulator(enum imx233_regulator_t reg, unsigned *value_mv,
227 unsigned *brownout_mv)
228{
229 uint32_t reg_val = *regulator_info[reg].reg;
230 /* read target value */
231 unsigned raw_val = (reg_val & regulator_info[reg].trg_bm) >> regulator_info[reg].trg_bp;
232 /* convert it to mv */
233 if(value_mv)
234 *value_mv = regulator_info[reg].min + regulator_info[reg].step * raw_val;
235 if(regulator_info[reg].flags & HAS_BO)
236 {
237 /* read brownout offset */
238 unsigned raw_bo = (reg_val & regulator_info[reg].bo_bm) >> regulator_info[reg].bo_bp;
239 /* convert it to mv */
240 if(brownout_mv)
241 *brownout_mv = regulator_info[reg].min + regulator_info[reg].step * (raw_val - raw_bo);
242 }
243 else if(brownout_mv)
244 *brownout_mv = 0;
245}
246
247void imx233_power_set_regulator(enum imx233_regulator_t reg, unsigned value_mv,
248 unsigned brownout_mv)
249{
250 // compute raw values
251 unsigned raw_val = (value_mv - regulator_info[reg].min) / regulator_info[reg].step;
252 unsigned raw_bo_offset = (value_mv - brownout_mv) / regulator_info[reg].step;
253 // update
254 uint32_t reg_val = (*regulator_info[reg].reg) & ~regulator_info[reg].trg_bm;
255 reg_val |= raw_val << regulator_info[reg].trg_bp;
256 if(regulator_info[reg].flags & HAS_BO)
257 {
258 reg_val &= ~regulator_info[reg].bo_bm;
259 reg_val |= raw_bo_offset << regulator_info[reg].bo_bp;
260 }
261 *regulator_info[reg].reg = reg_val;
262}
263
264// offset is -1,0 or 1
265void imx233_power_get_regulator_linreg(enum imx233_regulator_t reg,
266 bool *enabled, int *linreg_offset)
267{
268 if(enabled && regulator_info[reg].flags & HAS_LINREG)
269 *enabled = !!(*regulator_info[reg].reg & regulator_info[reg].linreg_bm);
270 else if(enabled)
271 *enabled = true;
272 if(regulator_info[reg].flags & HAS_LINREG_OFFSET)
273 {
274 unsigned v = (*regulator_info[reg].reg & regulator_info[reg].linreg_offset_bm);
275 v >>= regulator_info[reg].linreg_offset_bp;
276 if(linreg_offset)
277 *linreg_offset = (v == 0) ? 0 : (v == 1) ? 1 : -1;
278 }
279 else if(linreg_offset)
280 *linreg_offset = 0;
281}
282
283// offset is -1,0 or 1
284/*
285void imx233_power_set_regulator_linreg(enum imx233_regulator_t reg,
286 bool enabled, int linreg_offset)
287{
288}
289*/
290
291
168struct imx233_power_info_t imx233_power_get_info(unsigned flags) 292struct imx233_power_info_t imx233_power_get_info(unsigned flags)
169{ 293{
170 static int dcdc_freqsel[8] = { 294 static int dcdc_freqsel[8] = {
@@ -180,31 +304,6 @@ struct imx233_power_info_t imx233_power_get_info(unsigned flags)
180 304
181 struct imx233_power_info_t s; 305 struct imx233_power_info_t s;
182 memset(&s, 0, sizeof(s)); 306 memset(&s, 0, sizeof(s));
183 if(flags & POWER_INFO_VDDD)
184 {
185 s.vddd = HW_POWER_VDDDCTRL__TRG_MIN + HW_POWER_VDDDCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDDCTRL, TRG);
186 s.vddd_linreg = HW_POWER_VDDDCTRL & HW_POWER_VDDDCTRL__ENABLE_LINREG;
187 s.vddd_linreg_offset = __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 0 ? 0 :
188 __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 1 ? 25 : -25;
189 }
190 if(flags & POWER_INFO_VDDA)
191 {
192 s.vdda = HW_POWER_VDDACTRL__TRG_MIN + HW_POWER_VDDACTRL__TRG_STEP * __XTRACT(HW_POWER_VDDACTRL, TRG);
193 s.vdda_linreg = HW_POWER_VDDACTRL & HW_POWER_VDDACTRL__ENABLE_LINREG;
194 s.vdda_linreg_offset = __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 0 ? 0 :
195 __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 1 ? 25 : -25;
196 }
197 if(flags & POWER_INFO_VDDIO)
198 {
199 s.vddio = HW_POWER_VDDIOCTRL__TRG_MIN + HW_POWER_VDDIOCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDIOCTRL, TRG);
200 s.vddio_linreg_offset = __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 0 ? 0 :
201 __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 1 ? 25 : -25;
202 }
203 if(flags & POWER_INFO_VDDMEM)
204 {
205 s.vddmem = HW_POWER_VDDMEMCTRL__TRG_MIN + HW_POWER_VDDMEMCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDMEMCTRL, TRG);
206 s.vddmem_linreg = HW_POWER_VDDMEMCTRL & HW_POWER_VDDMEMCTRL__ENABLE_LINREG;
207 }
208 if(flags & POWER_INFO_DCDC) 307 if(flags & POWER_INFO_DCDC)
209 { 308 {
210 s.dcdc_sel_pllclk = HW_POWER_MISC & HW_POWER_MISC__SEL_PLLCLK; 309 s.dcdc_sel_pllclk = HW_POWER_MISC & HW_POWER_MISC__SEL_PLLCLK;