blob: 237e776e8790422dca0baad62732dd0b121bf8b3 [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
Vitaly Andrianovef509b92014-04-04 13:16:53 -040016int 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 */
35int 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 {
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +030051 ptstat = __raw_readl(KS2_PSC_BASE + PSC_REG_PSTAT);
Vitaly Andrianovef509b92014-04-04 13:16:53 -040052 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
62u32 psc_get_domain_num(u32 mod_num)
63{
64 u32 domain_num;
65
66 /* Get the power domain associated with the module number */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +030067 domain_num = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -040068 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 */
88int 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 */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300101 v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400102 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) {
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300118 pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400119 pdctl = PSC_REG_PDCTL_SET_NEXT(pdctl,
120 PSC_REG_VAL_PDCTL_NEXT_ON);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300121 __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400122 }
123
124 /* Set the next state for the module to enabled/disabled */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300125 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400126 mdctl = PSC_REG_MDCTL_SET_NEXT(mdctl, state);
127 mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, reset_iso);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300128 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400129
130 /* Trigger the enable */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300131 ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400132 ptcmd |= (u32)(1<<domain_num);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300133 __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400134
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 */
149int psc_enable_module(u32 mod_num)
150{
151 u32 mdctl;
152
153 /* Set the bit to apply reset */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300154 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400155 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 */
168int psc_disable_module(u32 mod_num)
169{
170 u32 mdctl;
171
172 /* Set the bit to apply reset */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300173 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400174 if ((mdctl & 0x3f) == 0)
175 return 0;
176 mdctl = PSC_REG_MDCTL_SET_LRSTZ(mdctl, 0);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300177 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400178
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 */
190int psc_set_reset_iso(u32 mod_num)
191{
192 u32 v;
193 u32 mdctl;
194
195 /* Set the reset isolation bit */
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300196 mdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400197 mdctl = PSC_REG_MDCTL_SET_RESET_ISO(mdctl, 1);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300198 __raw_writel(mdctl, KS2_PSC_BASE + PSC_REG_MDCTL(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400199
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300200 v = __raw_readl(KS2_PSC_BASE + PSC_REG_MDCFG(mod_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400201 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 */
212int psc_disable_domain(u32 domain_num)
213{
214 u32 pdctl;
215 u32 ptcmd;
216
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300217 pdctl = __raw_readl(KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400218 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);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300220 __raw_writel(pdctl, KS2_PSC_BASE + PSC_REG_PDCTL(domain_num));
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400221
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300222 ptcmd = __raw_readl(KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400223 ptcmd |= (u32)(1 << domain_num);
Khoronzhuk, Ivane6c94282014-08-28 16:07:45 +0300224 __raw_writel(ptcmd, KS2_PSC_BASE + PSC_REG_PTCMD);
Vitaly Andrianovef509b92014-04-04 13:16:53 -0400225
226 return psc_wait(domain_num);
227}