1 /*
2  * OMAP2 and OMAP3 powerdomain control
3  *
4  * Copyright (C) 2009-2011 Texas Instruments, Inc.
5  * Copyright (C) 2007-2009 Nokia Corporation
6  *
7  * Derived from mach-omap2/powerdomain.c written by Paul Walmsley
8  * Rajendra Nayak <rnayak@ti.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14 
15 #include <linux/io.h>
16 #include <linux/errno.h>
17 #include <linux/delay.h>
18 #include <linux/bug.h>
19 
20 #include <plat/prcm.h>
21 
22 #include "powerdomain.h"
23 #include "prm.h"
24 #include "prm-regbits-24xx.h"
25 #include "prm-regbits-34xx.h"
26 
27 
28 /* Common functions across OMAP2 and OMAP3 */
omap2_pwrdm_set_next_pwrst(struct powerdomain * pwrdm,u8 pwrst)29 static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
30 {
31 	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
32 				(pwrst << OMAP_POWERSTATE_SHIFT),
33 				pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
34 	return 0;
35 }
36 
omap2_pwrdm_read_next_pwrst(struct powerdomain * pwrdm)37 static int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
38 {
39 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
40 					     OMAP2_PM_PWSTCTRL,
41 					     OMAP_POWERSTATE_MASK);
42 }
43 
omap2_pwrdm_read_pwrst(struct powerdomain * pwrdm)44 static int omap2_pwrdm_read_pwrst(struct powerdomain *pwrdm)
45 {
46 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
47 					     OMAP2_PM_PWSTST,
48 					     OMAP_POWERSTATEST_MASK);
49 }
50 
omap2_pwrdm_set_mem_onst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)51 static int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
52 								u8 pwrst)
53 {
54 	u32 m;
55 
56 	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
57 
58 	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
59 				   OMAP2_PM_PWSTCTRL);
60 
61 	return 0;
62 }
63 
omap2_pwrdm_set_mem_retst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)64 static int omap2_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
65 								u8 pwrst)
66 {
67 	u32 m;
68 
69 	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
70 
71 	omap2_prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
72 				   OMAP2_PM_PWSTCTRL);
73 
74 	return 0;
75 }
76 
omap2_pwrdm_read_mem_pwrst(struct powerdomain * pwrdm,u8 bank)77 static int omap2_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
78 {
79 	u32 m;
80 
81 	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
82 
83 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP2_PM_PWSTST,
84 					     m);
85 }
86 
omap2_pwrdm_read_mem_retst(struct powerdomain * pwrdm,u8 bank)87 static int omap2_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
88 {
89 	u32 m;
90 
91 	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
92 
93 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
94 					     OMAP2_PM_PWSTCTRL, m);
95 }
96 
omap2_pwrdm_set_logic_retst(struct powerdomain * pwrdm,u8 pwrst)97 static int omap2_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
98 {
99 	u32 v;
100 
101 	v = pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE_MASK);
102 	omap2_prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE_MASK, v,
103 				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
104 
105 	return 0;
106 }
107 
omap2_pwrdm_wait_transition(struct powerdomain * pwrdm)108 static int omap2_pwrdm_wait_transition(struct powerdomain *pwrdm)
109 {
110 	u32 c = 0;
111 
112 	/*
113 	 * REVISIT: pwrdm_wait_transition() may be better implemented
114 	 * via a callback and a periodic timer check -- how long do we expect
115 	 * powerdomain transitions to take?
116 	 */
117 
118 	/* XXX Is this udelay() value meaningful? */
119 	while ((omap2_prm_read_mod_reg(pwrdm->prcm_offs, OMAP2_PM_PWSTST) &
120 		OMAP_INTRANSITION_MASK) &&
121 		(c++ < PWRDM_TRANSITION_BAILOUT))
122 			udelay(1);
123 
124 	if (c > PWRDM_TRANSITION_BAILOUT) {
125 		printk(KERN_ERR "powerdomain: waited too long for "
126 			"powerdomain %s to complete transition\n", pwrdm->name);
127 		return -EAGAIN;
128 	}
129 
130 	pr_debug("powerdomain: completed transition in %d loops\n", c);
131 
132 	return 0;
133 }
134 
135 /* Applicable only for OMAP3. Not supported on OMAP2 */
omap3_pwrdm_read_prev_pwrst(struct powerdomain * pwrdm)136 static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
137 {
138 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
139 					     OMAP3430_PM_PREPWSTST,
140 					     OMAP3430_LASTPOWERSTATEENTERED_MASK);
141 }
142 
omap3_pwrdm_read_logic_pwrst(struct powerdomain * pwrdm)143 static int omap3_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
144 {
145 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
146 					     OMAP2_PM_PWSTST,
147 					     OMAP3430_LOGICSTATEST_MASK);
148 }
149 
omap3_pwrdm_read_logic_retst(struct powerdomain * pwrdm)150 static int omap3_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
151 {
152 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
153 					     OMAP2_PM_PWSTCTRL,
154 					     OMAP3430_LOGICSTATEST_MASK);
155 }
156 
omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain * pwrdm)157 static int omap3_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
158 {
159 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
160 					     OMAP3430_PM_PREPWSTST,
161 					     OMAP3430_LASTLOGICSTATEENTERED_MASK);
162 }
163 
omap3_get_mem_bank_lastmemst_mask(u8 bank)164 static int omap3_get_mem_bank_lastmemst_mask(u8 bank)
165 {
166 	switch (bank) {
167 	case 0:
168 		return OMAP3430_LASTMEM1STATEENTERED_MASK;
169 	case 1:
170 		return OMAP3430_LASTMEM2STATEENTERED_MASK;
171 	case 2:
172 		return OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
173 	case 3:
174 		return OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
175 	default:
176 		WARN_ON(1); /* should never happen */
177 		return -EEXIST;
178 	}
179 	return 0;
180 }
181 
omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain * pwrdm,u8 bank)182 static int omap3_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
183 {
184 	u32 m;
185 
186 	m = omap3_get_mem_bank_lastmemst_mask(bank);
187 
188 	return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
189 				OMAP3430_PM_PREPWSTST, m);
190 }
191 
omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain * pwrdm)192 static int omap3_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
193 {
194 	omap2_prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
195 	return 0;
196 }
197 
omap3_pwrdm_enable_hdwr_sar(struct powerdomain * pwrdm)198 static int omap3_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
199 {
200 	return omap2_prm_rmw_mod_reg_bits(0,
201 					  1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
202 					  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
203 }
204 
omap3_pwrdm_disable_hdwr_sar(struct powerdomain * pwrdm)205 static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
206 {
207 	return omap2_prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
208 					  0, pwrdm->prcm_offs,
209 					  OMAP2_PM_PWSTCTRL);
210 }
211 
212 struct pwrdm_ops omap2_pwrdm_operations = {
213 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
214 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
215 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
216 	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
217 	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
218 	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
219 	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
220 	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
221 	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
222 };
223 
224 struct pwrdm_ops omap3_pwrdm_operations = {
225 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
226 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
227 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
228 	.pwrdm_read_prev_pwrst	= omap3_pwrdm_read_prev_pwrst,
229 	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
230 	.pwrdm_read_logic_pwrst	= omap3_pwrdm_read_logic_pwrst,
231 	.pwrdm_read_logic_retst	= omap3_pwrdm_read_logic_retst,
232 	.pwrdm_read_prev_logic_pwrst	= omap3_pwrdm_read_prev_logic_pwrst,
233 	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
234 	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
235 	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
236 	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
237 	.pwrdm_read_prev_mem_pwrst	= omap3_pwrdm_read_prev_mem_pwrst,
238 	.pwrdm_clear_all_prev_pwrst	= omap3_pwrdm_clear_all_prev_pwrst,
239 	.pwrdm_enable_hdwr_sar	= omap3_pwrdm_enable_hdwr_sar,
240 	.pwrdm_disable_hdwr_sar	= omap3_pwrdm_disable_hdwr_sar,
241 	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
242 };
243