[U-Boot] [PATCH 2/5] Enable booting of mx28 without battery
Graeme Russ
gruss at tss-engineering.com
Wed Jan 21 12:55:15 CET 2015
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 <gruss at 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
More information about the U-Boot
mailing list