]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
cleanup spl_power_init.c:
authorLothar Waßmann <LW@KARO-electronics.de>
Tue, 20 Mar 2012 11:01:45 +0000 (12:01 +0100)
committerLothar Waßmann <LW@KARO-electronics.de>
Tue, 20 Mar 2012 11:01:45 +0000 (12:01 +0100)
- use function mx28_get_batt_volt() instead of copying its code
- remove redundant ()
- remove empty lines
- remove bogus delay

arch/arm/cpu/arm926ejs/mx28/spl_power_init.c

index 2146742e1f7f250ec943534dbd0a9e8f4c7ee827..3f4728b7070de28e2be03bb373fb8103ca894062 100644 (file)
 
 #include "mx28_init.h"
 
-static struct mx28_power_regs *power_regs = (void *)MXS_POWER_BASE;
-
-#define DEBUG
-#define __static
-
-#include "debug.h"
-
-#undef __arch_getl
-#undef __arch_putl
-
-#define __arch_getl(a) arch_getl(a, __func__, __LINE__)
-static inline unsigned int arch_getl(volatile void *addr,
-                       const char *fn, unsigned int ln)
-{
-       volatile unsigned int *a = addr;
-       unsigned int val = *a;
-       dbg(0, "%s@%d: Read %x from %p\n", fn, ln, val, addr);
-       return val;
-}
-
-#define __arch_putl(v, a)      arch_putl(v, a, __func__, __LINE__)
-static inline void arch_putl(unsigned int val, volatile void *addr,
-                       const char *fn, unsigned int ln)
-{
-       volatile unsigned int *a = addr;
-
-       dbg(0, "%s@%d: Writing %x to %p\n", fn, ln, val, addr);
-       *a = val;
-}
-
-__static int mx28_power_vdd5v_gt_vddio(void)
-{
-       int power_sts = readl(&power_regs->hw_power_sts);
-return 0;
-       dbg(3, "%s@%d: %d\n", __func__, __LINE__,
-               !!(power_sts & POWER_STS_VDD5V_GT_VDDIO));
-       return power_sts & POWER_STS_VDD5V_GT_VDDIO;
-}
-
-static void memdump(unsigned long addr, unsigned long len)
-{
-#ifdef DEBUG
-       int i;
-       uint32_t *ptr = (void *)addr;
-
-       for (i = 0; i < len; i++) {
-               if (i % 4 == 0)
-                       dbg(3, "\n%x:", &ptr[i]);
-               dbg(3, " %x", ptr[i]);
-       }
-       dbg(3, "\n");
-#endif
-}
-
-__static void mx28_power_clock2xtal(void)
+void mx28_power_clock2xtal(void)
 {
        struct mx28_clkctrl_regs *clkctrl_regs =
                (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
        /* Set XTAL as CPU reference clock */
        writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
                &clkctrl_regs->hw_clkctrl_clkseq_set);
 }
 
-__static void mx28_power_clock2pll(void)
+void mx28_power_clock2pll(void)
 {
        struct mx28_clkctrl_regs *clkctrl_regs =
                (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
        writel(CLKCTRL_PLL0CTRL0_POWER,
                &clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
        early_delay(100);
@@ -108,12 +52,11 @@ __static void mx28_power_clock2pll(void)
                &clkctrl_regs->hw_clkctrl_clkseq_clr);
 }
 
-__static void mx28_power_clear_auto_restart(void)
+void mx28_power_clear_auto_restart(void)
 {
        struct mx28_rtc_regs *rtc_regs =
                (struct mx28_rtc_regs *)MXS_RTC_BASE;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
        writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr);
        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST)
                ;
@@ -121,7 +64,7 @@ __static void mx28_power_clear_auto_restart(void)
        writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr);
        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE)
                ;
-#ifdef CONFIG_MACH_MX28EVK
+
        /*
         * Due to the hardware design bug of mx28 EVK-A
         * we need to set the AUTO_RESTART bit.
@@ -140,16 +83,17 @@ __static void mx28_power_clear_auto_restart(void)
                ;
        while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK)
                ;
-#endif
 }
 
-__static void mx28_power_set_linreg(void)
+void mx28_power_set_linreg(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
        /* Set linear regulator 25mV below switching converter */
        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
                        POWER_VDDDCTRL_LINREG_OFFSET_MASK,
