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