Re: [PATCH] OMAP3: hwmod: support to specify the offset position of various SYSCONFIG register bits.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Thara,

this mostly looks good, but there are a few things to fix:

On Mon, 11 Jan 2010, Thara Gopinath wrote:

> 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 legacy or HL.
> 
> 31:30 SCHEME  Used to distinguish between old scheme and current.
>  Read 0x0:  Legacy ASP or WTBU scheme
>  Read 0x1:  Highlander 0.8 scheme
> 
> For legacy IP
>  13:12 MIDLEMODE
>  11:8  CLOCKACTIVITY
>  6     EMUSOFT
>  5     EMUFREE
>  4:3   SIDLEMODE
>  2     ENAWAKEUP
>  1     SOFTRESET
>  0     AUTOIDLE
> 
> For Highlander IP, 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_fields and omap_hwmod_sysc_highlander are defined 
> which can be used directly to populate the sysc_fields if the IP follows
> legacy or highlander 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@xxxxxx>
> Signed-off-by: Benoit Cousson <b-cousson@xxxxxx>
> Signed-off-by: Paul Walmsley <paul@xxxxxxxxx>

I haven't signed off on this one yet :-)

> ---
> 
> This patch is based off Kevin's tree origin/pm-wip/omap_device branch
> 
>  arch/arm/mach-omap2/omap_hwmod.c             |   14 ++++++++++++--
>  arch/arm/plat-omap/include/plat/omap_hwmod.h |   26 +++++++++++++++++---------
>  2 files changed, 29 insertions(+), 11 deletions(-)
> 
> Index: linux-omap-pm/arch/arm/mach-omap2/omap_hwmod.c
> ===================================================================
> --- linux-omap-pm.orig/arch/arm/mach-omap2/omap_hwmod.c
> +++ linux-omap-pm/arch/arm/mach-omap2/omap_hwmod.c
> @@ -135,12 +135,23 @@ static void _write_sysconfig(u32 v, stru
>  static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
>  				   u32 *v)
>  {
> +	u32 mstandby_mask = 0;
> +	u8 mstandby_shift = 0;

There's no reason these variables, or the similar variables below, need to 
be pre-initialized to zero.  Hopefully the compiler would optimize these 
assignments out, but in any case, please remove them, unless they are 
absolutely needed.

> +
>  	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) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");

Maybe consider WARN() instead?  That way, the user can see a stack dump 
and know what the offending function is.

> +		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;
>  }
> @@ -157,12 +168,22 @@ static int _set_master_standbymode(struc
>   */
>  static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
>  {
> +	u32 sidle_mask = 0;
> +	u8 sidle_shift = 0;

See above re: unnecessary assignment

> +
>  	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) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

Please add a blank line after closing this code block, as you did above

> +	sidle_shift = oh->sysconfig->sysc_fields->sidle_shift;
> +	sidle_mask = (0x3 << sidle_shift);
> +
> +	*v &= ~sidle_mask;
> +	*v |= __ffs(idlemode) << sidle_shift;
>  
>  	return 0;
>  }
> @@ -180,12 +201,22 @@ static int _set_slave_idlemode(struct om
>   */
>  static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
>  {
> +	u32 clkact_mask = 0;
> +	u8  clkact_shift = 0;

See above re: unnecessary assignment

> +
>  	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) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

See above re: blank line

> +	clkact_shift = oh->sysconfig->sysc_fields->clkact_shift;
> +	clkact_mask = (0x3 << clkact_shift);
> +
> +	*v &= ~clkact_mask;
> +	*v |= clockact << clkact_shift;
>  
>  	return 0;
>  }
> @@ -200,11 +231,19 @@ static int _set_clockactivity(struct oma
>   */
>  static int _set_softreset(struct omap_hwmod *oh, u32 *v)
>  {
> +	u32 softrst_mask = 0;

See above re: unnecessary assignment

> +
>  	if (!oh->sysconfig ||
>  	    !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET))
>  		return -EINVAL;
>  
> -	*v |= SYSC_SOFTRESET_MASK;
> +	if (!oh->sysconfig->sysc_fields) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

See above re: black line

> +	softrst_mask = (0x1 << oh->sysconfig->sysc_fields->srst_shift);
> +
> +	*v |= softrst_mask;
>  
>  	return 0;
>  }
> @@ -225,12 +264,22 @@ static int _set_softreset(struct omap_hw
>  static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
>  				u32 *v)
>  {
> +	u32 autoidle_mask = 0;
> +	u8 autoidle_shift = 0;
> +

See above re: unnecessary assignment

>  	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) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

See above re: blank line