-                       POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_ABOVE);
+                       POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
 
        clrsetbits_le32(&power_regs->hw_power_vddactrl,
                        POWER_VDDACTRL_LINREG_OFFSET_MASK,
@@ -158,13 +102,25 @@ __static void mx28_power_set_linreg(void)
        clrsetbits_le32(&power_regs->hw_power_vddioctrl,
                        POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
                        POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
-       dbg(3, "%s@%d: vddioctrl=%x\n", __func__, __LINE__,
-               readl(&power_regs->hw_power_vddioctrl));
 }
 
-__static void mx28_src_power_init(void)
+void mx28_power_setup_5v_detect(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
+       /* Start 5V detection */
+       clrsetbits_le32(&power_regs->hw_power_5vctrl,
+                       POWER_5VCTRL_VBUSVALID_TRSH_MASK,
+                       POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
+                       POWER_5VCTRL_PWRUP_VBUS_CMPS);
+}
+
+void mx28_src_power_init(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
        /* Improve efficieny and reduce transient ripple */
        writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST |
                POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set);
@@ -184,52 +140,397 @@ __static void mx28_src_power_init(void)
 
        clrsetbits_le32(&power_regs->hw_power_minpwr,
                        POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
-#ifndef CONFIG_SPL_FIXED_BATT_SUPPLY
+
        /* 5V to battery handoff ... FIXME */
        setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
        early_delay(30);
        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
-#endif
+}
+
+void mx28_power_init_4p2_params(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
+       /* Setup 4P2 parameters */
+       clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+               POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
+               POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET));
+
+       clrsetbits_le32(&power_regs->hw_power_5vctrl,
+               POWER_5VCTRL_HEADROOM_ADJ_MASK,
+               0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET);
+
+       clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+               POWER_DCDC4P2_DROPOUT_CTRL_MASK,
+               POWER_DCDC4P2_DROPOUT_CTRL_100MV |
+               POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL);
+
+       clrsetbits_le32(&power_regs->hw_power_5vctrl,
+               POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+               0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+}
+
+void mx28_enable_4p2_dcdc_input(int xfer)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
+       uint32_t prev_5v_brnout, prev_5v_droop;
+
+       prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
+                               POWER_5VCTRL_PWDN_5VBRNOUT;
+       prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
+                               POWER_CTRL_ENIRQ_VDD5V_DROOP;
+
+       clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
+       writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
+               &power_regs->hw_power_reset);
+
+       clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP);
+
+       if (xfer && (readl(&power_regs->hw_power_5vctrl) &
+                       POWER_5VCTRL_ENABLE_DCDC)) {
+               return;
+       }
+
+       /*
+        * Recording orignal values that will be modified temporarlily
+        * to handle a chip bug. See chip errata for CQ ENGR00115837
+        */
+       tmp = readl(&power_regs->hw_power_5vctrl);
+       vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK;
+       vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT;
+
+       pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO;
+
+       /*
+        * Disable mechanisms that get erroneously tripped by when setting
+        * the DCDC4P2 EN_DCDC
+        */
+       clrbits_le32(&power_regs->hw_power_5vctrl,
+               POWER_5VCTRL_VBUSVALID_5VDETECT |
+               POWER_5VCTRL_VBUSVALID_TRSH_MASK);
+
+       writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set);
+
+       if (xfer) {
+               setbits_le32(&power_regs->hw_power_5vctrl,
+                               POWER_5VCTRL_DCDC_XFER);
+               early_delay(20);
+               clrbits_le32(&power_regs->hw_power_5vctrl,
+                               POWER_5VCTRL_DCDC_XFER);
+
+               setbits_le32(&power_regs->hw_power_5vctrl,
+                               POWER_5VCTRL_ENABLE_DCDC);
+       } else {
+               setbits_le32(&power_regs->hw_power_dcdc4p2,
+                               POWER_DCDC4P2_ENABLE_DCDC);
+       }
+
+       early_delay(25);
+
+       clrsetbits_le32(&power_regs->hw_power_5vctrl,
+                       POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh);
+
+       if (vbus_5vdetect)
+               writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set);
+
+       if (!pwd_bo)
+               clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO);
+
+       while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ)
+               writel(POWER_CTRL_VBUS_VALID_IRQ,
+                       &power_regs->hw_power_ctrl_clr);
+
+       if (prev_5v_brnout) {
+               writel(POWER_5VCTRL_PWDN_5VBRNOUT,
+                       &power_regs->hw_power_5vctrl_set);
+               writel(POWER_RESET_UNLOCK_KEY,
+                       &power_regs->hw_power_reset);
+       } else {
+               writel(POWER_5VCTRL_PWDN_5VBRNOUT,
+                       &power_regs->hw_power_5vctrl_clr);
+               writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
+                       &power_regs->hw_power_reset);
+       }
+
+       while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ)
+               writel(POWER_CTRL_VDD5V_DROOP_IRQ,
+                       &power_regs->hw_power_ctrl_clr);
+
+       if (prev_5v_droop)
+               clrbits_le32(&power_regs->hw_power_ctrl,
+                               POWER_CTRL_ENIRQ_VDD5V_DROOP);
+       else
+               setbits_le32(&power_regs->hw_power_ctrl,
+                               POWER_CTRL_ENIRQ_VDD5V_DROOP);
+}
+
+void mx28_power_init_4p2_regulator(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t tmp, tmp2;
+
+       setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
+
+       writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
+
+       writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+               &power_regs->hw_power_5vctrl_clr);
+       clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK);
+
+       /* Power up the 4p2 rail and logic/control */
+       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+               &power_regs->hw_power_5vctrl_clr);
+
+       /*
+        * Start charging up the 4p2 capacitor. We ramp of this charge
+        * gradually to avoid large inrush current from the 5V cable which can
+        * cause transients/problems
+        */
+       mx28_enable_4p2_dcdc_input(0);
+
+       if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
+               /*
+                * If we arrived here, we were unable to recover from mx23 chip
+                * errata 5837. 4P2 is disabled and sufficient battery power is
+                * not present. Exiting to not enable DCDC power during 5V
+                * connected state.
+                */
+               clrbits_le32(&power_regs->hw_power_dcdc4p2,
+                       POWER_DCDC4P2_ENABLE_DCDC);
+               writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+                       &power_regs->hw_power_5vctrl_set);
+               hang();
+       }
+
+       /*
+        * Here we set the 4p2 brownout level to something very close to 4.2V.
+        * We then check the brownout status. If the brownout status is false,
+        * the voltage is already close to the target voltage of 4.2V so we
+        * can go ahead and set the 4P2 current limit to our max target limit.
+        * If the brownout status is true, we need to ramp us the current limit
+        * so that we don't cause large inrush current issues. We step up the
+        * current limit until the brownout status is false or until we've
+        * reached our maximum defined 4p2 current limit.
+        */
+       clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+                       POWER_DCDC4P2_BO_MASK,
+                       22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
+
+       if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) {
+               setbits_le32(&power_regs->hw_power_5vctrl,
+                       0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+       } else {
+               tmp = (readl(&power_regs->hw_power_5vctrl) &
+                       POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >>
+                       POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
+               while (tmp < 0x3f) {
+                       if (!(readl(&power_regs->hw_power_sts) &
+                                       POWER_STS_DCDC_4P2_BO)) {
+                               tmp = readl(&power_regs->hw_power_5vctrl);
+                               tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
+                               early_delay(100);
+                               writel(tmp, &power_regs->hw_power_5vctrl);
+                               break;
+                       } else {
+                               tmp++;
+                               tmp2 = readl(&power_regs->hw_power_5vctrl);
+                               tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
+                               tmp2 |= tmp <<
+                                       POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
+                               writel(tmp2, &power_regs->hw_power_5vctrl);
+                               early_delay(100);
+                       }
+               }
+       }
+
+       clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
+       writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+}
+
+void mx28_power_init_dcdc_4p2_source(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
+       if (!(readl(&power_regs->hw_power_dcdc4p2) &
+               POWER_DCDC4P2_ENABLE_DCDC)) {
+               hang();
+       }
+
+       mx28_enable_4p2_dcdc_input(1);
+
+       if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
+               clrbits_le32(&power_regs->hw_power_dcdc4p2,
+                       POWER_DCDC4P2_ENABLE_DCDC);
+               writel(POWER_5VCTRL_ENABLE_DCDC,
+                       &power_regs->hw_power_5vctrl_clr);
+               writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+                       &power_regs->hw_power_5vctrl_set);
+       }
+}
+
+void mx28_power_enable_4p2(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t vdddctrl, vddactrl, vddioctrl;
+       uint32_t tmp;
+
+       vdddctrl = readl(&power_regs->hw_power_vdddctrl);
+       vddactrl = readl(&power_regs->hw_power_vddactrl);
+       vddioctrl = readl(&power_regs->hw_power_vddioctrl);
+
+       setbits_le32(&power_regs->hw_power_vdddctrl,
+               POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
+               POWER_VDDDCTRL_PWDN_BRNOUT);
+
+       setbits_le32(&power_regs->hw_power_vddactrl,
+               POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG |
+               POWER_VDDACTRL_PWDN_BRNOUT);
+
+       setbits_le32(&power_regs->hw_power_vddioctrl,
+               POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT);
+
+       mx28_power_init_4p2_params();
+       mx28_power_init_4p2_regulator();
+
+       /* Shutdown battery (none present) */
+       clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
+       writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+       writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
+
+       mx28_power_init_dcdc_4p2_source();
+
+       writel(vdddctrl, &power_regs->hw_power_vdddctrl);
+       early_delay(20);
+       writel(vddactrl, &power_regs->hw_power_vddactrl);
+       early_delay(20);
+       writel(vddioctrl, &power_regs->hw_power_vddioctrl);
+
+       /*
+        * Check if FET is enabled on either powerout and if so,
+        * disable load.
+        */
+       tmp = 0;
+       tmp |= !(readl(&power_regs->hw_power_vdddctrl) &
+                       POWER_VDDDCTRL_DISABLE_FET);
+       tmp |= !(readl(&power_regs->hw_power_vddactrl) &
+                       POWER_VDDACTRL_DISABLE_FET);
+       tmp |= !(readl(&power_regs->hw_power_vddioctrl) &
+                       POWER_VDDIOCTRL_DISABLE_FET);
+       if (tmp)
+               writel(POWER_CHARGE_ENABLE_LOAD,
+                       &power_regs->hw_power_charge_clr);
+}
+
+void mx28_boot_valid_5v(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
+       /*
+        * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
+        * disconnect event. FIXME
+        */
+       writel(POWER_5VCTRL_VBUSVALID_5VDETECT,
+               &power_regs->hw_power_5vctrl_set);
+
+       /* Configure polarity to check for 5V disconnection. */
+       writel(POWER_CTRL_POLARITY_VBUSVALID |
+               POWER_CTRL_POLARITY_VDD5V_GT_VDDIO,
+               &power_regs->hw_power_ctrl_clr);
+
+       writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ,
+               &power_regs->hw_power_ctrl_clr);
+
+       mx28_power_enable_4p2();
 }
 
 void mx28_powerdown(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
        writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
        writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
                &power_regs->hw_power_reset);
 }
 
-__static void mx28_fixed_batt_boot(void)
+void mx28_handle_5v_conflict(void)
 {
-       writel(POWER_5VCTRL_PWDN_5VBRNOUT,
-               &power_regs->hw_power_5vctrl_set);
-       writel(POWER_5VCTRL_ENABLE_DCDC,
-               &power_regs->hw_power_5vctrl_set);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t tmp;
 
-       writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
+       setbits_le32(&power_regs->hw_power_vddioctrl,
+                       POWER_VDDIOCTRL_BO_OFFSET_MASK);
 
-       clrsetbits_le32(&power_regs->hw_power_vdddctrl,
-                       POWER_VDDDCTRL_DISABLE_FET |
-                       POWER_VDDDCTRL_ENABLE_LINREG,
-                       POWER_VDDDCTRL_DISABLE_STEPPING);
+       for (;;) {
+               tmp = readl(&power_regs->hw_power_sts);
 
-       /* Stop 5V detection */
-       writel(POWER_5VCTRL_PWRUP_VBUS_CMPS,
-               &power_regs->hw_power_5vctrl_clr);
+               if (tmp & POWER_STS_VDDIO_BO) {
+                       mx28_powerdown();
+                       break;
+               }
+
+               if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
+                       mx28_boot_valid_5v();
+                       break;
+               } else {
+                       mx28_powerdown();
+                       break;
+               }
+       }
 }
 
