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