fixed the return for the pscDelay function to eliminate the trap in pscWait()
[keystone-rtos/ibl.git] / src / hw / pscs / psc2 / psc.c
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 (1);
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)
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)
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)
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)
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)
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);
266   
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)
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)
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);