uboot/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Freescale i.MX28 Boot PMIC init
   4 *
   5 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
   6 * on behalf of DENX Software Engineering GmbH
   7 */
   8
   9#include <common.h>
  10#include <config.h>
  11#include <hang.h>
  12#include <log.h>
  13#include <asm/io.h>
  14#include <asm/arch/imx-regs.h>
  15
  16#include "mxs_init.h"
  17
  18#ifdef CONFIG_SYS_MXS_VDD5V_ONLY
  19#define DCDC4P2_DROPOUT_CONFIG  POWER_DCDC4P2_DROPOUT_CTRL_100MV | \
  20                                POWER_DCDC4P2_DROPOUT_CTRL_SRC_4P2
  21#else
  22#define DCDC4P2_DROPOUT_CONFIG  POWER_DCDC4P2_DROPOUT_CTRL_100MV | \
  23                                POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL
  24#endif
  25/**
  26 * mxs_power_clock2xtal() - Switch CPU core clock source to 24MHz XTAL
  27 *
  28 * This function switches the CPU core clock from PLL to 24MHz XTAL
  29 * oscilator. This is necessary if the PLL is being reconfigured to
  30 * prevent crash of the CPU core.
  31 */
  32static void mxs_power_clock2xtal(void)
  33{
  34        struct mxs_clkctrl_regs *clkctrl_regs =
  35                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  36
  37        debug("SPL: Switching CPU clock to 24MHz XTAL\n");
  38
  39        /* Set XTAL as CPU reference clock */
  40        writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
  41                &clkctrl_regs->hw_clkctrl_clkseq_set);
  42}
  43
  44/**
  45 * mxs_power_clock2pll() - Switch CPU core clock source to PLL
  46 *
  47 * This function switches the CPU core clock from 24MHz XTAL oscilator
  48 * to PLL. This can only be called once the PLL has re-locked and once
  49 * the PLL is stable after reconfiguration.
  50 */
  51static void mxs_power_clock2pll(void)
  52{
  53        struct mxs_clkctrl_regs *clkctrl_regs =
  54                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
  55
  56        debug("SPL: Switching CPU core clock source to PLL\n");
  57
  58        /*
  59         * TODO: Are we really? It looks like we turn on PLL0, but we then
  60         * set the CLKCTRL_CLKSEQ_BYPASS_CPU bit of the (which was already
  61         * set by mxs_power_clock2xtal()). Clearing this bit here seems to
  62         * introduce some instability (causing the CPU core to hang). Maybe
  63         * we aren't giving PLL0 enough time to stabilise?
  64         */
  65        setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
  66                        CLKCTRL_PLL0CTRL0_POWER);
  67        early_delay(100);
  68
  69        /*
  70         * TODO: Should the PLL0 FORCE_LOCK bit be set here followed be a
  71         * wait on the PLL0 LOCK bit?
  72         */
  73        setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
  74                        CLKCTRL_CLKSEQ_BYPASS_CPU);
  75}
  76
  77/**
  78 * mxs_power_set_auto_restart() - Set the auto-restart bit
  79 *
  80 * This function ungates the RTC block and sets the AUTO_RESTART
  81 * bit to work around a design bug on MX28EVK Rev. A .
  82 */
  83
  84static void mxs_power_set_auto_restart(void)
  85{
  86        struct mxs_rtc_regs *rtc_regs =
  87                (struct mxs_rtc_regs *)MXS_RTC_BASE;
  88
  89        debug("SPL: Setting auto-restart bit\n");
  90
  91        writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr);
  92        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST)
  93                ;
  94
  95        writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr);
  96        while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE)
  97                ;
  98
  99        /* Do nothing if flag already set */
 100        if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART)
 101                return;
 102
 103        while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK)
 104                ;
 105
 106        setbits_le32(&rtc_regs->hw_rtc_persistent0,
 107                        RTC_PERSISTENT0_AUTO_RESTART);
 108        writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_set);
 109        writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_clr);
 110        while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK)
 111                ;
 112        while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK)
 113                ;
 114}
 115
 116/**
 117 * mxs_power_set_linreg() - Set linear regulators 25mV below DC-DC converter
 118 *
 119 * This function configures the VDDIO, VDDA and VDDD linear regulators output
 120 * to be 25mV below the VDDIO, VDDA and VDDD output from the DC-DC switching
 121 * converter. This is the recommended setting for the case where we use both
 122 * linear regulators and DC-DC converter to power the VDDIO rail.
 123 */
 124static void mxs_power_set_linreg(void)
 125{
 126        struct mxs_power_regs *power_regs =
 127                (struct mxs_power_regs *)MXS_POWER_BASE;
 128
 129        /* Set linear regulator 25mV below switching converter */
 130        debug("SPL: Setting VDDD 25mV below DC-DC converters\n");
 131        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
 132                        POWER_VDDDCTRL_LINREG_OFFSET_MASK,
 133                        POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
 134
 135        debug("SPL: Setting VDDA 25mV below DC-DC converters\n");
 136        clrsetbits_le32(&power_regs->hw_power_vddactrl,
 137                        POWER_VDDACTRL_LINREG_OFFSET_MASK,
 138                        POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW);
 139
 140        debug("SPL: Setting VDDIO 25mV below DC-DC converters\n");
 141        clrsetbits_le32(&power_regs->hw_power_vddioctrl,
 142                        POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
 143                        POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
 144}
 145
 146/**
 147 * mxs_get_batt_volt() - Measure battery input voltage
 148 *
 149 * This function retrieves the battery input voltage and returns it.
 150 */
 151static int mxs_get_batt_volt(void)
 152{
 153        struct mxs_power_regs *power_regs =
 154                (struct mxs_power_regs *)MXS_POWER_BASE;
 155        uint32_t volt = readl(&power_regs->hw_power_battmonitor);
 156        volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
 157        volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
 158        volt *= 8;
 159
 160        debug("SPL: Battery Voltage = %dmV\n", volt);
 161        return volt;
 162}
 163
 164/**
 165 * mxs_is_batt_ready() - Test if the battery provides enough voltage to boot
 166 *
 167 * This function checks if the battery input voltage is higher than 3.6V and
 168 * therefore allows the system to successfully boot using this power source.
 169 */
 170static int mxs_is_batt_ready(void)
 171{
 172        return (mxs_get_batt_volt() >= 3600);
 173}
 174
 175/**
 176 * mxs_is_batt_good() - Test if battery is operational at all
 177 *
 178 * This function starts recharging the battery and tests if the input current
 179 * provided by the 5V input recharging the battery is also sufficient to power
 180 * the DC-DC converter.
 181 */
 182static int mxs_is_batt_good(void)
 183{
 184        struct mxs_power_regs *power_regs =
 185                (struct mxs_power_regs *)MXS_POWER_BASE;
 186        uint32_t volt = mxs_get_batt_volt();
 187
 188        if ((volt >= 2400) && (volt <= 4300)) {
 189                debug("SPL: Battery is good\n");
 190                return 1;
 191        }
 192
 193        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 194                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
 195                0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
 196        writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
 197                &power_regs->hw_power_5vctrl_clr);
 198
 199        clrsetbits_le32(&power_regs->hw_power_charge,
 200                POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
 201                POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
 202
 203        writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
 204        writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
 205                &power_regs->hw_power_5vctrl_clr);
 206
 207        early_delay(500000);
 208
 209        volt = mxs_get_batt_volt();
 210
 211        if (volt >= 3500) {
 212                debug("SPL: Battery Voltage too high\n");
 213                return 0;
 214        }
 215
 216        if (volt >= 2400) {
 217                debug("SPL: Battery is good\n");
 218                return 1;
 219        }
 220
 221        writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
 222                &power_regs->hw_power_charge_clr);
 223        writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
 224
 225        debug("SPL: Battery Voltage too low\n");
 226        return 0;
 227}
 228
 229/**
 230 * mxs_power_setup_5v_detect() - Start the 5V input detection comparator
 231 *
 232 * This function enables the 5V detection comparator and sets the 5V valid
 233 * threshold to 4.4V . We use 4.4V threshold here to make sure that even
 234 * under high load, the voltage drop on the 5V input won't be so critical
 235 * to cause undervolt on the 4P2 linear regulator supplying the DC-DC
 236 * converter and thus making the system crash.
 237 */
 238static void mxs_power_setup_5v_detect(void)
 239{
 240        struct mxs_power_regs *power_regs =
 241                (struct mxs_power_regs *)MXS_POWER_BASE;
 242
 243        /* Start 5V detection */
 244        debug("SPL: Starting 5V input detection comparator\n");
 245        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 246                        POWER_5VCTRL_VBUSVALID_TRSH_MASK,
 247                        POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
 248                        POWER_5VCTRL_PWRUP_VBUS_CMPS);
 249}
 250
 251/**
 252 * mxs_power_switch_dcdc_clocksource() - Switch PLL clock for DC-DC converters
 253 * @freqsel:    One of the POWER_MISC_FREQSEL_xxx defines to select the clock
 254 *
 255 * This function configures and then enables an alternative PLL clock source
 256 * for the DC-DC converters.
 257 */
 258void mxs_power_switch_dcdc_clocksource(uint32_t freqsel)
 259{
 260        struct mxs_power_regs *power_regs =
 261                (struct mxs_power_regs *)MXS_POWER_BASE;
 262
 263        /* Select clocksource for DC-DC converters */
 264        clrsetbits_le32(&power_regs->hw_power_misc,
 265                        POWER_MISC_FREQSEL_MASK,
 266                        freqsel);
 267        setbits_le32(&power_regs->hw_power_misc,
 268                        POWER_MISC_SEL_PLLCLK);
 269}
 270
 271/**
 272 * mxs_power_setup_dcdc_clocksource() - Setup PLL clock source for DC-DC converters
 273 *
 274 * Normally, there is no need to switch DC-DC clocksource. This is the reason,
 275 * why this function is a stub and does nothing. However, boards can implement
 276 * this function when required and call mxs_power_switch_dcdc_clocksource() to
 277 * switch to an alternative clock source.
 278 */
 279__weak void mxs_power_setup_dcdc_clocksource(void)
 280{
 281        debug("SPL: Using default DC-DC clocksource\n");
 282}
 283
 284/**
 285 * mxs_src_power_init() - Preconfigure the power block
 286 *
 287 * This function configures reasonable values for the DC-DC control loop
 288 * and battery monitor.
 289 */
 290static void mxs_src_power_init(void)
 291{
 292        struct mxs_power_regs *power_regs =
 293                (struct mxs_power_regs *)MXS_POWER_BASE;
 294
 295        debug("SPL: Pre-Configuring power block\n");
 296
 297        /* Improve efficieny and reduce transient ripple */
 298        writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST |
 299                POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set);
 300
 301        clrsetbits_le32(&power_regs->hw_power_dclimits,
 302                        POWER_DCLIMITS_POSLIMIT_BUCK_MASK,
 303                        0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET);
 304
 305        setbits_le32(&power_regs->hw_power_battmonitor,
 306                        POWER_BATTMONITOR_EN_BATADJ);
 307
 308        /* Increase the RCSCALE level for quick DCDC response to dynamic load */
 309        clrsetbits_le32(&power_regs->hw_power_loopctrl,
 310                        POWER_LOOPCTRL_EN_RCSCALE_MASK,
 311                        POWER_LOOPCTRL_RCSCALE_THRESH |
 312                        POWER_LOOPCTRL_EN_RCSCALE_8X);
 313
 314        clrsetbits_le32(&power_regs->hw_power_minpwr,
 315                        POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
 316
 317        /* 5V to battery handoff ... FIXME */
 318        setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
 319        early_delay(30);
 320        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
 321}
 322
 323/**
 324 * mxs_power_init_4p2_params() - Configure the parameters of the 4P2 regulator
 325 *
 326 * This function configures the necessary parameters for the 4P2 linear
 327 * regulator to supply the DC-DC converter from 5V input.
 328 */
 329static void mxs_power_init_4p2_params(void)
 330{
 331        struct mxs_power_regs *power_regs =
 332                (struct mxs_power_regs *)MXS_POWER_BASE;
 333
 334        debug("SPL: Configuring common 4P2 regulator params\n");
 335
 336        /* Setup 4P2 parameters */
 337        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
 338                POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
 339                POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET));
 340
 341        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 342                POWER_5VCTRL_HEADROOM_ADJ_MASK,
 343                0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET);
 344
 345        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
 346                POWER_DCDC4P2_DROPOUT_CTRL_MASK,
 347                DCDC4P2_DROPOUT_CONFIG);
 348
 349        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 350                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
 351                0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
 352}
 353
 354/**
 355 * mxs_enable_4p2_dcdc_input() - Enable or disable the DCDC input from 4P2
 356 * @xfer:       Select if the input shall be enabled or disabled
 357 *
 358 * This function enables or disables the 4P2 input into the DC-DC converter.
 359 */
 360static void mxs_enable_4p2_dcdc_input(int xfer)
 361{
 362        struct mxs_power_regs *power_regs =
 363                (struct mxs_power_regs *)MXS_POWER_BASE;
 364        uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
 365        uint32_t prev_5v_brnout, prev_5v_droop;
 366
 367        debug("SPL: %s 4P2 DC-DC Input\n", xfer ? "Enabling" : "Disabling");
 368
 369        if (xfer && (readl(&power_regs->hw_power_5vctrl) &
 370                        POWER_5VCTRL_ENABLE_DCDC)) {
 371                return;
 372        }
 373
 374        prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
 375                                POWER_5VCTRL_PWDN_5VBRNOUT;
 376        prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
 377                                POWER_CTRL_ENIRQ_VDD5V_DROOP;
 378
 379        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
 380        writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
 381                &power_regs->hw_power_reset);
 382
 383        clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP);
 384
 385        /*
 386         * Recording orignal values that will be modified temporarlily
 387         * to handle a chip bug. See chip errata for CQ ENGR00115837
 388         */
 389        tmp = readl(&power_regs->hw_power_5vctrl);
 390        vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK;
 391        vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT;
 392
 393        pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO;
 394
 395        /*
 396         * Disable mechanisms that get erroneously tripped by when setting
 397         * the DCDC4P2 EN_DCDC
 398         */
 399        clrbits_le32(&power_regs->hw_power_5vctrl,
 400                POWER_5VCTRL_VBUSVALID_5VDETECT |
 401                POWER_5VCTRL_VBUSVALID_TRSH_MASK);
 402
 403        writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set);
 404
 405        if (xfer) {
 406                setbits_le32(&power_regs->hw_power_5vctrl,
 407                                POWER_5VCTRL_DCDC_XFER);
 408                early_delay(20);
 409                clrbits_le32(&power_regs->hw_power_5vctrl,
 410                                POWER_5VCTRL_DCDC_XFER);
 411
 412                setbits_le32(&power_regs->hw_power_5vctrl,
 413                                POWER_5VCTRL_ENABLE_DCDC);
 414        } else {
 415                setbits_le32(&power_regs->hw_power_dcdc4p2,
 416                                POWER_DCDC4P2_ENABLE_DCDC);
 417        }
 418
 419        early_delay(25);
 420
 421        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 422                        POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh);
 423
 424        if (vbus_5vdetect)
 425                writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set);
 426
 427        if (!pwd_bo)
 428                clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO);
 429
 430        while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ)
 431                writel(POWER_CTRL_VBUS_VALID_IRQ,
 432                        &power_regs->hw_power_ctrl_clr);
 433
 434        if (prev_5v_brnout) {
 435                writel(POWER_5VCTRL_PWDN_5VBRNOUT,
 436                        &power_regs->hw_power_5vctrl_set);
 437                writel(POWER_RESET_UNLOCK_KEY,
 438                        &power_regs->hw_power_reset);
 439        } else {
 440                writel(POWER_5VCTRL_PWDN_5VBRNOUT,
 441                        &power_regs->hw_power_5vctrl_clr);
 442                writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
 443                        &power_regs->hw_power_reset);
 444        }
 445
 446        while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ)
 447                writel(POWER_CTRL_VDD5V_DROOP_IRQ,
 448                        &power_regs->hw_power_ctrl_clr);
 449
 450        if (prev_5v_droop)
 451                clrbits_le32(&power_regs->hw_power_ctrl,
 452                                POWER_CTRL_ENIRQ_VDD5V_DROOP);
 453        else
 454                setbits_le32(&power_regs->hw_power_ctrl,
 455                                POWER_CTRL_ENIRQ_VDD5V_DROOP);
 456}
 457
 458/**
 459 * mxs_power_init_4p2_regulator() - Start the 4P2 regulator
 460 *
 461 * This function enables the 4P2 regulator and switches the DC-DC converter
 462 * to use the 4P2 input.
 463 */
 464static void mxs_power_init_4p2_regulator(void)
 465{
 466        struct mxs_power_regs *power_regs =
 467                (struct mxs_power_regs *)MXS_POWER_BASE;
 468        uint32_t tmp, tmp2;
 469
 470        debug("SPL: Enabling 4P2 regulator\n");
 471
 472        setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
 473
 474        writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
 475
 476        writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
 477                &power_regs->hw_power_5vctrl_clr);
 478        clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK);
 479
 480        /* Power up the 4p2 rail and logic/control */
 481        writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
 482                &power_regs->hw_power_5vctrl_clr);
 483
 484        /*
 485         * Start charging up the 4p2 capacitor. We ramp of this charge
 486         * gradually to avoid large inrush current from the 5V cable which can
 487         * cause transients/problems
 488         */
 489        debug("SPL: Charging 4P2 capacitor\n");
 490        mxs_enable_4p2_dcdc_input(0);
 491
 492        if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
 493                /*
 494                 * If we arrived here, we were unable to recover from mx23 chip
 495                 * errata 5837. 4P2 is disabled and sufficient battery power is
 496                 * not present. Exiting to not enable DCDC power during 5V
 497                 * connected state.
 498                 */
 499                clrbits_le32(&power_regs->hw_power_dcdc4p2,
 500                        POWER_DCDC4P2_ENABLE_DCDC);
 501                writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
 502                        &power_regs->hw_power_5vctrl_set);
 503
 504                debug("SPL: Unable to recover from mx23 errata 5837\n");
 505                hang();
 506        }
 507
 508        /*
 509         * Here we set the 4p2 brownout level to something very close to 4.2V.
 510         * We then check the brownout status. If the brownout status is false,
 511         * the voltage is already close to the target voltage of 4.2V so we
 512         * can go ahead and set the 4P2 current limit to our max target limit.
 513         * If the brownout status is true, we need to ramp us the current limit
 514         * so that we don't cause large inrush current issues. We step up the
 515         * current limit until the brownout status is false or until we've
 516         * reached our maximum defined 4p2 current limit.
 517         */
 518        debug("SPL: Setting 4P2 brownout level\n");
 519        clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
 520                        POWER_DCDC4P2_BO_MASK,
 521                        22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
 522
 523        if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) {
 524                setbits_le32(&power_regs->hw_power_5vctrl,
 525                        0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
 526        } else {
 527                tmp = (readl(&power_regs->hw_power_5vctrl) &
 528                        POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >>
 529                        POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
 530                while (tmp < 0x3f) {
 531                        if (!(readl(&power_regs->hw_power_sts) &
 532                                        POWER_STS_DCDC_4P2_BO)) {
 533                                tmp = readl(&power_regs->hw_power_5vctrl);
 534                                tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
 535                                early_delay(100);
 536                                writel(tmp, &power_regs->hw_power_5vctrl);
 537                                break;
 538                        } else {
 539                                tmp++;
 540                                tmp2 = readl(&power_regs->hw_power_5vctrl);
 541                                tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
 542                                tmp2 |= tmp <<
 543                                        POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
 544                                writel(tmp2, &power_regs->hw_power_5vctrl);
 545                                early_delay(100);
 546                        }
 547                }
 548        }
 549
 550        clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
 551        writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 552}
 553
 554/**
 555 * mxs_power_init_dcdc_4p2_source() - Switch DC-DC converter to 4P2 source
 556 *
 557 * This function configures the DC-DC converter to be supplied from the 4P2
 558 * linear regulator.
 559 */
 560static void mxs_power_init_dcdc_4p2_source(void)
 561{
 562        struct mxs_power_regs *power_regs =
 563                (struct mxs_power_regs *)MXS_POWER_BASE;
 564
 565        debug("SPL: Switching DC-DC converters to 4P2\n");
 566
 567        if (!(readl(&power_regs->hw_power_dcdc4p2) &
 568                POWER_DCDC4P2_ENABLE_DCDC)) {
 569                debug("SPL: Already switched - aborting\n");
 570                hang();
 571        }
 572
 573        mxs_enable_4p2_dcdc_input(1);
 574
 575        if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
 576                clrbits_le32(&power_regs->hw_power_dcdc4p2,
 577                        POWER_DCDC4P2_ENABLE_DCDC);
 578                writel(POWER_5VCTRL_ENABLE_DCDC,
 579                        &power_regs->hw_power_5vctrl_clr);
 580                writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
 581                        &power_regs->hw_power_5vctrl_set);
 582        }
 583}
 584
 585/**
 586 * mxs_power_enable_4p2() - Power up the 4P2 regulator
 587 *
 588 * This function drives the process of powering up the 4P2 linear regulator
 589 * and switching the DC-DC converter input over to the 4P2 linear regulator.
 590 */
 591static void mxs_power_enable_4p2(void)
 592{
 593        struct mxs_power_regs *power_regs =
 594                (struct mxs_power_regs *)MXS_POWER_BASE;
 595        uint32_t vdddctrl, vddactrl, vddioctrl;
 596        uint32_t tmp;
 597
 598        debug("SPL: Powering up 4P2 regulator\n");
 599
 600        vdddctrl = readl(&power_regs->hw_power_vdddctrl);
 601        vddactrl = readl(&power_regs->hw_power_vddactrl);
 602        vddioctrl = readl(&power_regs->hw_power_vddioctrl);
 603
 604        setbits_le32(&power_regs->hw_power_vdddctrl,
 605                POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
 606                POWER_VDDDCTRL_PWDN_BRNOUT);
 607
 608        setbits_le32(&power_regs->hw_power_vddactrl,
 609                POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG |
 610                POWER_VDDACTRL_PWDN_BRNOUT);
 611
 612        setbits_le32(&power_regs->hw_power_vddioctrl,
 613                POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT);
 614
 615        mxs_power_init_4p2_params();
 616        mxs_power_init_4p2_regulator();
 617
 618        /* Shutdown battery (none present) */
 619        if (!mxs_is_batt_ready()) {
 620                clrbits_le32(&power_regs->hw_power_dcdc4p2,
 621                                POWER_DCDC4P2_BO_MASK);
 622                writel(POWER_CTRL_DCDC4P2_BO_IRQ,
 623                                &power_regs->hw_power_ctrl_clr);
 624                writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
 625                                &power_regs->hw_power_ctrl_clr);
 626        }
 627
 628        mxs_power_init_dcdc_4p2_source();
 629
 630        writel(vdddctrl, &power_regs->hw_power_vdddctrl);
 631        early_delay(20);
 632        writel(vddactrl, &power_regs->hw_power_vddactrl);
 633        early_delay(20);
 634        writel(vddioctrl, &power_regs->hw_power_vddioctrl);
 635
 636        /*
 637         * Check if FET is enabled on either powerout and if so,
 638         * disable load.
 639         */
 640        tmp = 0;
 641        tmp |= !(readl(&power_regs->hw_power_vdddctrl) &
 642                        POWER_VDDDCTRL_DISABLE_FET);
 643        tmp |= !(readl(&power_regs->hw_power_vddactrl) &
 644                        POWER_VDDACTRL_DISABLE_FET);
 645        tmp |= !(readl(&power_regs->hw_power_vddioctrl) &
 646                        POWER_VDDIOCTRL_DISABLE_FET);
 647        if (tmp)
 648                writel(POWER_CHARGE_ENABLE_LOAD,
 649                        &power_regs->hw_power_charge_clr);
 650
 651        debug("SPL: 4P2 regulator powered-up\n");
 652}
 653
 654/**
 655 * mxs_boot_valid_5v() - Boot from 5V supply
 656 *
 657 * This function configures the power block to boot from valid 5V input.
 658 * This is called only if the 5V is reliable and can properly supply the
 659 * CPU. This function proceeds to configure the 4P2 converter to be supplied
 660 * from the 5V input.
 661 */
 662static void mxs_boot_valid_5v(void)
 663{
 664        struct mxs_power_regs *power_regs =
 665                (struct mxs_power_regs *)MXS_POWER_BASE;
 666
 667        debug("SPL: Booting from 5V supply\n");
 668
 669        /*
 670         * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
 671         * disconnect event. FIXME
 672         */
 673        writel(POWER_5VCTRL_VBUSVALID_5VDETECT,
 674                &power_regs->hw_power_5vctrl_set);
 675
 676        /* Configure polarity to check for 5V disconnection. */
 677        writel(POWER_CTRL_POLARITY_VBUSVALID |
 678                POWER_CTRL_POLARITY_VDD5V_GT_VDDIO,
 679                &power_regs->hw_power_ctrl_clr);
 680
 681        writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ,
 682                &power_regs->hw_power_ctrl_clr);
 683
 684        mxs_power_enable_4p2();
 685}
 686
 687/**
 688 * mxs_powerdown() - Shut down the system
 689 *
 690 * This function powers down the CPU completely.
 691 */
 692static void mxs_powerdown(void)
 693{
 694        struct mxs_power_regs *power_regs =
 695                (struct mxs_power_regs *)MXS_POWER_BASE;
 696
 697        debug("Powering Down\n");
 698
 699        writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
 700        writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
 701                &power_regs->hw_power_reset);
 702}
 703
 704/**
 705 * mxs_batt_boot() - Configure the power block to boot from battery input
 706 *
 707 * This function configures the power block to boot from the battery voltage
 708 * supply.
 709 */
 710static void mxs_batt_boot(void)
 711{
 712        struct mxs_power_regs *power_regs =
 713                (struct mxs_power_regs *)MXS_POWER_BASE;
 714
 715        debug("SPL: Configuring power block to boot from battery\n");
 716
 717        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
 718        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
 719
 720        clrbits_le32(&power_regs->hw_power_dcdc4p2,
 721                        POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2);
 722        writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr);
 723
 724        /* 5V to battery handoff. */
 725        setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
 726        early_delay(30);
 727        clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
 728
 729        writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
 730
 731        clrsetbits_le32(&power_regs->hw_power_minpwr,
 732                        POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
 733
 734        mxs_power_set_linreg();
 735
 736        clrbits_le32(&power_regs->hw_power_vdddctrl,
 737                POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG);
 738
 739        clrbits_le32(&power_regs->hw_power_vddactrl,
 740                POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG);
 741
 742        clrbits_le32(&power_regs->hw_power_vddioctrl,
 743                POWER_VDDIOCTRL_DISABLE_FET);
 744
 745        setbits_le32(&power_regs->hw_power_5vctrl,
 746                POWER_5VCTRL_PWD_CHARGE_4P2_MASK);
 747
 748        setbits_le32(&power_regs->hw_power_5vctrl,
 749                POWER_5VCTRL_ENABLE_DCDC);
 750
 751        clrsetbits_le32(&power_regs->hw_power_5vctrl,
 752                POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
 753                0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
 754
 755        mxs_power_enable_4p2();
 756}
 757
 758/**
 759 * mxs_handle_5v_conflict() - Test if the 5V input is reliable
 760 *
 761 * This function tests if the 5V input can reliably supply the system. If it
 762 * can, then proceed to configuring the system to boot from 5V source, otherwise
 763 * try booting from battery supply. If we can not boot from battery supply
 764 * either, shut down the system.
 765 */
 766static void mxs_handle_5v_conflict(void)
 767{
 768        struct mxs_power_regs *power_regs =
 769                (struct mxs_power_regs *)MXS_POWER_BASE;
 770        uint32_t tmp;
 771
 772        debug("SPL: Resolving 5V conflict\n");
 773
 774        setbits_le32(&power_regs->hw_power_vddioctrl,
 775                        POWER_VDDIOCTRL_BO_OFFSET_MASK);
 776
 777        for (;;) {
 778                tmp = readl(&power_regs->hw_power_sts);
 779
 780                if (tmp & POWER_STS_VDDIO_BO) {
 781                        /*
 782                         * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes
 783                         * unreliable
 784                         */
 785                        debug("SPL: VDDIO has a brownout\n");
 786                        mxs_powerdown();
 787                        break;
 788                }
 789
 790                if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
 791                        debug("SPL: POWER_STS_VDD5V_GT_VDDIO is set\n");
 792                        mxs_boot_valid_5v();
 793                        break;
 794                } else {
 795                        debug("SPL: POWER_STS_VDD5V_GT_VDDIO is not set\n");
 796                        mxs_powerdown();
 797                        break;
 798                }
 799
 800                /*
 801                 * TODO: I can't see this being reached. We'll either
 802                 * powerdown or boot from a stable 5V supply.
 803                 */
 804                if (tmp & POWER_STS_PSWITCH_MASK) {
 805                        debug("SPL: POWER_STS_PSWITCH_MASK is set\n");
 806                        mxs_batt_boot();
 807                        break;
 808                }
 809        }
 810}
 811
 812/**
 813 * mxs_5v_boot() - Configure the power block to boot from 5V input
 814 *
 815 * This function handles configuration of the power block when supplied by
 816 * a 5V input.
 817 */
 818static void mxs_5v_boot(void)
 819{
 820        struct mxs_power_regs *power_regs =
 821                (struct mxs_power_regs *)MXS_POWER_BASE;
 822
 823        debug("SPL: Configuring power block to boot from 5V input\n");
 824
 825        /*
 826         * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID,
 827         * but their implementation always returns 1 so we omit it here.
 828         */
 829        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
 830                debug("SPL: 5V VDD good\n");
 831                mxs_boot_valid_5v();
 832                return;
 833        }
 834
 835        early_delay(1000);
 836        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
 837                debug("SPL: 5V VDD good (after delay)\n");
 838                mxs_boot_valid_5v();
 839                return;
 840        }
 841
 842        debug("SPL: 5V VDD not good\n");
 843        mxs_handle_5v_conflict();
 844}
 845
 846/**
 847 * mxs_init_batt_bo() - Configure battery brownout threshold
 848 *
 849 * This function configures the battery input brownout threshold. The value
 850 * at which the battery brownout happens is configured to 3.0V in the code.
 851 */
 852static void mxs_init_batt_bo(void)
 853{
 854        struct mxs_power_regs *power_regs =
 855                (struct mxs_power_regs *)MXS_POWER_BASE;
 856
 857        debug("SPL: Initialising battery brown-out level to 3.0V\n");
 858
 859        /* Brownout at 3V */
 860        clrsetbits_le32(&power_regs->hw_power_battmonitor,
 861                POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
 862                15 << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET);
 863
 864        writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 865        writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr);
 866}
 867
 868/**
 869 * mxs_switch_vddd_to_dcdc_source() - Switch VDDD rail to DC-DC converter
 870 *
 871 * This function turns off the VDDD linear regulator and therefore makes
 872 * the VDDD rail be supplied only by the DC-DC converter.
 873 */
 874static void mxs_switch_vddd_to_dcdc_source(void)
 875{
 876        struct mxs_power_regs *power_regs =
 877                (struct mxs_power_regs *)MXS_POWER_BASE;
 878
 879        debug("SPL: Switching VDDD to DC-DC converters\n");
 880
 881        clrsetbits_le32(&power_regs->hw_power_vdddctrl,
 882                POWER_VDDDCTRL_LINREG_OFFSET_MASK,
 883                POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
 884
 885        clrbits_le32(&power_regs->hw_power_vdddctrl,
 886                POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
 887                POWER_VDDDCTRL_DISABLE_STEPPING);
 888}
 889
 890/**
 891 * mxs_power_configure_power_source() - Configure power block source
 892 *
 893 * This function is the core of the power configuration logic. The function
 894 * selects the power block input source and configures the whole power block
 895 * accordingly. After the configuration is complete and the system is stable
 896 * again, the function switches the CPU clock source back to PLL. Finally,
 897 * the function switches the voltage rails to DC-DC converter.
 898 */
 899static void mxs_power_configure_power_source(void)
 900{
 901        int batt_ready, batt_good;
 902        struct mxs_power_regs *power_regs =
 903                (struct mxs_power_regs *)MXS_POWER_BASE;
 904        struct mxs_lradc_regs *lradc_regs =
 905                (struct mxs_lradc_regs *)MXS_LRADC_BASE;
 906
 907        debug("SPL: Configuring power source\n");
 908
 909        mxs_power_setup_dcdc_clocksource();
 910        mxs_src_power_init();
 911
 912        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
 913                batt_ready = mxs_is_batt_ready();
 914                if (batt_ready) {
 915                        /* 5V source detected, good battery detected. */
 916                        mxs_batt_boot();
 917                } else {
 918                        batt_good = mxs_is_batt_good();
 919                        if (!batt_good) {
 920                                /* 5V source detected, bad battery detected. */
 921                                writel(LRADC_CONVERSION_AUTOMATIC,
 922                                        &lradc_regs->hw_lradc_conversion_clr);
 923                                clrbits_le32(&power_regs->hw_power_battmonitor,
 924                                        POWER_BATTMONITOR_BATT_VAL_MASK);
 925                        }
 926                        mxs_5v_boot();
 927                }
 928        } else {
 929                /* 5V not detected, booting from battery. */
 930                mxs_batt_boot();
 931        }
 932
 933        /*
 934         * TODO: Do not switch CPU clock to PLL if we are VDD5V is sourced
 935         * from USB VBUS
 936         */
 937        mxs_power_clock2pll();
 938
 939        mxs_init_batt_bo();
 940
 941        mxs_switch_vddd_to_dcdc_source();
 942
 943#ifdef CONFIG_MX23
 944        /* Fire up the VDDMEM LinReg now that we're all set. */
 945        debug("SPL: Enabling mx23 VDDMEM linear regulator\n");
 946        writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT,
 947                &power_regs->hw_power_vddmemctrl);
 948#endif
 949}
 950
 951/**
 952 * mxs_enable_output_rail_protection() - Enable power rail protection
 953 *
 954 * This function enables overload protection on the power rails. This is
 955 * triggered if the power rails' voltage drops rapidly due to overload and
 956 * in such case, the supply to the powerrail is cut-off, protecting the
 957 * CPU from damage. Note that under such condition, the system will likely
 958 * crash or misbehave.
 959 */
 960static void mxs_enable_output_rail_protection(void)
 961{
 962        struct mxs_power_regs *power_regs =
 963                (struct mxs_power_regs *)MXS_POWER_BASE;
 964
 965        debug("SPL: Enabling output rail protection\n");
 966
 967        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
 968                POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 969
 970        setbits_le32(&power_regs->hw_power_vdddctrl,
 971                        POWER_VDDDCTRL_PWDN_BRNOUT);
 972
 973        setbits_le32(&power_regs->hw_power_vddactrl,
 974                        POWER_VDDACTRL_PWDN_BRNOUT);
 975
 976        setbits_le32(&power_regs->hw_power_vddioctrl,
 977                        POWER_VDDIOCTRL_PWDN_BRNOUT);
 978}
 979
 980/**
 981 * mxs_get_vddio_power_source_off() - Get VDDIO rail power source
 982 *
 983 * This function tests if the VDDIO rail is supplied by linear regulator
 984 * or by the DC-DC converter. Returns 1 if powered by linear regulator,
 985 * returns 0 if powered by the DC-DC converter.
 986 */
 987static int mxs_get_vddio_power_source_off(void)
 988{
 989        struct mxs_power_regs *power_regs =
 990                (struct mxs_power_regs *)MXS_POWER_BASE;
 991        uint32_t tmp;
 992
 993        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
 994                tmp = readl(&power_regs->hw_power_vddioctrl);
 995                if (tmp & POWER_VDDIOCTRL_DISABLE_FET) {
 996                        if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
 997                                POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
 998                                return 1;
 999                        }
1000                }
1001
1002                if (!(readl(&power_regs->hw_power_5vctrl) &
1003                        POWER_5VCTRL_ENABLE_DCDC)) {
1004                        if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
1005                                POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
1006                                return 1;
1007                        }
1008                }
1009        }
1010
1011        return 0;
1012
1013}
1014
1015/**
1016 * mxs_get_vddd_power_source_off() - Get VDDD rail power source
1017 *
1018 * This function tests if the VDDD rail is supplied by linear regulator
1019 * or by the DC-DC converter. Returns 1 if powered by linear regulator,
1020 * returns 0 if powered by the DC-DC converter.
1021 */
1022static int mxs_get_vddd_power_source_off(void)
1023{
1024        struct mxs_power_regs *power_regs =
1025                (struct mxs_power_regs *)MXS_POWER_BASE;
1026        uint32_t tmp;
1027
1028        tmp = readl(&power_regs->hw_power_vdddctrl);
1029        if (tmp & POWER_VDDDCTRL_DISABLE_FET) {
1030                if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
1031                        POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
1032                        return 1;
1033                }
1034        }
1035
1036        if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
1037                if (!(readl(&power_regs->hw_power_5vctrl) &
1038                        POWER_5VCTRL_ENABLE_DCDC)) {
1039                        return 1;
1040                }
1041        }
1042
1043        if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) {
1044                if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
1045                        POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) {
1046                        return 1;
1047                }
1048        }
1049
1050        return 0;
1051}
1052
1053struct mxs_vddx_cfg {
1054        uint32_t                *reg;
1055        uint8_t                 step_mV;
1056        uint16_t                lowest_mV;
1057        int                     (*powered_by_linreg)(void);
1058        uint32_t                trg_mask;
1059        uint32_t                bo_irq;
1060        uint32_t                bo_enirq;
1061        uint32_t                bo_offset_mask;
1062        uint32_t                bo_offset_offset;
1063};
1064
1065static const struct mxs_vddx_cfg mxs_vddio_cfg = {
1066        .reg                    = &(((struct mxs_power_regs *)MXS_POWER_BASE)->
1067                                        hw_power_vddioctrl),
1068#if defined(CONFIG_MX23)
1069        .step_mV                = 25,
1070#else
1071        .step_mV                = 50,
1072#endif
1073        .lowest_mV              = 2800,
1074        .powered_by_linreg      = mxs_get_vddio_power_source_off,
1075        .trg_mask               = POWER_VDDIOCTRL_TRG_MASK,
1076        .bo_irq                 = POWER_CTRL_VDDIO_BO_IRQ,
1077        .bo_enirq               = POWER_CTRL_ENIRQ_VDDIO_BO,
1078        .bo_offset_mask         = POWER_VDDIOCTRL_BO_OFFSET_MASK,
1079        .bo_offset_offset       = POWER_VDDIOCTRL_BO_OFFSET_OFFSET,
1080};
1081
1082static const struct mxs_vddx_cfg mxs_vddd_cfg = {
1083        .reg                    = &(((struct mxs_power_regs *)MXS_POWER_BASE)->
1084                                        hw_power_vdddctrl),
1085        .step_mV                = 25,
1086        .lowest_mV              = 800,
1087        .powered_by_linreg      = mxs_get_vddd_power_source_off,
1088        .trg_mask               = POWER_VDDDCTRL_TRG_MASK,
1089        .bo_irq                 = POWER_CTRL_VDDD_BO_IRQ,
1090        .bo_enirq               = POWER_CTRL_ENIRQ_VDDD_BO,
1091        .bo_offset_mask         = POWER_VDDDCTRL_BO_OFFSET_MASK,
1092        .bo_offset_offset       = POWER_VDDDCTRL_BO_OFFSET_OFFSET,
1093};
1094
1095#ifdef CONFIG_MX23
1096static const struct mxs_vddx_cfg mxs_vddmem_cfg = {
1097        .reg                    = &(((struct mxs_power_regs *)MXS_POWER_BASE)->
1098                                        hw_power_vddmemctrl),
1099        .step_mV                = 50,
1100        .lowest_mV              = 1700,
1101        .powered_by_linreg      = NULL,
1102        .trg_mask               = POWER_VDDMEMCTRL_TRG_MASK,
1103        .bo_irq                 = 0,
1104        .bo_enirq               = 0,
1105        .bo_offset_mask         = 0,
1106        .bo_offset_offset       = 0,
1107};
1108#endif
1109
1110/**
1111 * mxs_power_set_vddx() - Configure voltage on DC-DC converter rail
1112 * @cfg:                Configuration data of the DC-DC converter rail
1113 * @new_target:         New target voltage of the DC-DC converter rail
1114 * @new_brownout:       New brownout trigger voltage
1115 *
1116 * This function configures the output voltage on the DC-DC converter rail.
1117 * The rail is selected by the @cfg argument. The new voltage target is
1118 * selected by the @new_target and the voltage is specified in mV. The
1119 * new brownout value is selected by the @new_brownout argument and the
1120 * value is also in mV.
1121 */
1122static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
1123                                uint32_t new_target, uint32_t new_brownout)
1124{
1125        struct mxs_power_regs *power_regs =
1126                (struct mxs_power_regs *)MXS_POWER_BASE;
1127        uint32_t cur_target, diff, bo_int = 0;
1128        uint32_t powered_by_linreg = 0;
1129        int adjust_up, tmp;
1130
1131        new_brownout = DIV_ROUND_CLOSEST(new_target - new_brownout,
1132                                         cfg->step_mV);
1133
1134        cur_target = readl(cfg->reg);
1135        cur_target &= cfg->trg_mask;
1136        cur_target *= cfg->step_mV;
1137        cur_target += cfg->lowest_mV;
1138
1139        adjust_up = new_target > cur_target;
1140        if (cfg->powered_by_linreg)
1141                powered_by_linreg = cfg->powered_by_linreg();
1142
1143        if (adjust_up && cfg->bo_irq) {
1144                if (powered_by_linreg) {
1145                        bo_int = readl(cfg->reg);
1146                        clrbits_le32(cfg->reg, cfg->bo_enirq);
1147                }
1148                setbits_le32(cfg->reg, cfg->bo_offset_mask);
1149        }
1150
1151        do {
1152                if (abs(new_target - cur_target) > 100) {
1153                        if (adjust_up)
1154                                diff = cur_target + 100;
1155                        else
1156                                diff = cur_target - 100;
1157                } else {
1158                        diff = new_target;
1159                }
1160
1161                diff -= cfg->lowest_mV;
1162                diff /= cfg->step_mV;
1163
1164                clrsetbits_le32(cfg->reg, cfg->trg_mask, diff);
1165
1166                if (powered_by_linreg ||
1167                        (readl(&power_regs->hw_power_sts) &
1168                                POWER_STS_VDD5V_GT_VDDIO))
1169                        early_delay(500);
1170                else {
1171                        for (;;) {
1172                                tmp = readl(&power_regs->hw_power_sts);
1173                                if (tmp & POWER_STS_DC_OK)
1174                                        break;
1175                        }
1176                }
1177
1178                cur_target = readl(cfg->reg);
1179                cur_target &= cfg->trg_mask;
1180                cur_target *= cfg->step_mV;
1181                cur_target += cfg->lowest_mV;
1182        } while (new_target > cur_target);
1183
1184        if (cfg->bo_irq) {
1185                if (adjust_up && powered_by_linreg) {
1186                        writel(cfg->bo_irq, &power_regs->hw_power_ctrl_clr);
1187                        if (bo_int & cfg->bo_enirq)
1188                                setbits_le32(cfg->reg, cfg->bo_enirq);
1189                }
1190
1191                clrsetbits_le32(cfg->reg, cfg->bo_offset_mask,
1192                                new_brownout << cfg->bo_offset_offset);
1193        }
1194}
1195
1196/**
1197 * mxs_setup_batt_detect() - Start the battery voltage measurement logic
1198 *
1199 * This function starts and configures the LRADC block. This allows the
1200 * power initialization code to measure battery voltage and based on this
1201 * knowledge, decide whether to boot at all, boot from battery or boot
1202 * from 5V input.
1203 */
1204static void mxs_setup_batt_detect(void)
1205{
1206        debug("SPL: Starting battery voltage measurement logic\n");
1207
1208        mxs_lradc_init();
1209        mxs_lradc_enable_batt_measurement();
1210        early_delay(10);
1211}
1212
1213/**
1214 * mxs_ungate_power() - Ungate the POWER block
1215 *
1216 * This function ungates clock to the power block. In case the power block
1217 * was still gated at this point, it will not be possible to configure the
1218 * block and therefore the power initialization would fail. This function
1219 * is only needed on i.MX233, on i.MX28 the power block is always ungated.
1220 */
1221static void mxs_ungate_power(void)
1222{
1223#ifdef CONFIG_MX23
1224        struct mxs_power_regs *power_regs =
1225                (struct mxs_power_regs *)MXS_POWER_BASE;
1226
1227        writel(POWER_CTRL_CLKGATE, &power_regs->hw_power_ctrl_clr);
1228#endif
1229}
1230
1231/**
1232 * mxs_power_init() - The power block init main function
1233 *
1234 * This function calls all the power block initialization functions in
1235 * proper sequence to start the power block.
1236 */
1237void mxs_power_init(void)
1238{
1239        struct mxs_power_regs *power_regs =
1240                (struct mxs_power_regs *)MXS_POWER_BASE;
1241
1242        debug("SPL: Initialising Power Block\n");
1243
1244        mxs_ungate_power();
1245
1246        mxs_power_clock2xtal();
1247        mxs_power_set_auto_restart();
1248        mxs_power_set_linreg();
1249        mxs_power_setup_5v_detect();
1250
1251        mxs_setup_batt_detect();
1252
1253        mxs_power_configure_power_source();
1254        mxs_enable_output_rail_protection();
1255
1256        debug("SPL: Setting VDDIO to 3V3 (brownout @ 3v15)\n");
1257        mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150);
1258
1259        debug("SPL: Setting VDDD to 1V55 (brownout @ 1v400)\n");
1260        mxs_power_set_vddx(&mxs_vddd_cfg, 1550, 1400);
1261#ifdef CONFIG_MX23
1262        debug("SPL: Setting mx23 VDDMEM to 2V5 (brownout @ 1v7)\n");
1263        mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700);
1264#endif
1265        writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
1266                POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ |
1267                POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ |
1268                POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
1269
1270        writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
1271
1272        early_delay(1000);
1273}
1274
1275#ifdef  CONFIG_SPL_MXS_PSWITCH_WAIT
1276/**
1277 * mxs_power_wait_pswitch() - Wait for power switch to be pressed
1278 *
1279 * This function waits until the power-switch was pressed to start booting
1280 * the board.
1281 */
1282void mxs_power_wait_pswitch(void)
1283{
1284        struct mxs_power_regs *power_regs =
1285                (struct mxs_power_regs *)MXS_POWER_BASE;
1286
1287        debug("SPL: Waiting for power switch input\n");
1288        while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
1289                ;
1290}
1291#endif
1292