> +	autoidle_shift = oh->sysconfig->sysc_fields->autoidle_shift;
> +	autoidle_mask = (0x3 << autoidle_shift);
> +
> +	*v &= ~autoidle_mask;
> +	*v |= autoidle << autoidle_shift;
>  
>  	return 0;
>  }
> @@ -244,14 +293,20 @@ static int _set_module_autoidle(struct o
>   */
>  static int _enable_wakeup(struct omap_hwmod *oh)
>  {
> -	u32 v;
> +	u32 v, wakeup_mask = 0;

See above re: assignment

>  
>  	if (!oh->sysconfig ||
>  	    !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP))
>  		return -EINVAL;
>  
> +	if (!oh->sysconfig->sysc_fields) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

See above re: blank line

> +	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 */
> @@ -270,14 +325,20 @@ static int _enable_wakeup(struct omap_hw
>   */
>  static int _disable_wakeup(struct omap_hwmod *oh)
>  {
> -	u32 v;
> +	u32 v, wakeup_mask = 0;

See above re: assignment

>  
>  	if (!oh->sysconfig ||
>  	    !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP))
>  		return -EINVAL;
>  
> +	if (!oh->sysconfig->sysc_fields) {
> +		pr_warning("offset struct for sysconfig not provided!!!!\n");
> +		return -EINVAL;
> +	}

See above re: blank line

> +	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 */
> Index: linux-omap-pm/arch/arm/plat-omap/include/plat/omap_hwmod.h
> ===================================================================
> --- linux-omap-pm.orig/arch/arm/plat-omap/include/plat/omap_hwmod.h
> +++ linux-omap-pm/arch/arm/plat-omap/include/plat/omap_hwmod.h
> @@ -38,8 +38,9 @@
>  #include <plat/cpu.h>
>  
>  struct omap_device;
> +struct omap_hwmod_sysc_fields;
>  
> -/* OCP SYSCONFIG bit shifts/masks */
> +/* OCP SYSCONFIG bit shifts/masks Legacy scheme */
>  #define SYSC_MIDLEMODE_SHIFT		12
>  #define SYSC_MIDLEMODE_MASK		(0x3 << SYSC_MIDLEMODE_SHIFT)
>  #define SYSC_CLOCKACTIVITY_SHIFT	8
> @@ -53,6 +54,14 @@ struct omap_device;
>  #define SYSC_AUTOIDLE_SHIFT		0
>  #define SYSC_AUTOIDLE_MASK		(1 << SYSC_AUTOIDLE_SHIFT)

Since you use 'HIGH' below to indicate Highlander IPs, the above
should be renamed to include _LEGACY_ or _LGCY_ or something similar.

>  
> +/* OCP SYSCONFIG bit shifts/masks Highlander scheme */
> +#define SYSC_HIGH_SOFTRESET_SHIFT	0
> +#define SYSC_HIGH_SOFTRESET_MASK	(1 << SYSC_HIGH_SOFTRESET_SHIFT)
> +#define SYSC_HIGH_SIDLEMODE_SHIFT	2
> +#define SYSC_HIGH_SIDLEMODE_MASK	(0x3 << SYSC_HIGH_SIDLEMODE_SHIFT)
> +#define SYSC_HIGH_MIDLEMODE_SHIFT	4
> +#define SYSC_HIGH_MIDLEMODE_MASK	(0x3 << SYSC_HIGH_MIDLEMODE_SHIFT)
> +
>  /* OCP SYSSTATUS bit shifts/masks */
>  #define SYSS_RESETDONE_SHIFT		0
>  #define SYSS_RESETDONE_MASK		(1 << SYSS_RESETDONE_SHIFT)
> @@ -62,7 +71,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)
> @@ -235,6 +243,53 @@ struct omap_hwmod_ocp_if {
>  #define CLOCKACT_TEST_NONE	0x3
>  
>  /**
> + * struct omap_hwmod_sysc_fields - hwmod OCP_SYSCONFIG register field offsets.
> + * To be populated if the SYSCONFIG register offsets have deviated from the
> + * standard.

Don't these have to be populated in every case?

> + * @midle_shift: Offset of the midle bit
> + * @clkact_shift: Offset of the clockactivity bit
> + * @sidle_shift: Offset of the sidle bit
> + * @enawkup_shift: Offset of the enawakeup bit
> + * @sreset_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_sysc_legacy - OMAP3 legacy scheme for old IPs
> + *
> + * To be used by hwmod structure to specify the sysconfig offsets
> + * if the device ip follows the Legacy scheme.
> + */
> +static struct omap_hwmod_sysc_fields omap_hwmod_sysc_legacy = {
> +    .midle_shift	= SYSC_MIDLEMODE_SHIFT,
> +    .clkact_shift	= SYSC_CLOCKACTIVITY_SHIFT,
> +    .sidle_shift	= SYSC_SIDLEMODE_SHIFT,
> +    .enwkup_shift	= SYSC_ENAWAKEUP_SHIFT,
> +    .srst_shift		= SYSC_SOFTRESET_SHIFT,
> +    .autoidle_shift 	= SYSC_AUTOIDLE_SHIFT,
> +};
> +
> +/**
> + * struct omap_hwmod_sysc_fields - OMAP4 new scheme for Highlander compliant IPs
> + *
> + * To be used by hwmod structure to specify the sysconfig offsets if the
> + * device ip follows the highlander scheme
> + */
> +static struct omap_hwmod_sysc_fields omap_hwmod_sysc_highlander = {
> +    .midle_shift	= SYSC_HIGH_MIDLEMODE_SHIFT,
> +    .sidle_shift	= SYSC_HIGH_SIDLEMODE_SHIFT,
> +    .srst_shift		= SYSC_HIGH_SOFTRESET_SHIFT,
> +};

Please create a new C file for these two static allocations, something 
like mach-omap2/omap_hwmod_common_data.c.  The reason why is that we're 
(slowly) moving away from allocating memory in .h files, so there are no 
side-effects when these files are #included.  We just did the clock 
framework in the last merge window, e.g., mach-omap2/clock*data.c

Also, your structure member lines need to start with tabs, not spaces, per 
CodingStyle.

> +
> +/**
>   * 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)
> @@ -251,6 +306,13 @@ 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_legacy or
> + * omap_hwmod_highlander_legacy defined below if the device follows legacy
> + * or highlander scheme for the sysconfig register. If the device follows
> + * a differnet scheme for the sysconfig register , then this field has to
> + * be populated with the correct offset structure.
>   */
>  struct omap_hwmod_sysconfig {
>  	u16 rev_offs;
> @@ -259,6 +321,7 @@ struct omap_hwmod_sysconfig {
>  	u8 idlemodes;
>  	u8 sysc_flags;
>  	u8 clockact;
> +	struct omap_hwmod_sysc_fields *sysc_fields;
>  };
>  
>  /**
> 


- Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux