]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
ARM: mxs: fix VDDD brownout setting
[people/ms/u-boot.git] / arch / arm / cpu / arm926ejs / mxs / spl_power_init.c
index d25019a51ef2ab0aa58ac75b923898a885365959..1972de81a8edd2f542814922fb5485ec7e52c409 100644 (file)
 
 #include "mxs_init.h"
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+#define DCDC4P2_DROPOUT_CONFIG POWER_DCDC4P2_DROPOUT_CTRL_100MV | \
+                               POWER_DCDC4P2_DROPOUT_CTRL_SRC_4P2
+#else
+#define DCDC4P2_DROPOUT_CONFIG POWER_DCDC4P2_DROPOUT_CTRL_100MV | \
+                               POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL
+#endif
 /**
  * mxs_power_clock2xtal() - Switch CPU core clock source to 24MHz XTAL
  *
@@ -26,6 +33,8 @@ static void mxs_power_clock2xtal(void)
        struct mxs_clkctrl_regs *clkctrl_regs =
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
+       debug("SPL: Switching CPU clock to 24MHz XTAL\n");
+
        /* Set XTAL as CPU reference clock */
        writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
                &clkctrl_regs->hw_clkctrl_clkseq_set);
@@ -43,9 +52,23 @@ static void mxs_power_clock2pll(void)
        struct mxs_clkctrl_regs *clkctrl_regs =
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
+       debug("SPL: Switching CPU core clock source to PLL\n");
+
+       /*
+        * TODO: Are we really? It looks like we turn on PLL0, but we then
+        * set the CLKCTRL_CLKSEQ_BYPASS_CPU bit of the (which was already
+        * set by mxs_power_clock2xtal()). Clearing this bit here seems to
+        * introduce some instability (causing the CPU core to hang). Maybe
+        * we aren't giving PLL0 enough time to stabilise?
+        */
        setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
                        CLKCTRL_PLL0CTRL0_POWER);
        early_delay(100);
+
+       /*
+        * TODO: Should the PLL0 FORCE_LOCK bit be set here followed be a
+        * wait on the PLL0 LOCK bit?
+        */
        setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
                        CLKCTRL_CLKSEQ_BYPASS_CPU);
 }
@@ -62,6 +85,8 @@ static void mxs_power_set_auto_restart(void)
        struct mxs_rtc_regs *rtc_regs =
                (struct mxs_rtc_regs *)MXS_RTC_BASE;
 
+       debug("SPL: Setting auto-restart bit\n");
+
        writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr);
        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST)
                ;
@@ -101,14 +126,17 @@ static void mxs_power_set_linreg(void)
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
        /* Set linear regulator 25mV below switching converter */
+       debug("SPL: Setting VDDD 25mV below DC-DC converters\n");
        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
                        POWER_VDDDCTRL_LINREG_OFFSET_MASK,
                        POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
 
+       debug("SPL: Setting VDDA 25mV below DC-DC converters\n");
        clrsetbits_le32(&power_regs->hw_power_vddactrl,
                        POWER_VDDACTRL_LINREG_OFFSET_MASK,
                        POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW);
 
+       debug("SPL: Setting VDDIO 25mV below DC-DC converters\n");
        clrsetbits_le32(&power_regs->hw_power_vddioctrl,
                        POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
                        POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
@@ -127,6 +155,8 @@ static int mxs_get_batt_volt(void)
        volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
        volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
        volt *= 8;
+
+       debug("SPL: Battery Voltage = %dmV\n", volt);
        return volt;
 }
 
@@ -154,8 +184,10 @@ static int mxs_is_batt_good(void)
                (struct mxs_power_regs *)MXS_POWER_BASE;
        uint32_t volt = mxs_get_batt_volt();
 
-       if ((volt >= 2400) && (volt <= 4300))
+       if ((volt >= 2400) && (volt <= 4300)) {
+               debug("SPL: Battery is good\n");
                return 1;
+       }
 
        clrsetbits_le32(&power_regs->hw_power_5vctrl,
                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
@@ -175,16 +207,21 @@ static int mxs_is_batt_good(void)
 
        volt = mxs_get_batt_volt();
 
-       if (volt >= 3500)
+       if (volt >= 3500) {
+               debug("SPL: Battery Voltage too high\n");
                return 0;
+       }
 
-       if (volt >= 2400)
+       if (volt >= 2400) {
+               debug("SPL: Battery is good\n");
                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);
 
+       debug("SPL: Battery Voltage too low\n");
        return 0;
 }
 
@@ -203,6 +240,7 @@ static void mxs_power_setup_5v_detect(void)
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
        /* Start 5V detection */