-#ifndef CONFIG_SPL_FIXED_BATT_SUPPLY
-#define BATT_BO_VALUE  15
-#else
-/* Brownout at 3.08V */
-#define BATT_BO_VALUE  17
-#endif
+int mx28_get_batt_volt(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t volt = readl(&power_regs->hw_power_battmonitor);
+
+       volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
+       volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
+       volt *= 8;
+       return volt;
+}
+
+int mx28_is_batt_ready(void)
+{
+       return mx28_get_batt_volt() >= 3600;
+}
 
-__static void mx28_init_batt_bo(void)
+void mx28_5v_boot(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
-#ifndef CONFIG_SPL_FIXED_BATT_SUPPLY
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
+       /*
+        * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID,
+        * but their implementation always returns 1 so we omit it here.
+        */
+       if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+               mx28_boot_valid_5v();
+               return;
+       }
+
+       early_delay(1000);
+       if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+               mx28_boot_valid_5v();
+               return;
+       }
+
+       mx28_handle_5v_conflict();
+}
+
+void mx28_init_batt_bo(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
        /* Brownout at 3V */
        clrsetbits_le32(&power_regs->hw_power_battmonitor,
                POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
@@ -237,30 +538,83 @@ __static void mx28_init_batt_bo(void)
 
        writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr);
        writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr);
