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
42void charge_4p2_capacitance(void);
43void enable_4p2_linreg(void);
44void enable_dcdc(void);
45void enable_vbusvalid_comparator(void);
46void set_targets(void);
47void dcdc4p2_enable_dcdc(void);
48void p5vctrl_enable_dcdc(void);
49void 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 */
121int
122power_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 */
142void
143set_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 */
201void
202enable_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 */
236void
237enable_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 */
277void
278charge_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 */
301void
302enable_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 */
352void
353dcdc4p2_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 */
459void
460p5vctrl_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
562void
563enable_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