1 /***********************************************************************************
2 * FILE PURPOSE: Driver for the PSC module
3 ***********************************************************************************
4 * FILE NAME: psc.c
5 *
6 * DESCRIPTION: The boot loader PSC driver
7 *
8 * Copyright (C) 2006, Texas Instruments, Inc.
9 * @file psc.c
10 *
11 * @brief
12 * The PSC 2.0.x driver
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the
24 * distribution.
25 *
26 * Neither the name of Texas Instruments Incorporated nor the names of
27 * its contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 */
43 #include "types.h"
44 #include "pscapi.h"
45 #include "pscloc.h"
46 #include "target.h"
49 #define DEVICE_REG32_W(x,y) *(volatile unsigned int *)(x)=(y)
50 #define DEVICE_REG32_R(x) (*(volatile unsigned int *)(x))
52 /***********************************************************************************
53 * FUNCTION PURPOSE: Wait!
54 ***********************************************************************************
55 * DESCRIPTION: This function doesn't do didly. It loops around for a bit
56 * to give transitions some time to occur.
57 * This function always returns 1.
58 ***********************************************************************************/
59 int16 pscDelay (void)
60 {
61 volatile uint32 i;
62 for (i = 0; i < 100; i++);
64 return (0);
66 } /* pscDelay */
69 /***********************************************************************************
70 * FUNCTION PURPOSE: Wait for end of transitional state
71 ***********************************************************************************
72 * DESCRIPTION: Polls pstat for the selected domain and waits for transitions
73 * to be complete.
74 *
75 * Since this is boot loader code it is *ASSUMED* that interrupts
76 * are disabled and no other core is mucking around with the psc
77 * at the same time.
78 *
79 * Returns 0 when the domain is free. Returns -1 if a timeout
80 * occurred waiting for the completion.
81 ***********************************************************************************/
82 int16 pscWait (uint32 domainNum)
83 {
84 uint32 retry;
85 uint32 ptstat;
87 /* Do nothing if the power domain is in transition. This should never
88 * happen since the boot code is the only software accesses psc.
89 * It's still remotely possible that the hardware state machines initiate transitions.
90 * Don't trap if the domain (or a module in this domain) is
91 * stuck in transition. */
92 retry = 0;
94 do {
96 ptstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PSTAT);
97 ptstat = ptstat & (1 << domainNum);
99 } while ((ptstat != 0) && ((retry += pscDelay ()) < PSC_PTSTAT_TIMEOUT_LIMIT));
101 if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
102 return (-1);
104 return (0);
106 } /* pscWait */
109 /***********************************************************************************
110 * FUNCTION PURPOSE: Return the PSC state
111 ***********************************************************************************
112 * DESCRIPTION: Checks the power state of the module
113 ***********************************************************************************/
114 BOOL pscModuleIsEnabled (uint32 modNum)
115 {
116 uint32 domainNum;
117 uint32 mdstat;
119 /* Get the power domain associated with the module number */
120 domainNum = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
121 domainNum = PSC_REG_MDCFG_GET_PD (domainNum);
123 /* Wait for the status of the domain/module to be non-transitional,
124 * but don't trap if stuck in a transitional state. */
125 pscWait (domainNum);
127 mdstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDSTAT(modNum));
128 mdstat = PSC_REG_MDSTAT_GET_STATUS (mdstat);
130 if ((mdstat == PSC_REG_VAL_MDSTAT_STATE_ON) ||
131 (mdstat == PSC_REG_VAL_MDSTAT_STATE_ENABLE_IN_PROG))
132 return (TRUE);
134 else
136 return (FALSE);
138 } /* pscModuleIsEnabled */
143 /***********************************************************************************
144 * FUNCTION PURPOSE: Power up/down a module
145 ***********************************************************************************
146 * DESCRIPTION: Powers up/down the requested module and the associated power domain
147 * if required. No action is taken it the module is already
148 * powered up/down.
149 *
150 * This only controls modules. The domain in which the module
151 * resides will be left in the power on state. Multiple modules
152 * can exist in a power domain, so powering down the domain based
153 * on a single module is not done.
154 *
155 * Returns 0 on success, -1 if the module can't be powered up, or
156 * if there is a timeout waiting for the transition.
157 ***********************************************************************************/
158 int16 pscSetState (uint32 modNum, uint32 state)
159 {
161 uint32 domainNum;
162 uint32 pdctl;
163 uint32 mdctl;
164 uint32 ptcmd;
165 uint32 resetIso;
166 uint32 v;
168 /* Get the power domain associated with the module number, and reset
169 * isolation functionality */
170 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
171 domainNum = PSC_REG_MDCFG_GET_PD (v);
172 resetIso = PSC_REG_MDCFG_GET_RESET_ISO(v);
175 /* Wait for the status of the domain/module to be non-transitional */
176 if (pscWait (domainNum) != 0)
177 return (-1);
180 /* Perform configuration even if the current status matches the existing state */
183 /* Set the next state of the power domain to on. It's OK if the domain
184 * is always on. This code will not ever power down a domain, so no change
185 * is made if the new state is power down. */
186 if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
187 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
188 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_ON);
189 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
190 }
193 /* Set the next state for the module to enabled/disabled */
194 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
195 mdctl = PSC_REG_MDCTL_SET_NEXT (mdctl, state);
196 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, resetIso);
197 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
199 /* Trigger the enable */
200 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
201 ptcmd |= (uint32)(1<<domainNum);
202 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
205 /* Wait on the complete */
206 return (pscWait (domainNum));
208 } /* pscSetState*/
211 /***********************************************************************************
212 * FUNCTION PURPOSE: Power up a module
213 ***********************************************************************************
214 * DESCRIPTION: Powers up the requested module and the associated power domain
215 * if required. No action is taken it the module is already
216 * powered up.
217 *
218 * Returns 0 on success, -1 if the module can't be powered up, or
219 * if there is a timeout waiting for the transition.
220 ***********************************************************************************/
221 int16 pscEnableModule (uint32 modNum)
222 {
224 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_ON));
226 } /* pscEnableModule */
228 /************************************************************************************
229 * FUNCTION PURPOSE: Power down a module
230 ************************************************************************************
231 * DESCRIPTION: Powers down the requested module.
232 *
233 * Returns 0 on success, -1 on failure or timeout.
234 ************************************************************************************/
235 int16 pscDisableModule (uint32 modNum)
236 {
237 uint32 mdctl;
239 /* Set the bit to apply reset */
240 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
241 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
242 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
244 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE));
246 } /* pscDisableModule */
249 /************************************************************************************
250 * FUNCTION PURPOSE: Set the reset isolation bit in mdctl
251 ************************************************************************************
252 * DESCRIPTION: The reset isolation enable bit is set. The state of the module
253 * is not changed. Returns 0 if the module config showed that
254 * reset isolation is supported. Returns 1 otherwise. This is not
255 * an error, but setting the bit in mdctl has no effect.
256 ************************************************************************************/
257 int16 pscSetResetIso (uint32 modNum)
258 {
259 uint32 v;
260 uint32 mdctl;
262 /* Set the reset isolation bit */
263 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
264 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, 1);
265 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
267 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
268 if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
269 return (0);
271 return (1);
273 } /* pscSetResetIso */
275 /*************************************************************************************
276 * FUNCTION PURPOSE: Disable a power domain
277 *************************************************************************************
278 * DESCRIPTION: The power domain is disabled
279 *************************************************************************************/
280 int16 pscDisableDomain (uint32 domainNum)
281 {
282 uint32 pdctl;
283 uint32 ptcmd;
285 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
286 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
287 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
288 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
290 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
291 ptcmd |= (uint32)(1<<domainNum);
292 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
294 return (0);
296 } /* pscDisableDomain */
299 /*************************************************************************************
300 * FUNCTION PURPOSE: Power down a domain
301 *************************************************************************************
302 * DESCRIPTION: The specified power domain is set to the disabled state
303 *************************************************************************************/
304 void pscDisableModAndDomain (uint32 modNum, uint32 domainNum)
305 {
306 uint32 pdctl;
307 uint32 ptcmd;
308 uint32 mdctl;
311 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
312 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
313 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
314 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
317 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
318 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
319 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
321 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
323 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
324 ptcmd |= (uint32)(1<<domainNum);
325 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
328 /* Wait on the complete */
329 pscWait (domainNum);
331 }