[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