blob: 145aff8ac66f0c54a579420c7810a9fb5e69b01b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -04002/*
3 * Keystone: PSC configuration module
4 *
5 * (C) Copyright 2012-2014
6 * Texas Instruments Incorporated, <www.ti.com>
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -04007 */
8
9#include <common.h>
Simon Glassdbd79542020-05-10 11:40:11 -060010#include <linux/delay.h>
Masahiro Yamada64e4f7f2016-09-21 11:28:57 +090011#include <linux/errno.h>
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040012#include <asm/io.h>
13#include <asm/processor.h>
14#include <asm/arch/psc_defs.h>
15
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060016/**
17 * psc_delay() - delay for psc
18 *
19 * Return: 10
20 */
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040021int psc_delay(void)
22{
23 udelay(10);
24 return 10;
25}
26
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060027/**
28 * psc_wait() - Wait for end of transitional state
29 * @domain_num: GPSC domain number
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040030 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060031 * Polls pstat for the selected domain and waits for transitions to be complete.
32 * Since this is boot loader code it is *ASSUMED* that interrupts are disabled
33 * and no other core is mucking around with the psc at the same time.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040034 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060035 * Return: 0 when the domain is free. Returns -1 if a timeout occurred waiting
36 * for the completion.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040037 */
38int psc_wait(u32 domain_num)
39{
40 u32 retry;
41 u32 ptstat;
42
43 /*
44 * Do nothing if the power domain is in transition. This should never
45 * happen since the boot code is the only software accesses psc.
46 * It's still remotely possible that the hardware state machines
47 * initiate transitions.
48 * Don't trap if the domain (or a module in this domain) is
49 * stuck in transition.
50 */
51 retry = 0;
52
53 do {
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +030054 ptstat = __raw_readl(KS2_PSC_BASE + PSC_REG_PSTAT);
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040055 ptstat = ptstat & (1 << domain_num);
56 } while ((ptstat != 0) && ((retry += psc_delay()) <
57 PSC_PTSTAT_TIMEOUT_LIMIT));
58
59 if (retry >= PSC_PTSTAT_TIMEOUT_LIMIT)
60 return -1;
61
62 return 0;
63}
64
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060065/**
66 * psc_get_domain_num() - Get the domain number
67 * @mod_num: LPSC module number
68 */
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040069u32 psc_get_domain_num(u32 mod_num)
70{
71 u32 domain_num;
72
73 /* Get the power domain associated with the module number */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +030074 domain_num = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040075 domain_num = PSC_REG_MDCFG_GET_PD(domain_num);
76
77 return domain_num;
78}
79
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060080/**
81 * psc_set_state() - powers up/down a module
82 * @mod_num: LPSC module number
83 * @state: 1 to enable, 0 to disable.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040084 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060085 * Powers up/down the requested module and the associated power domain if
86 * required. No action is taken it the module is already powered up/down.
87 * This only controls modules. The domain in which the module resides will
88 * be left in the power on state. Multiple modules can exist in a power
89 * domain, so powering down the domain based on a single module is not done.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040090 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -060091 * Return: 0 on success, -1 if the module can't be powered up, or if there is a
92 * timeout waiting for the transition.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -040093 */
94int psc_set_state(u32 mod_num, u32 state)
95{
96 u32 domain_num;
97 u32 pdctl;
98 u32 mdctl;
99 u32 ptcmd;
100 u32 reset_iso;
101 u32 v;
102
103 /*
104 * Get the power domain associated with the module number, and reset
105 * isolation functionality
106 */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300107 v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400108 domain_num = PSC_REG_MDCFG_GET_PD(v);
109 reset_iso = PSC_REG_MDCFG_GET_RESET_ISO(v);
110
111 /* Wait for the status of the domain/module to be non-transitional */
112 if (psc_wait(domain_num) != 0)
113 return -1;
114
115 /*
116 * Perform configuration even if the current status matches the
117 * existing state
118 *
119 * Set the next state of the power domain to on. It's OK if the domain
120 * is always on. This code will not ever power down a domain, so no
121 * change is made if the new state is power down.
122 */
123 if (state == PSC_REG_VAL_MDCTL_NEXT_ON) {
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300124 pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400125 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl,
126 PSC_REG_VAL_PDCTL_NEXT_ON);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300127 __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400128 }
129
130 /* Set the next state for the module to enabled/disabled */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300131 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400132 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, state);
133 mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, reset_iso);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300134 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400135
136 /* Trigger the enable */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300137 ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400138 ptcmd |= (u32)(1<<domain_num);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300139 __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400140
141 /* Wait on the complete */
142 return psc_wait(domain_num);
143}
144
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600145/**
146 * psc_enable_module() - power up a module
147 * @mod_num: LPSC module number
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400148 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600149 * Powers up the requested module and the associated power domain
150 * if required. No action is taken it the module is already powered up.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400151 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600152 * Return: 0 on success, -1 if the module can't be powered up, or
153 * if there is a timeout waiting for the transition.
154 *
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400155 */
156int psc_enable_module(u32 mod_num)
157{
158 u32 mdctl;
159
160 /* Set the bit to apply reset */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300161 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400162 if ((mdctl & 0x3f) == PSC_REG_VAL_MDSTAT_STATE_ON)
163 return 0;
164
165 return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_ON);
166}
167
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600168/**
169 * psc_disable_module() - Power down a module
170 * @mod_num: LPSC module number
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400171 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600172 * Return: 0 on success, -1 on failure or timeout.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400173 */
174int psc_disable_module(u32 mod_num)
175{
176 u32 mdctl;
177
178 /* Set the bit to apply reset */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300179 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400180 if ((mdctl & 0x3f) == 0)
181 return 0;
182 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300183 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400184
185 return psc_set_state(mod_num, PSC_REG_VAL_MDCTL_NEXT_SWRSTDISABLE);
186}
187
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600188/**
189 * psc_set_reset_iso() - Set the reset isolation bit in mdctl
190 * @mod_num: LPSC module number
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400191 *
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600192 * The reset isolation enable bit is set. The state of the module is not
193 * changed.
194 *
195 * Return: 0 if the module config showed that reset isolation is supported.
196 * Returns 1 otherwise. This is not an error, but setting the bit in mdctl
197 * has no effect.
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400198 */
199int psc_set_reset_iso(u32 mod_num)
200{
201 u32 v;
202 u32 mdctl;
203
204 /* Set the reset isolation bit */
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300205 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400206 mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, 1);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300207 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400208
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300209 v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400210 if (PSC_REG_MDCFG_GET_RESET_ISO(v) == 1)
211 return 0;
212
213 return 1;
214}
215
Nishanth Menonb3ec5de2016-02-25 12:53:42 -0600216/**
217 * psc_disable_domain() - Disable a power domain
218 * @domain_num: GPSC domain number
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400219 */
220int psc_disable_domain(u32 domain_num)
221{
222 u32 pdctl;
223 u32 ptcmd;
224
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300225 pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400226 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl, PSC_REG_VAL_PDCTL_NEXT_OFF);
227 pdctl = PSC_REG_PDCTL_SET_PDMODE(pdctl, PSC_REG_VAL_PDCTL_PDMODE_SLEEP);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300228 __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400229
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300230 ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400231 ptcmd |= (u32)(1 << domain_num);
Khoronzhuk, Ivan49d39a22014-08-28 16:07:45 +0300232 __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianov7bcf4d62014-04-04 13:16:53 -0400233
234 return psc_wait(domain_num);
235}
Nishanth Menon06a10872016-02-25 12:53:44 -0600236
237/**
238 * psc_module_keep_in_reset_enabled() - Keep module in enabled,in-reset state
239 * @mod_num: LPSC module number
240 * @gate_clocks: Can the clocks be gated on this module?
241 *
242 * Enable the module, but do not release the module from local reset. This is
243 * necessary for many processor systems on keystone SoCs to allow for system
244 * initialization from a master processor prior to releasing the processor
245 * from reset.
246 */
247int psc_module_keep_in_reset_enabled(u32 mod_num, bool gate_clocks)
248{
249 u32 mdctl, ptcmd, mdstat;
250 u32 next_state;
251 int domain_num = psc_get_domain_num(mod_num);
252 int timeout = 100000;
253
254 /* Wait for any previous transitions to complete */
255 psc_wait(domain_num);
256 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
257 /* Should be set 0 to assert Local reset */
258 if ((mdctl & PSC_REG_MDCTL_SET_LRSTZ(mdctl, 1))) {
259 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
260 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
261 /* Wait for transition to take place */
262 psc_wait(domain_num);
263 }
264
265 /* Clear Module reset */
266 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
267 next_state = gate_clocks ? PSC_REG_VAL_MDCTL_NEXT_OFF :
268 PSC_REG_VAL_MDCTL_NEXT_ON;
269 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, next_state);
270 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
271 /* Trigger PD transition */
272 ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
273 ptcmd |= (u32)(1 << domain_num);
274 __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
275 psc_wait(domain_num);
276
277 mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
278 while (timeout) {
279 mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
280
281 if (!(PSC_REG_MDSTAT_GET_STATUS(mdstat) & 0x30) &&
282 PSC_REG_MDSTAT_GET_MRSTDONE(mdstat) &&
283 PSC_REG_MDSTAT_GET_LRSTDONE(mdstat))
284 break;
285 timeout--;
286 }
287
288 if (!timeout) {
289 printf("%s: Timedout waiting for mdstat(0x%08x) to change\n",
290 __func__, mdstat);
291 return -ETIMEDOUT;
292 }
293 return 0;
294}
295
296/**
297 * psc_module_release_from_reset() - Release the module from reset
298 * @mod_num: LPSC module number
299 *
300 * This is the follow through for the command 'psc_module_keep_in_reset_enabled'
301 * Allowing the module to be released from reset once all required inits are
302 * complete for the module. Typically, this allows the processor module to start
303 * execution.
304 */
305int psc_module_release_from_reset(u32 mod_num)
306{
307 u32 mdctl, mdstat;
308 int domain_num = psc_get_domain_num(mod_num);
309 int timeout = 100000;
310
311 /* Wait for any previous transitions to complete */
312 psc_wait(domain_num);
313 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
314 /* Should be set to 1 to de-assert Local reset */
315 if ((mdctl & PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0))) {
316 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 1);
317 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
318 /* Wait for transition to take place */
319 psc_wait(domain_num);
320 }
321 mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
322 while (timeout) {
323 mdstat = __raw_readl(KS2_PSC_BASE + PSC_REG_MDSTAT(mod_num));
324
325 if (!(PSC_REG_MDSTAT_GET_STATUS(mdstat) & 0x30) &&
326 PSC_REG_MDSTAT_GET_MRSTDONE(mdstat) &&
327 PSC_REG_MDSTAT_GET_LRSTDONE(mdstat))
328 break;
329 timeout--;
330 }
331
332 if (!timeout) {
333 printf("%s: Timedout waiting for mdstat(0x%08x) to change\n",
334 __func__, mdstat);
335 return -ETIMEDOUT;
336 }
337
338 return 0;
339}