085fa3ffbc874b62c4de02ba8b264af2229a2065
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 *
10 * @file psc.c
11 *
12 * @brief
13 * The PSC 2.0.x driver
14 *
15 ***********************************************************************************/
16 #include "types.h"
17 #include "pscapi.h"
18 #include "pscloc.h"
19 #include "target.h"
22 #define DEVICE_REG32_W(x,y) *(volatile unsigned int *)(x)=(y)
23 #define DEVICE_REG32_R(x) (*(volatile unsigned int *)(x))
25 /***********************************************************************************
26 * FUNCTION PURPOSE: Wait!
27 ***********************************************************************************
28 * DESCRIPTION: This function doesn't do didly. It loops around for a bit
29 * to give transitions some time to occur.
30 * This function always returns 1.
31 ***********************************************************************************/
32 int16 pscDelay (void)
33 {
34 volatile uint32 i;
35 for (i = 0; i < 100; i++);
37 return (0);
39 } /* pscDelay */
42 /***********************************************************************************
43 * FUNCTION PURPOSE: Wait for end of transitional state
44 ***********************************************************************************
45 * DESCRIPTION: Polls pstat for the selected domain and waits for transitions
46 * to be complete.
47 *
48 * Since this is boot loader code it is *ASSUMED* that interrupts
49 * are disabled and no other core is mucking around with the psc
50 * at the same time.
51 *
52 * Returns 0 when the domain is free. Returns -1 if a timeout
53 * occurred waiting for the completion.
54 ***********************************************************************************/
55 int16 pscWait (uint32 domainNum)
56 {
57 uint32 retry;
58 uint32 ptstat;
60 /* Do nothing if the power domain is in transition. This should never
61 * happen since the boot code is the only software accesses psc.
62 * It's still remotely possible that the hardware state machines initiate transitions.
63 * Don't trap if the domain (or a module in this domain) is
64 * stuck in transition. */
65 retry = 0;
67 do {
69 ptstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PSTAT);
70 ptstat = ptstat & (1 << domainNum);
72 } while ((ptstat != 0) && ((retry += pscDelay ()) < PSC_PTSTAT_TIMEOUT_LIMIT));
74 if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
75 return (-1);
77 return (0);
79 } /* pscWait */
82 /***********************************************************************************
83 * FUNCTION PURPOSE: Return the PSC state
84 ***********************************************************************************
85 * DESCRIPTION: Checks the power state of the module
86 ***********************************************************************************/
87 BOOL pscModuleIsEnabled (uint32 modNum)
88 {
89 uint32 domainNum;
90 uint32 mdstat;
92 /* Get the power domain associated with the module number */
93 domainNum = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
94 domainNum = PSC_REG_MDCFG_GET_PD (domainNum);
96 /* Wait for the status of the domain/module to be non-transitional,
97 * but don't trap if stuck in a transitional state. */
98 pscWait (domainNum);
100 mdstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDSTAT(modNum));
101 mdstat = PSC_REG_MDSTAT_GET_STATUS (mdstat);
103 if ((mdstat == PSC_REG_VAL_MDSTAT_STATE_ON) ||
104 (mdstat == PSC_REG_VAL_MDSTAT_STATE_ENABLE_IN_PROG))
105 return (TRUE);
107 else
109 return (FALSE);
111 } /* pscModuleIsEnabled */
116 /***********************************************************************************
117 * FUNCTION PURPOSE: Power up/down a module
118 ***********************************************************************************
119 * DESCRIPTION: Powers up/down the requested module and the associated power domain
120 * if required. No action is taken it the module is already
121 * powered up/down.
122 *
123 * This only controls modules. The domain in which the module
124 * resides will be left in the power on state. Multiple modules
125 * can exist in a power domain, so powering down the domain based
126 * on a single module is not done.
127 *
128 * Returns 0 on success, -1 if the module can't be powered up, or
129 * if there is a timeout waiting for the transition.
130 ***********************************************************************************/
131 int16 pscSetState (uint32 modNum, uint32 state)
132 {
134 uint32 domainNum;
135 uint32 pdctl;
136 uint32 mdctl;
137 uint32 ptcmd;
138 uint32 resetIso;
139 uint32 v;
141 /* Get the power domain associated with the module number, and reset
142 * isolation functionality */
143 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
144 domainNum = PSC_REG_MDCFG_GET_PD (v);
145 resetIso = PSC_REG_MDCFG_GET_RESET_ISO(v);
148 /* Wait for the status of the domain/module to be non-transitional */
149 if (pscWait (domainNum) != 0)
150 return (-1);
153 /* Perform configuration even if the current status matches the existing state */
156 /* Set the next state of the power domain to on. It's OK if the domain
157 * is always on. This code will not ever power down a domain, so no change
158 * is made if the new state is power down. */
159 if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
160 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
161 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_ON);
162 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
163 }
166 /* Set the next state for the module to enabled/disabled */
167 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
168 mdctl = PSC_REG_MDCTL_SET_NEXT (mdctl, state);
169 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, resetIso);
170 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
172 /* Trigger the enable */
173 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
174 ptcmd |= (uint32)(1<<domainNum);
175 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
178 /* Wait on the complete */
179 return (pscWait (domainNum));
181 } /* pscSetState*/
184 /***********************************************************************************
185 * FUNCTION PURPOSE: Power up a module
186 ***********************************************************************************
187 * DESCRIPTION: Powers up the requested module and the associated power domain
188 * if required. No action is taken it the module is already
189 * powered up.
190 *
191 * Returns 0 on success, -1 if the module can't be powered up, or
192 * if there is a timeout waiting for the transition.
193 ***********************************************************************************/
194 int16 pscEnableModule (uint32 modNum)
195 {
197 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_ON));
199 } /* pscEnableModule */
201 /************************************************************************************
202 * FUNCTION PURPOSE: Power down a module
203 ************************************************************************************
204 * DESCRIPTION: Powers down the requested module.
205 *
206 * Returns 0 on success, -1 on failure or timeout.
207 ************************************************************************************/
208 int16 pscDisableModule (uint32 modNum)
209 {
210 uint32 mdctl;
212 /* Set the bit to apply reset */
213 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
214 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
215 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
217 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE));
219 } /* pscDisableModule */
222 /************************************************************************************
223 * FUNCTION PURPOSE: Set the reset isolation bit in mdctl
224 ************************************************************************************
225 * DESCRIPTION: The reset isolation enable bit is set. The state of the module
226 * is not changed. Returns 0 if the module config showed that
227 * reset isolation is supported. Returns 1 otherwise. This is not
228 * an error, but setting the bit in mdctl has no effect.
229 ************************************************************************************/
230 int16 pscSetResetIso (uint32 modNum)
231 {
232 uint32 v;
233 uint32 mdctl;
235 /* Set the reset isolation bit */
236 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
237 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, 1);
238 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
240 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
241 if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
242 return (0);
244 return (1);
246 } /* pscSetResetIso */
248 /*************************************************************************************
249 * FUNCTION PURPOSE: Disable a power domain
250 *************************************************************************************
251 * DESCRIPTION: The power domain is disabled
252 *************************************************************************************/
253 int16 pscDisableDomain (uint32 domainNum)
254 {
255 uint32 pdctl;
256 uint32 ptcmd;
258 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
259 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
260 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
261 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
263 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
264 ptcmd |= (uint32)(1<<domainNum);
265 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
267 return (0);
269 } /* pscDisableDomain */
272 /*************************************************************************************
273 * FUNCTION PURPOSE: Power down a domain
274 *************************************************************************************
275 * DESCRIPTION: The specified power domain is set to the disabled state
276 *************************************************************************************/
277 void pscDisableModAndDomain (uint32 modNum, uint32 domainNum)
278 {
279 uint32 pdctl;
280 uint32 ptcmd;
281 uint32 mdctl;
284 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
285 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
286 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
287 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
290 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
291 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
292 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
294 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
296 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
297 ptcmd |= (uint32)(1<<domainNum);
298 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
301 /* Wait on the complete */
302 pscWait (domainNum);
304 }