-#else
-       setbits_le32(&power_regs->hw_power_battmonitor,
-               POWER_BATTMONITOR_PWDN_BATTBRNOUT);
-       writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr);
-#endif
 }
 
-__static void mx28_switch_vddd_to_dcdc_source(void)
+void mx28_switch_vddd_to_dcdc_source(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
-       clrsetbits_le32(&power_regs->hw_power_vdddctrl,
-                       POWER_VDDDCTRL_LINREG_OFFSET_MASK,
-                       POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
 
        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
-                       POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_DISABLE_STEPPING,
-                       POWER_VDDDCTRL_ENABLE_LINREG);
+               POWER_VDDDCTRL_LINREG_OFFSET_MASK,
+               POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
+
+       clrbits_le32(&power_regs->hw_power_vdddctrl,
+               POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
+               POWER_VDDDCTRL_DISABLE_STEPPING);
 }
 
-__static void mx28_enable_output_rail_protection(void)
+int mx28_is_batt_good(void)
 {
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+       uint32_t volt;
+
+       volt = mx28_get_batt_volt();
+
+       if ((volt >= 2400) && (volt <= 4300))
+               return 1;
+
+       clrsetbits_le32(&power_regs->hw_power_5vctrl,
+               POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+               0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+               &power_regs->hw_power_5vctrl_clr);
+
+       clrsetbits_le32(&power_regs->hw_power_charge,
+               POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+               POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
+
+       writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
+       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+               &power_regs->hw_power_5vctrl_clr);
+
+       early_delay(500000);
+
+       volt = mx28_get_batt_volt();
+
+       if (volt >= 3500)
+               return 0;
+
+       if (volt >= 2400)
+               return 1;
+
+       writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+               &power_regs->hw_power_charge_clr);
+       writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
+
+       return 0;
+}
+
+void mx28_power_configure_power_source(void)
+{
+       mx28_src_power_init();
+
+       mx28_5v_boot();
+       mx28_power_clock2pll();
+
+       mx28_init_batt_bo();
+       mx28_switch_vddd_to_dcdc_source();
+}
+
+void mx28_enable_output_rail_protection(void)
+{
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
                POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
-#if 0
+
        setbits_le32(&power_regs->hw_power_vdddctrl,
                        POWER_VDDDCTRL_PWDN_BRNOUT);
 
@@ -269,66 +623,48 @@ __static void mx28_enable_output_rail_protection(void)
 
        setbits_le32(&power_regs->hw_power_vddioctrl,
                        POWER_VDDIOCTRL_PWDN_BRNOUT);
-#else
-       clrbits_le32(&power_regs->hw_power_vdddctrl,
-                       POWER_VDDDCTRL_PWDN_BRNOUT);
-
-       clrbits_le32(&power_regs->hw_power_vddactrl,
-                       POWER_VDDACTRL_PWDN_BRNOUT);
-
-       clrbits_le32(&power_regs->hw_power_vddioctrl,
-                       POWER_VDDIOCTRL_PWDN_BRNOUT);
-#endif
 }
 
