]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/keystone/psc.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / keystone / psc.c
1 /*
2  * Keystone: PSC configuration module
3  *
4  * (C) Copyright 2012-2014
5  *     Texas Instruments Incorporated, <www.ti.com>
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <asm-generic/errno.h>
12 #include <asm/io.h>
13 #include <asm/processor.h>
14 #include <asm/arch/psc_defs.h>
15
16 #define DEVICE_REG32_R(addr)                    __raw_readl((u32 *)(addr))
17 #define DEVICE_REG32_W(addr, val)               __raw_writel(val, (u32 *)(addr))
18
19 #ifdef CONFIG_SOC_K2HK
20 #define DEVICE_PSC_BASE                         K2HK_PSC_BASE
21 #endif
22
23 int psc_delay(void)
24 {
25         udelay(10);
26         return 10;
27 }
28
29 /*
30  * FUNCTION PURPOSE: Wait for end of transitional state
31  *
32  * DESCRIPTION: Polls pstat for the selected domain and waits for transitions
33  *              to be complete.
34  *
35  *              Since this is boot loader code it is *ASSUMED* that interrupts
36  *              are disabled and no other core is mucking around with the psc
37  *              at the same time.
38  *
39  *              Returns 0 when the domain is free. Returns -1 if a timeout
40  *              occurred waiting for the completion.
41  */
42 int psc_wait(u32 domain_num)
43 {
44         u32 retry;
45         u32 ptstat;
46
47         /*
48          * Do nothing if the power domain is in transition. This should never
49          * happen since the boot code is the only software accesses psc.
50          * It's still remotely possible that the hardware state machines
51          * initiate transitions.
52          * Don't trap if the domain (or a module in this domain) is
53          * stuck in transition.
54          */
55         retry = 0;
56
57         do {
58                 ptstat = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PSTAT);
59                 ptstat = ptstat & (1 << domain_num);
60         } while ((ptstat != 0) && ((retry += psc_delay()) <
61                  PSC_PTSTAT_TIMEOUT_LIMIT));
62
63         if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
64                 return -1;
65
66         return 0;
67 }
68
69 u32 psc_get_domain_num(u32 mod_num)
70 {
71         u32 domain_num;
72
73         /* Get the power domain associated with the module number */
74         domain_num = DEVICE_REG32_R(DEVICE_PSC_BASE +
75                                     PSC_REG_MDCFG(mod_num));
76         domain_num = PSC_REG_MDCFG_GET_PD(domain_num);
77
78         return domain_num;
79 }
80
81 /*
82  * FUNCTION PURPOSE: Power up/down a module
83  *
84  * DESCRIPTION: Powers up/down the requested module and the associated power
85  *              domain if required. No action is taken it the module is
86  *              already powered up/down.
87  *
88  *              This only controls modules. The domain in which the module
89  *              resides will be left in the power on state. Multiple modules
90  *              can exist in a power domain, so powering down the domain based
91  *              on a single module is not done.
92  *
93  *              Returns 0 on success, -1 if the module can't be powered up, or
94  *              if there is a timeout waiting for the transition.
95  */
96 int psc_set_state(u32 mod_num, u32 state)
97 {
98         u32 domain_num;
99         u32 pdctl;
100         u32 mdctl;
101         u32 ptcmd;
102         u32 reset_iso;
103         u32 v;
104
105         /*
106          * Get the power domain associated with the module number, and reset
107          * isolation functionality
108          */
109         v = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCFG(mod_num));
110         domain_num = PSC_REG_MDCFG_GET_PD(v);
111         reset_iso  = PSC_REG_MDCFG_GET_RESET_ISO(v);
112
113         /* Wait for the status of the domain/module to be non-transitional */
114         if (psc_wait(domain_num) != 0)
115                 return -1;
116
117         /*
118          * Perform configuration even if the current status matches the
119          * existing state
120          *
121          * Set the next state of the power domain to on. It's OK if the domain
122          * is always on. This code will not ever power down a domain, so no
123          * change is made if the new state is power down.
124          */
125         if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
126                 pdctl = DEVICE_REG32_R(DEVICE_PSC_BASE +
127                                        PSC_REG_PDCTL(domain_num));
128                 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl,
129                                                PSC_REG_VAL_PDCTL_NEXT_ON);
130                 DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num),
131                                pdctl);
132         }
133
134         /* Set the next state for the module to enabled/disabled */
135         mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num));
136         mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, state);
137         mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, reset_iso);
138         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl);
139
140         /* Trigger the enable */
141         ptcmd = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PTCMD);
142         ptcmd |= (u32)(1<<domain_num);
143         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
144
145         /* Wait on the complete */
146         return psc_wait(domain_num);
147 }
148
149 /*
150  * FUNCTION PURPOSE: Power up a module
151  *
152  * DESCRIPTION: Powers up the requested module and the associated power domain
153  *              if required. No action is taken it the module is already
154  *              powered up.
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 int psc_enable_module(u32 mod_num)
160 {
161         u32 mdctl;
162
163         /* Set the bit to apply reset */
164         mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num));
165         if ((mdctl & 0x3f) == PSC_REG_VAL_MDSTAT_STATE_ON)
166                 return 0;
167
168         return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_ON);
169 }
170
171 /*
172  * FUNCTION PURPOSE: Power down a module
173  *
174  * DESCRIPTION: Powers down the requested module.
175  *
176  *              Returns 0 on success, -1 on failure or timeout.
177  */
178 int psc_disable_module(u32 mod_num)
179 {
180         u32 mdctl;
181
182         /* Set the bit to apply reset */
183         mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num));
184         if ((mdctl & 0x3f) == 0)
185                 return 0;
186         mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
187         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl);
188
189         return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
190 }
191
192 /*
193  * FUNCTION PURPOSE: Set the reset isolation bit in mdctl
194  *
195  * DESCRIPTION: The reset isolation enable bit is set. The state of the module
196  *              is not changed. Returns 0 if the module config showed that
197  *              reset isolation is supported. Returns 1 otherwise. This is not
198  *              an error, but setting the bit in mdctl has no effect.
199  */
200 int psc_set_reset_iso(u32 mod_num)
201 {
202         u32 v;
203         u32 mdctl;
204
205         /* Set the reset isolation bit */
206         mdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num));
207         mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, 1);
208         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_MDCTL(mod_num), mdctl);
209
210         v = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_MDCFG(mod_num));
211         if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
212                 return 0;
213
214         return 1;
215 }
216
217 /*
218  * FUNCTION PURPOSE: Disable a power domain
219  *
220  * DESCRIPTION: The power domain is disabled
221  */
222 int psc_disable_domain(u32 domain_num)
223 {
224         u32 pdctl;
225         u32 ptcmd;
226
227         pdctl = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num));
228         pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
229         pdctl = PSC_REG_PDCTL_SET_PDMODE(pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
230         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PDCTL(domain_num), pdctl);
231
232         ptcmd = DEVICE_REG32_R(DEVICE_PSC_BASE + PSC_REG_PTCMD);
233         ptcmd |= (u32)(1 << domain_num);
234         DEVICE_REG32_W(DEVICE_PSC_BASE + PSC_REG_PTCMD, ptcmd);
235
236         return psc_wait(domain_num);
237 }