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 "platform.h"
45 #include "pscapi.h"
46 #include "pscloc.h"
47 #include "target.h"
50 #define DEVICE_REG32_W(x,y) *(volatile unsigned int *)(x)=(y)
51 #define DEVICE_REG32_R(x) (*(volatile unsigned int *)(x))
53 /***********************************************************************************
54 * FUNCTION PURPOSE: Wait!
55 ***********************************************************************************
56 * DESCRIPTION: This function doesn't do didly. It loops around for a bit
57 * to give transitions some time to occur.
58 * This function always returns 1.
59 ***********************************************************************************/
60 int16_t pscDelay (void)
61 {
62 volatile uint32_t i;
63 for (i = 0; i < 100; i++);
65 return (0);
67 } /* pscDelay */
70 /***********************************************************************************
71 * FUNCTION PURPOSE: Wait for end of transitional state
72 ***********************************************************************************
73 * DESCRIPTION: Polls pstat for the selected domain and waits for transitions
74 * to be complete.
75 *
76 * Since this is boot loader code it is *ASSUMED* that interrupts
77 * are disabled and no other core is mucking around with the psc
78 * at the same time.
79 *
80 * Returns 0 when the domain is free. Returns -1 if a timeout
81 * occurred waiting for the completion.
82 ***********************************************************************************/
83 int16_t pscWait (uint32_t domainNum)
84 {
85 uint32_t retry;
86 uint32_t ptstat;
88 /* Do nothing if the power domain is in transition. This should never
89 * happen since the boot code is the only software accesses psc.
90 * It's still remotely possible that the hardware state machines initiate transitions.
91 * Don't trap if the domain (or a module in this domain) is
92 * stuck in transition. */
93 retry = 0;
95 do {
97 ptstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PSTAT);
98 ptstat = ptstat & (1 << domainNum);
100 } while ((ptstat != 0) && ((retry += pscDelay ()) < PSC_PTSTAT_TIMEOUT_LIMIT));
102 if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
103 return (-1);
105 return (0);
107 } /* pscWait */
110 /***********************************************************************************
111 * FUNCTION PURPOSE: Return the PSC state
112 ***********************************************************************************
113 * DESCRIPTION: Checks the power state of the module
114 ***********************************************************************************/
115 BOOL pscModuleIsEnabled (uint32_t modNum)
116 {
117 uint32_t domainNum;
118 uint32_t mdstat;
120 /* Get the power domain associated with the module number */
121 domainNum = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
122 domainNum = PSC_REG_MDCFG_GET_PD (domainNum);
124 /* Wait for the status of the domain/module to be non-transitional,
125 * but don't trap if stuck in a transitional state. */
126 pscWait (domainNum);
128 mdstat = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDSTAT(modNum));
129 mdstat = PSC_REG_MDSTAT_GET_STATUS (mdstat);
131 if ((mdstat == PSC_REG_VAL_MDSTAT_STATE_ON) ||
132 (mdstat == PSC_REG_VAL_MDSTAT_STATE_ENABLE_IN_PROG))
133 return (TRUE);
135 else
137 return (FALSE);
139 } /* pscModuleIsEnabled */
144 /***********************************************************************************
145 * FUNCTION PURPOSE: Power up/down a module
146 ***********************************************************************************
147 * DESCRIPTION: Powers up/down the requested module and the associated power domain
148 * if required. No action is taken it the module is already
149 * powered up/down.
150 *
151 * This only controls modules. The domain in which the module
152 * resides will be left in the power on state. Multiple modules
153 * can exist in a power domain, so powering down the domain based
154 * on a single module is not done.
155 *
156 * Returns 0 on success, -1 if the module can't be powered up, or
157 * if there is a timeout waiting for the transition.
158 ***********************************************************************************/
159 int16_t pscSetState (uint32_t modNum, uint32_t state)
160 {
162 uint32_t domainNum;
163 uint32_t pdctl;
164 uint32_t mdctl;
165 uint32_t ptcmd;
166 uint32_t resetIso;
167 uint32_t v;
169 /* Get the power domain associated with the module number, and reset
170 * isolation functionality */
171 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
172 domainNum = PSC_REG_MDCFG_GET_PD (v);
173 resetIso = PSC_REG_MDCFG_GET_RESET_ISO(v);
176 /* Wait for the status of the domain/module to be non-transitional */
177 if (pscWait (domainNum) != 0)
178 return (-1);
181 /* Perform configuration even if the current status matches the existing state */
184 /* Set the next state of the power domain to on. It's OK if the domain
185 * is always on. This code will not ever power down a domain, so no change
186 * is made if the new state is power down. */
187 if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
188 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
189 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_ON);
190 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
191 }
194 /* Set the next state for the module to enabled/disabled */
195 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
196 mdctl = PSC_REG_MDCTL_SET_NEXT (mdctl, state);
197 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, resetIso);
198 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
200 /* Trigger the enable */
201 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
202 ptcmd |= (uint32_t)(1<<domainNum);
203 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
206 /* Wait on the complete */
207 return (pscWait (domainNum));
209 } /* pscSetState*/
212 /***********************************************************************************
213 * FUNCTION PURPOSE: Power up a module
214 ***********************************************************************************
215 * DESCRIPTION: Powers up the requested module and the associated power domain
216 * if required. No action is taken it the module is already
217 * powered up.
218 *
219 * Returns 0 on success, -1 if the module can't be powered up, or
220 * if there is a timeout waiting for the transition.
221 ***********************************************************************************/
222 int16_t pscEnableModule (uint32_t modNum)
223 {
225 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_ON));
227 } /* pscEnableModule */
229 /************************************************************************************
230 * FUNCTION PURPOSE: Power down a module
231 ************************************************************************************
232 * DESCRIPTION: Powers down the requested module.
233 *
234 * Returns 0 on success, -1 on failure or timeout.
235 ************************************************************************************/
236 int16_t pscDisableModule (uint32_t modNum)
237 {
238 uint32_t mdctl;
240 /* Set the bit to apply reset */
241 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
242 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
243 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
245 return (pscSetState (modNum, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE));
247 } /* pscDisableModule */
250 /************************************************************************************
251 * FUNCTION PURPOSE: Set the reset isolation bit in mdctl
252 ************************************************************************************
253 * DESCRIPTION: The reset isolation enable bit is set. The state of the module
254 * is not changed. Returns 0 if the module config showed that
255 * reset isolation is supported. Returns 1 otherwise. This is not
256 * an error, but setting the bit in mdctl has no effect.
257 ************************************************************************************/
258 int16_t pscSetResetIso (uint32_t modNum)
259 {
260 uint32_t v;
261 uint32_t mdctl;
263 /* Set the reset isolation bit */
264 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
265 mdctl = PSC_REG_MDCTL_SET_RESET_ISO (mdctl, 1);
266 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
268 v = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCFG(modNum));
269 if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
270 return (0);
272 return (1);
274 } /* pscSetResetIso */
276 /*************************************************************************************
277 * FUNCTION PURPOSE: Disable a power domain
278 *************************************************************************************
279 * DESCRIPTION: The power domain is disabled
280 *************************************************************************************/
281 int16_t pscDisableDomain (uint32_t domainNum)
282 {
283 uint32_t pdctl;
284 uint32_t ptcmd;
286 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
287 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
288 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
289 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
291 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
292 ptcmd |= (uint32_t)(1<<domainNum);
293 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
295 return (0);
297 } /* pscDisableDomain */
300 /*************************************************************************************
301 * FUNCTION PURPOSE: Power down a domain
302 *************************************************************************************
303 * DESCRIPTION: The specified power domain is set to the disabled state
304 *************************************************************************************/
305 void pscDisableModAndDomain (uint32_t modNum, uint32_t domainNum)
306 {
307 uint32_t pdctl;
308 uint32_t ptcmd;
309 uint32_t mdctl;
312 mdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum));
313 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
314 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl,0);
315 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_MDCTL(modNum), mdctl);
318 pdctl = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum));
319 pdctl = PSC_REG_PDCTL_SET_NEXT (pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
320 pdctl = PSC_REG_PDCTL_SET_PDMODE (pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
322 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PDCTL(domainNum), pdctl);
324 ptcmd = DEVICE_REG32_R (DEVICE_PSC_BASE + PSC_REG_PTCMD);
325 ptcmd |= (uint32_t)(1<<domainNum);
326 DEVICE_REG32_W (DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
329 /* Wait on the complete */
330 pscWait (domainNum);
332 }