blob: c844dc84d503acae325013ccdab22c428a4f7537 [file] [log] [blame]
Vitaly Andrianovef509b92014-04-04 13:16:53 -04001/*
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
23int 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 */
42int 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
69u32 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 */
96int 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 */
159int 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 */
178int 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 */
200int 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 */
222int 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}