+       debug("SPL: Starting 5V input detection comparator\n");
        clrsetbits_le32(&power_regs->hw_power_5vctrl,
                        POWER_5VCTRL_VBUSVALID_TRSH_MASK,
                        POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
@@ -220,6 +258,8 @@ static void mxs_src_power_init(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Pre-Configuring power block\n");
+
        /* 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);
@@ -257,6 +297,8 @@ static void mxs_power_init_4p2_params(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Configuring common 4P2 regulator params\n");
+
        /* Setup 4P2 parameters */
        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
                POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
@@ -268,8 +310,7 @@ static void mxs_power_init_4p2_params(void)
 
        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
                POWER_DCDC4P2_DROPOUT_CTRL_MASK,
-               POWER_DCDC4P2_DROPOUT_CTRL_100MV |
-               POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL);
+               DCDC4P2_DROPOUT_CONFIG);
 
        clrsetbits_le32(&power_regs->hw_power_5vctrl,
                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
@@ -289,6 +330,13 @@ static void mxs_enable_4p2_dcdc_input(int xfer)
        uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
        uint32_t prev_5v_brnout, prev_5v_droop;
 
+       debug("SPL: %s 4P2 DC-DC Input\n", xfer ? "Enabling" : "Disabling");
+
+       if (xfer && (readl(&power_regs->hw_power_5vctrl) &
+                       POWER_5VCTRL_ENABLE_DCDC)) {
+               return;
+       }
+
        prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
                                POWER_5VCTRL_PWDN_5VBRNOUT;
        prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
@@ -300,11 +348,6 @@ static void mxs_enable_4p2_dcdc_input(int xfer)
 
        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
@@ -390,6 +433,8 @@ static void mxs_power_init_4p2_regulator(void)
                (struct mxs_power_regs *)MXS_POWER_BASE;
        uint32_t tmp, tmp2;
 
+       debug("SPL: Enabling 4P2 regulator\n");
+
        setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
 
        writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
@@ -407,6 +452,7 @@ static void mxs_power_init_4p2_regulator(void)
         * gradually to avoid large inrush current from the 5V cable which can
         * cause transients/problems
         */
+       debug("SPL: Charging 4P2 capacitor\n");
        mxs_enable_4p2_dcdc_input(0);
 
        if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
@@ -420,6 +466,8 @@ static void mxs_power_init_4p2_regulator(void)
                        POWER_DCDC4P2_ENABLE_DCDC);
                writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
                        &power_regs->hw_power_5vctrl_set);
+
+               debug("SPL: Unable to recover from mx23 errata 5837\n");
                hang();
        }
 
@@ -433,6 +481,7 @@ static void mxs_power_init_4p2_regulator(void)
         * current limit until the brownout status is false or until we've
         * reached our maximum defined 4p2 current limit.
         */
+       debug("SPL: Setting 4P2 brownout level\n");
        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
                        POWER_DCDC4P2_BO_MASK,
                        22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
@@ -479,8 +528,11 @@ static void mxs_power_init_dcdc_4p2_source(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Switching DC-DC converters to 4P2\n");
+
        if (!(readl(&power_regs->hw_power_dcdc4p2) &
                POWER_DCDC4P2_ENABLE_DCDC)) {
+               debug("SPL: Already switched - aborting\n");
                hang();
        }
 
@@ -509,6 +561,8 @@ static void mxs_power_enable_4p2(void)
        uint32_t vdddctrl, vddactrl, vddioctrl;
        uint32_t tmp;
 
+       debug("SPL: Powering up 4P2 regulator\n");
+
        vdddctrl = readl(&power_regs->hw_power_vdddctrl);
        vddactrl = readl(&power_regs->hw_power_vddactrl);
        vddioctrl = readl(&power_regs->hw_power_vddioctrl);
@@ -559,6 +613,8 @@ static void mxs_power_enable_4p2(void)
        if (tmp)
                writel(POWER_CHARGE_ENABLE_LOAD,
                        &power_regs->hw_power_charge_clr);
+
+       debug("SPL: 4P2 regulator powered-up\n");
 }
 
 /**
@@ -574,6 +630,8 @@ static void mxs_boot_valid_5v(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Booting from 5V supply\n");
+
        /*
         * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
         * disconnect event. FIXME
@@ -601,6 +659,9 @@ static void mxs_powerdown(void)
 {
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
+
+       debug("Powering Down\n");
+
        writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
        writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
                &power_regs->hw_power_reset);
@@ -617,6 +678,8 @@ static void mxs_batt_boot(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Configuring power block to boot from battery\n");
+
        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
 
@@ -672,6 +735,8 @@ static void mxs_handle_5v_conflict(void)
                (struct mxs_power_regs *)MXS_POWER_BASE;
        uint32_t tmp;
 
+       debug("SPL: Resolving 5V conflict\n");
+
        setbits_le32(&power_regs->hw_power_vddioctrl,
                        POWER_VDDIOCTRL_BO_OFFSET_MASK);
 
@@ -683,19 +748,27 @@ static void mxs_handle_5v_conflict(void)
                         * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes
                         * unreliable
                         */
