2 * Freescale i.MX28 Boot PMIC init
4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5 * on behalf of DENX Software Engineering GmbH
7 * SPDX-License-Identifier: GPL-2.0+
13 #include <asm/arch/imx-regs.h>
17 #ifdef CONFIG_SYS_SPL_VDDD_VAL
18 #define VDDD_VAL CONFIG_SYS_SPL_VDDD_VAL
22 #ifdef CONFIG_SYS_SPL_VDDIO_VAL
23 #define VDDIO_VAL CONFIG_SYS_SPL_VDDIO_VAL
25 #define VDDIO_VAL 3300
27 #ifdef CONFIG_SYS_SPL_VDDA_VAL
28 #define VDDA_VAL CONFIG_SYS_SPL_VDDA_VAL
32 #ifdef CONFIG_SYS_SPL_VDDMEM_VAL
33 #define VDDMEM_VAL CONFIG_SYS_SPL_VDDMEM_VAL
35 #define VDDMEM_VAL 1700
38 #ifdef CONFIG_SYS_SPL_VDDD_BO_VAL
39 #define VDDD_BO_VAL CONFIG_SYS_SPL_VDDD_BO_VAL
41 #define VDDD_BO_VAL 150
43 #ifdef CONFIG_SYS_SPL_VDDIO_BO_VAL
44 #define VDDIO_BO_VAL CONFIG_SYS_SPL_VDDIO_BO_VAL
46 #define VDDIO_BO_VAL 150
48 #ifdef CONFIG_SYS_SPL_VDDA_BO_VAL
49 #define VDDA_BO_VAL CONFIG_SYS_SPL_VDDA_BO_VAL
51 #define VDDA_BO_VAL 175
53 #ifdef CONFIG_SYS_SPL_VDDMEM_BO_VAL
54 #define VDDMEM_BO_VAL CONFIG_SYS_SPL_VDDMEM_BO_VAL
56 #define VDDMEM_BO_VAL 25
59 #ifdef CONFIG_SYS_SPL_BATT_BO_LEVEL
60 #if CONFIG_SYS_SPL_BATT_BO_LEVEL < 2400 || CONFIG_SYS_SPL_BATT_BO_LEVEL > 3640
61 #error CONFIG_SYS_SPL_BATT_BO_LEVEL out of range
63 #define BATT_BO_VAL (((CONFIG_SYS_SPL_BATT_BO_LEVEL) - 2400) / 40)
65 /* Brownout default at 3V */
66 #define BATT_BO_VAL ((3000 - 2400) / 40)
69 #ifdef CONFIG_SYS_SPL_FIXED_BATT_SUPPLY
70 static const int fixed_batt_supply = 1;
72 static const int fixed_batt_supply;
75 static struct mxs_power_regs *power_regs = (void *)MXS_POWER_BASE;
77 static void mxs_power_clock2xtal(void)
79 struct mxs_clkctrl_regs *clkctrl_regs =
80 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
82 /* Set XTAL as CPU reference clock */
83 writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
84 &clkctrl_regs->hw_clkctrl_clkseq_set);
87 static void mxs_power_clock2pll(void)
89 struct mxs_clkctrl_regs *clkctrl_regs =
90 (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
92 setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
93 CLKCTRL_PLL0CTRL0_POWER);
95 setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
96 CLKCTRL_CLKSEQ_BYPASS_CPU);
99 static int mxs_power_wait_rtc_stat(u32 mask)
101 int timeout = 5000; /* 3 ms according to i.MX28 Ref. Manual */
103 struct mxs_rtc_regs *rtc_regs = (void *)MXS_RTC_BASE;
105 while ((val = readl(&rtc_regs->hw_rtc_stat)) & mask) {
110 return !!(readl(&rtc_regs->hw_rtc_stat) & mask);
113 static int mxs_power_set_auto_restart(int on)
115 struct mxs_rtc_regs *rtc_regs = (void *)MXS_RTC_BASE;
118 * Due to the hardware design bug of mx28 EVK-A
119 * we need to set the AUTO_RESTART bit.
121 if (mxs_power_wait_rtc_stat(RTC_STAT_STALE_REGS_PERSISTENT0))
124 if ((!(readl(&rtc_regs->hw_rtc_persistent0) &
125 RTC_PERSISTENT0_AUTO_RESTART) ^ !on) == 0)
128 if (mxs_power_wait_rtc_stat(RTC_STAT_NEW_REGS_PERSISTENT0))
131 clrsetbits_le32(&rtc_regs->hw_rtc_persistent0,
132 !on * RTC_PERSISTENT0_AUTO_RESTART,
133 !!on * RTC_PERSISTENT0_AUTO_RESTART);
134 if (mxs_power_wait_rtc_stat(RTC_STAT_NEW_REGS_PERSISTENT0))
140 static void mxs_power_set_linreg(void)
142 /* Set linear regulator 25mV below switching converter */
143 clrsetbits_le32(&power_regs->hw_power_vdddctrl,
144 POWER_VDDDCTRL_LINREG_OFFSET_MASK,
145 POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
147 clrsetbits_le32(&power_regs->hw_power_vddactrl,
148 POWER_VDDACTRL_LINREG_OFFSET_MASK,
149 POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW);
151 clrsetbits_le32(&power_regs->hw_power_vddioctrl,
152 POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
153 POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
156 static int mxs_get_batt_volt(void)
158 uint32_t volt = readl(&power_regs->hw_power_battmonitor);
160 volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
161 volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
166 static int mxs_is_batt_ready(void)
168 return (mxs_get_batt_volt() >= 3600);
171 static int mxs_is_batt_good(void)
173 uint32_t volt = mxs_get_batt_volt();
175 if ((volt >= 2400) && (volt <= 4300))
178 clrsetbits_le32(&power_regs->hw_power_5vctrl,
179 POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
180 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
181 writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
182 &power_regs->hw_power_5vctrl_clr);
184 clrsetbits_le32(&power_regs->hw_power_charge,
185 POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
186 POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
188 writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
189 writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
190 &power_regs->hw_power_5vctrl_clr);
194 volt = mxs_get_batt_volt();
202 writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
203 &power_regs->hw_power_charge_clr);
204 writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
209 static void mxs_power_setup_5v_detect(void)
211 /* Start 5V detection */
212 clrsetbits_le32(&power_regs->hw_power_5vctrl,
213 POWER_5VCTRL_VBUSVALID_TRSH_MASK,
214 POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
215 POWER_5VCTRL_PWRUP_VBUS_CMPS);
218 static void mxs_src_power_init(void)
220 /* Improve efficieny and reduce transient ripple */
221 writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST |
222 POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set);
224 clrsetbits_le32(&power_regs->hw_power_dclimits,
225 POWER_DCLIMITS_POSLIMIT_BUCK_MASK,
226 0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET);
228 if (!fixed_batt_supply) {
229 /* FIXME: This requires the LRADC to be set up! */
230 setbits_le32(&power_regs->hw_power_battmonitor,
231 POWER_BATTMONITOR_EN_BATADJ);
233 clrbits_le32(&power_regs->hw_power_battmonitor,
234 POWER_BATTMONITOR_EN_BATADJ);
237 /* Increase the RCSCALE level for quick DCDC response to dynamic load */
238 clrsetbits_le32(&power_regs->hw_power_loopctrl,
239 POWER_LOOPCTRL_EN_RCSCALE_MASK,
240 POWER_LOOPCTRL_RCSCALE_THRESH |
241 POWER_LOOPCTRL_EN_RCSCALE_8X);
243 clrsetbits_le32(&power_regs->hw_power_minpwr,
244 POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
246 if (!fixed_batt_supply) {
247 /* 5V to battery handoff ... FIXME */
248 setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
250 clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
254 static void mxs_power_init_4p2_params(void)
256 /* Setup 4P2 parameters */
257 clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
258 POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
259 POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET));
261 clrsetbits_le32(&power_regs->hw_power_5vctrl,
262 POWER_5VCTRL_HEADROOM_ADJ_MASK,
263 0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET);
265 clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
266 POWER_DCDC4P2_DROPOUT_CTRL_MASK,
267 POWER_DCDC4P2_DROPOUT_CTRL_100MV |
268 POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL);
270 clrsetbits_le32(&power_regs->hw_power_5vctrl,
271 POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
272 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
275 static void mxs_enable_4p2_dcdc_input(int xfer)
277 uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
278 uint32_t prev_5v_brnout, prev_5v_droop;
280 prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
281 POWER_5VCTRL_PWDN_5VBRNOUT;
282 prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
283 POWER_CTRL_ENIRQ_VDD5V_DROOP;
285 clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
286 writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
287 &power_regs->hw_power_reset);
289 clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP);
291 if (xfer && (readl(&power_regs->hw_power_5vctrl) &
292 POWER_5VCTRL_ENABLE_DCDC)) {
297 * Recording orignal values that will be modified temporarlily
298 * to handle a chip bug. See chip errata for CQ ENGR00115837
300 tmp = readl(&power_regs->hw_power_5vctrl);
301 vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK;
302 vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT;
304 pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO;
307 * Disable mechanisms that get erroneously tripped by when setting
308 * the DCDC4P2 EN_DCDC
310 clrbits_le32(&power_regs->hw_power_5vctrl,
311 POWER_5VCTRL_VBUSVALID_5VDETECT |
312 POWER_5VCTRL_VBUSVALID_TRSH_MASK);
314 writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set);
317 setbits_le32(&power_regs->hw_power_5vctrl,
318 POWER_5VCTRL_DCDC_XFER);
320 clrbits_le32(&power_regs->hw_power_5vctrl,
321 POWER_5VCTRL_DCDC_XFER);
323 setbits_le32(&power_regs->hw_power_5vctrl,
324 POWER_5VCTRL_ENABLE_DCDC);
326 setbits_le32(&power_regs->hw_power_dcdc4p2,
327 POWER_DCDC4P2_ENABLE_DCDC);
332 clrsetbits_le32(&power_regs->hw_power_5vctrl,
333 POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh);
336 writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set);
339 clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO);
341 while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ)
342 writel(POWER_CTRL_VBUS_VALID_IRQ,
343 &power_regs->hw_power_ctrl_clr);
345 if (prev_5v_brnout) {
346 writel(POWER_5VCTRL_PWDN_5VBRNOUT,
347 &power_regs->hw_power_5vctrl_set);
348 writel(POWER_RESET_UNLOCK_KEY,
349 &power_regs->hw_power_reset);
351 writel(POWER_5VCTRL_PWDN_5VBRNOUT,
352 &power_regs->hw_power_5vctrl_clr);
353 writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
354 &power_regs->hw_power_reset);
357 while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ)
358 writel(POWER_CTRL_VDD5V_DROOP_IRQ,
359 &power_regs->hw_power_ctrl_clr);
362 clrbits_le32(&power_regs->hw_power_ctrl,
363 POWER_CTRL_ENIRQ_VDD5V_DROOP);
365 setbits_le32(&power_regs->hw_power_ctrl,
366 POWER_CTRL_ENIRQ_VDD5V_DROOP);
369 static void mxs_power_init_4p2_regulator(void)
373 setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
375 writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
377 writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
378 &power_regs->hw_power_5vctrl_clr);
379 clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK);
381 /* Power up the 4p2 rail and logic/control */
382 writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
383 &power_regs->hw_power_5vctrl_clr);
386 * Start charging up the 4p2 capacitor. We ramp of this charge
387 * gradually to avoid large inrush current from the 5V cable which can
388 * cause transients/problems
390 mxs_enable_4p2_dcdc_input(0);
392 if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
394 * If we arrived here, we were unable to recover from mx23 chip
395 * errata 5837. 4P2 is disabled and sufficient battery power is
396 * not present. Exiting to not enable DCDC power during 5V
399 clrbits_le32(&power_regs->hw_power_dcdc4p2,
400 POWER_DCDC4P2_ENABLE_DCDC);
401 writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
402 &power_regs->hw_power_5vctrl_set);
407 * Here we set the 4p2 brownout level to something very close to 4.2V.
408 * We then check the brownout status. If the brownout status is false,
409 * the voltage is already close to the target voltage of 4.2V so we
410 * can go ahead and set the 4P2 current limit to our max target limit.
411 * If the brownout status is true, we need to ramp us the current limit
412 * so that we don't cause large inrush current issues. We step up the
413 * current limit until the brownout status is false or until we've
414 * reached our maximum defined 4p2 current limit.
416 clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
417 POWER_DCDC4P2_BO_MASK,
418 22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
420 if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) {
421 setbits_le32(&power_regs->hw_power_5vctrl,
422 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
424 tmp = (readl(&power_regs->hw_power_5vctrl) &
425 POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >>
426 POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
428 if (!(readl(&power_regs->hw_power_sts) &
429 POWER_STS_DCDC_4P2_BO)) {
430 tmp = readl(&power_regs->hw_power_5vctrl);
431 tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
433 writel(tmp, &power_regs->hw_power_5vctrl);
437 tmp2 = readl(&power_regs->hw_power_5vctrl);
438 tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
440 POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
441 writel(tmp2, &power_regs->hw_power_5vctrl);
447 clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
448 writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
451 static void mxs_power_init_dcdc_4p2_source(void)
453 if (!(readl(&power_regs->hw_power_dcdc4p2) &
454 POWER_DCDC4P2_ENABLE_DCDC)) {
458 mxs_enable_4p2_dcdc_input(1);
460 if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
461 clrbits_le32(&power_regs->hw_power_dcdc4p2,
462 POWER_DCDC4P2_ENABLE_DCDC);
463 writel(POWER_5VCTRL_ENABLE_DCDC,
464 &power_regs->hw_power_5vctrl_clr);
465 writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
466 &power_regs->hw_power_5vctrl_set);
470 static void mxs_power_enable_4p2(void)
472 uint32_t vdddctrl, vddactrl, vddioctrl;
475 vdddctrl = readl(&power_regs->hw_power_vdddctrl);
476 vddactrl = readl(&power_regs->hw_power_vddactrl);
477 vddioctrl = readl(&power_regs->hw_power_vddioctrl);
479 setbits_le32(&power_regs->hw_power_vdddctrl,
480 POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
481 POWER_VDDDCTRL_PWDN_BRNOUT);
483 setbits_le32(&power_regs->hw_power_vddactrl,
484 POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG |
485 POWER_VDDACTRL_PWDN_BRNOUT);
487 setbits_le32(&power_regs->hw_power_vddioctrl,
488 POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT);
490 mxs_power_init_4p2_params();
491 mxs_power_init_4p2_regulator();
493 /* Shutdown battery (none present) */
494 if (!mxs_is_batt_ready()) {
495 clrbits_le32(&power_regs->hw_power_dcdc4p2,
496 POWER_DCDC4P2_BO_MASK);
497 writel(POWER_CTRL_DCDC4P2_BO_IRQ,
498 &power_regs->hw_power_ctrl_clr);
499 writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
500 &power_regs->hw_power_ctrl_clr);
503 mxs_power_init_dcdc_4p2_source();
505 writel(vdddctrl, &power_regs->hw_power_vdddctrl);
507 writel(vddactrl, &power_regs->hw_power_vddactrl);
509 writel(vddioctrl, &power_regs->hw_power_vddioctrl);
512 * Check if FET is enabled on either powerout and if so,
516 tmp |= !(readl(&power_regs->hw_power_vdddctrl) &
517 POWER_VDDDCTRL_DISABLE_FET);
518 tmp |= !(readl(&power_regs->hw_power_vddactrl) &
519 POWER_VDDACTRL_DISABLE_FET);
520 tmp |= !(readl(&power_regs->hw_power_vddioctrl) &
521 POWER_VDDIOCTRL_DISABLE_FET);
523 writel(POWER_CHARGE_ENABLE_LOAD,
524 &power_regs->hw_power_charge_clr);
527 static void mxs_boot_valid_5v(void)
530 * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
531 * disconnect event. FIXME
533 writel(POWER_5VCTRL_VBUSVALID_5VDETECT,
534 &power_regs->hw_power_5vctrl_set);
536 /* Configure polarity to check for 5V disconnection. */
537 writel(POWER_CTRL_POLARITY_VBUSVALID |
538 POWER_CTRL_POLARITY_VDD5V_GT_VDDIO,
539 &power_regs->hw_power_ctrl_clr);
541 writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ,
542 &power_regs->hw_power_ctrl_clr);
544 mxs_power_enable_4p2();
547 static void mxs_powerdown(void)
549 writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
550 writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
551 &power_regs->hw_power_reset);
554 static void mxs_batt_boot(void)
556 clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
557 clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
559 clrbits_le32(&power_regs->hw_power_dcdc4p2,
560 POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2);
561 writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr);
563 /* 5V to battery handoff. */
564 setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
566 clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
568 writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
570 clrsetbits_le32(&power_regs->hw_power_minpwr,
571 POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
573 mxs_power_set_linreg();
575 clrbits_le32(&power_regs->hw_power_vdddctrl,
576 POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG);
578 clrbits_le32(&power_regs->hw_power_vddactrl,
579 POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG);
581 clrbits_le32(&power_regs->hw_power_vddioctrl,
582 POWER_VDDIOCTRL_DISABLE_FET);
584 setbits_le32(&power_regs->hw_power_5vctrl,
585 POWER_5VCTRL_PWD_CHARGE_4P2_MASK);
587 setbits_le32(&power_regs->hw_power_5vctrl,
588 POWER_5VCTRL_ENABLE_DCDC);
590 clrsetbits_le32(&power_regs->hw_power_5vctrl,
591 POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
592 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
595 static void mxs_handle_5v_conflict(void)
599 setbits_le32(&power_regs->hw_power_vddioctrl,
600 POWER_VDDIOCTRL_BO_OFFSET_MASK);
603 tmp = readl(&power_regs->hw_power_sts);
605 if (tmp & POWER_STS_VDDIO_BO) {
607 * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes
614 if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
622 if (tmp & POWER_STS_PSWITCH_MASK) {
629 static void mxs_5v_boot(void)
632 * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID,
633 * but their implementation always returns 1 so we omit it here.
635 if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
641 if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
646 mxs_handle_5v_conflict();
649 static void mxs_fixed_batt_boot(void)
651 writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr);
653 setbits_le32(&power_regs->hw_power_5vctrl,
654 POWER_5VCTRL_PWDN_5VBRNOUT |
655 POWER_5VCTRL_ENABLE_DCDC |
656 POWER_5VCTRL_ILIMIT_EQ_ZERO |
657 POWER_5VCTRL_PWDN_5VBRNOUT |
658 POWER_5VCTRL_PWD_CHARGE_4P2_MASK);
660 writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
662 clrbits_le32(&power_regs->hw_power_vdddctrl,
663 POWER_VDDDCTRL_DISABLE_FET |
664 POWER_VDDDCTRL_ENABLE_LINREG |
665 POWER_VDDDCTRL_DISABLE_STEPPING);
667 clrbits_le32(&power_regs->hw_power_vddactrl,
668 POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG |
669 POWER_VDDACTRL_DISABLE_STEPPING);
671 clrbits_le32(&power_regs->hw_power_vddioctrl,
672 POWER_VDDIOCTRL_DISABLE_FET |
673 POWER_VDDIOCTRL_DISABLE_STEPPING);
675 /* Stop 5V detection */
676 writel(POWER_5VCTRL_PWRUP_VBUS_CMPS,
677 &power_regs->hw_power_5vctrl_clr);
680 static void mxs_init_batt_bo(void)
682 clrsetbits_le32(&power_regs->hw_power_battmonitor,
683 POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
684 BATT_BO_VAL << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET);
686 writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr);
687 writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr);
690 static void mxs_switch_vddd_to_dcdc_source(void)
692 clrsetbits_le32(&power_regs->hw_power_vdddctrl,
693 POWER_VDDDCTRL_LINREG_OFFSET_MASK,
694 POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
696 clrbits_le32(&power_regs->hw_power_vdddctrl,
697 POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
698 POWER_VDDDCTRL_DISABLE_STEPPING);
701 static void mxs_power_configure_power_source(void)
703 struct mxs_lradc_regs *lradc_regs =
704 (struct mxs_lradc_regs *)MXS_LRADC_BASE;
706 mxs_src_power_init();
708 if (!fixed_batt_supply) {
709 if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
710 if (mxs_is_batt_ready()) {
711 /* 5V source detected, good battery detected. */
714 if (!mxs_is_batt_good()) {
715 /* 5V source detected, bad battery detected. */
716 writel(LRADC_CONVERSION_AUTOMATIC,
717 &lradc_regs->hw_lradc_conversion_clr);
718 clrbits_le32(&power_regs->hw_power_battmonitor,
719 POWER_BATTMONITOR_BATT_VAL_MASK);
724 /* 5V not detected, booting from battery. */
728 mxs_fixed_batt_boot();
731 mxs_power_clock2pll();
735 mxs_switch_vddd_to_dcdc_source();
738 /* Fire up the VDDMEM LinReg now that we're all set. */
739 writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT,
740 &power_regs->hw_power_vddmemctrl);
744 static void mxs_enable_output_rail_protection(void)
746 writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
747 POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
749 setbits_le32(&power_regs->hw_power_vdddctrl,
750 POWER_VDDDCTRL_PWDN_BRNOUT);
752 setbits_le32(&power_regs->hw_power_vddactrl,
753 POWER_VDDACTRL_PWDN_BRNOUT);
755 setbits_le32(&power_regs->hw_power_vddioctrl,
756 POWER_VDDIOCTRL_PWDN_BRNOUT);
759 static int mxs_get_vddio_power_source_off(void)
763 if ((readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) &&
764 !(readl(&power_regs->hw_power_5vctrl) &
765 POWER_5VCTRL_ILIMIT_EQ_ZERO)) {
767 tmp = readl(&power_regs->hw_power_vddioctrl);
768 if (tmp & POWER_VDDIOCTRL_DISABLE_FET) {
769 if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
770 POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
775 if (!(readl(&power_regs->hw_power_5vctrl) &
776 POWER_5VCTRL_ENABLE_DCDC)) {
777 if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
778 POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
787 static int mxs_get_vddd_power_source_off(void)
791 tmp = readl(&power_regs->hw_power_vdddctrl);
792 if (tmp & POWER_VDDDCTRL_DISABLE_FET) {
793 if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
794 POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
799 if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
800 if (!(readl(&power_regs->hw_power_5vctrl) &
801 POWER_5VCTRL_ENABLE_DCDC)) {
806 if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) {
807 if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
808 POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) {
816 static int mxs_get_vdda_power_source_off(void)
820 tmp = readl(&power_regs->hw_power_vddactrl);
821 if (tmp & POWER_VDDACTRL_DISABLE_FET) {
822 if ((tmp & POWER_VDDACTRL_LINREG_OFFSET_MASK) ==
823 POWER_VDDACTRL_LINREG_OFFSET_0STEPS) {
828 if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
829 if (!(readl(&power_regs->hw_power_5vctrl) &
830 POWER_5VCTRL_ENABLE_DCDC)) {
835 if (!(tmp & POWER_VDDACTRL_ENABLE_LINREG)) {
836 if ((tmp & POWER_VDDACTRL_LINREG_OFFSET_MASK) ==
837 POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW) {
845 struct mxs_vddx_cfg {
850 int (*powered_by_linreg)(void);
854 uint32_t bo_offset_mask;
855 uint32_t bo_offset_offset;
858 #define POWER_REG(n) &((struct mxs_power_regs *)MXS_POWER_BASE)->n
860 static const struct mxs_vddx_cfg mxs_vddio_cfg = {
861 .reg = POWER_REG(hw_power_vddioctrl),
862 #if defined(CONFIG_MX23)
869 .powered_by_linreg = mxs_get_vddio_power_source_off,
870 .trg_mask = POWER_VDDIOCTRL_TRG_MASK,
871 .bo_irq = POWER_CTRL_VDDIO_BO_IRQ,
872 .bo_enirq = POWER_CTRL_ENIRQ_VDDIO_BO,
873 .bo_offset_mask = POWER_VDDIOCTRL_BO_OFFSET_MASK,
874 .bo_offset_offset = POWER_VDDIOCTRL_BO_OFFSET_OFFSET,
877 static const struct mxs_vddx_cfg mxs_vddd_cfg = {
878 .reg = POWER_REG(hw_power_vdddctrl),
882 .powered_by_linreg = mxs_get_vddd_power_source_off,
883 .trg_mask = POWER_VDDDCTRL_TRG_MASK,
884 .bo_irq = POWER_CTRL_VDDD_BO_IRQ,
885 .bo_enirq = POWER_CTRL_ENIRQ_VDDD_BO,
886 .bo_offset_mask = POWER_VDDDCTRL_BO_OFFSET_MASK,
887 .bo_offset_offset = POWER_VDDDCTRL_BO_OFFSET_OFFSET,
890 static const struct mxs_vddx_cfg mxs_vdda_cfg = {
891 .reg = POWER_REG(hw_power_vddactrl),
895 .powered_by_linreg = mxs_get_vdda_power_source_off,
896 .trg_mask = POWER_VDDACTRL_TRG_MASK,
897 .bo_irq = POWER_CTRL_VDDA_BO_IRQ,
898 .bo_enirq = POWER_CTRL_ENIRQ_VDDA_BO,
899 .bo_offset_mask = POWER_VDDACTRL_BO_OFFSET_MASK,
900 .bo_offset_offset = POWER_VDDACTRL_BO_OFFSET_OFFSET,
904 static const struct mxs_vddx_cfg mxs_vddmem_cfg = {
905 .reg = POWER_REG(hw_power_vddmemctrl),
909 .powered_by_linreg = NULL,
910 .trg_mask = POWER_VDDMEMCTRL_TRG_MASK,
914 .bo_offset_offset = 0,
918 static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
919 uint32_t new_target, uint32_t new_brownout)
921 uint32_t cur_target, diff, bo_int = 0;
922 int powered_by_linreg = 0;
925 if (new_target < cfg->lowest_mV)
926 new_target = cfg->lowest_mV;
927 if (new_target > cfg->highest_mV)
928 new_target = cfg->highest_mV;
930 new_brownout = DIV_ROUND(new_target - new_brownout, cfg->step_mV);
932 cur_target = readl(cfg->reg);
933 cur_target &= cfg->trg_mask;
934 cur_target *= cfg->step_mV;
935 cur_target += cfg->lowest_mV;
937 adjust_up = new_target > cur_target;
938 if (cfg->powered_by_linreg)
939 powered_by_linreg = cfg->powered_by_linreg();
941 if (adjust_up && cfg->bo_irq) {
942 if (powered_by_linreg) {
943 bo_int = readl(cfg->reg);
944 clrbits_le32(cfg->reg, cfg->bo_enirq);
946 setbits_le32(cfg->reg, cfg->bo_offset_mask);
950 if (abs(new_target - cur_target) > 100) {
952 diff = cur_target + 100;
954 diff = cur_target - 100;
959 diff -= cfg->lowest_mV;
960 diff /= cfg->step_mV;
962 clrsetbits_le32(cfg->reg, cfg->trg_mask, diff);
964 if (powered_by_linreg ||
965 (readl(&power_regs->hw_power_sts) &
966 POWER_STS_VDD5V_GT_VDDIO)) {
969 while (!(readl(&power_regs->hw_power_sts) &
975 cur_target = readl(cfg->reg);
976 cur_target &= cfg->trg_mask;
977 cur_target *= cfg->step_mV;
978 cur_target += cfg->lowest_mV;
979 } while (new_target > cur_target);
982 if (adjust_up && powered_by_linreg) {
983 writel(cfg->bo_irq, &power_regs->hw_power_ctrl_clr);
984 if (bo_int & cfg->bo_enirq)
985 setbits_le32(cfg->reg, cfg->bo_enirq);
988 clrsetbits_le32(cfg->reg, cfg->bo_offset_mask,
989 new_brownout << cfg->bo_offset_offset);
993 static void mxs_setup_batt_detect(void)
996 mxs_lradc_enable_batt_measurement();
1000 static void mxs_ungate_power(void)
1003 writel(POWER_CTRL_CLKGATE, &power_regs->hw_power_ctrl_clr);
1007 #ifdef CONFIG_CONFIG_MACH_MX28EVK
1008 #define auto_restart 1
1010 #define auto_restart 0
1013 void mxs_power_init(void)
1017 mxs_power_clock2xtal();
1018 if (mxs_power_set_auto_restart(auto_restart)) {
1019 serial_puts("Inconsistent value in RTC_PERSISTENT0 register; power-on-reset required\n");
1021 mxs_power_set_linreg();
1023 if (!fixed_batt_supply) {
1024 mxs_power_setup_5v_detect();
1025 mxs_setup_batt_detect();
1028 mxs_power_configure_power_source();
1029 mxs_enable_output_rail_protection();
1031 mxs_power_set_vddx(&mxs_vddio_cfg, VDDIO_VAL, VDDIO_BO_VAL);
1032 mxs_power_set_vddx(&mxs_vddd_cfg, VDDD_VAL, VDDD_BO_VAL);
1033 mxs_power_set_vddx(&mxs_vdda_cfg, VDDA_VAL, VDDA_BO_VAL);
1035 mxs_power_set_vddx(&mxs_vddmem_cfg, VDDMEM_VAL, VDDMEM_BO_VAL);
1037 setbits_le32(&power_regs->hw_power_vddmemctrl,
1038 POWER_VDDMEMCTRL_ENABLE_LINREG);
1040 clrbits_le32(&power_regs->hw_power_vddmemctrl,
1041 POWER_VDDMEMCTRL_ENABLE_ILIMIT);
1043 clrbits_le32(&power_regs->hw_power_vddmemctrl,
1044 POWER_VDDMEMCTRL_ENABLE_LINREG);
1046 writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
1047 POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ |
1048 POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ |
1049 POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
1050 if (!fixed_batt_supply)
1051 writel(POWER_5VCTRL_PWDN_5VBRNOUT,
1052 &power_regs->hw_power_5vctrl_set);
1055 #ifdef CONFIG_SPL_MXS_PSWITCH_WAIT
1056 void mxs_power_wait_pswitch(void)
1058 while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))