aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThara Gopinath <thara@ti.com>2010-02-24 14:05:58 -0500
committerPaul Walmsley <paul@pwsan.com>2010-02-24 14:05:58 -0500
commit358f0e630d5409ab3837b86db3595560eae773b6 (patch)
tree0b4d6d8c555bee693f50819e7d717a43548643a5
parent5eb75f557843132da08938609def2774ee467d95 (diff)
OMAP3: hwmod: support to specify the offset position of various SYSCONFIG register bits.
In OMAP3 Some modules like Smartreflex do not have the regular sysconfig register.Instead clockactivity bits are part of another register at a different bit position than the usual bit positions 8 and 9. In OMAP4, a new scheme is available due to the new protocol between the PRCM and the IPs. Depending of the scheme, the SYSCONFIG bitfields position will be different. The IP_REVISION register should be at offset 0x00. It should contain a SCHEME field. From this we can determine whether the IP follows legacy scheme or the new scheme. 31:30 SCHEME Used to distinguish between old scheme and current. Read 0x0: Legacy protocol. Read 0x1: New PRCM protocol defined for new OMAP4 IPs For legacy IP 13:12 MIDLEMODE 11:8 CLOCKACTIVITY 6 EMUSOFT 5 EMUFREE 4:3 SIDLEMODE 2 ENAWAKEUP 1 SOFTRESET 0 AUTOIDLE For new OMAP4 IP's, the bit position in SYSCONFIG is (for simple target): 5:4 STANDBYMODE (Ex MIDLEMODE) 3:2 IDLEMODE (Ex SIDLEMODE) 1 FREEEMU (Ex EMUFREE) 0 SOFTRESET Unfortunately In OMAP4 also some IPs will not follow any of these two schemes. This is the case at least for McASP, SmartReflex and some security IPs. This patch introduces a new field sysc_fields in omap_hwmod_sysconfig which can be used by the hwmod structures to specify the offsets for the sysconfig register of the IP.Also two static structures omap_hwmod_sysc_type1 and omap_hwmod_sysc_type2 are defined which can be used directly to populate the sysc_fields if the IP follows legacy or new OMAP4 scheme. If the IP follows none of these two schemes a new omap_hwmod_sysc_fields structure has to be defined and passed as part of omap_hwmod_sysconfig. Signed-off-by: Thara Gopinath <thara@ti.com> Signed-off-by: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c100
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_common_data.c44
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h73
4 files changed, 191 insertions, 29 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index dfc49a0c6927..3ebd0b6525df 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -5,7 +5,8 @@
5# Common support 5# Common support
6obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o 6obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o
7 7
8omap-2-3-common = irq.o sdrc.o omap_hwmod.o 8omap-2-3-common = irq.o sdrc.o omap_hwmod.o \
9 omap_hwmod_common_data.o
9omap-3-4-common = dpll3xxx.o 10omap-3-4-common = dpll3xxx.o
10prcm-common = prcm.o powerdomain.o 11prcm-common = prcm.o powerdomain.o
11clock-common = clock.o clock_common_data.o \ 12clock-common = clock.o clock_common_data.o \
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 70912d1c71e0..fb11ec176d55 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -137,12 +137,24 @@ static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
137static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode, 137static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
138 u32 *v) 138 u32 *v)
139{ 139{
140 u32 mstandby_mask;
141 u8 mstandby_shift;
142
140 if (!oh->sysconfig || 143 if (!oh->sysconfig ||
141 !(oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE)) 144 !(oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE))
142 return -EINVAL; 145 return -EINVAL;
143 146
144 *v &= ~SYSC_MIDLEMODE_MASK; 147 if (!oh->sysconfig->sysc_fields) {
145 *v |= __ffs(standbymode) << SYSC_MIDLEMODE_SHIFT; 148 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
149 "sysconfig not provided!\n");
150 return -EINVAL;
151 }
152
153 mstandby_shift = oh->sysconfig->sysc_fields->midle_shift;
154 mstandby_mask = (0x3 << mstandby_shift);
155
156 *v &= ~mstandby_mask;
157 *v |= __ffs(standbymode) << mstandby_shift;
146 158
147 return 0; 159 return 0;
148} 160}
@@ -159,12 +171,24 @@ static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
159 */ 171 */
160static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v) 172static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
161{ 173{
174 u32 sidle_mask;
175 u8 sidle_shift;
176
162 if (!oh->sysconfig || 177 if (!oh->sysconfig ||
163 !(oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE)) 178 !(oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE))
164 return -EINVAL; 179 return -EINVAL;
165 180
166 *v &= ~SYSC_SIDLEMODE_MASK; 181 if (!oh->sysconfig->sysc_fields) {
167 *v |= __ffs(idlemode) << SYSC_SIDLEMODE_SHIFT; 182 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
183 "sysconfig not provided!\n");
184 return -EINVAL;
185 }
186
187 sidle_shift = oh->sysconfig->sysc_fields->sidle_shift;
188 sidle_mask = (0x3 << sidle_shift);
189
190 *v &= ~sidle_mask;
191 *v |= __ffs(idlemode) << sidle_shift;
168 192
169 return 0; 193 return 0;
170} 194}
@@ -182,12 +206,24 @@ static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
182 */ 206 */
183static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v) 207static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
184{ 208{
209 u32 clkact_mask;
210 u8 clkact_shift;
211
185 if (!oh->sysconfig || 212 if (!oh->sysconfig ||
186 !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) 213 !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY))
187 return -EINVAL; 214 return -EINVAL;
188 215
189 *v &= ~SYSC_CLOCKACTIVITY_MASK; 216 if (!oh->sysconfig->sysc_fields) {
190 *v |= clockact << SYSC_CLOCKACTIVITY_SHIFT; 217 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
218 "sysconfig not provided!\n");
219 return -EINVAL;
220 }
221
222 clkact_shift = oh->sysconfig->sysc_fields->clkact_shift;
223 clkact_mask = (0x3 << clkact_shift);
224
225 *v &= ~clkact_mask;
226 *v |= clockact << clkact_shift;
191 227
192 return 0; 228 return 0;
193} 229}
@@ -202,11 +238,21 @@ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
202 */ 238 */
203static int _set_softreset(struct omap_hwmod *oh, u32 *v) 239static int _set_softreset(struct omap_hwmod *oh, u32 *v)
204{ 240{
241 u32 softrst_mask;
242
205 if (!oh->sysconfig || 243 if (!oh->sysconfig ||
206 !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET)) 244 !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET))
207 return -EINVAL; 245 return -EINVAL;
208 246
209 *v |= SYSC_SOFTRESET_MASK; 247 if (!oh->sysconfig->sysc_fields) {
248 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
249 "sysconfig not provided!\n");
250 return -EINVAL;
251 }
252
253 softrst_mask = (0x1 << oh->sysconfig->sysc_fields->srst_shift);
254
255 *v |= softrst_mask;
210 256
211 return 0; 257 return 0;
212} 258}
@@ -227,12 +273,24 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
227static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, 273static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
228 u32 *v) 274 u32 *v)
229{ 275{
276 u32 autoidle_mask;
277 u8 autoidle_shift;
278
230 if (!oh->sysconfig || 279 if (!oh->sysconfig ||
231 !(oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE)) 280 !(oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE))
232 return -EINVAL; 281 return -EINVAL;
233 282
234 *v &= ~SYSC_AUTOIDLE_MASK; 283 if (!oh->sysconfig->sysc_fields) {
235 *v |= autoidle << SYSC_AUTOIDLE_SHIFT; 284 WARN(oh->sysconfig->sysc_fields, "offset struct for "
285 "sysconfig not provided!\n");
286 return -EINVAL;
287 }
288
289 autoidle_shift = oh->sysconfig->sysc_fields->autoidle_shift;
290 autoidle_mask = (0x3 << autoidle_shift);
291
292 *v &= ~autoidle_mask;
293 *v |= autoidle << autoidle_shift;
236 294
237 return 0; 295 return 0;
238} 296}
@@ -246,14 +304,22 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
246 */ 304 */
247static int _enable_wakeup(struct omap_hwmod *oh) 305static int _enable_wakeup(struct omap_hwmod *oh)
248{ 306{
249 u32 v; 307 u32 v, wakeup_mask;
250 308
251 if (!oh->sysconfig || 309 if (!oh->sysconfig ||
252 !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) 310 !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP))
253 return -EINVAL; 311 return -EINVAL;
254 312
313 if (!oh->sysconfig->sysc_fields) {
314 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
315 "sysconfig not provided!\n");
316 return -EINVAL;
317 }
318
319 wakeup_mask = (0x1 << oh->sysconfig->sysc_fields->enwkup_shift);
320
255 v = oh->_sysc_cache; 321 v = oh->_sysc_cache;
256 v |= SYSC_ENAWAKEUP_MASK; 322 v |= wakeup_mask;
257 _write_sysconfig(v, oh); 323 _write_sysconfig(v, oh);
258 324
259 /* XXX test pwrdm_get_wken for this hwmod's subsystem */ 325 /* XXX test pwrdm_get_wken for this hwmod's subsystem */
@@ -272,14 +338,22 @@ static int _enable_wakeup(struct omap_hwmod *oh)
272 */ 338 */
273static int _disable_wakeup(struct omap_hwmod *oh) 339static int _disable_wakeup(struct omap_hwmod *oh)
274{ 340{
275 u32 v; 341 u32 v, wakeup_mask;
276 342
277 if (!oh->sysconfig || 343 if (!oh->sysconfig ||
278 !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) 344 !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP))
279 return -EINVAL; 345 return -EINVAL;
280 346
347 if (!oh->sysconfig->sysc_fields) {
348 WARN(!oh->sysconfig->sysc_fields, "offset struct for "
349 "sysconfig not provided!\n");
350 return -EINVAL;
351 }
352
353 wakeup_mask = (0x1 << oh->sysconfig->sysc_fields->enwkup_shift);
354
281 v = oh->_sysc_cache; 355 v = oh->_sysc_cache;
282 v &= ~SYSC_ENAWAKEUP_MASK; 356 v &= ~wakeup_mask;
283 _write_sysconfig(v, oh); 357 _write_sysconfig(v, oh);
284 358
285 /* XXX test pwrdm_get_wken for this hwmod's subsystem */ 359 /* XXX test pwrdm_get_wken for this hwmod's subsystem */
diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.c b/arch/arm/mach-omap2/omap_hwmod_common_data.c
new file mode 100644
index 000000000000..2567c6edc6af
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_hwmod_common_data.c
@@ -0,0 +1,44 @@
1/*
2 * omap_hwmod common data structures
3 *
4 * Copyright (C) 2010 Texas Instruments, Inc.
5 * Thara Gopinath <thara@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This data/structures are to be used while defining OMAP on-chip module
12 * data and their integration with other OMAP modules and Linux.
13 */
14
15#include <plat/omap_hwmod.h>
16
17/**
18 * struct omap_hwmod_sysc_type1 - TYPE1 sysconfig scheme.
19 *
20 * To be used by hwmod structure to specify the sysconfig offsets
21 * if the device ip is compliant with the original PRCM protocol
22 * defined for OMAP2420.
23 */
24struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1 = {
25 .midle_shift = SYSC_TYPE1_MIDLEMODE_SHIFT,
26 .clkact_shift = SYSC_TYPE1_CLOCKACTIVITY_SHIFT,
27 .sidle_shift = SYSC_TYPE1_SIDLEMODE_SHIFT,
28 .enwkup_shift = SYSC_TYPE1_ENAWAKEUP_SHIFT,
29 .srst_shift = SYSC_TYPE1_SOFTRESET_SHIFT,
30 .autoidle_shift = SYSC_TYPE1_AUTOIDLE_SHIFT,
31};
32
33/**
34 * struct omap_hwmod_sysc_type2 - TYPE2 sysconfig scheme.
35 *
36 * To be used by hwmod structure to specify the sysconfig offsets if the
37 * device ip is compliant with the new PRCM protocol defined for new
38 * OMAP4 IPs.
39 */
40struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2 = {
41 .midle_shift = SYSC_TYPE2_MIDLEMODE_SHIFT,
42 .sidle_shift = SYSC_TYPE2_SIDLEMODE_SHIFT,
43 .srst_shift = SYSC_TYPE2_SOFTRESET_SHIFT,
44};
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 921990e2a29a..665420e89c21 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -33,25 +33,42 @@
33#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H 33#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
34 34
35#include <linux/kernel.h> 35#include <linux/kernel.h>
36#include <linux/list.h>
36#include <linux/ioport.h> 37#include <linux/ioport.h>
37
38#include <plat/cpu.h> 38#include <plat/cpu.h>
39 39
40struct omap_device; 40struct omap_device;
41 41
42/* OCP SYSCONFIG bit shifts/masks */ 42extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1;
43#define SYSC_MIDLEMODE_SHIFT 12 43extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2;
44#define SYSC_MIDLEMODE_MASK (0x3 << SYSC_MIDLEMODE_SHIFT) 44
45#define SYSC_CLOCKACTIVITY_SHIFT 8 45/*
46#define SYSC_CLOCKACTIVITY_MASK (0x3 << SYSC_CLOCKACTIVITY_SHIFT) 46 * OCP SYSCONFIG bit shifts/masks TYPE1. These are for IPs compliant
47#define SYSC_SIDLEMODE_SHIFT 3 47 * with the original PRCM protocol defined for OMAP2420
48#define SYSC_SIDLEMODE_MASK (0x3 << SYSC_SIDLEMODE_SHIFT) 48 */
49#define SYSC_ENAWAKEUP_SHIFT 2 49#define SYSC_TYPE1_MIDLEMODE_SHIFT 12
50#define SYSC_ENAWAKEUP_MASK (1 << SYSC_ENAWAKEUP_SHIFT) 50#define SYSC_TYPE1_MIDLEMODE_MASK (0x3 << SYSC_MIDLEMODE_SHIFT)
51#define SYSC_SOFTRESET_SHIFT 1 51#define SYSC_TYPE1_CLOCKACTIVITY_SHIFT 8
52#define SYSC_SOFTRESET_MASK (1 << SYSC_SOFTRESET_SHIFT) 52#define SYSC_TYPE1_CLOCKACTIVITY_MASK (0x3 << SYSC_CLOCKACTIVITY_SHIFT)
53#define SYSC_AUTOIDLE_SHIFT 0 53#define SYSC_TYPE1_SIDLEMODE_SHIFT 3
54#define SYSC_AUTOIDLE_MASK (1 << SYSC_AUTOIDLE_SHIFT) 54#define SYSC_TYPE1_SIDLEMODE_MASK (0x3 << SYSC_SIDLEMODE_SHIFT)
55#define SYSC_TYPE1_ENAWAKEUP_SHIFT 2
56#define SYSC_TYPE1_ENAWAKEUP_MASK (1 << SYSC_ENAWAKEUP_SHIFT)
57#define SYSC_TYPE1_SOFTRESET_SHIFT 1
58#define SYSC_TYPE1_SOFTRESET_MASK (1 << SYSC_SOFTRESET_SHIFT)
59#define SYSC_TYPE1_AUTOIDLE_SHIFT 0
60#define SYSC_TYPE1_AUTOIDLE_MASK (1 << SYSC_AUTOIDLE_SHIFT)
61
62/*
63 * OCP SYSCONFIG bit shifts/masks TYPE2. These are for IPs compliant
64 * with the new PRCM protocol defined for new OMAP4 IPs.
65 */
66#define SYSC_TYPE2_SOFTRESET_SHIFT 0
67#define SYSC_TYPE2_SOFTRESET_MASK (1 << SYSC_TYPE2_SOFTRESET_SHIFT)
68#define SYSC_TYPE2_SIDLEMODE_SHIFT 2
69#define SYSC_TYPE2_SIDLEMODE_MASK (0x3 << SYSC_TYPE2_SIDLEMODE_SHIFT)
70#define SYSC_TYPE2_MIDLEMODE_SHIFT 4
71#define SYSC_TYPE2_MIDLEMODE_MASK (0x3 << SYSC_TYPE2_MIDLEMODE_SHIFT)
55 72
56/* OCP SYSSTATUS bit shifts/masks */ 73/* OCP SYSSTATUS bit shifts/masks */
57#define SYSS_RESETDONE_SHIFT 0 74#define SYSS_RESETDONE_SHIFT 0
@@ -62,7 +79,6 @@ struct omap_device;
62#define HWMOD_IDLEMODE_NO (1 << 1) 79#define HWMOD_IDLEMODE_NO (1 << 1)
63#define HWMOD_IDLEMODE_SMART (1 << 2) 80#define HWMOD_IDLEMODE_SMART (1 << 2)
64 81
65
66/** 82/**
67 * struct omap_hwmod_irq_info - MPU IRQs used by the hwmod 83 * struct omap_hwmod_irq_info - MPU IRQs used by the hwmod
68 * @name: name of the IRQ channel (module local name) 84 * @name: name of the IRQ channel (module local name)
@@ -236,6 +252,24 @@ struct omap_hwmod_ocp_if {
236#define CLOCKACT_TEST_NONE 0x3 252#define CLOCKACT_TEST_NONE 0x3
237 253
238/** 254/**
255 * struct omap_hwmod_sysc_fields - hwmod OCP_SYSCONFIG register field offsets.
256 * @midle_shift: Offset of the midle bit
257 * @clkact_shift: Offset of the clockactivity bit
258 * @sidle_shift: Offset of the sidle bit
259 * @enwkup_shift: Offset of the enawakeup bit
260 * @srst_shift: Offset of the softreset bit
261 * @autoidle_shift: Offset of the autoidle bit.
262 */
263struct omap_hwmod_sysc_fields {
264 u8 midle_shift;
265 u8 clkact_shift;
266 u8 sidle_shift;
267 u8 enwkup_shift;
268 u8 srst_shift;
269 u8 autoidle_shift;
270};
271
272/**
239 * struct omap_hwmod_sysconfig - hwmod OCP_SYSCONFIG/OCP_SYSSTATUS data 273 * struct omap_hwmod_sysconfig - hwmod OCP_SYSCONFIG/OCP_SYSSTATUS data
240 * @rev_offs: IP block revision register offset (from module base addr) 274 * @rev_offs: IP block revision register offset (from module base addr)
241 * @sysc_offs: OCP_SYSCONFIG register offset (from module base addr) 275 * @sysc_offs: OCP_SYSCONFIG register offset (from module base addr)
@@ -252,6 +286,14 @@ struct omap_hwmod_ocp_if {
252 * been associated with the clocks marked in @clockact. This field is 286 * been associated with the clocks marked in @clockact. This field is
253 * only used if HWMOD_SET_DEFAULT_CLOCKACT is set (see below) 287 * only used if HWMOD_SET_DEFAULT_CLOCKACT is set (see below)
254 * 288 *
289 *
290 * @sysc_fields: structure containing the offset positions of various bits in
291 * SYSCONFIG register. This can be populated using omap_hwmod_sysc_type1 or
292 * omap_hwmod_sysc_type2 defined in omap_hwmod_common_data.c depending on
293 * whether the device ip is compliant with the original PRCM protocol
294 * defined for OMAP2420 or the new PRCM protocol for new OMAP4 IPs.
295 * If the device follows a differnt scheme for the sysconfig register ,
296 * then this field has to be populated with the correct offset structure.
255 */ 297 */
256struct omap_hwmod_sysconfig { 298struct omap_hwmod_sysconfig {
257 u16 rev_offs; 299 u16 rev_offs;
@@ -260,6 +302,7 @@ struct omap_hwmod_sysconfig {
260 u8 idlemodes; 302 u8 idlemodes;
261 u8 sysc_flags; 303 u8 sysc_flags;
262 u8 clockact; 304 u8 clockact;
305 struct omap_hwmod_sysc_fields *sysc_fields;
263}; 306};
264 307
265/** 308/**