diff options
author | Thara Gopinath <thara@ti.com> | 2010-02-24 12:05:58 -0700 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2010-02-24 12:05:58 -0700 |
commit | 358f0e630d5409ab3837b86db3595560eae773b6 (patch) | |
tree | 0b4d6d8c555bee693f50819e7d717a43548643a5 /arch/arm/mach-omap2/omap_hwmod.c | |
parent | 5eb75f557843132da08938609def2774ee467d95 (diff) | |
download | linux-358f0e630d5409ab3837b86db3595560eae773b6.tar.gz linux-358f0e630d5409ab3837b86db3595560eae773b6.tar.bz2 linux-358f0e630d5409ab3837b86db3595560eae773b6.zip |
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>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 100 |
1 files changed, 87 insertions, 13 deletions
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) static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode, u32 *v) { + u32 mstandby_mask; + u8 mstandby_shift; + if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE)) return -EINVAL; - *v &= ~SYSC_MIDLEMODE_MASK; - *v |= __ffs(standbymode) << SYSC_MIDLEMODE_SHIFT; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + mstandby_shift = oh->sysconfig->sysc_fields->midle_shift; + mstandby_mask = (0x3 << mstandby_shift); + + *v &= ~mstandby_mask; + *v |= __ffs(standbymode) << mstandby_shift; return 0; } @@ -159,12 +171,24 @@ static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode, */ static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v) { + u32 sidle_mask; + u8 sidle_shift; + if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE)) return -EINVAL; - *v &= ~SYSC_SIDLEMODE_MASK; - *v |= __ffs(idlemode) << SYSC_SIDLEMODE_SHIFT; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + sidle_shift = oh->sysconfig->sysc_fields->sidle_shift; + sidle_mask = (0x3 << sidle_shift); + + *v &= ~sidle_mask; + *v |= __ffs(idlemode) << sidle_shift; return 0; } @@ -182,12 +206,24 @@ static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v) */ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v) { + u32 clkact_mask; + u8 clkact_shift; + if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) return -EINVAL; - *v &= ~SYSC_CLOCKACTIVITY_MASK; - *v |= clockact << SYSC_CLOCKACTIVITY_SHIFT; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + clkact_shift = oh->sysconfig->sysc_fields->clkact_shift; + clkact_mask = (0x3 << clkact_shift); + + *v &= ~clkact_mask; + *v |= clockact << clkact_shift; return 0; } @@ -202,11 +238,21 @@ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v) */ static int _set_softreset(struct omap_hwmod *oh, u32 *v) { + u32 softrst_mask; + if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET)) return -EINVAL; - *v |= SYSC_SOFTRESET_MASK; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + softrst_mask = (0x1 << oh->sysconfig->sysc_fields->srst_shift); + + *v |= softrst_mask; return 0; } @@ -227,12 +273,24 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v) static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, u32 *v) { + u32 autoidle_mask; + u8 autoidle_shift; + if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE)) return -EINVAL; - *v &= ~SYSC_AUTOIDLE_MASK; - *v |= autoidle << SYSC_AUTOIDLE_SHIFT; + if (!oh->sysconfig->sysc_fields) { + WARN(oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + autoidle_shift = oh->sysconfig->sysc_fields->autoidle_shift; + autoidle_mask = (0x3 << autoidle_shift); + + *v &= ~autoidle_mask; + *v |= autoidle << autoidle_shift; return 0; } @@ -246,14 +304,22 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, */ static int _enable_wakeup(struct omap_hwmod *oh) { - u32 v; + u32 v, wakeup_mask; if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) return -EINVAL; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + wakeup_mask = (0x1 << oh->sysconfig->sysc_fields->enwkup_shift); + v = oh->_sysc_cache; - v |= SYSC_ENAWAKEUP_MASK; + v |= wakeup_mask; _write_sysconfig(v, oh); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -272,14 +338,22 @@ static int _enable_wakeup(struct omap_hwmod *oh) */ static int _disable_wakeup(struct omap_hwmod *oh) { - u32 v; + u32 v, wakeup_mask; if (!oh->sysconfig || !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) return -EINVAL; + if (!oh->sysconfig->sysc_fields) { + WARN(!oh->sysconfig->sysc_fields, "offset struct for " + "sysconfig not provided!\n"); + return -EINVAL; + } + + wakeup_mask = (0x1 << oh->sysconfig->sysc_fields->enwkup_shift); + v = oh->_sysc_cache; - v &= ~SYSC_ENAWAKEUP_MASK; + v &= ~wakeup_mask; _write_sysconfig(v, oh); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ |