1 /*
2  * OMAP4 powerdomain control
3  *
4  * Copyright (C) 2009-2010 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 "powerdomain.h"
20 #include <plat/prcm.h>
21 #include "prm2xxx_3xxx.h"
22 #include "prm44xx.h"
23 #include "prminst44xx.h"
24 #include "prm-regbits-44xx.h"
25 
omap4_pwrdm_set_next_pwrst(struct powerdomain * pwrdm,u8 pwrst)26 static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
27 {
28 	omap4_prminst_rmw_inst_reg_bits(OMAP_POWERSTATE_MASK,
29 					(pwrst << OMAP_POWERSTATE_SHIFT),
30 					pwrdm->prcm_partition,
31 					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
32 	return 0;
33 }
34 
omap4_pwrdm_read_next_pwrst(struct powerdomain * pwrdm)35 static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
36 {
37 	u32 v;
38 
39 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
40 					OMAP4_PM_PWSTCTRL);
41 	v &= OMAP_POWERSTATE_MASK;
42 	v >>= OMAP_POWERSTATE_SHIFT;
43 
44 	return v;
45 }
46 
omap4_pwrdm_read_pwrst(struct powerdomain * pwrdm)47 static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm)
48 {
49 	u32 v;
50 
51 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
52 					OMAP4_PM_PWSTST);
53 	v &= OMAP_POWERSTATEST_MASK;
54 	v >>= OMAP_POWERSTATEST_SHIFT;
55 
56 	return v;
57 }
58 
omap4_pwrdm_read_prev_pwrst(struct powerdomain * pwrdm)59 static int omap4_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
60 {
61 	u32 v;
62 
63 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
64 					OMAP4_PM_PWSTST);
65 	v &= OMAP4430_LASTPOWERSTATEENTERED_MASK;
66 	v >>= OMAP4430_LASTPOWERSTATEENTERED_SHIFT;
67 
68 	return v;
69 }
70 
omap4_pwrdm_set_lowpwrstchange(struct powerdomain * pwrdm)71 static int omap4_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
72 {
73 	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
74 					(1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
75 					pwrdm->prcm_partition,
76 					pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
77 	return 0;
78 }
79 
omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain * pwrdm)80 static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
81 {
82 	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK,
83 					OMAP4430_LASTPOWERSTATEENTERED_MASK,
84 					pwrdm->prcm_partition,
85 					pwrdm->prcm_offs, OMAP4_PM_PWSTST);
86 	return 0;
87 }
88 
omap4_pwrdm_set_logic_retst(struct powerdomain * pwrdm,u8 pwrst)89 static int omap4_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
90 {
91 	u32 v;
92 
93 	v = pwrst << __ffs(OMAP4430_LOGICRETSTATE_MASK);
94 	omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOGICRETSTATE_MASK, v,
95 					pwrdm->prcm_partition, pwrdm->prcm_offs,
96 					OMAP4_PM_PWSTCTRL);
97 
98 	return 0;
99 }
100 
omap4_pwrdm_set_mem_onst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)101 static int omap4_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
102 				    u8 pwrst)
103 {
104 	u32 m;
105 
106 	m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
107 
108 	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
109 					pwrdm->prcm_partition, pwrdm->prcm_offs,
110 					OMAP4_PM_PWSTCTRL);
111 
112 	return 0;
113 }
114 
omap4_pwrdm_set_mem_retst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)115 static int omap4_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
116 				     u8 pwrst)
117 {
118 	u32 m;
119 
120 	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
121 
122 	omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
123 					pwrdm->prcm_partition, pwrdm->prcm_offs,
124 					OMAP4_PM_PWSTCTRL);
125 
126 	return 0;
127 }
128 
omap4_pwrdm_read_logic_pwrst(struct powerdomain * pwrdm)129 static int omap4_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
130 {
131 	u32 v;
132 
133 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
134 					OMAP4_PM_PWSTST);
135 	v &= OMAP4430_LOGICSTATEST_MASK;
136 	v >>= OMAP4430_LOGICSTATEST_SHIFT;
137 
138 	return v;
139 }
140 
omap4_pwrdm_read_logic_retst(struct powerdomain * pwrdm)141 static int omap4_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
142 {
143 	u32 v;
144 
145 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
146 					OMAP4_PM_PWSTCTRL);
147 	v &= OMAP4430_LOGICRETSTATE_MASK;
148 	v >>= OMAP4430_LOGICRETSTATE_SHIFT;
149 
150 	return v;
151 }
152 
omap4_pwrdm_read_mem_pwrst(struct powerdomain * pwrdm,u8 bank)153 static int omap4_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
154 {
155 	u32 m, v;
156 
157 	m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
158 
159 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
160 					OMAP4_PM_PWSTST);
161 	v &= m;
162 	v >>= __ffs(m);
163 
164 	return v;
165 }
166 
omap4_pwrdm_read_mem_retst(struct powerdomain * pwrdm,u8 bank)167 static int omap4_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
168 {
169 	u32 m, v;
170 
171 	m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
172 
173 	v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
174 					OMAP4_PM_PWSTCTRL);
175 	v &= m;
176 	v >>= __ffs(m);
177 
178 	return v;
179 }
180 
omap4_pwrdm_wait_transition(struct powerdomain * pwrdm)181 static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
182 {
183 	u32 c = 0;
184 
185 	/*
186 	 * REVISIT: pwrdm_wait_transition() may be better implemented
187 	 * via a callback and a periodic timer check -- how long do we expect
188 	 * powerdomain transitions to take?
189 	 */
190 
191 	/* XXX Is this udelay() value meaningful? */
192 	while ((omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
193 					    pwrdm->prcm_offs,
194 					    OMAP4_PM_PWSTST) &
195 		OMAP_INTRANSITION_MASK) &&
196 	       (c++ < PWRDM_TRANSITION_BAILOUT))
197 		udelay(1);
198 
199 	if (c > PWRDM_TRANSITION_BAILOUT) {
200 		printk(KERN_ERR "powerdomain: waited too long for "
201 		       "powerdomain %s to complete transition\n", pwrdm->name);
202 		return -EAGAIN;
203 	}
204 
205 	pr_debug("powerdomain: completed transition in %d loops\n", c);
206 
207 	return 0;
208 }
209 
210 struct pwrdm_ops omap4_pwrdm_operations = {
211 	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
212 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
213 	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
214 	.pwrdm_read_prev_pwrst	= omap4_pwrdm_read_prev_pwrst,
215 	.pwrdm_set_lowpwrstchange	= omap4_pwrdm_set_lowpwrstchange,
216 	.pwrdm_clear_all_prev_pwrst	= omap4_pwrdm_clear_all_prev_pwrst,
217 	.pwrdm_set_logic_retst	= omap4_pwrdm_set_logic_retst,
218 	.pwrdm_read_logic_pwrst	= omap4_pwrdm_read_logic_pwrst,
219 	.pwrdm_read_logic_retst	= omap4_pwrdm_read_logic_retst,
220 	.pwrdm_read_mem_pwrst	= omap4_pwrdm_read_mem_pwrst,
221 	.pwrdm_read_mem_retst	= omap4_pwrdm_read_mem_retst,
222 	.pwrdm_set_mem_onst	= omap4_pwrdm_set_mem_onst,
223 	.pwrdm_set_mem_retst	= omap4_pwrdm_set_mem_retst,
224 	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
225 };
226