Section 4.1.2 of Freescale Application Note AN4199 describes the
configuration required to operate the mx28 from a 5V source without a
battery. This patch implements the changes to the Freescale bootlets
which allow this configuration to properly boot the mx28 processor

Signed-off-by: Graeme Russ <gr...@tss-engineering.com>
---

 arch/arm/cpu/arm926ejs/mxs/spl_power_init.c | 190 +++++++++++++++++++++++++++-
 doc/README.mxs                              |  10 ++
 2 files changed, 197 insertions(+), 3 deletions(-)

diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c 
b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
index 7fb734e..e469381 100644
--- a/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
+++ b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
@@ -14,6 +14,22 @@
 
 #include "mxs_init.h"
 
+#if defined(CONFIG_MX28)
+/*
+ * The minimum DCDC operating voltage for i.MX28 with loading is 3.3V.
+ * we will set the BRWNOUT_LVL bitfield the 3.2V value for 0.1V margin.
+ */
+#define BATTERY_BRWNOUT_BITFIELD_VALUE 20 /* 20 = 3.2V */
+#else
+/*
+ * At the time of this writing, 3V is greater than the minimum DCDC
+ * operating voltage for i.MX233 as listed in by the "Battery / DCDC Input
+ * Voltage" parameter listed in the reference manual so we will set the
+ * BRWNOUT_LVL bitfield to 3V value.
+ */
+#define BATTERY_BRWNOUT_BITFIELD_VALUE 15 /* 15 = 3.0V */
+#endif
+
 /**
  * mxs_power_clock2xtal() - Switch CPU core clock source to 24MHz XTAL
  *
@@ -88,6 +104,7 @@ static void mxs_power_set_auto_restart(void)
        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE)
                ;
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
        /* Do nothing if flag already set */
        if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART)
                return;
@@ -103,6 +120,7 @@ static void mxs_power_set_auto_restart(void)
                ;
        while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK)
                ;
+#endif
 }
 
 /**
@@ -135,6 +153,7 @@ static void mxs_power_set_linreg(void)
                        POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
 }
 
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
 /**
  * mxs_get_batt_volt() - Measure battery input voltage
  *
@@ -217,6 +236,7 @@ static int mxs_is_batt_good(void)
        debug("SPL: Battery Voltage too low\n");
        return 0;
 }
+#endif
 
 /**
  * mxs_power_setup_5v_detect() - Start the 5V input detection comparator
@@ -301,10 +321,19 @@ static void mxs_power_init_4p2_params(void)
                POWER_5VCTRL_HEADROOM_ADJ_MASK,
                0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET);
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       debug("SPL: Configuring 4P2 VDD5V only regulator params\n");
+       clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+                       POWER_DCDC4P2_DROPOUT_CTRL_MASK,
+                       POWER_DCDC4P2_DROPOUT_CTRL_100MV |
+                       POWER_DCDC4P2_DROPOUT_CTRL_SRC_4P2);
+#else
+       debug("SPL: Configuring VDD5V + Battery 4P2 regulator params\n");
        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
                POWER_DCDC4P2_DROPOUT_CTRL_MASK,
                POWER_DCDC4P2_DROPOUT_CTRL_100MV |
                POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL);
+#endif
 
        clrsetbits_le32(&power_regs->hw_power_5vctrl,
                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
@@ -387,9 +416,11 @@ static void mxs_enable_4p2_dcdc_input(int xfer)
        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 (xfer)
+               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,
@@ -480,6 +511,23 @@ static void mxs_power_init_4p2_regulator(void)
                        POWER_DCDC4P2_BO_MASK,
                        22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       debug("SPL: Ramping up current limit (VDD5V only)\n");
+
+       tmp = (readl(&power_regs->hw_power_5vctrl) &
+               POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >>
+               POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
+       while (tmp < 0x3f) {
+               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);
+       }
+#else
+       debug("SPL: Ramping up current limit (VDD5V + Battery)\n");
        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);
@@ -506,6 +554,30 @@ static void mxs_power_init_4p2_regulator(void)
                        }
                }
        }
+#endif
+       /*
+        * TODO: If VDD5V is sourced from USB VBUS, we need to set the
+        * current limit so we don't exceed the USB specifications. The
+        * USB standard states that a device can only draw 100mA unless it
+        * requests more from the host - after which it may draw up to
+        * 500mA. Then we have Charging Ports which may deliver up to 1.5A
+        * (without needing a request from the device).
+        *
+        * NOTE: The source code for the Freescale bootlets seems to be
+        * internally inconsistent - The printf() claims 100mA, while
+        * VBUS_CURRENT_LIMIT is defined as 400mA.
+        *
+        * NOTE: We should also limit the CPU clock frequency in order to
+        * reduce the likelyhood of the USB VBUS current limit being exceeded
+        *
+        * The following would limit the USB VBUS current draw to 100mA
+        *
+        *      clrsetbits_le32(&power_regs->hw_power_5vctrl,
+        *              POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+        *              0x10 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+        *
+        *      early_delay(10000);
+        */
 
        clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
        writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
