Bug fix for automatic file format detection
[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  *
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)
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)
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)
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)
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);
239   
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)
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)
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);