+                       debug("SPL: VDDIO has a brownout\n");
                        mxs_powerdown();
                        break;
                }
 
                if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
+                       debug("SPL: POWER_STS_VDD5V_GT_VDDIO is set\n");
                        mxs_boot_valid_5v();
                        break;
                } else {
+                       debug("SPL: POWER_STS_VDD5V_GT_VDDIO is not set\n");
                        mxs_powerdown();
                        break;
                }
 
+               /*
+                * TODO: I can't see this being reached. We'll either
+                * powerdown or boot from a stable 5V supply.
+                */
                if (tmp & POWER_STS_PSWITCH_MASK) {
+                       debug("SPL: POWER_STS_PSWITCH_MASK is set\n");
                        mxs_batt_boot();
                        break;
                }
@@ -713,21 +786,26 @@ static void mxs_5v_boot(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Configuring power block to boot from 5V input\n");
+
        /*
         * 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) {
+               debug("SPL: 5V VDD good\n");
                mxs_boot_valid_5v();
                return;
        }
 
        early_delay(1000);
        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+               debug("SPL: 5V VDD good (after delay)\n");
                mxs_boot_valid_5v();
                return;
        }
 
+       debug("SPL: 5V VDD not good\n");
        mxs_handle_5v_conflict();
 }
 
@@ -742,6 +820,8 @@ static void mxs_init_batt_bo(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Initialising battery brown-out level to 3.0V\n");
+
        /* Brownout at 3V */
        clrsetbits_le32(&power_regs->hw_power_battmonitor,
                POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
@@ -762,6 +842,8 @@ static void mxs_switch_vddd_to_dcdc_source(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Switching VDDD to DC-DC converters\n");
+
        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
                POWER_VDDDCTRL_LINREG_OFFSET_MASK,
                POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
@@ -788,6 +870,8 @@ static void mxs_power_configure_power_source(void)
        struct mxs_lradc_regs *lradc_regs =
                (struct mxs_lradc_regs *)MXS_LRADC_BASE;
 
+       debug("SPL: Configuring power source\n");
+
        mxs_src_power_init();
 
        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
@@ -811,6 +895,10 @@ static void mxs_power_configure_power_source(void)
                mxs_batt_boot();
        }
 
+       /*
+        * TODO: Do not switch CPU clock to PLL if we are VDD5V is sourced
+        * from USB VBUS
+        */
        mxs_power_clock2pll();
 
        mxs_init_batt_bo();
@@ -819,6 +907,7 @@ static void mxs_power_configure_power_source(void)
 
 #ifdef CONFIG_MX23
        /* Fire up the VDDMEM LinReg now that we're all set. */
+       debug("SPL: Enabling mx23 VDDMEM linear regulator\n");
        writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT,
                &power_regs->hw_power_vddmemctrl);
 #endif
@@ -838,6 +927,8 @@ static void mxs_enable_output_rail_protection(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Enabling output rail protection\n");
+
        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
                POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 
@@ -1002,7 +1093,8 @@ static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
        uint32_t powered_by_linreg = 0;
        int adjust_up, tmp;
 
-       new_brownout = DIV_ROUND(new_target - new_brownout, cfg->step_mV);
+       new_brownout = DIV_ROUND_CLOSEST(new_target - new_brownout,
+                                        cfg->step_mV);
 
        cur_target = readl(cfg->reg);
        cur_target &= cfg->trg_mask;
@@ -1076,6 +1168,8 @@ static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
  */
 static void mxs_setup_batt_detect(void)
 {
+       debug("SPL: Starting battery voltage measurement logic\n");
+
        mxs_lradc_init();
        mxs_lradc_enable_batt_measurement();
        early_delay(10);
@@ -1110,6 +1204,8 @@ void mxs_power_init(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Initialising Power Block\n");
+
        mxs_ungate_power();
 
        mxs_power_clock2xtal();
@@ -1122,9 +1218,13 @@ void mxs_power_init(void)
        mxs_power_configure_power_source();
        mxs_enable_output_rail_protection();
 
+       debug("SPL: Setting VDDIO to 3V3 (brownout @ 3v15)\n");
        mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150);
-       mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000);
+
+       debug("SPL: Setting VDDD to 1V5 (brownout @ 1v315)\n");
+       mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1315);
 #ifdef CONFIG_MX23
+       debug("SPL: Setting mx23 VDDMEM to 2V5 (brownout @ 1v7)\n");
        mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700);
 #endif
        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
@@ -1149,6 +1249,7 @@ void mxs_power_wait_pswitch(void)
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
 
+       debug("SPL: Waiting for power switch input\n");
        while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
                ;
 }