xref: /netbsd-src/sys/arch/evbarm/stand/bootimx23/power_prep.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 /* $Id: power_prep.c,v 1.3 2012/12/16 19:08:45 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/types.h>
34 #include <sys/cdefs.h>
35 
36 #include <arm/imx/imx23_powerreg.h>
37 
38 #include <lib/libsa/stand.h>
39 
40 #include "common.h"
41 
42 static void set_vddd_target(uint8_t);
43 static void set_vdda_target(uint8_t);
44 static void set_vddio_target(uint8_t);
45 static void set_vddmem_target(uint8_t);
46 #ifdef DEBUG
47 static void print_regs(void);
48 #endif
49 
50 #define VDDD_TARGET	0x1e	/* 1550 mV */
51 #define VDDA_TARGET	0x0a	/* 1750 mV */
52 #define VDDIO_TARGET	0x0c	/* 3100 mV */
53 #define VDDMEM_TARGET	0x10	/* 2500 mV */
54 
55 static int five_volts = 0;
56 
57 /*
58  * If 5V is present, all power rails are powered from the LinRegs.
59  *
60  * If powered from the battery, the DC-DC converter starts when battery power
61  * is detected and the PSWITCH button is pressed. In this state, the VDDA and
62  * VDDIO rails are powered on from DC-DC, but the VDDD rail is powered from its
63  * LinReg.
64  */
65 int
66 power_prep(void)
67 {
68 	if (REG_RD(HW_POWER_BASE + HW_POWER_STS) & HW_POWER_STS_VDD5V_GT_VDDIO)
69 		five_volts = 1;
70 #ifdef DEBUG
71 	if (five_volts)
72 		printf("Powered from 5V\n\r");
73 	else
74 		printf("Powered from the battery.\n\r");
75 	print_regs();
76 #endif
77 	set_vddd_target(VDDD_TARGET);
78 	set_vdda_target(VDDA_TARGET);
79 	set_vddio_target(VDDIO_TARGET);
80 	set_vddmem_target(VDDMEM_TARGET);
81 #ifdef DEBUG
82 	print_regs();
83 #endif
84 	return 0;
85 }
86 
87 /*
88  * Set VDDD target voltage.
89  */
90 static void
91 set_vddd_target(uint8_t target)
92 {
93 	uint32_t vddd;
94 	uint8_t curtrg;
95 
96 	vddd = REG_RD(HW_POWER_BASE + HW_POWER_VDDDCTRL);
97 
98 	/*
99 	 * VDDD is always powered from the linear regulator.
100 	 *
101 	 * Setting LINREG_OFFSET to 0 is recommended when powering VDDD from
102 	 * the linear regulator. It is also recommended to set DISABLE_STEPPING
103 	 * when powering VDDD from the linear regulators.
104 	 */
105 	vddd &= ~(HW_POWER_VDDDCTRL_LINREG_OFFSET);
106 	vddd |= HW_POWER_VDDDCTRL_DISABLE_STEPPING;
107 
108 	REG_WR(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddd);
109 	delay(1000);
110 
111 	curtrg = __SHIFTOUT(vddd, HW_POWER_VDDDCTRL_TRG);
112 
113 	/* Because HW stepping is disabled, raise voltage to target slowly. */
114 	for (curtrg++; curtrg <= target; curtrg++) {
115 		vddd = REG_RD(HW_POWER_BASE + HW_POWER_VDDDCTRL);
116 		vddd &= ~(HW_POWER_VDDDCTRL_TRG);
117 		vddd |= __SHIFTIN(curtrg, HW_POWER_VDDDCTRL_TRG);
118 		REG_WR(HW_POWER_BASE + HW_POWER_VDDDCTRL, vddd);
119 		delay(1000);
120 	}
121 
122 	return;
123 }
124 
125 static void
126 set_vdda_target(uint8_t target)
127 {
128 	uint32_t vdda;
129 	uint8_t curtrg;
130 
131 	vdda = REG_RD(HW_POWER_BASE + HW_POWER_VDDACTRL);
132 
133 	/*
134 	 * Setting LINREG_OFFSET to 0 is recommended when powering VDDA from
135 	 * the linear regulator. It is also recommended to set DISABLE_STEPPING
136 	 * when powering VDDA from the linear regulators.
137 	 */
138 	if (five_volts) {
139 		vdda &= ~(HW_POWER_VDDACTRL_LINREG_OFFSET);
140 		vdda |= HW_POWER_VDDACTRL_DISABLE_STEPPING;
141 		REG_WR(HW_POWER_BASE + HW_POWER_VDDACTRL, vdda);
142 		delay(1000);
143 
144 		curtrg = __SHIFTOUT(vdda, HW_POWER_VDDACTRL_TRG);
145 
146 		/*
147 		 * Because HW stepping is disabled, raise voltage to target
148 		 * slowly.
149 		 */
150 		for (curtrg++; curtrg <= target; curtrg++) {
151 			vdda = REG_RD(HW_POWER_BASE + HW_POWER_VDDACTRL);
152 			vdda &= ~(HW_POWER_VDDACTRL_TRG);
153 			vdda |= __SHIFTIN(curtrg, HW_POWER_VDDACTRL_TRG);
154 			REG_WR(HW_POWER_BASE + HW_POWER_VDDACTRL, vdda);
155 			delay(1000);
156 		}
157 	} else {
158 		vdda |= __SHIFTIN(target, HW_POWER_VDDACTRL_TRG);
159 		REG_WR(HW_POWER_BASE + HW_POWER_VDDACTRL, vdda);
160 	}
161 
162 	return;
163 }
164 
165 static void
166 set_vddio_target(uint8_t target)
167 {
168 	uint32_t vddio;
169 	uint8_t curtrg;
170 
171 	vddio = REG_RD(HW_POWER_BASE + HW_POWER_VDDIOCTRL);
172 
173 	/*
174 	 * Setting LINREG_OFFSET to 0 is recommended when powering VDDIO from
175 	 * the linear regulator. It is also recommended to set DISABLE_STEPPING
176 	 * when powering VDDIO from the linear regulators.
177 	 */
178 	if (five_volts) {
179 		vddio &= ~(HW_POWER_VDDIOCTRL_LINREG_OFFSET);
180 		vddio |= HW_POWER_VDDIOCTRL_DISABLE_STEPPING;
181 		REG_WR(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddio);
182 		delay(1000);
183 
184 		curtrg = __SHIFTOUT(vddio, HW_POWER_VDDIOCTRL_TRG);
185 
186 		/*
187 		 * Because HW stepping is disabled, raise voltage to target
188 		 * slowly.
189 		 */
190 		for (curtrg++; curtrg <= target; curtrg++) {
191 			vddio = REG_RD(HW_POWER_BASE + HW_POWER_VDDIOCTRL);
192 			vddio &= ~(HW_POWER_VDDIOCTRL_TRG);
193 			vddio |= __SHIFTIN(curtrg, HW_POWER_VDDIOCTRL_TRG);
194 			REG_WR(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddio);
195 			delay(1000);
196 		}
197 	} else {
198 		vddio |= __SHIFTIN(target, HW_POWER_VDDIOCTRL_TRG);
199 		REG_WR(HW_POWER_BASE + HW_POWER_VDDIOCTRL, vddio);
200 	}
201 
202 	return;
203 }
204 
205 static void
206 set_vddmem_target(uint8_t target)
207 {
208 	uint32_t vddmem;
209 
210 	/* Set target. */
211 	vddmem = REG_RD(HW_POWER_BASE + HW_POWER_VDDMEMCTRL);
212 	vddmem &= ~(HW_POWER_VDDMEMCTRL_TRG);
213 	vddmem |= __SHIFTIN(target, HW_POWER_VDDMEMCTRL_TRG);
214 	REG_WR(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddmem);
215 	delay(1000);
216 
217 	/* Enable VDDMEM */
218 	vddmem = REG_RD(HW_POWER_BASE + HW_POWER_VDDMEMCTRL);
219 	vddmem |= (HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
220 	    HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT |
221 	    HW_POWER_VDDMEMCTRL_ENABLE_LINREG);
222 	REG_WR(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddmem);
223 	delay(500);
224 	vddmem &= ~(HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
225 	    HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT);
226 	REG_WR(HW_POWER_BASE + HW_POWER_VDDMEMCTRL, vddmem);
227 
228 	return;
229 }
230 #ifdef DEBUG
231 #define PRINT_REG(REG)							\
232 	printf(#REG "\t%x\n\r", REG_RD(HW_POWER_BASE + REG));
233 
234 static void
235 print_regs(void)
236 {
237 	PRINT_REG(HW_POWER_CTRL);
238 	PRINT_REG(HW_POWER_5VCTRL);
239 	PRINT_REG(HW_POWER_MINPWR);
240 	PRINT_REG(HW_POWER_CHARGE);
241 	PRINT_REG(HW_POWER_VDDDCTRL);
242 	PRINT_REG(HW_POWER_VDDACTRL);
243 	PRINT_REG(HW_POWER_VDDIOCTRL);
244 	PRINT_REG(HW_POWER_VDDMEMCTRL);
245 	PRINT_REG(HW_POWER_DCDC4P2);
246 	PRINT_REG(HW_POWER_MISC);
247 	PRINT_REG(HW_POWER_DCLIMITS);
248 	PRINT_REG(HW_POWER_LOOPCTRL);
249 	PRINT_REG(HW_POWER_STS);
250 	PRINT_REG(HW_POWER_SPEED);
251 	PRINT_REG(HW_POWER_BATTMONITOR);
252 	PRINT_REG(HW_POWER_RESET);
253 	PRINT_REG(HW_POWER_DEBUG);
254 	PRINT_REG(HW_POWER_SPECIAL);
255 	PRINT_REG(HW_POWER_VERSION);
256 
257 	return;
258 }
259 #endif
260