update mcsdk_tools based on platform library 00.03
[keystone-rtos/mcsdk-tools.git] / post / src / 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 "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)
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)
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)
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)
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)
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)
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)
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);