diff options
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 100 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_common_data.c | 44 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/omap_hwmod.h | 73 |
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 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o -omap-2-3-common = irq.o sdrc.o omap_hwmod.o +omap-2-3-common = irq.o sdrc.o omap_hwmod.o \ + omap_hwmod_common_data.o omap-3-4-common = dpll3xxx.o prcm-common = prcm.o powerdomain.o clock-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) 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 */ 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 @@ +/* + * omap_hwmod common data structures + * + * Copyright (C) 2010 Texas Instruments, Inc. + * Thara Gopinath <thara@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This data/structures are to be used while defining OMAP on-chip module + * data and their integration with other OMAP modules and Linux. + */ + +#include <plat/omap_hwmod.h> + +/** + * struct omap_hwmod_sysc_type1 - TYPE1 sysconfig scheme. + * + * To be used by hwmod structure to specify the sysconfig offsets + * if the device ip is compliant with the original PRCM protocol + * defined for OMAP2420. + */ +struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1 = { + .midle_shift = SYSC_TYPE1_MIDLEMODE_SHIFT, + .clkact_shift = SYSC_TYPE1_CLOCKACTIVITY_SHIFT, + .sidle_shift = SYSC_TYPE1_SIDLEMODE_SHIFT, + .enwkup_shift = SYSC_TYPE1_ENAWAKEUP_SHIFT, + .srst_shift = SYSC_TYPE1_SOFTRESET_SHIFT, + .autoidle_shift = SYSC_TYPE1_AUTOIDLE_SHIFT, +}; + +/** + * struct omap_hwmod_sysc_type2 - TYPE2 sysconfig scheme. + * + * To be used by hwmod structure to specify the sysconfig offsets if the + * device ip is compliant with the new PRCM protocol defined for new + * OMAP4 IPs. + */ +struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2 = { + .midle_shift = SYSC_TYPE2_MIDLEMODE_SHIFT, + .sidle_shift = SYSC_TYPE2_SIDLEMODE_SHIFT, + .srst_shift = SYSC_TYPE2_SOFTRESET_SHIFT, +}; 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 @@ #define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H #include <linux/kernel.h> +#include <linux/list.h> #include <linux/ioport.h> - #include <plat/cpu.h> struct omap_device; -/* OCP SYSCONFIG bit shifts/masks */ -#define SYSC_MIDLEMODE_SHIFT 12 -#define SYSC_MIDLEMODE_MASK (0x3 << SYSC_MIDLEMODE_SHIFT) -#define SYSC_CLOCKACTIVITY_SHIFT 8 -#define SYSC_CLOCKACTIVITY_MASK (0x3 << SYSC_CLOCKACTIVITY_SHIFT) -#define SYSC_SIDLEMODE_SHIFT 3 -#define SYSC_SIDLEMODE_MASK (0x3 << SYSC_SIDLEMODE_SHIFT) -#define SYSC_ENAWAKEUP_SHIFT 2 -#define SYSC_ENAWAKEUP_MASK (1 << SYSC_ENAWAKEUP_SHIFT) -#define SYSC_SOFTRESET_SHIFT 1 -#define SYSC_SOFTRESET_MASK (1 << SYSC_SOFTRESET_SHIFT) -#define SYSC_AUTOIDLE_SHIFT 0 -#define SYSC_AUTOIDLE_MASK (1 << SYSC_AUTOIDLE_SHIFT) +extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1; +extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2; + +/* + * OCP SYSCONFIG bit shifts/masks TYPE1. These are for IPs compliant + * with the original PRCM protocol defined for OMAP2420 + */ +#define SYSC_TYPE1_MIDLEMODE_SHIFT 12 +#define SYSC_TYPE1_MIDLEMODE_MASK (0x3 << SYSC_MIDLEMODE_SHIFT) +#define SYSC_TYPE1_CLOCKACTIVITY_SHIFT 8 +#define SYSC_TYPE1_CLOCKACTIVITY_MASK (0x3 << SYSC_CLOCKACTIVITY_SHIFT) +#define SYSC_TYPE1_SIDLEMODE_SHIFT 3 +#define SYSC_TYPE1_SIDLEMODE_MASK (0x3 << SYSC_SIDLEMODE_SHIFT) +#define SYSC_TYPE1_ENAWAKEUP_SHIFT 2 +#define SYSC_TYPE1_ENAWAKEUP_MASK (1 << SYSC_ENAWAKEUP_SHIFT) +#define SYSC_TYPE1_SOFTRESET_SHIFT 1 +#define SYSC_TYPE1_SOFTRESET_MASK (1 << SYSC_SOFTRESET_SHIFT) +#define SYSC_TYPE1_AUTOIDLE_SHIFT 0 +#define SYSC_TYPE1_AUTOIDLE_MASK (1 << SYSC_AUTOIDLE_SHIFT) + +/* + * OCP SYSCONFIG bit shifts/masks TYPE2. These are for IPs compliant + * with the new PRCM protocol defined for new OMAP4 IPs. + */ +#define SYSC_TYPE2_SOFTRESET_SHIFT 0 +#define SYSC_TYPE2_SOFTRESET_MASK (1 << SYSC_TYPE2_SOFTRESET_SHIFT) +#define SYSC_TYPE2_SIDLEMODE_SHIFT 2 +#define SYSC_TYPE2_SIDLEMODE_MASK (0x3 << SYSC_TYPE2_SIDLEMODE_SHIFT) +#define SYSC_TYPE2_MIDLEMODE_SHIFT 4 +#define SYSC_TYPE2_MIDLEMODE_MASK (0x3 << SYSC_TYPE2_MIDLEMODE_SHIFT) /* OCP SYSSTATUS bit shifts/masks */ #define SYSS_RESETDONE_SHIFT 0 @@ -62,7 +79,6 @@ struct omap_device; #define HWMOD_IDLEMODE_NO (1 << 1) #define HWMOD_IDLEMODE_SMART (1 << 2) - /** * struct omap_hwmod_irq_info - MPU IRQs used by the hwmod * @name: name of the IRQ channel (module local name) @@ -236,6 +252,24 @@ struct omap_hwmod_ocp_if { #define CLOCKACT_TEST_NONE 0x3 /** + * struct omap_hwmod_sysc_fields - hwmod OCP_SYSCONFIG register field offsets. + * @midle_shift: Offset of the midle bit + * @clkact_shift: Offset of the clockactivity bit + * @sidle_shift: Offset of the sidle bit + * @enwkup_shift: Offset of the enawakeup bit + * @srst_shift: Offset of the softreset bit + * @autoidle_shift: Offset of the autoidle bit. + */ +struct omap_hwmod_sysc_fields { + u8 midle_shift; + u8 clkact_shift; + u8 sidle_shift; + u8 enwkup_shift; + u8 srst_shift; + u8 autoidle_shift; +}; + +/** * struct omap_hwmod_sysconfig - hwmod OCP_SYSCONFIG/OCP_SYSSTATUS data * @rev_offs: IP block revision register offset (from module base addr) * @sysc_offs: OCP_SYSCONFIG register offset (from module base addr) @@ -252,6 +286,14 @@ struct omap_hwmod_ocp_if { * been associated with the clocks marked in @clockact. This field is * only used if HWMOD_SET_DEFAULT_CLOCKACT is set (see below) * + * + * @sysc_fields: structure containing the offset positions of various bits in + * SYSCONFIG register. This can be populated using omap_hwmod_sysc_type1 or + * omap_hwmod_sysc_type2 defined in omap_hwmod_common_data.c depending on + * whether the device ip is compliant with the original PRCM protocol + * defined for OMAP2420 or the new PRCM protocol for new OMAP4 IPs. + * If the device follows a differnt scheme for the sysconfig register , + * then this field has to be populated with the correct offset structure. */ struct omap_hwmod_sysconfig { u16 rev_offs; @@ -260,6 +302,7 @@ struct omap_hwmod_sysconfig { u8 idlemodes; u8 sysc_flags; u8 clockact; + struct omap_hwmod_sysc_fields *sysc_fields; }; /** |