-__static int mx28_get_vddio_power_source_off(void)
+int mx28_get_vddio_power_source_off(void)
 {
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
        uint32_t tmp;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
-       if (mx28_power_vdd5v_gt_vddio()) {
+       if ((readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) &&
+               !(readl(&power_regs->hw_power_5vctrl) &
+                       POWER_5VCTRL_ILIMIT_EQ_ZERO)) {
+
                tmp = readl(&power_regs->hw_power_vddioctrl);
                if (tmp & POWER_VDDIOCTRL_DISABLE_FET) {
                        if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
                                POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
-                               dbg(3, "%s@%d: 1\n", __func__, __LINE__);
                                return 1;
                        }
                }
 
                if (!(readl(&power_regs->hw_power_5vctrl) &
                        POWER_5VCTRL_ENABLE_DCDC)) {
-                       dbg(3, "tmp=%x mask %x = %x == %x?\n",
-                               tmp, POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
-                               tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
-                               POWER_VDDDCTRL_LINREG_OFFSET_0STEPS);
                        if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
                                POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
-                               dbg(3, "%s@%d: 1\n", __func__, __LINE__);
-                               return 1;
-                       }
-                       if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
-                               POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW) {
-                               dbg(3, "%s@%d: 1\n", __func__, __LINE__);
                                return 1;
                        }
                }
        }
-       dbg(3, "%s@%d: 0\n", __func__, __LINE__);
+
        return 0;
 }
 
-__static int mx28_get_vddd_power_source_off(void)
+int mx28_get_vddd_power_source_off(void)
 {
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
        uint32_t tmp;
 
-return 0;
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
        tmp = readl(&power_regs->hw_power_vdddctrl);
        if (tmp & POWER_VDDDCTRL_DISABLE_FET) {
                if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
                        POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
-                       dbg(3, "%s@%d: 1\n", __func__, __LINE__);
                        return 1;
                }
        }
@@ -336,33 +672,28 @@ return 0;
        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
                if (!(readl(&power_regs->hw_power_5vctrl) &
                        POWER_5VCTRL_ENABLE_DCDC)) {
-                       dbg(3, "%s@%d: 1\n", __func__, __LINE__);
                        return 1;
                }
        }
 
-       if ((tmp & POWER_VDDDCTRL_ENABLE_LINREG)) {
+       if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) {
                if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
                        POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) {
-                       dbg(3, "%s@%d: 1\n", __func__, __LINE__);
                        return 1;
                }
        }
-       dbg(3, "%s@%d: 0\n", __func__, __LINE__);
+
        return 0;
 }
 
-__static void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
+void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
 {
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
        uint32_t cur_target, diff, bo_int = 0;
-       uint32_t powered_by_linreg;
+       uint32_t powered_by_linreg = 0;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
-       new_brownout = (new_target - new_brownout) / 25;
-       if (new_brownout > 7) {
-               dbg(3, "Bad VDDD brownout offset\n");
-               new_brownout = 7;
-       }
+       new_brownout = new_target - new_brownout;
 
        cur_target = readl(&power_regs->hw_power_vddioctrl);
        cur_target &= POWER_VDDIOCTRL_TRG_MASK;
@@ -370,12 +701,6 @@ __static void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
        cur_target += 2800;     /* 2800 mV lowest */
 
        powered_by_linreg = mx28_get_vddio_power_source_off();
-       if (new_target != cur_target)
-               dbg(3, "%s@%d: stepping VDDIO from %u to %u\n", __func__, __LINE__,
-                       cur_target, new_target);
-       else
-               dbg(3, "%s@%d: VDDIO is at %u\n", __func__, __LINE__,
-                       cur_target, new_target);
        if (new_target > cur_target) {
 
                if (powered_by_linreg) {
@@ -397,19 +722,15 @@ __static void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
 
                        clrsetbits_le32(&power_regs->hw_power_vddioctrl,
                                POWER_VDDIOCTRL_TRG_MASK, diff);
-                       dbg(3, "%s@%d: vddioctrl=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_vddioctrl));
 
                        if (powered_by_linreg)
                                early_delay(1500);
                        else {
                                while (!(readl(&power_regs->hw_power_sts) &
-                                               POWER_STS_DC_OK)) {
-                                       early_delay(1);
-                               }
+                                       POWER_STS_DC_OK))
+                                       ;
+
                        }
-                       dbg(3, "%s@%d: sts=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_sts));
 
                        cur_target = readl(&power_regs->hw_power_vddioctrl);
                        cur_target &= POWER_VDDIOCTRL_TRG_MASK;
@@ -423,10 +744,7 @@ __static void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
                        if (bo_int & POWER_CTRL_ENIRQ_VDDIO_BO)
                                setbits_le32(&power_regs->hw_power_vddioctrl,
                                                POWER_CTRL_ENIRQ_VDDIO_BO);
-                       dbg(3, "%s@%d: vddioctrl=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_vddioctrl));
                }
-               dbg(3, "%s@%d: Done\n", __func__, __LINE__);
        } else {
                do {
                        if (cur_target - new_target > 100)
@@ -444,51 +762,38 @@ __static void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
                                early_delay(1500);
                        else {
                                while (!(readl(&power_regs->hw_power_sts) &
-                                               POWER_STS_DC_OK)) {
-                                       early_delay(1);
-                               }
+                                       POWER_STS_DC_OK))
+                                       ;
+
                        }
-                       dbg(3, "%s@%d: sts=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_sts));
 
                        cur_target = readl(&power_regs->hw_power_vddioctrl);
                        cur_target &= POWER_VDDIOCTRL_TRG_MASK;
                        cur_target *= 50;       /* 50 mV step*/
                        cur_target += 2800;     /* 2800 mV lowest */
                } while (new_target < cur_target);
-               dbg(3, "%s@%d: Done\n", __func__, __LINE__);
        }
 
        clrsetbits_le32(&power_regs->hw_power_vddioctrl,
                        POWER_VDDDCTRL_BO_OFFSET_MASK,
                        new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
-       dbg(3, "%s@%d: vddioctrl=%x\n", __func__, __LINE__,
-               readl(&power_regs->hw_power_vddioctrl));
 }
 
-__static void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
+void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
 {
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
        uint32_t cur_target, diff, bo_int = 0;
-       uint32_t powered_by_linreg;
+       uint32_t powered_by_linreg = 0;
+
+       new_brownout = new_target - new_brownout;
 
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
-       new_brownout = (new_target - new_brownout) / 25;
-       if (new_brownout > 7) {
-               dbg(3, "Bad VDDD brownout offset\n");
-               new_brownout = 7;
-       }
        cur_target = readl(&power_regs->hw_power_vdddctrl);
        cur_target &= POWER_VDDDCTRL_TRG_MASK;
        cur_target *= 25;       /* 25 mV step*/
        cur_target += 800;      /* 800 mV lowest */
 
        powered_by_linreg = mx28_get_vddd_power_source_off();
-       if (new_target != cur_target)
-               dbg(3, "%s@%d: stepping VDDD from %u to %u\n", __func__, __LINE__,
-                       cur_target, new_target);
-       else
-               dbg(3, "%s@%d: VDDD is at %u\n", __func__, __LINE__,
-                       cur_target, new_target);
        if (new_target > cur_target) {
                if (powered_by_linreg) {
                        bo_int = readl(&power_regs->hw_power_vdddctrl);
@@ -515,12 +820,10 @@ __static void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
                                early_delay(1500);
                        else {
                                while (!(readl(&power_regs->hw_power_sts) &
-                                               POWER_STS_DC_OK)) {
-                                       early_delay(1);
-                               }
+                                       POWER_STS_DC_OK))
+                                       ;
+
                        }
-                       dbg(3, "%s@%d: sts=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_sts));
 
                        cur_target = readl(&power_regs->hw_power_vdddctrl);
                        cur_target &= POWER_VDDDCTRL_TRG_MASK;
@@ -535,7 +838,6 @@ __static void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
                                setbits_le32(&power_regs->hw_power_vdddctrl,
                                                POWER_CTRL_ENIRQ_VDDD_BO);
                }
-               dbg(3, "%s@%d: Done\n", __func__, __LINE__);
        } else {
                do {
                        if (cur_target - new_target > 100)
@@ -553,19 +855,16 @@ __static void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
                                early_delay(1500);
                        else {
                                while (!(readl(&power_regs->hw_power_sts) &
-                                               POWER_STS_DC_OK)) {
-                                       early_delay(1);
-                               }
+                                       POWER_STS_DC_OK))
+                                       ;
+
                        }
-                       dbg(3, "%s@%d: sts=%x\n", __func__, __LINE__,
-                               readl(&power_regs->hw_power_sts));
 
                        cur_target = readl(&power_regs->hw_power_vdddctrl);
                        cur_target &= POWER_VDDDCTRL_TRG_MASK;
                        cur_target *= 25;       /* 25 mV step*/
                        cur_target += 800;      /* 800 mV lowest */
                } while (new_target < cur_target);