@@ -524,11 +596,13 @@ static void mxs_power_init_dcdc_4p2_source(void)
 
        debug("SPL: Switching DC-DC converters to 4P2\n");
 
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
        if (!(readl(&power_regs->hw_power_dcdc4p2) &
                POWER_DCDC4P2_ENABLE_DCDC)) {
                debug("SPL: Already switched - aborting\n");
                hang();
        }
+#endif
 
        mxs_enable_4p2_dcdc_input(1);
 
@@ -576,6 +650,14 @@ static void mxs_power_enable_4p2(void)
        mxs_power_init_4p2_regulator();
 
        /* Shutdown battery (none present) */
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       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_set);
+#else
        if (!mxs_is_batt_ready()) {
                clrbits_le32(&power_regs->hw_power_dcdc4p2,
                                POWER_DCDC4P2_BO_MASK);
@@ -584,6 +666,7 @@ static void mxs_power_enable_4p2(void)
                writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
                                &power_regs->hw_power_ctrl_clr);
        }
+#endif
 
        mxs_power_init_dcdc_4p2_source();
 
@@ -661,6 +744,7 @@ static void mxs_powerdown(void)
                &power_regs->hw_power_reset);
 }
 
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
 /**
  * mxs_batt_boot() - Configure the power block to boot from battery input
  *
@@ -714,6 +798,7 @@ static void mxs_batt_boot(void)
 
        mxs_power_enable_4p2();
 }
+#endif
 
 /**
  * mxs_handle_5v_conflict() - Test if the 5V input is reliable
@@ -757,6 +842,7 @@ static void mxs_handle_5v_conflict(void)
                        break;
                }
 
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
                /*
                 * TODO: I can't see this being reached. We'll either
                 * powerdown or boot from a stable 5V supply.
@@ -766,6 +852,7 @@ static void mxs_handle_5v_conflict(void)
                        mxs_batt_boot();
                        break;
                }
+#endif
        }
 }
 
@@ -803,6 +890,7 @@ static void mxs_5v_boot(void)
        mxs_handle_5v_conflict();
 }
 
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
 /**
  * mxs_init_batt_bo() - Configure battery brownout threshold
  *
@@ -824,6 +912,7 @@ static void mxs_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);
 }
+#endif
 
 /**
  * mxs_switch_vddd_to_dcdc_source() - Switch VDDD rail to DC-DC converter
@@ -858,7 +947,12 @@ static void mxs_switch_vddd_to_dcdc_source(void)
  */
 static void mxs_power_configure_power_source(void)
 {
+#ifndef CONFIG_SYS_MXS_VDD5V_ONLY
        int batt_ready, batt_good;
+#else
+       struct mxs_rtc_regs *rtc_regs =
+               (struct mxs_rtc_regs *)MXS_RTC_BASE;
+#endif
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
        struct mxs_lradc_regs *lradc_regs =
@@ -868,6 +962,44 @@ static void mxs_power_configure_power_source(void)
 
        mxs_src_power_init();
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       /*
+        * device configured for no source to DCDC_BATT input (5V only power
+        * source).  This boot option doesn't waste time looking for a good
+        * battery.  Battery powered operation and automatic voltage
+        * measurements are disabled.
+        */
+
+       /* TODO: Find out what the purpose of these two lines is */
+       setbits_le32(&rtc_regs->hw_rtc_persistent1,
+                    TC_PERSISTENT1_GENERAL_USB_BOOT_PLAYER);
+       clrbits_le32(&rtc_regs->hw_rtc_persistent1,
+                    RTC_PERSISTENT1_GENERAL_ENUM_500MA_2X);
+
+       /*
+        * Disable automatic battery voltage measurements which seem
+        * unnecessary for this configuration.
+        */
+       debug("SPL: Disabling automatic battery voltage measurements\n");
+       setbits_le32(&power_regs->hw_power_battmonitor,
+                    POWER_BATTMONITOR_EN_BATADJ);
+       writel(LRADC_CONVERSION_AUTOMATIC,
+              &lradc_regs->hw_lradc_conversion_clr);
+       writel(525 << POWER_BATTMONITOR_BATT_VAL_OFFSET,
+              &power_regs->hw_power_battmonitor);
+
+       clrsetbits_le32(&power_regs->hw_power_battmonitor,
+                       POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
+                       BATTERY_BRWNOUT_BITFIELD_VALUE <<
+                       POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET);
+       mxs_5v_boot();
+
+       /*
+        * TODO: Do not switch CPU clock to PLL if we are VDD5V is sourced
+        * from USB VBUS
+        */
+       mxs_power_clock2pll();
+#else
        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
                batt_ready = mxs_is_batt_ready();
                if (batt_ready) {
@@ -896,6 +1028,7 @@ static void mxs_power_configure_power_source(void)
        mxs_power_clock2pll();
 
        mxs_init_batt_bo();
+#endif
 
        mxs_switch_vddd_to_dcdc_source();
 
@@ -1197,9 +1330,24 @@ void mxs_power_init(void)
 {
        struct mxs_power_regs *power_regs =
                (struct mxs_power_regs *)MXS_POWER_BASE;
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       struct mxs_pinctrl_regs *pinctrl_regs =
+               (struct mxs_pinctrl_regs *)MXS_PINCTRL_BASE;
+       struct mxs_lradc_regs *lradc_regs =
+               (struct mxs_lradc_regs *)MXS_LRADC_BASE;
+#endif
 
        debug("SPL: Initialising Power Block\n");
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       debug("SPL: Configured for VDD 5V only (no battery)\n");
+       /* Set high drive strength to SSP0 */
+       clrsetbits_le32(&pinctrl_regs->hw_pinctrl_drive8,
+                       0x33333333, 0x22222222);
+       clrsetbits_le32(&pinctrl_regs->hw_pinctrl_drive9,
+                       0x333, 0x222);
+#endif
+
        mxs_ungate_power();
 
        mxs_power_clock2xtal();
@@ -1215,12 +1363,26 @@ void mxs_power_init(void)
        debug("SPL: Setting VDDIO to 3V3 (brownout @ 3v15)\n");
        mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150);
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+       setbits_le32(&power_regs->hw_power_vddioctrl,
+                    0x7 << POWER_VDDIOCTRL_BO_OFFSET_OFFSET);
+       clrbits_le32(&power_regs->hw_power_vddioctrl,
+                    0x1 << POWER_VDDIOCTRL_BO_OFFSET_OFFSET);
+
+       debug("SPL: Setting VDDD to 1V35 (brownout @ 1v2)\n");
+       mxs_power_set_vddx(&mxs_vddd_cfg, 1350, 1200);
+#ifdef CONFIG_MX23
+       debug("SPL: Setting VDDMEM to 3V3 (brownout @ 3v15)\n");
+       mxs_power_set_vddx(&mxs_vddmem_cfg, 3300, 3150);
+#endif
+#else
        debug("SPL: Setting VDDD to 1V5 (brownout @ 1v0)\n");
        mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000);
 #ifdef CONFIG_MX23
        debug("SPL: Setting mx23 VDDMEM to 2V5 (brownout @ 1v7)\n");
        mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700);
 #endif
