[PATCH] OMAP2plus: PM: omap_device: API for set/get MIDLE mode

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

 



Certain errata's in OMAP2plus processors will require disabling
master standby mode before completing on going operation. Without
this, the results will be unpredictable.
Ex: OMAP3430 ES1.0(Errata ID:i88) will require DMA to be put in
no mstandby mode before disabling the channel after completing
the data transfer operation.

Since current implementation of PM run time framework does not support
changing sysconfig settings during middle of the on going operation,
these API's will support the same.

These API's should be used by device drivers only incase of
erratum applicable to their modules if there is no other methods
to resolve.

Signed-off-by: G, Manjunath Kondaiah <manjugk@xxxxxx>
Cc: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
Cc: Paul Walmsley <paul@xxxxxxxxx>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   83 ++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    3 +
 arch/arm/plat-omap/omap_device.c             |   36 +++++++++++
 3 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 955861a..4f638fe 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -250,6 +250,35 @@ static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
 }
 
 /**
+ * _get_master_standbymode: get the OCP_SYSCONFIG MIDLEMODE field in @midlemode
+ * @oh: struct omap_hwmod *
+ * @standbymode: pointer to get mstandby mode bits(shifted to bit 0)
+ *
+ * Get the master standby mode bits in @midlemode for the @oh hwmod.
+ * Does not fetch the data from the hardware instead returns value
+ * from sysc_cache. Returns -EINVAL upon error or 0 upon success.
+ */
+static int _get_master_standbymode(struct omap_hwmod *oh, u32 *midlemode)
+{
+	u32 mstandby_mask;
+	u8 mstandby_shift;
+
+	if (!oh->class->sysc ||
+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE))
+		return -EINVAL;
+
+	if (!oh->class->sysc->sysc_fields) {
+		WARN(1, "omap_hwmod: %s: offset struct for sysconfig not"
+					" provided in class\n", oh->name);
+		return -EINVAL;
+	}
+
+	*midlemode = ((oh->_sysc_cache) & mstandby_mask) >> mstandby_shift;
+
+	return 0;
+}
+
+/**
  * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v
  * @oh: struct omap_hwmod *
  * @idlemode: SIDLEMODE field bits
@@ -1421,6 +1450,60 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode)
 }
 
 /**
+ * omap_hwmod_set_master_idlemode - set the hwmod's OCP master idlemode
+ * @oh: struct omap_hwmod *
+ * @idlemode: SIDLEMODE field bits (shifted to bit 0)
+ *
+ * Sets the IP block's OCP master idlemode in hardware, and updates our
+ * local copy.  Intended to be used by drivers that have some erratum
+ * that requires direct manipulation of the MIDLEMODE bits.  Returns
+ * -EINVAL if @oh is null, or passes along the return value from
+ * _set_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_set_master_idlemode(struct omap_hwmod *oh, u8 midlemode)
+{
+	u32 v;
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	v = oh->_sysc_cache;
+
+	retval = _set_master_standbymode(oh, midlemode, &v);
+	if (!retval)
+		_write_sysconfig(v, oh);
+
+	return retval;
+}
+
+/**
+ * omap_hwmod_get_master_idlemode - set the hwmod's OCP master idlemode
+ * @oh: struct omap_hwmod *
+ * @idlemode: pointer to get SIDLEMODE field bits (shifted to bit 0)
+ *
+ * Gets the IP block's OCP master idlemode from our local copy. Intended
+ * to be used by drivers that have some erratum that requires direct
+ * manipulation of the MIDLEMODE bits. Returns -EINVAL if @oh is null,
+ * or passes along the return value from _get_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_get_master_idlemode(struct omap_hwmod *oh, u32 *idlemode)
+{
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	retval = _get_master_standbymode(oh, idlemode);
+
+	return retval;
+}
+
+/**
  * omap_hwmod_register - register a struct omap_hwmod
  * @oh: struct omap_hwmod *
  *
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index c1835af..13d5f0a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -524,6 +524,9 @@ int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 
 int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
 
+int omap_hwmod_set_master_idlemode(struct omap_hwmod *oh, u8 midlemode);
+int omap_hwmod_get_master_idlemode(struct omap_hwmod *oh, u32 *idlemode);
+
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index abe933c..d782314 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -584,6 +584,42 @@ int omap_device_idle(struct platform_device *pdev)
 }
 
 /**
+ * omap_device_mstandby - set/get mstandby mode an omap_device
+ * @od: struct omap_device * to idle
+ * @midlemode: MIDLEMODE field bits (shifted to bit 0)
+ * @set_mstandby: flag for mstandby get/set
+ *
+ * Sets/Gets the IP block's OCP master standby in hardware. Intended
+ * to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_idlemode()/omap_hwmod_get_master_idlemode().
+ */
+int omap_device_mstandby(struct platform_device *pdev, u8 *midlemode,
+						bool set_mstandby)
+{
+	int ret, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	oh = *od->hwmods;
+	for (i = 0; i < od->hwmods_cnt; i++) {
+		if (set_mstandby)
+			ret = omap_hwmod_set_master_idlemode(oh, *midlemode);
+		else
+			ret = omap_hwmod_get_master_idlemode(oh, midlemode);
+	}
+	return ret;
+}
+
+/**
  * omap_device_shutdown - shut down an omap_device
  * @od: struct omap_device * to shut down
  *
-- 
1.7.0.4

--
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