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