-               dbg(3, "%s@%d: Done\n", __func__, __LINE__);
        }
 
        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
@@ -575,62 +874,35 @@ __static void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
 
 void mx28_power_init(void)
 {
-       dprintf("%s: %s %s\n", __func__, __DATE__, __TIME__);
-       dbg(0, "ctrl=%x\n", readl(&power_regs->hw_power_ctrl));
-       dbg(0, "sts=%x\n", readl(&power_regs->hw_power_sts));
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
 
-       dbg(3, "%s@%d\n", __func__, __LINE__);
        mx28_power_clock2xtal();
-       dbg(3, "%s@%d\n", __func__, __LINE__);
        mx28_power_clear_auto_restart();
-       dbg(3, "%s@%d\n", __func__, __LINE__);
        mx28_power_set_linreg();
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-
-       mx28_src_power_init();
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-       early_delay(10000);
-       mx28_fixed_batt_boot();
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-       early_delay(10000);
-       mx28_power_clock2pll();
-       early_delay(10000);
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-       mx28_init_batt_bo();
-       early_delay(10000);
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-       mx28_switch_vddd_to_dcdc_source();
-       early_delay(10000);
-
-       dbg(3, "%s@%d\n", __func__, __LINE__);
+       mx28_power_setup_5v_detect();
+       mx28_power_configure_power_source();
        mx28_enable_output_rail_protection();
 
-       dbg(3, "%s@%d\n", __func__, __LINE__);
        mx28_power_set_vddio(3300, 3150);
 
-       dbg(3, "%s@%d\n", __func__, __LINE__);
-       mx28_power_set_vddd(1500, 1325);
-       dbg(3, "%s@%d\n", __func__, __LINE__);
+       mx28_power_set_vddd(1350, 1200);
 
        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
                POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ |
                POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ |
                POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 
-       dbg(3, "sts=%x\n", readl(&power_regs->hw_power_sts));
-       dbg(3, "vddioctrl=%x\n", readl(&power_regs->hw_power_vddioctrl));
-       dbg(3, "vdddctrl=%x\n", readl(&power_regs->hw_power_vdddctrl));
-       dbg(3, "5vctrl=%x\n", readl(&power_regs->hw_power_5vctrl));
-       dbg(3, "dcdc4p2=%x\n", readl(&power_regs->hw_power_dcdc4p2));
-       dbg(3, "%s@%d: Finished\n", __func__, __LINE__);
-       memdump(0x80044000, 0x60);
-       early_delay(1000);
+       writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
+
 }
 
 #ifdef CONFIG_SPL_MX28_PSWITCH_WAIT
 void mx28_power_wait_pswitch(void)
 {
-       dbg(3, "%s@%d: \n", __func__, __LINE__);
+       struct mx28_power_regs *power_regs =
+               (struct mx28_power_regs *)MXS_POWER_BASE;
+
        while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
                ;
 }