+#endif
        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 |
@@ -1228,6 +1390,28 @@ void mxs_power_init(void)
 
        writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
 
+#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
+#if defined(CONFIG_MX28)
+       /*
+        * On i.MX28, a new bit has been added to allow automatic hardware
+        * shutdown if VDD4P2 browns out.  If we permanently only have a VDD5V
+        * source, we want to enable this bit.  For devices with dead batteries,
+        * we could also temporarily set this bit until the kernel battery
+        * charger sufficiently charges the battery but we won't do this for
+        * now as the latest release kernel versions aren't aware of  it
+        * and thus don't handle the proper setting/clearing of this bit.
+        */
+       writel(1<<7, &power_regs->hw_power_refctrl);
+#endif
+       setbits_le32(&power_regs->hw_power_battmonitor,
+                    POWER_BATTMONITOR_PWDN_BATTBRNOUT_5VDETECT_EN |
+                    POWER_BATTMONITOR_EN_BATADJ |
+                    POWER_BATTMONITOR_PWDN_BATTBRNOUT);
+       clrsetbits_le32(&lradc_regs->hw_lradc_ctrl4,
+                       LRADC_CTRL4_LRADC6SELECT_MASK,
+                       LRADC_CTRL4_LRADC6SELECT_CHANNEL6);
+#endif
+
        early_delay(1000);
 }
 
diff --git a/doc/README.mxs b/doc/README.mxs
index ed2e568..ba0408e 100644
--- a/doc/README.mxs
+++ b/doc/README.mxs
@@ -185,6 +185,16 @@ NOTE: If the user needs to adjust the start sector, the 
"mxsboot" tool contains
       a "-p" switch for that purpose. The "-p" switch takes the sector number 
as
       an argument.
 
+3.1) MXS Specific Configuration Variables
+-----------------------------------------
+The following C pre-processor defines can be included in the board specific
+configuration file:
+
+CONFIG_SYS_MXS_VDD5V_ONLY - Board designs implementing a power circuit
+consisting of a 5V DC supply only (i.e. without a battery), as per Section
+4.1.2 of Freescale Semiconductor Application Note AN4199 MUST include this
+configuration variable in the board configuration file
+
 4) Installation of U-Boot into NAND flash on a MX28 based board
 ---------------------------------------------------------------
 
-- 
1.9.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to