xref: /openbmc/u-boot/arch/arm/mach-keystone/psc.c (revision 23ff8633)
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 }
228