Home | History | Annotate | Line # | Download | only in bootimx23
power_prep.c revision 1.1
      1 /* $Id: power_prep.c,v 1.1 2012/11/20 19:08:46 jkunz Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Petri Laakso.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/param.h>
     33 #include <sys/cdefs.h>
     34 #include <sys/types.h>
     35 
     36 #include <arm/imx/imx23_powerreg.h>
     37 
     38 #include <lib/libsa/stand.h>
     39 
     40 #include "common.h"
     41 
     42 void charge_4p2_capacitance(void);
     43 void enable_4p2_linreg(void);
     44 void enable_dcdc(void);
     45 void enable_vbusvalid_comparator(void);
     46 void set_targets(void);
     47 void dcdc4p2_enable_dcdc(void);
     48 void p5vctrl_enable_dcdc(void);
     49 void enable_vddmem(void);
     50 
     51 /*
     52  * Power rail voltage targets, brownout levels and linear regulator
     53  * offsets from the target.
     54  *
     55  * Supply	Target	BO	LinReg offset
     56  * ------------------------------------------
     57  * VDDD		1.550 V	1.450 V	-25 mV
     58  * VDDA		1.750 V	1.575 V	-25 mV
     59  * VDDIO	3.100 V	2.925 V	-25 mV
     60  * VDDMEM	2.500 V <na>	<na>
     61  *
     62  * BO = Brownout level below target.
     63  */
     64 #define VDDD_TARGET 0x1e
     65 #define VDDD_BO_OFFSET 0x4
     66 #define VDDD_LINREG_OFFSET 0x02
     67 
     68 #define VDDA_TARGET 0x0A
     69 #define VDDA_BO_OFFSET 0x07
     70 #define VDDA_LINREG_OFFSET 0x02
     71 
     72 #define VDDIO_TARGET 0x0C
     73 #define VDDIO_BO_OFFSET 0x07
     74 #define VDDIO_LINREG_OFFSET 0x02
     75 
     76 #define VDDMEM_TARGET 0x10
     77 
     78 /*
     79  * Threshold voltage for the VBUSVALID comparator.
     80  * Always make sure that the VDD5V voltage level is higher.
     81  */
     82 #define VBUSVALID_TRSH 0x02	/* 4.1 V */
     83 
     84 /* Limits for BATT charger + 4P2 current */
     85 #define P4P2_ILIMIT_MIN 0x01	/* 10 mA */
     86 #define P4P2_ILIMIT_MAX 0x3f	/* 780 mA */
     87 
     88 /*
     89  * Trip point for the comparison between the DCDC_4P2 and BATTERY pin.
     90  * If this voltage comparation is true then 5 V originated power will supply
     91  * the DCDC. Otherwise battery will be used.
     92  */
     93 #define DCDC4P2_CMPTRIP 0x00	/* DCDC_4P2 pin > 0.85 * BATTERY pin */
     94 
     95 /*
     96  * Adjust the behavior of the DCDC and 4.2 V circuit.
     97  * Two MSBs control the VDD4P2 brownout below the DCDC4P2_TRG before the
     98  * regulation circuit steals battery charge. Two LSBs control which power
     99  * source is selected by the DCDC.
    100  */
    101 #define DCDC4P2_DROPOUT_CTRL_BO_200 0x0C
    102 #define DCDC4P2_DROPOUT_CTRL_BO_100 0x08
    103 #define DCDC4P2_DROPOUT_CTRL_BO_050 0x04
    104 #define DCDC4P2_DROPOUT_CTRL_BO_025 0x00
    105 
    106 #define DCDC4P2_DROPOUT_CTRL_SEL_4P2 0x00	/* Don't use battery at all. */
    107 #define DCDC4P2_DROPOUT_CTRL_SEL_BATT_IF_GT_4P2 0x01	/* BATT if 4P2 < BATT */
    108 #define DCDC4P2_DROPOUT_CTRL_SEL_HIGHER 0x02	/* Selects which ever is
    109 						 * higher. */
    110 
    111 #define DCDC4P2_DROPOUT_CTRL (DCDC4P2_DROPOUT_CTRL_BO_200 |\
    112 	    DCDC4P2_DROPOUT_CTRL_SEL_4P2)
    113 
    114 /*
    115  * Prepare system for a 5 V operation.
    116  *
    117  * The system uses inefficient linear regulators as a power source after boot.
    118  * This code enables the use of more energy efficient DC-DC converter as a
    119  * power source.
    120  */
    121 int
    122 power_prep(void)
    123 {
    124 
    125 	/* Enable clocks to the power block */
    126 	REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR, HW_POWER_CTRL_CLKGATE);
    127 
    128 	set_targets();
    129 	enable_vbusvalid_comparator();
    130 	enable_4p2_linreg();
    131 	charge_4p2_capacitance();
    132 	enable_dcdc();
    133 	enable_vddmem();
    134 
    135 	return 0;
    136 }
    137 
    138 /*
    139  * Set switching converter voltage targets, brownout levels and linear
    140  * regulator output offsets.
    141  */
    142 void
    143 set_targets(void)
    144 {
    145 	uint32_t vddctrl;
    146 
    147 	/* VDDD */
    148 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDDCTRL);
    149 
    150 	vddctrl &= ~(HW_POWER_VDDDCTRL_LINREG_OFFSET |
    151 	    HW_POWER_VDDDCTRL_BO_OFFSET |
    152 	    HW_POWER_VDDDCTRL_TRG);
    153 	vddctrl |=
    154 	    __SHIFTIN(VDDD_LINREG_OFFSET, HW_POWER_VDDDCTRL_LINREG_OFFSET) |
    155 	    __SHIFTIN(VDDD_BO_OFFSET, HW_POWER_VDDDCTRL_BO_OFFSET) |
    156 	    __SHIFTIN(VDDD_TARGET, HW_POWER_VDDDCTRL_TRG);
    157 
    158 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddctrl);
    159 
    160 	/* VDDA */
    161 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDACTRL);
    162 
    163 	vddctrl &= ~(HW_POWER_VDDACTRL_LINREG_OFFSET |
    164 	    HW_POWER_VDDACTRL_BO_OFFSET |
    165 	    HW_POWER_VDDACTRL_TRG);
    166 	vddctrl |=
    167 	    __SHIFTIN(VDDA_LINREG_OFFSET, HW_POWER_VDDACTRL_LINREG_OFFSET) |
    168 	    __SHIFTIN(VDDA_BO_OFFSET, HW_POWER_VDDACTRL_BO_OFFSET) |
    169 	    __SHIFTIN(VDDA_TARGET, HW_POWER_VDDACTRL_TRG);
    170 
    171 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDACTRL, vddctrl);
    172 
    173 	/* VDDIO */
    174 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDIOCTRL);
    175 
    176 	vddctrl &= ~(HW_POWER_VDDIOCTRL_LINREG_OFFSET |
    177 	    HW_POWER_VDDIOCTRL_BO_OFFSET |
    178 	    HW_POWER_VDDIOCTRL_TRG);
    179 	vddctrl |=
    180 	    __SHIFTIN(VDDIO_LINREG_OFFSET, HW_POWER_VDDACTRL_LINREG_OFFSET) |
    181 	    __SHIFTIN(VDDIO_BO_OFFSET, HW_POWER_VDDACTRL_BO_OFFSET) |
    182 	    __SHIFTIN(VDDIO_TARGET, HW_POWER_VDDACTRL_TRG);
    183 
    184 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddctrl);
    185 
    186 	/* VDDMEM */
    187 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDMEMCTRL);
    188 	vddctrl &= ~(HW_POWER_VDDMEMCTRL_TRG);
    189 	vddctrl |= __SHIFTIN(VDDMEM_TARGET, HW_POWER_VDDMEMCTRL_TRG);
    190 
    191 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl);
    192 
    193 	return;
    194 }
    195 
    196 /*
    197  * VBUSVALID comparator is accurate method to determine the presence of 5 V.
    198  * Turn on the comparator, set its voltage treshold and instruct DC-DC to
    199  * use it.
    200  */
    201 void
    202 enable_vbusvalid_comparator()
    203 {
    204 	uint32_t p5vctrl;
    205 
    206 	/*
    207 	 * Disable 5 V brownout detection temporarily because setting
    208 	 * VBUSVALID_5VDETECT can cause false brownout.
    209 	 */
    210 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    211 	    HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    212 
    213 	p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    214 
    215 	p5vctrl &= ~HW_POWER_5VCTRL_VBUSVALID_TRSH;
    216 	p5vctrl |=
    217 	    /* Turn on VBUS comparators. */
    218 	    (HW_POWER_5VCTRL_PWRUP_VBUS_CMPS |
    219 	    /* Set treshold for VBUSVALID comparator. */
    220 	    __SHIFTIN(VBUSVALID_TRSH, HW_POWER_5VCTRL_VBUSVALID_TRSH) |
    221 	    /* Set DC-DC to use VBUSVALID comparator. */
    222 	    HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    223 
    224 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl);
    225 
    226 	/* Enable temporarily disabled 5 V brownout detection. */
    227 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    228 	    HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    229 
    230 	return;
    231 }
    232 
    233 /*
    234  * Enable 4P2 linear regulator.
    235  */
    236 void
    237 enable_4p2_linreg(void)
    238 {
    239 	uint32_t dcdc4p2;
    240 	uint32_t p5vctrl;
    241 
    242 	dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2);
    243 	/* Set the 4P2 target to 4.2 V and BO to 3.6V by clearing TRG and BO
    244 	 * field. */
    245 	dcdc4p2 &= ~(HW_POWER_DCDC4P2_TRG | HW_POWER_DCDC4P2_BO);
    246 	/* Enable the 4P2 circuitry to control the LinReg. */
    247 	dcdc4p2 |= HW_POWER_DCDC4P2_ENABLE_4P2;
    248 	REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2);
    249 
    250 	/* The 4P2 LinReg needs a static load to operate correctly. Since the
    251 	 * DC-DC is not yet loading the LinReg, another load must be used. */
    252 	REG_WRITE(HW_POWER_BASE + HW_POWER_CHARGE_SET,
    253 	    HW_POWER_CHARGE_ENABLE_LOAD);
    254 
    255 	p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    256 	p5vctrl &= ~(HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT |
    257 	    /* Power on the 4P2 LinReg. ON = 0x0, OFF = 0x1 */
    258 	    HW_POWER_5VCTRL_PWD_CHARGE_4P2);
    259 	p5vctrl |=
    260 	    /* Provide an initial current limit for the 4P2 LinReg with the
    261 	     * smallest value possible. */
    262 	    __SHIFTIN(P4P2_ILIMIT_MIN, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    263 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl);
    264 
    265 	/* Ungate the path from 4P2 LinReg to DC-DC. */
    266 	dcdc4p2_enable_dcdc();
    267 
    268 	return;
    269 }
    270 
    271 /*
    272  * There is capacitor on the 4P2 output which must be charged before powering
    273  * on the 4P2 linear regulator to avoid brownouts on the 5 V source.
    274  * Charging is done by slowly increasing current limit until it reaches
    275  * P4P2_ILIMIT_MAX.
    276  */
    277 void
    278 charge_4p2_capacitance(void)
    279 {
    280 	uint32_t ilimit;
    281 	uint32_t p5vctrl;
    282 
    283 	p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    284 	ilimit = __SHIFTOUT(p5vctrl, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    285 
    286 	/* Increment current limit slowly. */
    287 	while (ilimit < P4P2_ILIMIT_MAX) {
    288 		ilimit++;
    289 		p5vctrl &= ~(HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    290 		p5vctrl |= __SHIFTIN(ilimit, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    291 		REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl);
    292 		delay_us(10000);
    293 	}
    294 
    295 	return;
    296 }
    297 
    298 /*
    299  * Enable DCDC to use 4P2 regulator and set its power source selection logic.
    300  */
    301 void
    302 enable_dcdc(void)
    303 {
    304 	uint32_t dcdc4p2;
    305 	uint32_t vddctrl;
    306 
    307 	dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2);
    308 	dcdc4p2 &= ~(HW_POWER_DCDC4P2_CMPTRIP | HW_POWER_DCDC4P2_DROPOUT_CTRL);
    309 	/* Comparison between the DCDC_4P2 pin and BATTERY pin to choose which
    310 	 * will supply the DCDC. */
    311 	dcdc4p2 |= __SHIFTIN(DCDC4P2_CMPTRIP, HW_POWER_DCDC4P2_CMPTRIP);
    312 	/* DC-DC brownout and select logic. */
    313 	dcdc4p2 |= __SHIFTIN(DCDC4P2_DROPOUT_CTRL,
    314 	    HW_POWER_DCDC4P2_DROPOUT_CTRL);
    315 	REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2);
    316 
    317 	/* Disable the automatic DC-DC startup when 5 V is lost (it is on
    318 	 * already) */
    319 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    320 	    HW_POWER_5VCTRL_DCDC_XFER);
    321 
    322 	p5vctrl_enable_dcdc();
    323 
    324 	/* Enable switching converter outputs and disable linear regulators
    325 	 * for VDDD, VDDIO and VDDA. */
    326 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDDCTRL);
    327 	vddctrl &= ~(HW_POWER_VDDDCTRL_DISABLE_FET |
    328 	    HW_POWER_VDDDCTRL_ENABLE_LINREG);
    329 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddctrl);
    330 
    331 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDIOCTRL);
    332 	vddctrl &= ~HW_POWER_VDDIOCTRL_DISABLE_FET;
    333 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddctrl);
    334 
    335 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDACTRL);
    336 	vddctrl &= ~(HW_POWER_VDDACTRL_DISABLE_FET |
    337 	    HW_POWER_VDDACTRL_ENABLE_LINREG);
    338 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDACTRL, vddctrl);
    339 
    340 	/* The 4P2 LinReg needs a static load to operate correctly. Since the
    341 	 * DC-DC is already running we can remove extra 100 ohm load enabled
    342 	 * before. */
    343 	REG_WRITE(HW_POWER_BASE + HW_POWER_CHARGE_CLR,
    344 	    HW_POWER_CHARGE_ENABLE_LOAD);
    345 
    346 	return;
    347 }
    348 
    349 /*
    350  * DCDC4P2 DCDC enable sequence according to errata #5837
    351  */
    352 void
    353 dcdc4p2_enable_dcdc(void)
    354 {
    355 	uint32_t dcdc4p2;
    356 	uint32_t p5vctrl;
    357 	uint32_t p5vctrl_saved;
    358 	uint32_t pctrl;
    359 	uint32_t pctrl_saved;
    360 
    361 	pctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_CTRL);
    362 	p5vctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    363 
    364 	/* Disable the power rail brownout interrupts. */
    365 	REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    366 	    (HW_POWER_CTRL_ENIRQ_VDDA_BO |
    367 	    HW_POWER_CTRL_ENIRQ_VDDD_BO |
    368 	    HW_POWER_CTRL_ENIRQ_VDDIO_BO));
    369 
    370 	/* Set the HW_POWER_5VCTRL PWRUP_VBUS_CMPS bit (may already be set) */
    371 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    372 	    HW_POWER_5VCTRL_PWRUP_VBUS_CMPS);
    373 
    374 	/* Set the HW_POWER_5VCTRL VBUSVALID_5VDETECT bit to 0 */
    375 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    376 	    HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    377 
    378 	/* Set the HW_POWER_5VCTRL VBUSVALID_TRSH to 0x0 (2.9 V) */
    379 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    380 	    HW_POWER_5VCTRL_VBUSVALID_TRSH);
    381 
    382 	/* Disable VBUSDROOP status and interrupt. */
    383 	REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    384 	    (HW_POWER_CTRL_VDD5V_DROOP_IRQ | HW_POWER_CTRL_ENIRQ_VDD5V_DROOP));
    385 
    386 	/* Set the ENABLE_DCDC bit in HW_POWER_DCDC4P2. */
    387 	dcdc4p2 = REG_READ(HW_POWER_BASE + HW_POWER_DCDC4P2);
    388 	dcdc4p2 |= HW_POWER_DCDC4P2_ENABLE_DCDC;
    389 	REG_WRITE(HW_POWER_BASE + HW_POWER_DCDC4P2, dcdc4p2);
    390 
    391 	delay_us(100);
    392 
    393 	pctrl = REG_READ(HW_POWER_BASE + HW_POWER_CTRL);
    394 	/* VBUSVALID_IRQ is set. */
    395 	if (__SHIFTOUT(pctrl, HW_POWER_CTRL_VBUSVALID_IRQ)) {
    396 		/* Set and clear the PWD_CHARGE_4P2 bit to repower on the 4P2
    397 		 * regulator because it is automatically shut off on a
    398 		 * VBUSVALID false condition. */
    399 		REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    400 		    HW_POWER_5VCTRL_PWD_CHARGE_4P2);
    401 		REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    402 		    HW_POWER_5VCTRL_PWD_CHARGE_4P2);
    403 		/* Ramp up the CHARGE_4P2_ILIMIT value at this point. */
    404 		charge_4p2_capacitance();
    405 	}
    406 
    407 	/* Restore modified bits back to HW_POWER_CTRL. */
    408 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDA_BO)
    409 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    410 		    HW_POWER_CTRL_ENIRQ_VDDA_BO);
    411 	else
    412 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    413 		    HW_POWER_CTRL_ENIRQ_VDDA_BO);
    414 
    415 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDD_BO)
    416 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    417 		    HW_POWER_CTRL_ENIRQ_VDDD_BO);
    418 	else
    419 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    420 		    HW_POWER_CTRL_ENIRQ_VDDD_BO);
    421 
    422 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDIO_BO)
    423 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    424 		    HW_POWER_CTRL_ENIRQ_VDDIO_BO);
    425 	else
    426 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    427 		    HW_POWER_CTRL_ENIRQ_VDDIO_BO);
    428 
    429 	if (pctrl_saved & HW_POWER_CTRL_VDD5V_DROOP_IRQ)
    430 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    431 		    HW_POWER_CTRL_VDD5V_DROOP_IRQ);
    432 	else
    433 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    434 		    HW_POWER_CTRL_VDD5V_DROOP_IRQ);
    435 
    436 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDD5V_DROOP)
    437 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    438 		    HW_POWER_CTRL_ENIRQ_VDD5V_DROOP);
    439 	else
    440 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    441 		    HW_POWER_CTRL_ENIRQ_VDD5V_DROOP);
    442 
    443 	/* Restore modified bits back to HW_POWER_5VCTRL. */
    444 	p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    445 	p5vctrl &= ~(HW_POWER_5VCTRL_PWRUP_VBUS_CMPS |
    446 	    HW_POWER_5VCTRL_VBUSVALID_5VDETECT |
    447 	    HW_POWER_5VCTRL_VBUSVALID_TRSH);
    448 	p5vctrl |= __SHIFTOUT(p5vctrl_saved, HW_POWER_5VCTRL_VBUSVALID_TRSH) |
    449 	    (p5vctrl_saved & HW_POWER_5VCTRL_PWRUP_VBUS_CMPS) |
    450 	    (p5vctrl_saved & HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    451 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl);
    452 
    453 	return;
    454 }
    455 
    456 /*
    457  * 5VCTRL DCDC enable sequence according to errata #5837
    458  */
    459 void
    460 p5vctrl_enable_dcdc(void)
    461 {
    462 	uint32_t p5vctrl;
    463 	uint32_t p5vctrl_saved;
    464 	uint32_t pctrl;
    465 	uint32_t pctrl_saved;
    466 
    467 	pctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_CTRL);
    468 	p5vctrl_saved = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    469 
    470 	/* Disable the power rail brownout interrupts. */
    471 	REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    472 	    HW_POWER_CTRL_ENIRQ_VDDA_BO |
    473 	    HW_POWER_CTRL_ENIRQ_VDDD_BO |
    474 	    HW_POWER_CTRL_ENIRQ_VDDIO_BO);
    475 
    476 	/* Set the HW_POWER_5VCTRL PWRUP_VBUS_CMPS bit (may already be set) */
    477 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    478 	    HW_POWER_5VCTRL_PWRUP_VBUS_CMPS);
    479 
    480 	/* Set the HW_POWER_5VCTRL VBUSVALID_5VDETECT bit to 1 */
    481 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    482 	    HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    483 
    484 	/* Set the HW_POWER_5VCTRL VBUSVALID_TRSH to 0x0 (2.9 V) */
    485 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    486 	    HW_POWER_5VCTRL_VBUSVALID_TRSH);
    487 
    488 	/* Disable VBUSDROOP status and interrupt. */
    489 	REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    490 	    (HW_POWER_CTRL_VDD5V_DROOP_IRQ | HW_POWER_CTRL_ENIRQ_VDD5V_DROOP));
    491 
    492 	/* Work over errata #2816 by disabling 5 V brownout while modifying
    493 	 * ENABLE_DCDC. */
    494 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_CLR,
    495 	    HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    496 
    497 	/* Set the ENABLE_DCDC bit in HW_POWER_5VCTRL. */
    498 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    499 	    HW_POWER_5VCTRL_ENABLE_DCDC);
    500 
    501 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL_SET,
    502 	    HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    503 
    504 	delay_us(100);
    505 
    506 	pctrl = REG_READ(HW_POWER_BASE + HW_POWER_CTRL);
    507 	/* VBUSVALID_IRQ is set. */
    508 	if (__SHIFTOUT(pctrl, HW_POWER_CTRL_VBUSVALID_IRQ)) {
    509 		/* repeat the sequence for enabling the 4P2 regulator and DCDC
    510 		 * from 4P2. */
    511 		enable_4p2_linreg();
    512 	}
    513 	/* Restore modified bits back to HW_POWER_CTRL. */
    514 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDA_BO)
    515 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    516 		    HW_POWER_CTRL_ENIRQ_VDDA_BO);
    517 	else
    518 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    519 		    HW_POWER_CTRL_ENIRQ_VDDA_BO);
    520 
    521 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDD_BO)
    522 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    523 		    HW_POWER_CTRL_ENIRQ_VDDD_BO);
    524 	else
    525 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    526 		    HW_POWER_CTRL_ENIRQ_VDDD_BO);
    527 
    528 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDDIO_BO)
    529 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    530 		    HW_POWER_CTRL_ENIRQ_VDDIO_BO);
    531 	else
    532 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    533 		    HW_POWER_CTRL_ENIRQ_VDDIO_BO);
    534 
    535 	if (pctrl_saved & HW_POWER_CTRL_VDD5V_DROOP_IRQ)
    536 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    537 		    HW_POWER_CTRL_VDD5V_DROOP_IRQ);
    538 	else
    539 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    540 		    HW_POWER_CTRL_VDD5V_DROOP_IRQ);
    541 
    542 	if (pctrl_saved & HW_POWER_CTRL_ENIRQ_VDD5V_DROOP)
    543 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_SET,
    544 		    HW_POWER_CTRL_ENIRQ_VDD5V_DROOP);
    545 	else
    546 		REG_WRITE(HW_POWER_BASE + HW_POWER_CTRL_CLR,
    547 		    HW_POWER_CTRL_ENIRQ_VDD5V_DROOP);
    548 
    549 	/* Restore modified bits back to HW_POWER_5VCTRL. */
    550 	p5vctrl = REG_READ(HW_POWER_BASE + HW_POWER_5VCTRL);
    551 	p5vctrl &= ~(HW_POWER_5VCTRL_PWRUP_VBUS_CMPS |
    552 	    HW_POWER_5VCTRL_VBUSVALID_5VDETECT |
    553 	    HW_POWER_5VCTRL_VBUSVALID_TRSH);
    554 	p5vctrl |= __SHIFTOUT(p5vctrl_saved, HW_POWER_5VCTRL_VBUSVALID_TRSH) |
    555 	    (p5vctrl_saved & HW_POWER_5VCTRL_PWRUP_VBUS_CMPS) |
    556 	    (p5vctrl_saved & HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    557 	REG_WRITE(HW_POWER_BASE + HW_POWER_5VCTRL, p5vctrl);
    558 
    559 	return;
    560 }
    561 
    562 void
    563 enable_vddmem(void)
    564 {
    565 	uint32_t vddctrl;
    566 
    567 	/* VDDMEM */
    568 	vddctrl = REG_READ(HW_POWER_BASE + HW_POWER_VDDMEMCTRL);
    569 	vddctrl |= (HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
    570 	    HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT |
    571 	    HW_POWER_VDDMEMCTRL_ENABLE_LINREG);
    572 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl);
    573 	delay_us(500);
    574 	vddctrl &= ~(HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
    575 	    HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT);
    576 	REG_WRITE(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddctrl);
    577 
    578 	return;
    579 }
    580