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