All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-13 22:20 ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-omap; +Cc: devicetree, Kevin Hilman, linux-arm-kernel, devicetree-discuss

This is v4 of the OPP50 (VDD CORE 0.95V during suspend) patch set.

Adjusting voltages to this lower operating point during suspend saves
additional power. This operating point can only be reached when SDRAM is
in self refresh and certain DPLLs have been put into bypass mode. This
means that the code to change the regulator to run at the correct voltage
must be run from either SRAM or the Cortex-M3 (CM3) PM co-processor must
perform the action.

As different boards will power VDD CORE through different methods, the
necessary steps must be contained within the device tree. In order to
accommodate this, additional device tree properties have been created that
can be placed in I2C bus nodes. The properties give a sequence of I2C
commands that should be run at suspend and resume time.

The purpose and method of executing these sequences is left up to each
platform. In the case of the am33xx, the CM3 firmware writes out the
simple I2C sequences.

Each sequence is a series of I2C write commands. The first byte is the
length of the write, the second byte the I2C device to address, and the
following bytes are the message.

Example:

i2c0: i2c@44e0b000 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c0_pins>;

	status = "okay";
	clock-frequency = <400000>;
 
	/* Set OPP50 (0.95V) for VDD core */
	sleep_sequence = /bits/ 8 <
		0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
	>;

	/* Set OPP100 (1.10V) for VDD core */
	wake_sequence = /bits/ 8 <
		0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
	>;

	tps: tps@2d {
		reg = <0x2d>;
	};
};

In the above example, the sequence "0x25 0x1f" is written to the I2C
device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that as
a write to a register at address 0x25.

I'd really like to get some feedback on the devicetree bindings.

The patch set depends on the latest am335x suspend resume patch set from Dave
Gerlach[1], which also depends on the latest Mailbox patch set from Suman
Anna[2], and the latest CM3 firmware[3].

Changes since v1:
* Rebased onto new am335x PM branch
* Changed to use 5th param register

Changes since v2:
* Pass bus speed in kHz to M3 firmware

Changes since v3:
* Rebase to Dave Gerlach's am335x suspend/resume patch set
* Add device tree documentation
* Add dts changes for evmsk and gp evm

[1] http://comments.gmane.org/gmane.linux.ports.arm.omap/102561
[2] http://comments.gmane.org/gmane.linux.ports.arm.kernel/258196
[3] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

Russ Dill (4):
  ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
  ARM: dts: add AM33XX vdd core opp50 suspend for AM335X GP EVM.
  ARM: dts: AM33XX vdd core opp50 suspend for EVM-SK

 .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
 arch/arm/boot/dts/am335x-bone.dts                  | 25 +++++-
 arch/arm/boot/dts/am335x-evm.dts                   | 10 +++
 arch/arm/boot/dts/am335x-evmsk.dts                 | 10 +++
 arch/arm/mach-omap2/control.c                      |  1 +
 arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h                       |  2 +
 arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
 8 files changed, 230 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt

-- 
1.8.3.2


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-13 22:20 ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

This is v4 of the OPP50 (VDD CORE 0.95V during suspend) patch set.

Adjusting voltages to this lower operating point during suspend saves
additional power. This operating point can only be reached when SDRAM is
in self refresh and certain DPLLs have been put into bypass mode. This
means that the code to change the regulator to run at the correct voltage
must be run from either SRAM or the Cortex-M3 (CM3) PM co-processor must
perform the action.

As different boards will power VDD CORE through different methods, the
necessary steps must be contained within the device tree. In order to
accommodate this, additional device tree properties have been created that
can be placed in I2C bus nodes. The properties give a sequence of I2C
commands that should be run at suspend and resume time.

The purpose and method of executing these sequences is left up to each
platform. In the case of the am33xx, the CM3 firmware writes out the
simple I2C sequences.

Each sequence is a series of I2C write commands. The first byte is the
length of the write, the second byte the I2C device to address, and the
following bytes are the message.

Example:

i2c0: i2c at 44e0b000 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c0_pins>;

	status = "okay";
	clock-frequency = <400000>;
 
	/* Set OPP50 (0.95V) for VDD core */
	sleep_sequence = /bits/ 8 <
		0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
	>;

	/* Set OPP100 (1.10V) for VDD core */
	wake_sequence = /bits/ 8 <
		0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
	>;

	tps: tps at 2d {
		reg = <0x2d>;
	};
};

In the above example, the sequence "0x25 0x1f" is written to the I2C
device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that as
a write to a register at address 0x25.

I'd really like to get some feedback on the devicetree bindings.

The patch set depends on the latest am335x suspend resume patch set from Dave
Gerlach[1], which also depends on the latest Mailbox patch set from Suman
Anna[2], and the latest CM3 firmware[3].

Changes since v1:
* Rebased onto new am335x PM branch
* Changed to use 5th param register

Changes since v2:
* Pass bus speed in kHz to M3 firmware

Changes since v3:
* Rebase to Dave Gerlach's am335x suspend/resume patch set
* Add device tree documentation
* Add dts changes for evmsk and gp evm

[1] http://comments.gmane.org/gmane.linux.ports.arm.omap/102561
[2] http://comments.gmane.org/gmane.linux.ports.arm.kernel/258196
[3] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

Russ Dill (4):
  ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
  ARM: dts: add AM33XX vdd core opp50 suspend for AM335X GP EVM.
  ARM: dts: AM33XX vdd core opp50 suspend for EVM-SK

 .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
 arch/arm/boot/dts/am335x-bone.dts                  | 25 +++++-
 arch/arm/boot/dts/am335x-evm.dts                   | 10 +++
 arch/arm/boot/dts/am335x-evmsk.dts                 | 10 +++
 arch/arm/mach-omap2/control.c                      |  1 +
 arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h                       |  2 +
 arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
 8 files changed, 230 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt

-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-13 22:20 ` Russ Dill
@ 2013-08-13 22:20   ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-omap; +Cc: devicetree, Kevin Hilman, linux-arm-kernel, devicetree-discuss

Changes since v1:
* Rebased onto new am335x PM branch
* Changed to use 5th param register

Changes since v2:
* Passes I2C bus speed in kHz to M3 firmware

Changes since v3:
* Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
* Additional comments
* Added device-tree binding documentation

This patch adds the ability to pass an I2C sleep sequence and wake sequence
to the Cortex-M3. This is useful for adjusting voltages during sleep that
cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
support is required.

Each sequence is a series of I2C transfers in the form:

u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...

The length indicates the number of bytes to transfer, including the register
address. The length of each transfer is limited by the I2C buffer size of
32 bytes.

The sequences are taken from the i2c1 node in the device tree. The property
name for the sleep sequence is "sleep_sequence" and the property name for
the wake sequence is "wake_sequence". Each property should be an array of
bytes.

No actions are performed if the properties are not present in the device
tree.

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
 arch/arm/mach-omap2/control.c                      |  1 +
 arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h                       |  2 +
 arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
 5 files changed, 186 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
new file mode 100644
index 0000000..af19372
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
@@ -0,0 +1,44 @@
+I2C suspend/resume sequences
+
+This provides the ability for a simple I2C sequence to be written at
+suspend time and resume time. This is for sequences that cannot be written
+by the I2C bus driver for reasons such as needing to be run from SRAM
+or needing to be written by firmware.
+
+The sequence is composed of messages. Each message contains a length byte,
+an address byte, and then the message.
+
+Optional properties:
+- sleep_sequence
+	I2C sequence to write during suspend
+
+- wake_sequence
+	I2C sequence to write during wake
+
+Examples :
+
+i2c0: i2c@0 {
+	/* Set OPP50 (0.95V) for VDD core */
+	sleep_sequence = /bits/ 8 <
+		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+	>;
+
+	/* Set OPP100 (1.10V) for VDD core */
+	wake_sequence = /bits/ 8 <
+		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+	>;
+}
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 934041a..dfbd5f0 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
 	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
 	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
 	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+	omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
 }
 
 int am33xx_pm_status(void)
diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
index d291c76..8880da3 100644
--- a/arch/arm/mach-omap2/pm33xx.c
+++ b/arch/arm/mach-omap2/pm33xx.c
@@ -29,6 +29,7 @@
 #include <linux/ti_emif.h>
 #include <linux/omap-mailbox.h>
 
+#include <asm/unaligned.h>
 #include <asm/suspend.h>
 #include <asm/proc-fns.h>
 #include <asm/sizes.h>
@@ -50,6 +51,10 @@
 static void __iomem *am33xx_emif_base;
 static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
 static struct clockdomain *gfx_l4ls_clkdm;
+static char *am33xx_i2c_sleep_sequence;
+static char *am33xx_i2c_wake_sequence;
+static size_t i2c_sleep_sequence_sz;
+static size_t i2c_wake_sequence_sz;
 
 struct wakeup_src wakeups[] = {
 	{.irq_nr = 35,	.src = "USB0_PHY"},
@@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
 static int am33xx_pm_begin(suspend_state_t state)
 {
 	int i;
+	unsigned long param4;
+	int pos;
 
 	cpu_idle_poll_ctrl(true);
 
+	param4 = DS_IPC_DEFAULT;
+
+	wkup_m3_reset_data_pos();
+	if (am33xx_i2c_sleep_sequence) {
+		pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
+						i2c_sleep_sequence_sz);
+		/* Lower 16 bits stores offset to sleep sequence */
+		param4 &= ~0xffff;
+		param4 |= pos;
+	}
+
+	if (am33xx_i2c_wake_sequence) {
+		pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
+						i2c_wake_sequence_sz);
+		/* Upper 16 bits stores offset to wake sequence */
+		param4 &= ~0xffff0000;
+		param4 |= pos << 16;
+	}
+
 	am33xx_pm->ipc.sleep_mode	= IPC_CMD_DS0;
 	am33xx_pm->ipc.param1		= DS_IPC_DEFAULT;
 	am33xx_pm->ipc.param2		= DS_IPC_DEFAULT;
+	am33xx_pm->ipc.param4		= param4;
 
 	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
 
@@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
 	return 0;
 }
 
+static int __init am33xx_setup_sleep_sequence(void)
+{
+	int ret;
+	int sz;
+	const void *prop;
+	struct device *dev;
+	u32 freq_hz = 100000;
+	unsigned short freq_khz;
+
+	/*
+	 * We put the device tree node in the I2C controller that will
+	 * be sending the sequence. i2c1 is the only controller that can
+	 * be accessed by the firmware as it is the only controller in the
+	 * WKUP domain.
+	 */
+	dev = omap_device_get_by_hwmod_name("i2c1");
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
+	freq_khz = freq_hz / 1000;
+
+	prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
+	if (prop) {
+		/*
+		 * Length is sequence length + 2 bytes for freq_khz, and 1
+		 * byte for terminator.
+		 */
+		am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
+		if (!am33xx_i2c_sleep_sequence)
+			return -ENOMEM;
+		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
+		memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
+		i2c_sleep_sequence_sz = sz + 3;
+	}
+
+	prop = of_get_property(dev->of_node, "wake_sequence", &sz);
+	if (prop) {
+		am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
+		if (!am33xx_i2c_wake_sequence) {
+			ret = -ENOMEM;
+			goto cleanup_sleep;
+		}
+		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
+		memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
+		i2c_wake_sequence_sz = sz + 3;
+	}
+
+	return 0;
+
+cleanup_sleep:
+	kfree(am33xx_i2c_sleep_sequence);
+	am33xx_i2c_sleep_sequence = NULL;
+	return ret;
+}
+
 int __init am33xx_pm_init(void)
 {
 	int ret;
@@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
 		}
 	}
 
+	ret = am33xx_setup_sleep_sequence();
+	if (ret) {
+		pr_err("Error fetching I2C sleep/wake sequence\n");
+		goto err;
+	}
+
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
 	/* CEFUSE domain can be turned off post bootup */
diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
index befdd11..d0f08a5 100644
--- a/arch/arm/mach-omap2/pm33xx.h
+++ b/arch/arm/mach-omap2/pm33xx.h
@@ -52,6 +52,8 @@ struct forced_standby_module {
 };
 
 int wkup_m3_copy_code(const u8 *data, size_t size);
+void wkup_m3_reset_data_pos(void);
+int wkup_m3_copy_data(const u8 *data, size_t size);
 int wkup_m3_prepare(void);
 void wkup_m3_register_txev_handler(void (*txev_handler)(void));
 
diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
index 8eaa7f3..a541de9 100644
--- a/arch/arm/mach-omap2/wkup_m3.c
+++ b/arch/arm/mach-omap2/wkup_m3.c
@@ -35,6 +35,9 @@
 struct wkup_m3_context {
 	struct device	*dev;
 	void __iomem	*code;
+	void __iomem	*data;
+	void __iomem	*data_end;
+	size_t		data_size;
 	void (*txev_handler)(void);
 };
 
@@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
 	return 0;
 }
 
+/*
+ * This pair of functions allows data to be stuffed into the end of the
+ * CM3 data memory. This is currently used for passing the I2C sleep/wake
+ * sequences to the firmware.
+ */
+
+/* Clear out the pointer for data stored at the end of DMEM */
+void wkup_m3_reset_data_pos(void)
+{
+	wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
+}
+
+/*
+ * Store a block of data at the end of DMEM, return the offset within DMEM
+ * that the data is stored at, or -ENOMEM if the data did not fit
+ */
+int wkup_m3_copy_data(const u8 *data, size_t size)
+{
+	if (wkup_m3->data + size > wkup_m3->data_end)
+		return -ENOMEM;
+	wkup_m3->data_end -= size;
+	memcpy_toio(wkup_m3->data_end, data, size);
+	return wkup_m3->data_end - wkup_m3->data;
+}
 
 void wkup_m3_register_txev_handler(void (*txev_handler)(void))
 {
@@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
 static int wkup_m3_probe(struct platform_device *pdev)
 {
 	int irq, ret = 0;
-	struct resource *mem;
+	struct resource *umem, *dmem;
 
 	pm_runtime_enable(&pdev->dev);
 
@@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (!irq) {
-		dev_err(wkup_m3->dev, "no irq resource\n");
+		dev_err(&pdev->dev, "no irq resource\n");
+		ret = -ENXIO;
+		goto err;
+	}
+
+	umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!umem) {
+		dev_err(&pdev->dev, "no UMEM resource\n");
 		ret = -ENXIO;
 		goto err;
 	}
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(wkup_m3->dev, "no memory resource\n");
+	dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!dmem) {
+		dev_err(&pdev->dev, "no DMEM resource\n");
 		ret = -ENXIO;
 		goto err;
 	}
@@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
 
 	wkup_m3->dev = &pdev->dev;
 
-	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
+	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
+	if (!wkup_m3->code) {
+		dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
+		ret = -EADDRNOTAVAIL;
+		goto err;
+	}
+
+	wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
 	if (!wkup_m3->code) {
-		dev_err(wkup_m3->dev, "could not ioremap\n");
+		dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
 		ret = -EADDRNOTAVAIL;
 		goto err;
 	}
+	wkup_m3->data_size = resource_size(dmem);
+	wkup_m3_reset_data_pos();
 
 	ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
 		  IRQF_DISABLED, "wkup_m3_txev", NULL);
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-13 22:20   ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

Changes since v1:
* Rebased onto new am335x PM branch
* Changed to use 5th param register

Changes since v2:
* Passes I2C bus speed in kHz to M3 firmware

Changes since v3:
* Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
* Additional comments
* Added device-tree binding documentation

This patch adds the ability to pass an I2C sleep sequence and wake sequence
to the Cortex-M3. This is useful for adjusting voltages during sleep that
cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
support is required.

Each sequence is a series of I2C transfers in the form:

u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...

The length indicates the number of bytes to transfer, including the register
address. The length of each transfer is limited by the I2C buffer size of
32 bytes.

The sequences are taken from the i2c1 node in the device tree. The property
name for the sleep sequence is "sleep_sequence" and the property name for
the wake sequence is "wake_sequence". Each property should be an array of
bytes.

No actions are performed if the properties are not present in the device
tree.

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
 arch/arm/mach-omap2/control.c                      |  1 +
 arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h                       |  2 +
 arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
 5 files changed, 186 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
new file mode 100644
index 0000000..af19372
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
@@ -0,0 +1,44 @@
+I2C suspend/resume sequences
+
+This provides the ability for a simple I2C sequence to be written at
+suspend time and resume time. This is for sequences that cannot be written
+by the I2C bus driver for reasons such as needing to be run from SRAM
+or needing to be written by firmware.
+
+The sequence is composed of messages. Each message contains a length byte,
+an address byte, and then the message.
+
+Optional properties:
+- sleep_sequence
+	I2C sequence to write during suspend
+
+- wake_sequence
+	I2C sequence to write during wake
+
+Examples :
+
+i2c0: i2c at 0 {
+	/* Set OPP50 (0.95V) for VDD core */
+	sleep_sequence = /bits/ 8 <
+		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+	>;
+
+	/* Set OPP100 (1.10V) for VDD core */
+	wake_sequence = /bits/ 8 <
+		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+	>;
+}
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 934041a..dfbd5f0 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
 	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
 	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
 	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+	omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
 }
 
 int am33xx_pm_status(void)
diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
index d291c76..8880da3 100644
--- a/arch/arm/mach-omap2/pm33xx.c
+++ b/arch/arm/mach-omap2/pm33xx.c
@@ -29,6 +29,7 @@
 #include <linux/ti_emif.h>
 #include <linux/omap-mailbox.h>
 
+#include <asm/unaligned.h>
 #include <asm/suspend.h>
 #include <asm/proc-fns.h>
 #include <asm/sizes.h>
@@ -50,6 +51,10 @@
 static void __iomem *am33xx_emif_base;
 static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
 static struct clockdomain *gfx_l4ls_clkdm;
+static char *am33xx_i2c_sleep_sequence;
+static char *am33xx_i2c_wake_sequence;
+static size_t i2c_sleep_sequence_sz;
+static size_t i2c_wake_sequence_sz;
 
 struct wakeup_src wakeups[] = {
 	{.irq_nr = 35,	.src = "USB0_PHY"},
@@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
 static int am33xx_pm_begin(suspend_state_t state)
 {
 	int i;
+	unsigned long param4;
+	int pos;
 
 	cpu_idle_poll_ctrl(true);
 
+	param4 = DS_IPC_DEFAULT;
+
+	wkup_m3_reset_data_pos();
+	if (am33xx_i2c_sleep_sequence) {
+		pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
+						i2c_sleep_sequence_sz);
+		/* Lower 16 bits stores offset to sleep sequence */
+		param4 &= ~0xffff;
+		param4 |= pos;
+	}
+
+	if (am33xx_i2c_wake_sequence) {
+		pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
+						i2c_wake_sequence_sz);
+		/* Upper 16 bits stores offset to wake sequence */
+		param4 &= ~0xffff0000;
+		param4 |= pos << 16;
+	}
+
 	am33xx_pm->ipc.sleep_mode	= IPC_CMD_DS0;
 	am33xx_pm->ipc.param1		= DS_IPC_DEFAULT;
 	am33xx_pm->ipc.param2		= DS_IPC_DEFAULT;
+	am33xx_pm->ipc.param4		= param4;
 
 	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
 
@@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
 	return 0;
 }
 
+static int __init am33xx_setup_sleep_sequence(void)
+{
+	int ret;
+	int sz;
+	const void *prop;
+	struct device *dev;
+	u32 freq_hz = 100000;
+	unsigned short freq_khz;
+
+	/*
+	 * We put the device tree node in the I2C controller that will
+	 * be sending the sequence. i2c1 is the only controller that can
+	 * be accessed by the firmware as it is the only controller in the
+	 * WKUP domain.
+	 */
+	dev = omap_device_get_by_hwmod_name("i2c1");
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
+	freq_khz = freq_hz / 1000;
+
+	prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
+	if (prop) {
+		/*
+		 * Length is sequence length + 2 bytes for freq_khz, and 1
+		 * byte for terminator.
+		 */
+		am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
+		if (!am33xx_i2c_sleep_sequence)
+			return -ENOMEM;
+		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
+		memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
+		i2c_sleep_sequence_sz = sz + 3;
+	}
+
+	prop = of_get_property(dev->of_node, "wake_sequence", &sz);
+	if (prop) {
+		am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
+		if (!am33xx_i2c_wake_sequence) {
+			ret = -ENOMEM;
+			goto cleanup_sleep;
+		}
+		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
+		memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
+		i2c_wake_sequence_sz = sz + 3;
+	}
+
+	return 0;
+
+cleanup_sleep:
+	kfree(am33xx_i2c_sleep_sequence);
+	am33xx_i2c_sleep_sequence = NULL;
+	return ret;
+}
+
 int __init am33xx_pm_init(void)
 {
 	int ret;
@@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
 		}
 	}
 
+	ret = am33xx_setup_sleep_sequence();
+	if (ret) {
+		pr_err("Error fetching I2C sleep/wake sequence\n");
+		goto err;
+	}
+
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
 	/* CEFUSE domain can be turned off post bootup */
diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
index befdd11..d0f08a5 100644
--- a/arch/arm/mach-omap2/pm33xx.h
+++ b/arch/arm/mach-omap2/pm33xx.h
@@ -52,6 +52,8 @@ struct forced_standby_module {
 };
 
 int wkup_m3_copy_code(const u8 *data, size_t size);
+void wkup_m3_reset_data_pos(void);
+int wkup_m3_copy_data(const u8 *data, size_t size);
 int wkup_m3_prepare(void);
 void wkup_m3_register_txev_handler(void (*txev_handler)(void));
 
diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
index 8eaa7f3..a541de9 100644
--- a/arch/arm/mach-omap2/wkup_m3.c
+++ b/arch/arm/mach-omap2/wkup_m3.c
@@ -35,6 +35,9 @@
 struct wkup_m3_context {
 	struct device	*dev;
 	void __iomem	*code;
+	void __iomem	*data;
+	void __iomem	*data_end;
+	size_t		data_size;
 	void (*txev_handler)(void);
 };
 
@@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
 	return 0;
 }
 
+/*
+ * This pair of functions allows data to be stuffed into the end of the
+ * CM3 data memory. This is currently used for passing the I2C sleep/wake
+ * sequences to the firmware.
+ */
+
+/* Clear out the pointer for data stored at the end of DMEM */
+void wkup_m3_reset_data_pos(void)
+{
+	wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
+}
+
+/*
+ * Store a block of data at the end of DMEM, return the offset within DMEM
+ * that the data is stored at, or -ENOMEM if the data did not fit
+ */
+int wkup_m3_copy_data(const u8 *data, size_t size)
+{
+	if (wkup_m3->data + size > wkup_m3->data_end)
+		return -ENOMEM;
+	wkup_m3->data_end -= size;
+	memcpy_toio(wkup_m3->data_end, data, size);
+	return wkup_m3->data_end - wkup_m3->data;
+}
 
 void wkup_m3_register_txev_handler(void (*txev_handler)(void))
 {
@@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
 static int wkup_m3_probe(struct platform_device *pdev)
 {
 	int irq, ret = 0;
-	struct resource *mem;
+	struct resource *umem, *dmem;
 
 	pm_runtime_enable(&pdev->dev);
 
@@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (!irq) {
-		dev_err(wkup_m3->dev, "no irq resource\n");
+		dev_err(&pdev->dev, "no irq resource\n");
+		ret = -ENXIO;
+		goto err;
+	}
+
+	umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!umem) {
+		dev_err(&pdev->dev, "no UMEM resource\n");
 		ret = -ENXIO;
 		goto err;
 	}
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(wkup_m3->dev, "no memory resource\n");
+	dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!dmem) {
+		dev_err(&pdev->dev, "no DMEM resource\n");
 		ret = -ENXIO;
 		goto err;
 	}
@@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
 
 	wkup_m3->dev = &pdev->dev;
 
-	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
+	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
+	if (!wkup_m3->code) {
+		dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
+		ret = -EADDRNOTAVAIL;
+		goto err;
+	}
+
+	wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
 	if (!wkup_m3->code) {
-		dev_err(wkup_m3->dev, "could not ioremap\n");
+		dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
 		ret = -EADDRNOTAVAIL;
 		goto err;
 	}
+	wkup_m3->data_size = resource_size(dmem);
+	wkup_m3_reset_data_pos();
 
 	ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
 		  IRQF_DISABLED, "wkup_m3_txev", NULL);
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
  2013-08-13 22:20 ` Russ Dill
@ 2013-08-13 22:20   ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-omap; +Cc: devicetree, Kevin Hilman, linux-arm-kernel, devicetree-discuss

Changes since v1:
* Rebased onto new am335x PM branch

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
are written out by the Cortex-M3.

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 444b4ed..3f6528d 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -127,10 +127,33 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+			>;
+
 			tps: tps@24 {
 				reg = <0x24>;
 			};
-
 		};
 	};
 
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
@ 2013-08-13 22:20   ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

Changes since v1:
* Rebased onto new am335x PM branch

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
are written out by the Cortex-M3.

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 444b4ed..3f6528d 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -127,10 +127,33 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
+				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
+				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
+				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
+				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
+				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
+			>;
+
 			tps: tps at 24 {
 				reg = <0x24>;
 			};
-
 		};
 	};
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 3/4] ARM: dts: add AM33XX vdd core opp50 suspend for AM335X GP EVM.
  2013-08-13 22:20 ` Russ Dill
@ 2013-08-13 22:20   ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-omap; +Cc: devicetree, Kevin Hilman, linux-arm-kernel, devicetree-discuss

From: Hebbar, Gururaja <gururaja.hebbar@ti.com>

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the EVM layout and PMIC, the TPS65910. The sequences
are written out by the Cortex-M3.

Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 3aee1a4..81ce169 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -166,6 +166,16 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
+			>;
+
 			tps: tps@2d {
 				reg = <0x2d>;
 			};
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 3/4] ARM: dts: add AM33XX vdd core opp50 suspend for AM335X GP EVM.
@ 2013-08-13 22:20   ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

From: Hebbar, Gururaja <gururaja.hebbar@ti.com>

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the EVM layout and PMIC, the TPS65910. The sequences
are written out by the Cortex-M3.

Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-evm.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 3aee1a4..81ce169 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -166,6 +166,16 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
+			>;
+
 			tps: tps at 2d {
 				reg = <0x2d>;
 			};
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 4/4] ARM: dts: AM33XX vdd core opp50 suspend for EVM-SK
  2013-08-13 22:20 ` Russ Dill
@ 2013-08-13 22:20   ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-omap; +Cc: devicetree, Kevin Hilman, linux-arm-kernel, devicetree-discuss

From: Hebbar, Gururaja <gururaja.hebbar@ti.com>

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the EVM-SK layout and PMIC, the TPS65910. The sequences
are written out by the Cortex-M3.

Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-evmsk.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 0c8ad17..704bbb3 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -174,6 +174,16 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
+			>;
+
 			tps: tps@2d {
 				reg = <0x2d>;
 			};
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH v4 4/4] ARM: dts: AM33XX vdd core opp50 suspend for EVM-SK
@ 2013-08-13 22:20   ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-13 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

From: Hebbar, Gururaja <gururaja.hebbar@ti.com>

This adds a sleep and wake sequence to set the VDD core voltage to the
OPP50 level, 0.950V. This saves power during suspend. The sequences are
specific to the EVM-SK layout and PMIC, the TPS65910. The sequences
are written out by the Cortex-M3.

Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/boot/dts/am335x-evmsk.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 0c8ad17..704bbb3 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -174,6 +174,16 @@
 			status = "okay";
 			clock-frequency = <400000>;
 
+			/* Set OPP50 (0.95V) for VDD core */
+			sleep_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
+			>;
+
+			/* Set OPP100 (1.10V) for VDD core */
+			wake_sequence = /bits/ 8 <
+				0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
+			>;
+
 			tps: tps at 2d {
 				reg = <0x2d>;
 			};
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
  2013-08-13 22:20   ` Russ Dill
@ 2013-08-14  8:59     ` Gururaja Hebbar
  -1 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-14  8:59 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On 8/14/2013 3:50 AM, Russ Dill wrote:
> Changes since v1:
> * Rebased onto new am335x PM branch
> 
> This adds a sleep and wake sequence to set the VDD core voltage to the
> OPP50 level, 0.950V. This saves power during suspend. The sequences are
> specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
> are written out by the Cortex-M3.
> 
> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
> ---
>  arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
> index 444b4ed..3f6528d 100644
> --- a/arch/arm/boot/dts/am335x-bone.dts
> +++ b/arch/arm/boot/dts/am335x-bone.dts
> @@ -127,10 +127,33 @@
>  			status = "okay";
>  			clock-frequency = <400000>;
>  
> +			/* Set OPP50 (0.95V) for VDD core */
> +			sleep_sequence = /bits/ 8 <

For user readability, can you mention the PMIC used here as a comment?

> +				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +			>;
> +
> +			/* Set OPP100 (1.10V) for VDD core */
> +			wake_sequence = /bits/ 8 <
> +				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +			>;
> +
>  			tps: tps@24 {
>  				reg = <0x24>;
>  			};
> -
>  		};
>  	};
>  
> 

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
@ 2013-08-14  8:59     ` Gururaja Hebbar
  0 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-14  8:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 8/14/2013 3:50 AM, Russ Dill wrote:
> Changes since v1:
> * Rebased onto new am335x PM branch
> 
> This adds a sleep and wake sequence to set the VDD core voltage to the
> OPP50 level, 0.950V. This saves power during suspend. The sequences are
> specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
> are written out by the Cortex-M3.
> 
> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
> ---
>  arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
> index 444b4ed..3f6528d 100644
> --- a/arch/arm/boot/dts/am335x-bone.dts
> +++ b/arch/arm/boot/dts/am335x-bone.dts
> @@ -127,10 +127,33 @@
>  			status = "okay";
>  			clock-frequency = <400000>;
>  
> +			/* Set OPP50 (0.95V) for VDD core */
> +			sleep_sequence = /bits/ 8 <

For user readability, can you mention the PMIC used here as a comment?

> +				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +				0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +			>;
> +
> +			/* Set OPP100 (1.10V) for VDD core */
> +			wake_sequence = /bits/ 8 <
> +				0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +				0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +				0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +				0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +				0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +			>;
> +
>  			tps: tps at 24 {
>  				reg = <0x24>;
>  			};
> -
>  		};
>  	};
>  
> 

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-13 22:20   ` Russ Dill
@ 2013-08-14 10:18     ` Gururaja Hebbar
  -1 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-14 10:18 UTC (permalink / raw)
  To: Russ Dill
  Cc: linux-omap, devicetree, Kevin Hilman, linux-arm-kernel,
	devicetree-discuss

On 8/14/2013 3:50 AM, Russ Dill wrote:
> Changes since v1:
> * Rebased onto new am335x PM branch
> * Changed to use 5th param register
> 
> Changes since v2:
> * Passes I2C bus speed in kHz to M3 firmware
> 
> Changes since v3:
> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
> * Additional comments
> * Added device-tree binding documentation

AFAIK, Change logs should come below scissors line (---).
However there was some discussion to keep it in the commit message.
Don't know what happened to it finally. But till date, all revision
patch set has the change log under the scissor line.

> 
> This patch adds the ability to pass an I2C sleep sequence and wake sequence
> to the Cortex-M3. This is useful for adjusting voltages during sleep that
> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
> support is required.
> 
> Each sequence is a series of I2C transfers in the form:
> 
> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
> 
> The length indicates the number of bytes to transfer, including the register
> address. The length of each transfer is limited by the I2C buffer size of
> 32 bytes.
> 
> The sequences are taken from the i2c1 node in the device tree. The property
> name for the sleep sequence is "sleep_sequence" and the property name for
> the wake sequence is "wake_sequence". Each property should be an array of
> bytes.
> 
> No actions are performed if the properties are not present in the device
> tree.
> 
> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
> ---
>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>  arch/arm/mach-omap2/control.c                      |  1 +
>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>  5 files changed, 186 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> new file mode 100644
> index 0000000..af19372
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> @@ -0,0 +1,44 @@
> +I2C suspend/resume sequences
> +
> +This provides the ability for a simple I2C sequence to be written at
> +suspend time and resume time. This is for sequences that cannot be written
> +by the I2C bus driver for reasons such as needing to be run from SRAM
> +or needing to be written by firmware.
> +
> +The sequence is composed of messages. Each message contains a length byte,
> +an address byte, and then the message.
> +
> +Optional properties:
> +- sleep_sequence
> +	I2C sequence to write during suspend
> +
> +- wake_sequence
> +	I2C sequence to write during wake
> +
> +Examples :
> +
> +i2c0: i2c@0 {
> +	/* Set OPP50 (0.95V) for VDD core */
> +	sleep_sequence = /bits/ 8 <
> +		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +	>;

This data is not related to i2c. Right? Then why is it under i2c dt node?

There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
respective boards). Can't these details go under those nodes?

> +
> +	/* Set OPP100 (1.10V) for VDD core */
> +	wake_sequence = /bits/ 8 <
> +		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +	>;
> +}
> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
> index 934041a..dfbd5f0 100644
> --- a/arch/arm/mach-omap2/control.c
> +++ b/arch/arm/mach-omap2/control.c
> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>  	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>  	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>  	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
> +	omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>  }
>  
>  int am33xx_pm_status(void)
> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
> index d291c76..8880da3 100644
> --- a/arch/arm/mach-omap2/pm33xx.c
> +++ b/arch/arm/mach-omap2/pm33xx.c
> @@ -29,6 +29,7 @@
>  #include <linux/ti_emif.h>
>  #include <linux/omap-mailbox.h>
>  
> +#include <asm/unaligned.h>
>  #include <asm/suspend.h>
>  #include <asm/proc-fns.h>
>  #include <asm/sizes.h>
> @@ -50,6 +51,10 @@
>  static void __iomem *am33xx_emif_base;
>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>  static struct clockdomain *gfx_l4ls_clkdm;
> +static char *am33xx_i2c_sleep_sequence;
> +static char *am33xx_i2c_wake_sequence;
> +static size_t i2c_sleep_sequence_sz;
> +static size_t i2c_wake_sequence_sz;
>  
>  struct wakeup_src wakeups[] = {
>  	{.irq_nr = 35,	.src = "USB0_PHY"},
> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>  static int am33xx_pm_begin(suspend_state_t state)
>  {
>  	int i;
> +	unsigned long param4;
> +	int pos;
>  
>  	cpu_idle_poll_ctrl(true);
>  
> +	param4 = DS_IPC_DEFAULT;
> +
> +	wkup_m3_reset_data_pos();
> +	if (am33xx_i2c_sleep_sequence) {
> +		pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
> +						i2c_sleep_sequence_sz);

Why do we need to copy this data (same constant data) on every iteration?

> +		/* Lower 16 bits stores offset to sleep sequence */
> +		param4 &= ~0xffff;
> +		param4 |= pos;
> +	}
> +
> +	if (am33xx_i2c_wake_sequence) {
> +		pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
> +						i2c_wake_sequence_sz);
> +		/* Upper 16 bits stores offset to wake sequence */
> +		param4 &= ~0xffff0000;
> +		param4 |= pos << 16;
> +	}
> +

Seems above entire change can be done only once.

>  	am33xx_pm->ipc.sleep_mode	= IPC_CMD_DS0;
>  	am33xx_pm->ipc.param1		= DS_IPC_DEFAULT;
>  	am33xx_pm->ipc.param2		= DS_IPC_DEFAULT;
> +	am33xx_pm->ipc.param4		= param4;
>  
>  	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>  
> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>  	return 0;
>  }
>  
> +static int __init am33xx_setup_sleep_sequence(void)
> +{
> +	int ret;
> +	int sz;
> +	const void *prop;
> +	struct device *dev;
> +	u32 freq_hz = 100000;

Magic number?

> +	unsigned short freq_khz;
> +
> +	/*
> +	 * We put the device tree node in the I2C controller that will
> +	 * be sending the sequence. i2c1 is the only controller that can
> +	 * be accessed by the firmware as it is the only controller in the
> +	 * WKUP domain.

and on which the PMIC sits I believe?

> +	 */
> +	dev = omap_device_get_by_hwmod_name("i2c1");
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
> +	freq_khz = freq_hz / 1000;

Magic number?

> +
> +	prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
> +	if (prop) {
> +		/*
> +		 * Length is sequence length + 2 bytes for freq_khz, and 1
> +		 * byte for terminator.
> +		 */
> +		am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
> +		if (!am33xx_i2c_sleep_sequence)
> +			return -ENOMEM;
> +		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
> +		memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);

so, looking at entire code, it seems there is 3 memory space for same
data (or 1 original + 2 copy)

1. in DT
2. in am33xx_i2c_[sleep/wake]_sequence
3. in SRAm by call to wkup_m3_copy_data()

why not directly copy to SRAM from DT?

> +		i2c_sleep_sequence_sz = sz + 3;
> +	}
> +
> +	prop = of_get_property(dev->of_node, "wake_sequence", &sz);
> +	if (prop) {
> +		am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
> +		if (!am33xx_i2c_wake_sequence) {
> +			ret = -ENOMEM;
> +			goto cleanup_sleep;
> +		}
> +		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
> +		memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
> +		i2c_wake_sequence_sz = sz + 3;
> +	}
> +
> +	return 0;
> +
> +cleanup_sleep:
> +	kfree(am33xx_i2c_sleep_sequence);
> +	am33xx_i2c_sleep_sequence = NULL;
> +	return ret;
> +}
> +
>  int __init am33xx_pm_init(void)
>  {
>  	int ret;
> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>  		}
>  	}
>  
> +	ret = am33xx_setup_sleep_sequence();
> +	if (ret) {
> +		pr_err("Error fetching I2C sleep/wake sequence\n");
> +		goto err;
> +	}
> +
>  	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>  
>  	/* CEFUSE domain can be turned off post bootup */
> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
> index befdd11..d0f08a5 100644
> --- a/arch/arm/mach-omap2/pm33xx.h
> +++ b/arch/arm/mach-omap2/pm33xx.h
> @@ -52,6 +52,8 @@ struct forced_standby_module {
>  };
>  
>  int wkup_m3_copy_code(const u8 *data, size_t size);
> +void wkup_m3_reset_data_pos(void);
> +int wkup_m3_copy_data(const u8 *data, size_t size);
>  int wkup_m3_prepare(void);
>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>  
> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
> index 8eaa7f3..a541de9 100644
> --- a/arch/arm/mach-omap2/wkup_m3.c
> +++ b/arch/arm/mach-omap2/wkup_m3.c
> @@ -35,6 +35,9 @@
>  struct wkup_m3_context {
>  	struct device	*dev;
>  	void __iomem	*code;
> +	void __iomem	*data;
> +	void __iomem	*data_end;
> +	size_t		data_size;
>  	void (*txev_handler)(void);
>  };
>  
> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>  	return 0;
>  }
>  
> +/*
> + * This pair of functions allows data to be stuffed into the end of the
> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
> + * sequences to the firmware.
> + */
> +
> +/* Clear out the pointer for data stored at the end of DMEM */
> +void wkup_m3_reset_data_pos(void)
> +{
> +	wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
> +}
> +
> +/*
> + * Store a block of data at the end of DMEM, return the offset within DMEM
> + * that the data is stored at, or -ENOMEM if the data did not fit
> + */
> +int wkup_m3_copy_data(const u8 *data, size_t size)
> +{
> +	if (wkup_m3->data + size > wkup_m3->data_end)
> +		return -ENOMEM;
> +	wkup_m3->data_end -= size;
> +	memcpy_toio(wkup_m3->data_end, data, size);
> +	return wkup_m3->data_end - wkup_m3->data;
> +}
>  
>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>  {
> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>  static int wkup_m3_probe(struct platform_device *pdev)
>  {
>  	int irq, ret = 0;
> -	struct resource *mem;
> +	struct resource *umem, *dmem;
>  
>  	pm_runtime_enable(&pdev->dev);
>  
> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>  
>  	irq = platform_get_irq(pdev, 0);
>  	if (!irq) {
> -		dev_err(wkup_m3->dev, "no irq resource\n");
> +		dev_err(&pdev->dev, "no irq resource\n");

unrelated change?. Better to mention this as code cleanup in commit.

> +		ret = -ENXIO;
> +		goto err;
> +	}
> +
> +	umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!umem) {
> +		dev_err(&pdev->dev, "no UMEM resource\n");
>  		ret = -ENXIO;
>  		goto err;
>  	}
>  
> -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!mem) {
> -		dev_err(wkup_m3->dev, "no memory resource\n");
> +	dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!dmem) {
> +		dev_err(&pdev->dev, "no DMEM resource\n");
>  		ret = -ENXIO;
>  		goto err;
>  	}
> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>  
>  	wkup_m3->dev = &pdev->dev;
>  
> -	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
> +	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
> +	if (!wkup_m3->code) {
> +		dev_err(wkup_m3->dev, "could not ioremap UMEM\n");

why not use "pdev->dev" here?

> +		ret = -EADDRNOTAVAIL;
> +		goto err;
> +	}
> +
> +	wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>  	if (!wkup_m3->code) {

I believe this is just a copy/paste error. s/code/data

> -		dev_err(wkup_m3->dev, "could not ioremap\n");
> +		dev_err(wkup_m3->dev, "could not ioremap DMEM\n");

same as above.

>  		ret = -EADDRNOTAVAIL;
>  		goto err;
>  	}
> +	wkup_m3->data_size = resource_size(dmem);
> +	wkup_m3_reset_data_pos();
>  
>  	ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>  		  IRQF_DISABLED, "wkup_m3_txev", NULL);
> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
> linux-omap" in the body of a message to majordomo@vger.kernel.org More
> majordomo info at http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-14 10:18     ` Gururaja Hebbar
  0 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-14 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 8/14/2013 3:50 AM, Russ Dill wrote:
> Changes since v1:
> * Rebased onto new am335x PM branch
> * Changed to use 5th param register
> 
> Changes since v2:
> * Passes I2C bus speed in kHz to M3 firmware
> 
> Changes since v3:
> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
> * Additional comments
> * Added device-tree binding documentation

AFAIK, Change logs should come below scissors line (---).
However there was some discussion to keep it in the commit message.
Don't know what happened to it finally. But till date, all revision
patch set has the change log under the scissor line.

> 
> This patch adds the ability to pass an I2C sleep sequence and wake sequence
> to the Cortex-M3. This is useful for adjusting voltages during sleep that
> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
> support is required.
> 
> Each sequence is a series of I2C transfers in the form:
> 
> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
> 
> The length indicates the number of bytes to transfer, including the register
> address. The length of each transfer is limited by the I2C buffer size of
> 32 bytes.
> 
> The sequences are taken from the i2c1 node in the device tree. The property
> name for the sleep sequence is "sleep_sequence" and the property name for
> the wake sequence is "wake_sequence". Each property should be an array of
> bytes.
> 
> No actions are performed if the properties are not present in the device
> tree.
> 
> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
> ---
>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>  arch/arm/mach-omap2/control.c                      |  1 +
>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>  5 files changed, 186 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> new file mode 100644
> index 0000000..af19372
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
> @@ -0,0 +1,44 @@
> +I2C suspend/resume sequences
> +
> +This provides the ability for a simple I2C sequence to be written at
> +suspend time and resume time. This is for sequences that cannot be written
> +by the I2C bus driver for reasons such as needing to be run from SRAM
> +or needing to be written by firmware.
> +
> +The sequence is composed of messages. Each message contains a length byte,
> +an address byte, and then the message.
> +
> +Optional properties:
> +- sleep_sequence
> +	I2C sequence to write during suspend
> +
> +- wake_sequence
> +	I2C sequence to write during wake
> +
> +Examples :
> +
> +i2c0: i2c at 0 {
> +	/* Set OPP50 (0.95V) for VDD core */
> +	sleep_sequence = /bits/ 8 <
> +		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +		0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +	>;

This data is not related to i2c. Right? Then why is it under i2c dt node?

There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
respective boards). Can't these details go under those nodes?

> +
> +	/* Set OPP100 (1.10V) for VDD core */
> +	wake_sequence = /bits/ 8 <
> +		0x02 0x24 0x0b 0x6d /* Password unlock 1 */
> +		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +		0x02 0x24 0x0b 0x6d /* Password unlock 2 */
> +		0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 1 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +		0x02 0x24 0x0b 0x6c /* Password unlock 2 */
> +		0x02 0x24 0x11 0x86 /* Apply DCDC changes */
> +	>;
> +}
> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
> index 934041a..dfbd5f0 100644
> --- a/arch/arm/mach-omap2/control.c
> +++ b/arch/arm/mach-omap2/control.c
> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>  	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>  	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>  	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
> +	omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>  }
>  
>  int am33xx_pm_status(void)
> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
> index d291c76..8880da3 100644
> --- a/arch/arm/mach-omap2/pm33xx.c
> +++ b/arch/arm/mach-omap2/pm33xx.c
> @@ -29,6 +29,7 @@
>  #include <linux/ti_emif.h>
>  #include <linux/omap-mailbox.h>
>  
> +#include <asm/unaligned.h>
>  #include <asm/suspend.h>
>  #include <asm/proc-fns.h>
>  #include <asm/sizes.h>
> @@ -50,6 +51,10 @@
>  static void __iomem *am33xx_emif_base;
>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>  static struct clockdomain *gfx_l4ls_clkdm;
> +static char *am33xx_i2c_sleep_sequence;
> +static char *am33xx_i2c_wake_sequence;
> +static size_t i2c_sleep_sequence_sz;
> +static size_t i2c_wake_sequence_sz;
>  
>  struct wakeup_src wakeups[] = {
>  	{.irq_nr = 35,	.src = "USB0_PHY"},
> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>  static int am33xx_pm_begin(suspend_state_t state)
>  {
>  	int i;
> +	unsigned long param4;
> +	int pos;
>  
>  	cpu_idle_poll_ctrl(true);
>  
> +	param4 = DS_IPC_DEFAULT;
> +
> +	wkup_m3_reset_data_pos();
> +	if (am33xx_i2c_sleep_sequence) {
> +		pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
> +						i2c_sleep_sequence_sz);

Why do we need to copy this data (same constant data) on every iteration?

> +		/* Lower 16 bits stores offset to sleep sequence */
> +		param4 &= ~0xffff;
> +		param4 |= pos;
> +	}
> +
> +	if (am33xx_i2c_wake_sequence) {
> +		pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
> +						i2c_wake_sequence_sz);
> +		/* Upper 16 bits stores offset to wake sequence */
> +		param4 &= ~0xffff0000;
> +		param4 |= pos << 16;
> +	}
> +

Seems above entire change can be done only once.

>  	am33xx_pm->ipc.sleep_mode	= IPC_CMD_DS0;
>  	am33xx_pm->ipc.param1		= DS_IPC_DEFAULT;
>  	am33xx_pm->ipc.param2		= DS_IPC_DEFAULT;
> +	am33xx_pm->ipc.param4		= param4;
>  
>  	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>  
> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>  	return 0;
>  }
>  
> +static int __init am33xx_setup_sleep_sequence(void)
> +{
> +	int ret;
> +	int sz;
> +	const void *prop;
> +	struct device *dev;
> +	u32 freq_hz = 100000;

Magic number?

> +	unsigned short freq_khz;
> +
> +	/*
> +	 * We put the device tree node in the I2C controller that will
> +	 * be sending the sequence. i2c1 is the only controller that can
> +	 * be accessed by the firmware as it is the only controller in the
> +	 * WKUP domain.

and on which the PMIC sits I believe?

> +	 */
> +	dev = omap_device_get_by_hwmod_name("i2c1");
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
> +	freq_khz = freq_hz / 1000;

Magic number?

> +
> +	prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
> +	if (prop) {
> +		/*
> +		 * Length is sequence length + 2 bytes for freq_khz, and 1
> +		 * byte for terminator.
> +		 */
> +		am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
> +		if (!am33xx_i2c_sleep_sequence)
> +			return -ENOMEM;
> +		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
> +		memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);

so, looking at entire code, it seems there is 3 memory space for same
data (or 1 original + 2 copy)

1. in DT
2. in am33xx_i2c_[sleep/wake]_sequence
3. in SRAm by call to wkup_m3_copy_data()

why not directly copy to SRAM from DT?

> +		i2c_sleep_sequence_sz = sz + 3;
> +	}
> +
> +	prop = of_get_property(dev->of_node, "wake_sequence", &sz);
> +	if (prop) {
> +		am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
> +		if (!am33xx_i2c_wake_sequence) {
> +			ret = -ENOMEM;
> +			goto cleanup_sleep;
> +		}
> +		put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
> +		memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
> +		i2c_wake_sequence_sz = sz + 3;
> +	}
> +
> +	return 0;
> +
> +cleanup_sleep:
> +	kfree(am33xx_i2c_sleep_sequence);
> +	am33xx_i2c_sleep_sequence = NULL;
> +	return ret;
> +}
> +
>  int __init am33xx_pm_init(void)
>  {
>  	int ret;
> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>  		}
>  	}
>  
> +	ret = am33xx_setup_sleep_sequence();
> +	if (ret) {
> +		pr_err("Error fetching I2C sleep/wake sequence\n");
> +		goto err;
> +	}
> +
>  	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>  
>  	/* CEFUSE domain can be turned off post bootup */
> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
> index befdd11..d0f08a5 100644
> --- a/arch/arm/mach-omap2/pm33xx.h
> +++ b/arch/arm/mach-omap2/pm33xx.h
> @@ -52,6 +52,8 @@ struct forced_standby_module {
>  };
>  
>  int wkup_m3_copy_code(const u8 *data, size_t size);
> +void wkup_m3_reset_data_pos(void);
> +int wkup_m3_copy_data(const u8 *data, size_t size);
>  int wkup_m3_prepare(void);
>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>  
> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
> index 8eaa7f3..a541de9 100644
> --- a/arch/arm/mach-omap2/wkup_m3.c
> +++ b/arch/arm/mach-omap2/wkup_m3.c
> @@ -35,6 +35,9 @@
>  struct wkup_m3_context {
>  	struct device	*dev;
>  	void __iomem	*code;
> +	void __iomem	*data;
> +	void __iomem	*data_end;
> +	size_t		data_size;
>  	void (*txev_handler)(void);
>  };
>  
> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>  	return 0;
>  }
>  
> +/*
> + * This pair of functions allows data to be stuffed into the end of the
> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
> + * sequences to the firmware.
> + */
> +
> +/* Clear out the pointer for data stored at the end of DMEM */
> +void wkup_m3_reset_data_pos(void)
> +{
> +	wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
> +}
> +
> +/*
> + * Store a block of data at the end of DMEM, return the offset within DMEM
> + * that the data is stored at, or -ENOMEM if the data did not fit
> + */
> +int wkup_m3_copy_data(const u8 *data, size_t size)
> +{
> +	if (wkup_m3->data + size > wkup_m3->data_end)
> +		return -ENOMEM;
> +	wkup_m3->data_end -= size;
> +	memcpy_toio(wkup_m3->data_end, data, size);
> +	return wkup_m3->data_end - wkup_m3->data;
> +}
>  
>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>  {
> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>  static int wkup_m3_probe(struct platform_device *pdev)
>  {
>  	int irq, ret = 0;
> -	struct resource *mem;
> +	struct resource *umem, *dmem;
>  
>  	pm_runtime_enable(&pdev->dev);
>  
> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>  
>  	irq = platform_get_irq(pdev, 0);
>  	if (!irq) {
> -		dev_err(wkup_m3->dev, "no irq resource\n");
> +		dev_err(&pdev->dev, "no irq resource\n");

unrelated change?. Better to mention this as code cleanup in commit.

> +		ret = -ENXIO;
> +		goto err;
> +	}
> +
> +	umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!umem) {
> +		dev_err(&pdev->dev, "no UMEM resource\n");
>  		ret = -ENXIO;
>  		goto err;
>  	}
>  
> -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!mem) {
> -		dev_err(wkup_m3->dev, "no memory resource\n");
> +	dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!dmem) {
> +		dev_err(&pdev->dev, "no DMEM resource\n");
>  		ret = -ENXIO;
>  		goto err;
>  	}
> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>  
>  	wkup_m3->dev = &pdev->dev;
>  
> -	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
> +	wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
> +	if (!wkup_m3->code) {
> +		dev_err(wkup_m3->dev, "could not ioremap UMEM\n");

why not use "pdev->dev" here?

> +		ret = -EADDRNOTAVAIL;
> +		goto err;
> +	}
> +
> +	wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>  	if (!wkup_m3->code) {

I believe this is just a copy/paste error. s/code/data

> -		dev_err(wkup_m3->dev, "could not ioremap\n");
> +		dev_err(wkup_m3->dev, "could not ioremap DMEM\n");

same as above.

>  		ret = -EADDRNOTAVAIL;
>  		goto err;
>  	}
> +	wkup_m3->data_size = resource_size(dmem);
> +	wkup_m3_reset_data_pos();
>  
>  	ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>  		  IRQF_DISABLED, "wkup_m3_txev", NULL);
> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
> linux-omap" in the body of a message to majordomo at vger.kernel.org More
> majordomo info at http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-13 22:20 ` Russ Dill
@ 2013-08-14 13:38   ` Jan Lübbe
  -1 siblings, 0 replies; 84+ messages in thread
From: Jan Lübbe @ 2013-08-14 13:38 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
> The purpose and method of executing these sequences is left up to each
> platform. In the case of the am33xx, the CM3 firmware writes out the
> simple I2C sequences.
> 
> Each sequence is a series of I2C write commands. The first byte is the
> length of the write, the second byte the I2C device to address, and
> the following bytes are the message.

>         /* Set OPP100 (1.10V) for VDD core */
>         wake_sequence = /bits/ 8 <
>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>         >;
> 
>         tps: tps@2d {
>                 reg = <0x2d>;
>         };

> In the above example, the sequence "0x25 0x1f" is written to the I2C
> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
> as a write to a register at address 0x25.

> I'd really like to get some feedback on the devicetree bindings. 

Shouldn't the TPS driver know how to generate this sequence? It seems
fragile to do voltage adjustments behind the back of the regulator
framework and the TPS driver. The wake-sequence values should match the
(in-memory) regulator configuration on resume (which may have been
changed by DVFS).

The CM3 driver needs to figure out where the core regulator is connected
using using either DT or the regulator framework and ask the TPS (via a
new interface) for register writes for sleep/wake sequences. Then those
sequences will actually match the correct voltages configured using
DT/DVFS.

Regards,
Jan
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-14 13:38   ` Jan Lübbe
  0 siblings, 0 replies; 84+ messages in thread
From: Jan Lübbe @ 2013-08-14 13:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
> The purpose and method of executing these sequences is left up to each
> platform. In the case of the am33xx, the CM3 firmware writes out the
> simple I2C sequences.
> 
> Each sequence is a series of I2C write commands. The first byte is the
> length of the write, the second byte the I2C device to address, and
> the following bytes are the message.

>         /* Set OPP100 (1.10V) for VDD core */
>         wake_sequence = /bits/ 8 <
>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>         >;
> 
>         tps: tps at 2d {
>                 reg = <0x2d>;
>         };

> In the above example, the sequence "0x25 0x1f" is written to the I2C
> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
> as a write to a register at address 0x25.

> I'd really like to get some feedback on the devicetree bindings. 

Shouldn't the TPS driver know how to generate this sequence? It seems
fragile to do voltage adjustments behind the back of the regulator
framework and the TPS driver. The wake-sequence values should match the
(in-memory) regulator configuration on resume (which may have been
changed by DVFS).

The CM3 driver needs to figure out where the core regulator is connected
using using either DT or the regulator framework and ask the TPS (via a
new interface) for register writes for sleep/wake sequences. Then those
sequences will actually match the correct voltages configured using
DT/DVFS.

Regards,
Jan
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-14 13:38   ` Jan Lübbe
@ 2013-08-14 22:21     ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:21 UTC (permalink / raw)
  To: Jan Lübbe
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>> The purpose and method of executing these sequences is left up to each
>> platform. In the case of the am33xx, the CM3 firmware writes out the
>> simple I2C sequences.
>>
>> Each sequence is a series of I2C write commands. The first byte is the
>> length of the write, the second byte the I2C device to address, and
>> the following bytes are the message.
>
>>         /* Set OPP100 (1.10V) for VDD core */
>>         wake_sequence = /bits/ 8 <
>>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>>         >;
>>
>>         tps: tps@2d {
>>                 reg = <0x2d>;
>>         };
>
>> In the above example, the sequence "0x25 0x1f" is written to the I2C
>> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
>> as a write to a register at address 0x25.
>
>> I'd really like to get some feedback on the devicetree bindings.
>
> Shouldn't the TPS driver know how to generate this sequence? It seems
> fragile to do voltage adjustments behind the back of the regulator
> framework and the TPS driver. The wake-sequence values should match the
> (in-memory) regulator configuration on resume (which may have been
> changed by DVFS).

The sequence is both PMIC specific and board specific. Additionally,
the PMICs used aren't am335x specific. It would be nice to have the
regulator framework and the driver write all this out, but the
sequence is written out by the Cortex-M3 processor running some PM
firmware. Even if the code was changed to run on the A8, it'd have to
run from a small piece of SRAM.

As far as DVFS, I'm not aware of any DVFS implementations that muck
with VDD CORE.

> The CM3 driver needs to figure out where the core regulator is connected
> using using either DT or the regulator framework and ask the TPS (via a
> new interface) for register writes for sleep/wake sequences. Then those
> sequences will actually match the correct voltages configured using
> DT/DVFS.

That seems like it'd add a lot of complexity to the regulator
subsystem, as well as all the PMIC and other I2C regulators that any
users of these device tree properties may end up using for not a lot
of gain. There would be two separate code paths for any used
I2C regulator or PMIC for setting voltages.

> Regards,
> Jan
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-14 22:21     ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>> The purpose and method of executing these sequences is left up to each
>> platform. In the case of the am33xx, the CM3 firmware writes out the
>> simple I2C sequences.
>>
>> Each sequence is a series of I2C write commands. The first byte is the
>> length of the write, the second byte the I2C device to address, and
>> the following bytes are the message.
>
>>         /* Set OPP100 (1.10V) for VDD core */
>>         wake_sequence = /bits/ 8 <
>>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>>         >;
>>
>>         tps: tps at 2d {
>>                 reg = <0x2d>;
>>         };
>
>> In the above example, the sequence "0x25 0x1f" is written to the I2C
>> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
>> as a write to a register at address 0x25.
>
>> I'd really like to get some feedback on the devicetree bindings.
>
> Shouldn't the TPS driver know how to generate this sequence? It seems
> fragile to do voltage adjustments behind the back of the regulator
> framework and the TPS driver. The wake-sequence values should match the
> (in-memory) regulator configuration on resume (which may have been
> changed by DVFS).

The sequence is both PMIC specific and board specific. Additionally,
the PMICs used aren't am335x specific. It would be nice to have the
regulator framework and the driver write all this out, but the
sequence is written out by the Cortex-M3 processor running some PM
firmware. Even if the code was changed to run on the A8, it'd have to
run from a small piece of SRAM.

As far as DVFS, I'm not aware of any DVFS implementations that muck
with VDD CORE.

> The CM3 driver needs to figure out where the core regulator is connected
> using using either DT or the regulator framework and ask the TPS (via a
> new interface) for register writes for sleep/wake sequences. Then those
> sequences will actually match the correct voltages configured using
> DT/DVFS.

That seems like it'd add a lot of complexity to the regulator
subsystem, as well as all the PMIC and other I2C regulators that any
users of these device tree properties may end up using for not a lot
of gain. There would be two separate code paths for any used
I2C regulator or PMIC for setting voltages.

> Regards,
> Jan
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
  2013-08-14  8:59     ` Gururaja Hebbar
@ 2013-08-14 22:21       ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:21 UTC (permalink / raw)
  To: Gururaja Hebbar
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On Wed, Aug 14, 2013 at 1:59 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> On 8/14/2013 3:50 AM, Russ Dill wrote:
>> Changes since v1:
>> * Rebased onto new am335x PM branch
>>
>> This adds a sleep and wake sequence to set the VDD core voltage to the
>> OPP50 level, 0.950V. This saves power during suspend. The sequences are
>> specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
>> are written out by the Cortex-M3.
>>
>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>> ---
>>  arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
>>  1 file changed, 24 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
>> index 444b4ed..3f6528d 100644
>> --- a/arch/arm/boot/dts/am335x-bone.dts
>> +++ b/arch/arm/boot/dts/am335x-bone.dts
>> @@ -127,10 +127,33 @@
>>                       status = "okay";
>>                       clock-frequency = <400000>;
>>
>> +                     /* Set OPP50 (0.95V) for VDD core */
>> +                     sleep_sequence = /bits/ 8 <
>
> For user readability, can you mention the PMIC used here as a comment?

Sounds like a good modification, will do.

>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +                             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +                             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                     >;
>> +
>> +                     /* Set OPP100 (1.10V) for VDD core */
>> +                     wake_sequence = /bits/ 8 <
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +                             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +                             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                     >;
>> +
>>                       tps: tps@24 {
>>                               reg = <0x24>;
>>                       };
>> -
>>               };
>>       };
>>
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone.
@ 2013-08-14 22:21       ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 14, 2013 at 1:59 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> On 8/14/2013 3:50 AM, Russ Dill wrote:
>> Changes since v1:
>> * Rebased onto new am335x PM branch
>>
>> This adds a sleep and wake sequence to set the VDD core voltage to the
>> OPP50 level, 0.950V. This saves power during suspend. The sequences are
>> specific to the Beaglebone layout and PMIC, the TPS65217. The sequences
>> are written out by the Cortex-M3.
>>
>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>> ---
>>  arch/arm/boot/dts/am335x-bone.dts | 25 ++++++++++++++++++++++++-
>>  1 file changed, 24 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
>> index 444b4ed..3f6528d 100644
>> --- a/arch/arm/boot/dts/am335x-bone.dts
>> +++ b/arch/arm/boot/dts/am335x-bone.dts
>> @@ -127,10 +127,33 @@
>>                       status = "okay";
>>                       clock-frequency = <400000>;
>>
>> +                     /* Set OPP50 (0.95V) for VDD core */
>> +                     sleep_sequence = /bits/ 8 <
>
> For user readability, can you mention the PMIC used here as a comment?

Sounds like a good modification, will do.

>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +                             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +                             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                     >;
>> +
>> +                     /* Set OPP100 (1.10V) for VDD core */
>> +                     wake_sequence = /bits/ 8 <
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +                             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +                             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +                             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +                             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +                     >;
>> +
>>                       tps: tps at 24 {
>>                               reg = <0x24>;
>>                       };
>> -
>>               };
>>       };
>>
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-14 10:18     ` Gururaja Hebbar
@ 2013-08-14 22:34       ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:34 UTC (permalink / raw)
  To: Gururaja Hebbar
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> On 8/14/2013 3:50 AM, Russ Dill wrote:
>> Changes since v1:
>> * Rebased onto new am335x PM branch
>> * Changed to use 5th param register
>>
>> Changes since v2:
>> * Passes I2C bus speed in kHz to M3 firmware
>>
>> Changes since v3:
>> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
>> * Additional comments
>> * Added device-tree binding documentation
>
> AFAIK, Change logs should come below scissors line (---).
> However there was some discussion to keep it in the commit message.
> Don't know what happened to it finally. But till date, all revision
> patch set has the change log under the scissor line.

Will fix is v2.

>>
>> This patch adds the ability to pass an I2C sleep sequence and wake sequence
>> to the Cortex-M3. This is useful for adjusting voltages during sleep that
>> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
>> support is required.
>>
>> Each sequence is a series of I2C transfers in the form:
>>
>> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
>>
>> The length indicates the number of bytes to transfer, including the register
>> address. The length of each transfer is limited by the I2C buffer size of
>> 32 bytes.
>>
>> The sequences are taken from the i2c1 node in the device tree. The property
>> name for the sleep sequence is "sleep_sequence" and the property name for
>> the wake sequence is "wake_sequence". Each property should be an array of
>> bytes.
>>
>> No actions are performed if the properties are not present in the device
>> tree.
>>
>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>> ---
>>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>>  arch/arm/mach-omap2/control.c                      |  1 +
>>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>>  5 files changed, 186 insertions(+), 7 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>> new file mode 100644
>> index 0000000..af19372
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>> @@ -0,0 +1,44 @@
>> +I2C suspend/resume sequences
>> +
>> +This provides the ability for a simple I2C sequence to be written at
>> +suspend time and resume time. This is for sequences that cannot be written
>> +by the I2C bus driver for reasons such as needing to be run from SRAM
>> +or needing to be written by firmware.
>> +
>> +The sequence is composed of messages. Each message contains a length byte,
>> +an address byte, and then the message.
>> +
>> +Optional properties:
>> +- sleep_sequence
>> +     I2C sequence to write during suspend
>> +
>> +- wake_sequence
>> +     I2C sequence to write during wake
>> +
>> +Examples :
>> +
>> +i2c0: i2c@0 {
>> +     /* Set OPP50 (0.95V) for VDD core */
>> +     sleep_sequence = /bits/ 8 <
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +     >;
>
> This data is not related to i2c. Right? Then why is it under i2c dt node?
>
> There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
> respective boards). Can't these details go under those nodes?

The i2c node was chosen for several reasons. First that the bus speed
is included in the message to the CM3 firmware. The bus speed and
sequence can then be read from the same device tree node. Second so
it's clear which I2C bus this is being sent out on. Including it under
the PMIC node would mean that the code would have to search each child
of the I2C bus for a sequence and if multiple children had sequences,
it would not know in which order to send those sequences out.

>> +
>> +     /* Set OPP100 (1.10V) for VDD core */
>> +     wake_sequence = /bits/ 8 <
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +     >;
>> +}
>> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
>> index 934041a..dfbd5f0 100644
>> --- a/arch/arm/mach-omap2/control.c
>> +++ b/arch/arm/mach-omap2/control.c
>> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>>       omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>>       omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>>       omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
>> +     omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>>  }
>>
>>  int am33xx_pm_status(void)
>> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
>> index d291c76..8880da3 100644
>> --- a/arch/arm/mach-omap2/pm33xx.c
>> +++ b/arch/arm/mach-omap2/pm33xx.c
>> @@ -29,6 +29,7 @@
>>  #include <linux/ti_emif.h>
>>  #include <linux/omap-mailbox.h>
>>
>> +#include <asm/unaligned.h>
>>  #include <asm/suspend.h>
>>  #include <asm/proc-fns.h>
>>  #include <asm/sizes.h>
>> @@ -50,6 +51,10 @@
>>  static void __iomem *am33xx_emif_base;
>>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>>  static struct clockdomain *gfx_l4ls_clkdm;
>> +static char *am33xx_i2c_sleep_sequence;
>> +static char *am33xx_i2c_wake_sequence;
>> +static size_t i2c_sleep_sequence_sz;
>> +static size_t i2c_wake_sequence_sz;
>>
>>  struct wakeup_src wakeups[] = {
>>       {.irq_nr = 35,  .src = "USB0_PHY"},
>> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>>  static int am33xx_pm_begin(suspend_state_t state)
>>  {
>>       int i;
>> +     unsigned long param4;
>> +     int pos;
>>
>>       cpu_idle_poll_ctrl(true);
>>
>> +     param4 = DS_IPC_DEFAULT;
>> +
>> +     wkup_m3_reset_data_pos();
>> +     if (am33xx_i2c_sleep_sequence) {
>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>> +                                             i2c_sleep_sequence_sz);
>
> Why do we need to copy this data (same constant data) on every iteration?

Because the CM3 firmware is reset after each suspend/resume cycle. The
firmware reset handler reinitializes the DMEM.

>> +             /* Lower 16 bits stores offset to sleep sequence */
>> +             param4 &= ~0xffff;
>> +             param4 |= pos;
>> +     }
>> +
>> +     if (am33xx_i2c_wake_sequence) {
>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>> +                                             i2c_wake_sequence_sz);
>> +             /* Upper 16 bits stores offset to wake sequence */
>> +             param4 &= ~0xffff0000;
>> +             param4 |= pos << 16;
>> +     }
>> +
>
> Seems above entire change can be done only once.
>
>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>> +     am33xx_pm->ipc.param4           = param4;
>>
>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>
>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>       return 0;
>>  }
>>
>> +static int __init am33xx_setup_sleep_sequence(void)
>> +{
>> +     int ret;
>> +     int sz;
>> +     const void *prop;
>> +     struct device *dev;
>> +     u32 freq_hz = 100000;
>
> Magic number?

It's taken from drivers/i2c/busses/i2c-omap.c

    u32 freq = 100000; /* default to 100000 Hz */

I'll add a comment to that effect.

>> +     unsigned short freq_khz;
>> +
>> +     /*
>> +      * We put the device tree node in the I2C controller that will
>> +      * be sending the sequence. i2c1 is the only controller that can
>> +      * be accessed by the firmware as it is the only controller in the
>> +      * WKUP domain.
>
> and on which the PMIC sits I believe?

Yes, but this code is designed not to be PMIC specific as one could
chose to regulate VDD_CORE with any PMIC, or even with a standalone
I2C controlled regulator.

>> +      */
>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>> +     if (IS_ERR(dev))
>> +             return PTR_ERR(dev);
>> +
>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>> +     freq_khz = freq_hz / 1000;
>
> Magic number?

Nah, converting between metric prefixes this way is pretty common in the kernel.

>> +
>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>> +     if (prop) {
>> +             /*
>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>> +              * byte for terminator.
>> +              */
>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>> +             if (!am33xx_i2c_sleep_sequence)
>> +                     return -ENOMEM;
>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>
> so, looking at entire code, it seems there is 3 memory space for same
> data (or 1 original + 2 copy)
>
> 1. in DT
> 2. in am33xx_i2c_[sleep/wake]_sequence
> 3. in SRAm by call to wkup_m3_copy_data()
>
> why not directly copy to SRAM from DT?

As pointed out above, the firmware reset handler would wipe it out.

>> +             i2c_sleep_sequence_sz = sz + 3;
>> +     }
>> +
>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>> +     if (prop) {
>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>> +             if (!am33xx_i2c_wake_sequence) {
>> +                     ret = -ENOMEM;
>> +                     goto cleanup_sleep;
>> +             }
>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>> +             i2c_wake_sequence_sz = sz + 3;
>> +     }
>> +
>> +     return 0;
>> +
>> +cleanup_sleep:
>> +     kfree(am33xx_i2c_sleep_sequence);
>> +     am33xx_i2c_sleep_sequence = NULL;
>> +     return ret;
>> +}
>> +
>>  int __init am33xx_pm_init(void)
>>  {
>>       int ret;
>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>               }
>>       }
>>
>> +     ret = am33xx_setup_sleep_sequence();
>> +     if (ret) {
>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>> +             goto err;
>> +     }
>> +
>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>
>>       /* CEFUSE domain can be turned off post bootup */
>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>> index befdd11..d0f08a5 100644
>> --- a/arch/arm/mach-omap2/pm33xx.h
>> +++ b/arch/arm/mach-omap2/pm33xx.h
>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>  };
>>
>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>> +void wkup_m3_reset_data_pos(void);
>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>  int wkup_m3_prepare(void);
>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>
>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>> index 8eaa7f3..a541de9 100644
>> --- a/arch/arm/mach-omap2/wkup_m3.c
>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>> @@ -35,6 +35,9 @@
>>  struct wkup_m3_context {
>>       struct device   *dev;
>>       void __iomem    *code;
>> +     void __iomem    *data;
>> +     void __iomem    *data_end;
>> +     size_t          data_size;
>>       void (*txev_handler)(void);
>>  };
>>
>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>       return 0;
>>  }
>>
>> +/*
>> + * This pair of functions allows data to be stuffed into the end of the
>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>> + * sequences to the firmware.
>> + */
>> +
>> +/* Clear out the pointer for data stored at the end of DMEM */
>> +void wkup_m3_reset_data_pos(void)
>> +{
>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>> +}
>> +
>> +/*
>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>> + * that the data is stored at, or -ENOMEM if the data did not fit
>> + */
>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>> +{
>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>> +             return -ENOMEM;
>> +     wkup_m3->data_end -= size;
>> +     memcpy_toio(wkup_m3->data_end, data, size);
>> +     return wkup_m3->data_end - wkup_m3->data;
>> +}
>>
>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>  {
>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>  static int wkup_m3_probe(struct platform_device *pdev)
>>  {
>>       int irq, ret = 0;
>> -     struct resource *mem;
>> +     struct resource *umem, *dmem;
>>
>>       pm_runtime_enable(&pdev->dev);
>>
>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>
>>       irq = platform_get_irq(pdev, 0);
>>       if (!irq) {
>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>> +             dev_err(&pdev->dev, "no irq resource\n");
>
> unrelated change?. Better to mention this as code cleanup in commit.

Will add a comment to that effect, the underlying error should be
fixed in the next suspend/resume patch though.

>> +             ret = -ENXIO;
>> +             goto err;
>> +     }
>> +
>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (!umem) {
>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>               ret = -ENXIO;
>>               goto err;
>>       }
>>
>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> -     if (!mem) {
>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +     if (!dmem) {
>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>               ret = -ENXIO;
>>               goto err;
>>       }
>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>
>>       wkup_m3->dev = &pdev->dev;
>>
>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>> +     if (!wkup_m3->code) {
>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>
> why not use "pdev->dev" here?

Either one works

>> +             ret = -EADDRNOTAVAIL;
>> +             goto err;
>> +     }
>> +
>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>       if (!wkup_m3->code) {
>
> I believe this is just a copy/paste error. s/code/data

Doh, thanks!

>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>
> same as above.
>
>>               ret = -EADDRNOTAVAIL;
>>               goto err;
>>       }
>> +     wkup_m3->data_size = resource_size(dmem);
>> +     wkup_m3_reset_data_pos();
>>
>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>> linux-omap" in the body of a message to majordomo@vger.kernel.org More
>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-14 22:34       ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-14 22:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> On 8/14/2013 3:50 AM, Russ Dill wrote:
>> Changes since v1:
>> * Rebased onto new am335x PM branch
>> * Changed to use 5th param register
>>
>> Changes since v2:
>> * Passes I2C bus speed in kHz to M3 firmware
>>
>> Changes since v3:
>> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
>> * Additional comments
>> * Added device-tree binding documentation
>
> AFAIK, Change logs should come below scissors line (---).
> However there was some discussion to keep it in the commit message.
> Don't know what happened to it finally. But till date, all revision
> patch set has the change log under the scissor line.

Will fix is v2.

>>
>> This patch adds the ability to pass an I2C sleep sequence and wake sequence
>> to the Cortex-M3. This is useful for adjusting voltages during sleep that
>> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
>> support is required.
>>
>> Each sequence is a series of I2C transfers in the form:
>>
>> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
>>
>> The length indicates the number of bytes to transfer, including the register
>> address. The length of each transfer is limited by the I2C buffer size of
>> 32 bytes.
>>
>> The sequences are taken from the i2c1 node in the device tree. The property
>> name for the sleep sequence is "sleep_sequence" and the property name for
>> the wake sequence is "wake_sequence". Each property should be an array of
>> bytes.
>>
>> No actions are performed if the properties are not present in the device
>> tree.
>>
>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>> ---
>>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>>  arch/arm/mach-omap2/control.c                      |  1 +
>>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>>  5 files changed, 186 insertions(+), 7 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>> new file mode 100644
>> index 0000000..af19372
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>> @@ -0,0 +1,44 @@
>> +I2C suspend/resume sequences
>> +
>> +This provides the ability for a simple I2C sequence to be written at
>> +suspend time and resume time. This is for sequences that cannot be written
>> +by the I2C bus driver for reasons such as needing to be run from SRAM
>> +or needing to be written by firmware.
>> +
>> +The sequence is composed of messages. Each message contains a length byte,
>> +an address byte, and then the message.
>> +
>> +Optional properties:
>> +- sleep_sequence
>> +     I2C sequence to write during suspend
>> +
>> +- wake_sequence
>> +     I2C sequence to write during wake
>> +
>> +Examples :
>> +
>> +i2c0: i2c at 0 {
>> +     /* Set OPP50 (0.95V) for VDD core */
>> +     sleep_sequence = /bits/ 8 <
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +     >;
>
> This data is not related to i2c. Right? Then why is it under i2c dt node?
>
> There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
> respective boards). Can't these details go under those nodes?

The i2c node was chosen for several reasons. First that the bus speed
is included in the message to the CM3 firmware. The bus speed and
sequence can then be read from the same device tree node. Second so
it's clear which I2C bus this is being sent out on. Including it under
the PMIC node would mean that the code would have to search each child
of the I2C bus for a sequence and if multiple children had sequences,
it would not know in which order to send those sequences out.

>> +
>> +     /* Set OPP100 (1.10V) for VDD core */
>> +     wake_sequence = /bits/ 8 <
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>> +     >;
>> +}
>> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
>> index 934041a..dfbd5f0 100644
>> --- a/arch/arm/mach-omap2/control.c
>> +++ b/arch/arm/mach-omap2/control.c
>> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>>       omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>>       omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>>       omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
>> +     omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>>  }
>>
>>  int am33xx_pm_status(void)
>> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
>> index d291c76..8880da3 100644
>> --- a/arch/arm/mach-omap2/pm33xx.c
>> +++ b/arch/arm/mach-omap2/pm33xx.c
>> @@ -29,6 +29,7 @@
>>  #include <linux/ti_emif.h>
>>  #include <linux/omap-mailbox.h>
>>
>> +#include <asm/unaligned.h>
>>  #include <asm/suspend.h>
>>  #include <asm/proc-fns.h>
>>  #include <asm/sizes.h>
>> @@ -50,6 +51,10 @@
>>  static void __iomem *am33xx_emif_base;
>>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>>  static struct clockdomain *gfx_l4ls_clkdm;
>> +static char *am33xx_i2c_sleep_sequence;
>> +static char *am33xx_i2c_wake_sequence;
>> +static size_t i2c_sleep_sequence_sz;
>> +static size_t i2c_wake_sequence_sz;
>>
>>  struct wakeup_src wakeups[] = {
>>       {.irq_nr = 35,  .src = "USB0_PHY"},
>> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>>  static int am33xx_pm_begin(suspend_state_t state)
>>  {
>>       int i;
>> +     unsigned long param4;
>> +     int pos;
>>
>>       cpu_idle_poll_ctrl(true);
>>
>> +     param4 = DS_IPC_DEFAULT;
>> +
>> +     wkup_m3_reset_data_pos();
>> +     if (am33xx_i2c_sleep_sequence) {
>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>> +                                             i2c_sleep_sequence_sz);
>
> Why do we need to copy this data (same constant data) on every iteration?

Because the CM3 firmware is reset after each suspend/resume cycle. The
firmware reset handler reinitializes the DMEM.

>> +             /* Lower 16 bits stores offset to sleep sequence */
>> +             param4 &= ~0xffff;
>> +             param4 |= pos;
>> +     }
>> +
>> +     if (am33xx_i2c_wake_sequence) {
>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>> +                                             i2c_wake_sequence_sz);
>> +             /* Upper 16 bits stores offset to wake sequence */
>> +             param4 &= ~0xffff0000;
>> +             param4 |= pos << 16;
>> +     }
>> +
>
> Seems above entire change can be done only once.
>
>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>> +     am33xx_pm->ipc.param4           = param4;
>>
>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>
>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>       return 0;
>>  }
>>
>> +static int __init am33xx_setup_sleep_sequence(void)
>> +{
>> +     int ret;
>> +     int sz;
>> +     const void *prop;
>> +     struct device *dev;
>> +     u32 freq_hz = 100000;
>
> Magic number?

It's taken from drivers/i2c/busses/i2c-omap.c

    u32 freq = 100000; /* default to 100000 Hz */

I'll add a comment to that effect.

>> +     unsigned short freq_khz;
>> +
>> +     /*
>> +      * We put the device tree node in the I2C controller that will
>> +      * be sending the sequence. i2c1 is the only controller that can
>> +      * be accessed by the firmware as it is the only controller in the
>> +      * WKUP domain.
>
> and on which the PMIC sits I believe?

Yes, but this code is designed not to be PMIC specific as one could
chose to regulate VDD_CORE with any PMIC, or even with a standalone
I2C controlled regulator.

>> +      */
>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>> +     if (IS_ERR(dev))
>> +             return PTR_ERR(dev);
>> +
>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>> +     freq_khz = freq_hz / 1000;
>
> Magic number?

Nah, converting between metric prefixes this way is pretty common in the kernel.

>> +
>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>> +     if (prop) {
>> +             /*
>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>> +              * byte for terminator.
>> +              */
>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>> +             if (!am33xx_i2c_sleep_sequence)
>> +                     return -ENOMEM;
>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>
> so, looking at entire code, it seems there is 3 memory space for same
> data (or 1 original + 2 copy)
>
> 1. in DT
> 2. in am33xx_i2c_[sleep/wake]_sequence
> 3. in SRAm by call to wkup_m3_copy_data()
>
> why not directly copy to SRAM from DT?

As pointed out above, the firmware reset handler would wipe it out.

>> +             i2c_sleep_sequence_sz = sz + 3;
>> +     }
>> +
>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>> +     if (prop) {
>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>> +             if (!am33xx_i2c_wake_sequence) {
>> +                     ret = -ENOMEM;
>> +                     goto cleanup_sleep;
>> +             }
>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>> +             i2c_wake_sequence_sz = sz + 3;
>> +     }
>> +
>> +     return 0;
>> +
>> +cleanup_sleep:
>> +     kfree(am33xx_i2c_sleep_sequence);
>> +     am33xx_i2c_sleep_sequence = NULL;
>> +     return ret;
>> +}
>> +
>>  int __init am33xx_pm_init(void)
>>  {
>>       int ret;
>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>               }
>>       }
>>
>> +     ret = am33xx_setup_sleep_sequence();
>> +     if (ret) {
>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>> +             goto err;
>> +     }
>> +
>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>
>>       /* CEFUSE domain can be turned off post bootup */
>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>> index befdd11..d0f08a5 100644
>> --- a/arch/arm/mach-omap2/pm33xx.h
>> +++ b/arch/arm/mach-omap2/pm33xx.h
>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>  };
>>
>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>> +void wkup_m3_reset_data_pos(void);
>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>  int wkup_m3_prepare(void);
>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>
>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>> index 8eaa7f3..a541de9 100644
>> --- a/arch/arm/mach-omap2/wkup_m3.c
>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>> @@ -35,6 +35,9 @@
>>  struct wkup_m3_context {
>>       struct device   *dev;
>>       void __iomem    *code;
>> +     void __iomem    *data;
>> +     void __iomem    *data_end;
>> +     size_t          data_size;
>>       void (*txev_handler)(void);
>>  };
>>
>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>       return 0;
>>  }
>>
>> +/*
>> + * This pair of functions allows data to be stuffed into the end of the
>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>> + * sequences to the firmware.
>> + */
>> +
>> +/* Clear out the pointer for data stored at the end of DMEM */
>> +void wkup_m3_reset_data_pos(void)
>> +{
>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>> +}
>> +
>> +/*
>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>> + * that the data is stored at, or -ENOMEM if the data did not fit
>> + */
>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>> +{
>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>> +             return -ENOMEM;
>> +     wkup_m3->data_end -= size;
>> +     memcpy_toio(wkup_m3->data_end, data, size);
>> +     return wkup_m3->data_end - wkup_m3->data;
>> +}
>>
>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>  {
>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>  static int wkup_m3_probe(struct platform_device *pdev)
>>  {
>>       int irq, ret = 0;
>> -     struct resource *mem;
>> +     struct resource *umem, *dmem;
>>
>>       pm_runtime_enable(&pdev->dev);
>>
>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>
>>       irq = platform_get_irq(pdev, 0);
>>       if (!irq) {
>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>> +             dev_err(&pdev->dev, "no irq resource\n");
>
> unrelated change?. Better to mention this as code cleanup in commit.

Will add a comment to that effect, the underlying error should be
fixed in the next suspend/resume patch though.

>> +             ret = -ENXIO;
>> +             goto err;
>> +     }
>> +
>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (!umem) {
>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>               ret = -ENXIO;
>>               goto err;
>>       }
>>
>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> -     if (!mem) {
>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +     if (!dmem) {
>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>               ret = -ENXIO;
>>               goto err;
>>       }
>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>
>>       wkup_m3->dev = &pdev->dev;
>>
>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>> +     if (!wkup_m3->code) {
>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>
> why not use "pdev->dev" here?

Either one works

>> +             ret = -EADDRNOTAVAIL;
>> +             goto err;
>> +     }
>> +
>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>       if (!wkup_m3->code) {
>
> I believe this is just a copy/paste error. s/code/data

Doh, thanks!

>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>
> same as above.
>
>>               ret = -EADDRNOTAVAIL;
>>               goto err;
>>       }
>> +     wkup_m3->data_size = resource_size(dmem);
>> +     wkup_m3_reset_data_pos();
>>
>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>> linux-omap" in the body of a message to majordomo at vger.kernel.org More
>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-14 22:21     ` Russ Dill
@ 2013-08-15  8:00       ` Jan Lübbe
  -1 siblings, 0 replies; 84+ messages in thread
From: Jan Lübbe @ 2013-08-15  8:00 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On Wed, 2013-08-14 at 15:21 -0700, Russ Dill wrote:
> > The CM3 driver needs to figure out where the core regulator is connected
> > using using either DT or the regulator framework and ask the TPS (via a
> > new interface) for register writes for sleep/wake sequences. Then those
> > sequences will actually match the correct voltages configured using
> > DT/DVFS.
> 
> That seems like it'd add a lot of complexity to the regulator
> subsystem, as well as all the PMIC and other I2C regulators that any
> users of these device tree properties may end up using for not a lot
> of gain. There would be two separate code paths for any used
> I2C regulator or PMIC for setting voltages.

Yes, it would be additional complexity, but it would avoid duplicating
information which is already in the DT (location&address of the PMIC,
type of pmic) and in the kernel (how to program voltages for a given
regulator). As DT is supposed to describe the hardware, duplicate
information should be unnecessary.

One different way to look at this is that the CM3 firmware is a separate
consumer of the DT. DT being OS-indepentent, the CM3 firmware should be
able to get all the information it needs from the DT (maybe with help
from the CM3 driver).

Regards,
Jan 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-15  8:00       ` Jan Lübbe
  0 siblings, 0 replies; 84+ messages in thread
From: Jan Lübbe @ 2013-08-15  8:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2013-08-14 at 15:21 -0700, Russ Dill wrote:
> > The CM3 driver needs to figure out where the core regulator is connected
> > using using either DT or the regulator framework and ask the TPS (via a
> > new interface) for register writes for sleep/wake sequences. Then those
> > sequences will actually match the correct voltages configured using
> > DT/DVFS.
> 
> That seems like it'd add a lot of complexity to the regulator
> subsystem, as well as all the PMIC and other I2C regulators that any
> users of these device tree properties may end up using for not a lot
> of gain. There would be two separate code paths for any used
> I2C regulator or PMIC for setting voltages.

Yes, it would be additional complexity, but it would avoid duplicating
information which is already in the DT (location&address of the PMIC,
type of pmic) and in the kernel (how to program voltages for a given
regulator). As DT is supposed to describe the hardware, duplicate
information should be unnecessary.

One different way to look at this is that the CM3 firmware is a separate
consumer of the DT. DT being OS-indepentent, the CM3 firmware should be
able to get all the information it needs from the DT (maybe with help
from the CM3 driver).

Regards,
Jan 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-14 22:34       ` Russ Dill
@ 2013-08-16  7:16         ` Gururaja Hebbar
  -1 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-16  7:16 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On 8/15/2013 4:04 AM, Russ Dill wrote:
> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>> Changes since v1:
>>> * Rebased onto new am335x PM branch
>>> * Changed to use 5th param register
>>>
>>> Changes since v2:
>>> * Passes I2C bus speed in kHz to M3 firmware
>>>
>>> Changes since v3:
>>> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
>>> * Additional comments
>>> * Added device-tree binding documentation
>>
>> AFAIK, Change logs should come below scissors line (---).
>> However there was some discussion to keep it in the commit message.
>> Don't know what happened to it finally. But till date, all revision
>> patch set has the change log under the scissor line.
> 
> Will fix is v2.
> 
>>>
>>> This patch adds the ability to pass an I2C sleep sequence and wake sequence
>>> to the Cortex-M3. This is useful for adjusting voltages during sleep that
>>> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
>>> support is required.
>>>
>>> Each sequence is a series of I2C transfers in the form:
>>>
>>> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
>>>
>>> The length indicates the number of bytes to transfer, including the register
>>> address. The length of each transfer is limited by the I2C buffer size of
>>> 32 bytes.
>>>
>>> The sequences are taken from the i2c1 node in the device tree. The property
>>> name for the sleep sequence is "sleep_sequence" and the property name for
>>> the wake sequence is "wake_sequence". Each property should be an array of
>>> bytes.
>>>
>>> No actions are performed if the properties are not present in the device
>>> tree.
>>>
>>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>>> ---
>>>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>>>  arch/arm/mach-omap2/control.c                      |  1 +
>>>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>>>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>>>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>>>  5 files changed, 186 insertions(+), 7 deletions(-)
>>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>> new file mode 100644
>>> index 0000000..af19372
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>> @@ -0,0 +1,44 @@
>>> +I2C suspend/resume sequences
>>> +
>>> +This provides the ability for a simple I2C sequence to be written at
>>> +suspend time and resume time. This is for sequences that cannot be written
>>> +by the I2C bus driver for reasons such as needing to be run from SRAM
>>> +or needing to be written by firmware.
>>> +
>>> +The sequence is composed of messages. Each message contains a length byte,
>>> +an address byte, and then the message.
>>> +
>>> +Optional properties:
>>> +- sleep_sequence
>>> +     I2C sequence to write during suspend
>>> +
>>> +- wake_sequence
>>> +     I2C sequence to write during wake
>>> +
>>> +Examples :
>>> +
>>> +i2c0: i2c@0 {
>>> +     /* Set OPP50 (0.95V) for VDD core */
>>> +     sleep_sequence = /bits/ 8 <
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +     >;
>>
>> This data is not related to i2c. Right? Then why is it under i2c dt node?
>>
>> There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
>> respective boards). Can't these details go under those nodes?
> 
> The i2c node was chosen for several reasons. First that the bus speed
> is included in the message to the CM3 firmware. The bus speed and
> sequence can then be read from the same device tree node. Second so
> it's clear which I2C bus this is being sent out on. Including it under
> the PMIC node would mean that the code would have to search each child
> of the I2C bus for a sequence and if multiple children had sequences,
> it would not know in which order to send those sequences out.

Agreed

> 
>>> +
>>> +     /* Set OPP100 (1.10V) for VDD core */
>>> +     wake_sequence = /bits/ 8 <
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +     >;
>>> +}
>>> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
>>> index 934041a..dfbd5f0 100644
>>> --- a/arch/arm/mach-omap2/control.c
>>> +++ b/arch/arm/mach-omap2/control.c
>>> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>>>       omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>>>       omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>>>       omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
>>> +     omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>>>  }
>>>
>>>  int am33xx_pm_status(void)
>>> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
>>> index d291c76..8880da3 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.c
>>> +++ b/arch/arm/mach-omap2/pm33xx.c
>>> @@ -29,6 +29,7 @@
>>>  #include <linux/ti_emif.h>
>>>  #include <linux/omap-mailbox.h>
>>>
>>> +#include <asm/unaligned.h>
>>>  #include <asm/suspend.h>
>>>  #include <asm/proc-fns.h>
>>>  #include <asm/sizes.h>
>>> @@ -50,6 +51,10 @@
>>>  static void __iomem *am33xx_emif_base;
>>>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>>>  static struct clockdomain *gfx_l4ls_clkdm;
>>> +static char *am33xx_i2c_sleep_sequence;
>>> +static char *am33xx_i2c_wake_sequence;
>>> +static size_t i2c_sleep_sequence_sz;
>>> +static size_t i2c_wake_sequence_sz;
>>>
>>>  struct wakeup_src wakeups[] = {
>>>       {.irq_nr = 35,  .src = "USB0_PHY"},
>>> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>>>  static int am33xx_pm_begin(suspend_state_t state)
>>>  {
>>>       int i;
>>> +     unsigned long param4;
>>> +     int pos;
>>>
>>>       cpu_idle_poll_ctrl(true);
>>>
>>> +     param4 = DS_IPC_DEFAULT;
>>> +
>>> +     wkup_m3_reset_data_pos();
>>> +     if (am33xx_i2c_sleep_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>> +                                             i2c_sleep_sequence_sz);
>>
>> Why do we need to copy this data (same constant data) on every iteration?
> 
> Because the CM3 firmware is reset after each suspend/resume cycle. The
> firmware reset handler reinitializes the DMEM.

Is it. Do you have any more information about the same?

Even then, you can copy from DT to CM3 and remove 2nd temp storage. Right?

> 
>>> +             /* Lower 16 bits stores offset to sleep sequence */
>>> +             param4 &= ~0xffff;
>>> +             param4 |= pos;
>>> +     }
>>> +
>>> +     if (am33xx_i2c_wake_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>>> +                                             i2c_wake_sequence_sz);
>>> +             /* Upper 16 bits stores offset to wake sequence */
>>> +             param4 &= ~0xffff0000;
>>> +             param4 |= pos << 16;
>>> +     }
>>> +
>>
>> Seems above entire change can be done only once.
>>
>>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>>> +     am33xx_pm->ipc.param4           = param4;
>>>
>>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>>
>>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>>       return 0;
>>>  }
>>>
>>> +static int __init am33xx_setup_sleep_sequence(void)
>>> +{
>>> +     int ret;
>>> +     int sz;
>>> +     const void *prop;
>>> +     struct device *dev;
>>> +     u32 freq_hz = 100000;
>>
>> Magic number?
> 
> It's taken from drivers/i2c/busses/i2c-omap.c
> 
>     u32 freq = 100000; /* default to 100000 Hz */
> 
> I'll add a comment to that effect.
> 
>>> +     unsigned short freq_khz;
>>> +
>>> +     /*
>>> +      * We put the device tree node in the I2C controller that will
>>> +      * be sending the sequence. i2c1 is the only controller that can
>>> +      * be accessed by the firmware as it is the only controller in the
>>> +      * WKUP domain.
>>
>> and on which the PMIC sits I believe?
> 
> Yes, but this code is designed not to be PMIC specific as one could
> chose to regulate VDD_CORE with any PMIC, or even with a standalone
> I2C controlled regulator.
> 
>>> +      */
>>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>>> +     if (IS_ERR(dev))
>>> +             return PTR_ERR(dev);
>>> +
>>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>>> +     freq_khz = freq_hz / 1000;
>>
>> Magic number?
> 
> Nah, converting between metric prefixes this way is pretty common in the kernel.

oh. Correct.

> 
>>> +
>>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>>> +     if (prop) {
>>> +             /*
>>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>>> +              * byte for terminator.
>>> +              */
>>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_sleep_sequence)
>>> +                     return -ENOMEM;
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>>
>> so, looking at entire code, it seems there is 3 memory space for same
>> data (or 1 original + 2 copy)
>>
>> 1. in DT
>> 2. in am33xx_i2c_[sleep/wake]_sequence
>> 3. in SRAm by call to wkup_m3_copy_data()
>>
>> why not directly copy to SRAM from DT?
> 
> As pointed out above, the firmware reset handler would wipe it out.

i have update my comment above.

> 
>>> +             i2c_sleep_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>>> +     if (prop) {
>>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_wake_sequence) {
>>> +                     ret = -ENOMEM;
>>> +                     goto cleanup_sleep;
>>> +             }
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>>> +             i2c_wake_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     return 0;
>>> +
>>> +cleanup_sleep:
>>> +     kfree(am33xx_i2c_sleep_sequence);
>>> +     am33xx_i2c_sleep_sequence = NULL;
>>> +     return ret;
>>> +}
>>> +
>>>  int __init am33xx_pm_init(void)
>>>  {
>>>       int ret;
>>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>>               }
>>>       }
>>>
>>> +     ret = am33xx_setup_sleep_sequence();
>>> +     if (ret) {
>>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>>> +             goto err;
>>> +     }
>>> +
>>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>>
>>>       /* CEFUSE domain can be turned off post bootup */
>>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>>> index befdd11..d0f08a5 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.h
>>> +++ b/arch/arm/mach-omap2/pm33xx.h
>>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>>  };
>>>
>>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>>> +void wkup_m3_reset_data_pos(void);
>>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>>  int wkup_m3_prepare(void);
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>>
>>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>>> index 8eaa7f3..a541de9 100644
>>> --- a/arch/arm/mach-omap2/wkup_m3.c
>>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>>> @@ -35,6 +35,9 @@
>>>  struct wkup_m3_context {
>>>       struct device   *dev;
>>>       void __iomem    *code;
>>> +     void __iomem    *data;
>>> +     void __iomem    *data_end;
>>> +     size_t          data_size;
>>>       void (*txev_handler)(void);
>>>  };
>>>
>>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>>       return 0;
>>>  }
>>>
>>> +/*
>>> + * This pair of functions allows data to be stuffed into the end of the
>>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>>> + * sequences to the firmware.
>>> + */
>>> +
>>> +/* Clear out the pointer for data stored at the end of DMEM */
>>> +void wkup_m3_reset_data_pos(void)
>>> +{
>>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>>> +}
>>> +
>>> +/*
>>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>>> + * that the data is stored at, or -ENOMEM if the data did not fit
>>> + */
>>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>>> +{
>>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>>> +             return -ENOMEM;
>>> +     wkup_m3->data_end -= size;
>>> +     memcpy_toio(wkup_m3->data_end, data, size);
>>> +     return wkup_m3->data_end - wkup_m3->data;
>>> +}
>>>
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>>  {
>>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>>  static int wkup_m3_probe(struct platform_device *pdev)
>>>  {
>>>       int irq, ret = 0;
>>> -     struct resource *mem;
>>> +     struct resource *umem, *dmem;
>>>
>>>       pm_runtime_enable(&pdev->dev);
>>>
>>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       irq = platform_get_irq(pdev, 0);
>>>       if (!irq) {
>>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>>> +             dev_err(&pdev->dev, "no irq resource\n");
>>
>> unrelated change?. Better to mention this as code cleanup in commit.
> 
> Will add a comment to that effect, the underlying error should be
> fixed in the next suspend/resume patch though.
> 
>>> +             ret = -ENXIO;
>>> +             goto err;
>>> +     }
>>> +
>>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +     if (!umem) {
>>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>>
>>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> -     if (!mem) {
>>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>> +     if (!dmem) {
>>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       wkup_m3->dev = &pdev->dev;
>>>
>>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>>> +     if (!wkup_m3->code) {
>>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>>
>> why not use "pdev->dev" here?
> 
> Either one works

just for consistency.

> 
>>> +             ret = -EADDRNOTAVAIL;
>>> +             goto err;
>>> +     }
>>> +
>>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>>       if (!wkup_m3->code) {
>>
>> I believe this is just a copy/paste error. s/code/data
> 
> Doh, thanks!
> 
>>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>>
>> same as above.
>>
>>>               ret = -EADDRNOTAVAIL;
>>>               goto err;
>>>       }
>>> +     wkup_m3->data_size = resource_size(dmem);
>>> +     wkup_m3_reset_data_pos();
>>>
>>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>>> linux-omap" in the body of a message to majordomo@vger.kernel.org More
>>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-16  7:16         ` Gururaja Hebbar
  0 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-16  7:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 8/15/2013 4:04 AM, Russ Dill wrote:
> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>> Changes since v1:
>>> * Rebased onto new am335x PM branch
>>> * Changed to use 5th param register
>>>
>>> Changes since v2:
>>> * Passes I2C bus speed in kHz to M3 firmware
>>>
>>> Changes since v3:
>>> * Rebased to 3.11-rc3, moves some functionality to wkup_m3.c
>>> * Additional comments
>>> * Added device-tree binding documentation
>>
>> AFAIK, Change logs should come below scissors line (---).
>> However there was some discussion to keep it in the commit message.
>> Don't know what happened to it finally. But till date, all revision
>> patch set has the change log under the scissor line.
> 
> Will fix is v2.
> 
>>>
>>> This patch adds the ability to pass an I2C sleep sequence and wake sequence
>>> to the Cortex-M3. This is useful for adjusting voltages during sleep that
>>> cannot be lowered while SDRAM is active. A modified M3 firmware with I2C
>>> support is required.
>>>
>>> Each sequence is a series of I2C transfers in the form:
>>>
>>> u8 length | u8 chip address | u8 byte0/reg address | u8 byte 1 | u8 byte n ...
>>>
>>> The length indicates the number of bytes to transfer, including the register
>>> address. The length of each transfer is limited by the I2C buffer size of
>>> 32 bytes.
>>>
>>> The sequences are taken from the i2c1 node in the device tree. The property
>>> name for the sleep sequence is "sleep_sequence" and the property name for
>>> the wake sequence is "wake_sequence". Each property should be an array of
>>> bytes.
>>>
>>> No actions are performed if the properties are not present in the device
>>> tree.
>>>
>>> Signed-off-by: Russ Dill <Russ.Dill@ti.com>
>>> ---
>>>  .../devicetree/bindings/i2c/i2c-suspend-resume.txt | 44 +++++++++++
>>>  arch/arm/mach-omap2/control.c                      |  1 +
>>>  arch/arm/mach-omap2/pm33xx.c                       | 89 ++++++++++++++++++++++
>>>  arch/arm/mach-omap2/pm33xx.h                       |  2 +
>>>  arch/arm/mach-omap2/wkup_m3.c                      | 57 ++++++++++++--
>>>  5 files changed, 186 insertions(+), 7 deletions(-)
>>>  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>> new file mode 100644
>>> index 0000000..af19372
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c-suspend-resume.txt
>>> @@ -0,0 +1,44 @@
>>> +I2C suspend/resume sequences
>>> +
>>> +This provides the ability for a simple I2C sequence to be written at
>>> +suspend time and resume time. This is for sequences that cannot be written
>>> +by the I2C bus driver for reasons such as needing to be run from SRAM
>>> +or needing to be written by firmware.
>>> +
>>> +The sequence is composed of messages. Each message contains a length byte,
>>> +an address byte, and then the message.
>>> +
>>> +Optional properties:
>>> +- sleep_sequence
>>> +     I2C sequence to write during suspend
>>> +
>>> +- wake_sequence
>>> +     I2C sequence to write during wake
>>> +
>>> +Examples :
>>> +
>>> +i2c0: i2c at 0 {
>>> +     /* Set OPP50 (0.95V) for VDD core */
>>> +     sleep_sequence = /bits/ 8 <
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>>> +             0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +     >;
>>
>> This data is not related to i2c. Right? Then why is it under i2c dt node?
>>
>> There is already a wakeup node (wkup_m3) and a pmic node (pmic node for
>> respective boards). Can't these details go under those nodes?
> 
> The i2c node was chosen for several reasons. First that the bus speed
> is included in the message to the CM3 firmware. The bus speed and
> sequence can then be read from the same device tree node. Second so
> it's clear which I2C bus this is being sent out on. Including it under
> the PMIC node would mean that the code would have to search each child
> of the I2C bus for a sequence and if multiple children had sequences,
> it would not know in which order to send those sequences out.

Agreed

> 
>>> +
>>> +     /* Set OPP100 (1.10V) for VDD core */
>>> +     wake_sequence = /bits/ 8 <
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 1 */
>>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>>> +             0x02 0x24 0x0b 0x6d /* Password unlock 2 */
>>> +             0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 1 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +             0x02 0x24 0x0b 0x6c /* Password unlock 2 */
>>> +             0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>>> +     >;
>>> +}
>>> diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
>>> index 934041a..dfbd5f0 100644
>>> --- a/arch/arm/mach-omap2/control.c
>>> +++ b/arch/arm/mach-omap2/control.c
>>> @@ -639,6 +639,7 @@ void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
>>>       omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
>>>       omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
>>>       omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
>>> +     omap_ctrl_writel(data->param4, AM33XX_CONTROL_IPC_MSG_REG5);
>>>  }
>>>
>>>  int am33xx_pm_status(void)
>>> diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
>>> index d291c76..8880da3 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.c
>>> +++ b/arch/arm/mach-omap2/pm33xx.c
>>> @@ -29,6 +29,7 @@
>>>  #include <linux/ti_emif.h>
>>>  #include <linux/omap-mailbox.h>
>>>
>>> +#include <asm/unaligned.h>
>>>  #include <asm/suspend.h>
>>>  #include <asm/proc-fns.h>
>>>  #include <asm/sizes.h>
>>> @@ -50,6 +51,10 @@
>>>  static void __iomem *am33xx_emif_base;
>>>  static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
>>>  static struct clockdomain *gfx_l4ls_clkdm;
>>> +static char *am33xx_i2c_sleep_sequence;
>>> +static char *am33xx_i2c_wake_sequence;
>>> +static size_t i2c_sleep_sequence_sz;
>>> +static size_t i2c_wake_sequence_sz;
>>>
>>>  struct wakeup_src wakeups[] = {
>>>       {.irq_nr = 35,  .src = "USB0_PHY"},
>>> @@ -232,12 +237,34 @@ static void am33xx_m3_state_machine_reset(void)
>>>  static int am33xx_pm_begin(suspend_state_t state)
>>>  {
>>>       int i;
>>> +     unsigned long param4;
>>> +     int pos;
>>>
>>>       cpu_idle_poll_ctrl(true);
>>>
>>> +     param4 = DS_IPC_DEFAULT;
>>> +
>>> +     wkup_m3_reset_data_pos();
>>> +     if (am33xx_i2c_sleep_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>> +                                             i2c_sleep_sequence_sz);
>>
>> Why do we need to copy this data (same constant data) on every iteration?
> 
> Because the CM3 firmware is reset after each suspend/resume cycle. The
> firmware reset handler reinitializes the DMEM.

Is it. Do you have any more information about the same?

Even then, you can copy from DT to CM3 and remove 2nd temp storage. Right?

> 
>>> +             /* Lower 16 bits stores offset to sleep sequence */
>>> +             param4 &= ~0xffff;
>>> +             param4 |= pos;
>>> +     }
>>> +
>>> +     if (am33xx_i2c_wake_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>>> +                                             i2c_wake_sequence_sz);
>>> +             /* Upper 16 bits stores offset to wake sequence */
>>> +             param4 &= ~0xffff0000;
>>> +             param4 |= pos << 16;
>>> +     }
>>> +
>>
>> Seems above entire change can be done only once.
>>
>>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>>> +     am33xx_pm->ipc.param4           = param4;
>>>
>>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>>
>>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>>       return 0;
>>>  }
>>>
>>> +static int __init am33xx_setup_sleep_sequence(void)
>>> +{
>>> +     int ret;
>>> +     int sz;
>>> +     const void *prop;
>>> +     struct device *dev;
>>> +     u32 freq_hz = 100000;
>>
>> Magic number?
> 
> It's taken from drivers/i2c/busses/i2c-omap.c
> 
>     u32 freq = 100000; /* default to 100000 Hz */
> 
> I'll add a comment to that effect.
> 
>>> +     unsigned short freq_khz;
>>> +
>>> +     /*
>>> +      * We put the device tree node in the I2C controller that will
>>> +      * be sending the sequence. i2c1 is the only controller that can
>>> +      * be accessed by the firmware as it is the only controller in the
>>> +      * WKUP domain.
>>
>> and on which the PMIC sits I believe?
> 
> Yes, but this code is designed not to be PMIC specific as one could
> chose to regulate VDD_CORE with any PMIC, or even with a standalone
> I2C controlled regulator.
> 
>>> +      */
>>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>>> +     if (IS_ERR(dev))
>>> +             return PTR_ERR(dev);
>>> +
>>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>>> +     freq_khz = freq_hz / 1000;
>>
>> Magic number?
> 
> Nah, converting between metric prefixes this way is pretty common in the kernel.

oh. Correct.

> 
>>> +
>>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>>> +     if (prop) {
>>> +             /*
>>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>>> +              * byte for terminator.
>>> +              */
>>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_sleep_sequence)
>>> +                     return -ENOMEM;
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>>
>> so, looking at entire code, it seems there is 3 memory space for same
>> data (or 1 original + 2 copy)
>>
>> 1. in DT
>> 2. in am33xx_i2c_[sleep/wake]_sequence
>> 3. in SRAm by call to wkup_m3_copy_data()
>>
>> why not directly copy to SRAM from DT?
> 
> As pointed out above, the firmware reset handler would wipe it out.

i have update my comment above.

> 
>>> +             i2c_sleep_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>>> +     if (prop) {
>>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_wake_sequence) {
>>> +                     ret = -ENOMEM;
>>> +                     goto cleanup_sleep;
>>> +             }
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>>> +             i2c_wake_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     return 0;
>>> +
>>> +cleanup_sleep:
>>> +     kfree(am33xx_i2c_sleep_sequence);
>>> +     am33xx_i2c_sleep_sequence = NULL;
>>> +     return ret;
>>> +}
>>> +
>>>  int __init am33xx_pm_init(void)
>>>  {
>>>       int ret;
>>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>>               }
>>>       }
>>>
>>> +     ret = am33xx_setup_sleep_sequence();
>>> +     if (ret) {
>>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>>> +             goto err;
>>> +     }
>>> +
>>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>>
>>>       /* CEFUSE domain can be turned off post bootup */
>>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>>> index befdd11..d0f08a5 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.h
>>> +++ b/arch/arm/mach-omap2/pm33xx.h
>>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>>  };
>>>
>>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>>> +void wkup_m3_reset_data_pos(void);
>>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>>  int wkup_m3_prepare(void);
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>>
>>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>>> index 8eaa7f3..a541de9 100644
>>> --- a/arch/arm/mach-omap2/wkup_m3.c
>>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>>> @@ -35,6 +35,9 @@
>>>  struct wkup_m3_context {
>>>       struct device   *dev;
>>>       void __iomem    *code;
>>> +     void __iomem    *data;
>>> +     void __iomem    *data_end;
>>> +     size_t          data_size;
>>>       void (*txev_handler)(void);
>>>  };
>>>
>>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>>       return 0;
>>>  }
>>>
>>> +/*
>>> + * This pair of functions allows data to be stuffed into the end of the
>>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>>> + * sequences to the firmware.
>>> + */
>>> +
>>> +/* Clear out the pointer for data stored at the end of DMEM */
>>> +void wkup_m3_reset_data_pos(void)
>>> +{
>>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>>> +}
>>> +
>>> +/*
>>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>>> + * that the data is stored at, or -ENOMEM if the data did not fit
>>> + */
>>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>>> +{
>>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>>> +             return -ENOMEM;
>>> +     wkup_m3->data_end -= size;
>>> +     memcpy_toio(wkup_m3->data_end, data, size);
>>> +     return wkup_m3->data_end - wkup_m3->data;
>>> +}
>>>
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>>  {
>>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>>  static int wkup_m3_probe(struct platform_device *pdev)
>>>  {
>>>       int irq, ret = 0;
>>> -     struct resource *mem;
>>> +     struct resource *umem, *dmem;
>>>
>>>       pm_runtime_enable(&pdev->dev);
>>>
>>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       irq = platform_get_irq(pdev, 0);
>>>       if (!irq) {
>>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>>> +             dev_err(&pdev->dev, "no irq resource\n");
>>
>> unrelated change?. Better to mention this as code cleanup in commit.
> 
> Will add a comment to that effect, the underlying error should be
> fixed in the next suspend/resume patch though.
> 
>>> +             ret = -ENXIO;
>>> +             goto err;
>>> +     }
>>> +
>>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +     if (!umem) {
>>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>>
>>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> -     if (!mem) {
>>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>> +     if (!dmem) {
>>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       wkup_m3->dev = &pdev->dev;
>>>
>>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>>> +     if (!wkup_m3->code) {
>>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>>
>> why not use "pdev->dev" here?
> 
> Either one works

just for consistency.

> 
>>> +             ret = -EADDRNOTAVAIL;
>>> +             goto err;
>>> +     }
>>> +
>>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>>       if (!wkup_m3->code) {
>>
>> I believe this is just a copy/paste error. s/code/data
> 
> Doh, thanks!
> 
>>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>>
>> same as above.
>>
>>>               ret = -EADDRNOTAVAIL;
>>>               goto err;
>>>       }
>>> +     wkup_m3->data_size = resource_size(dmem);
>>> +     wkup_m3_reset_data_pos();
>>>
>>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>>> linux-omap" in the body of a message to majordomo at vger.kernel.org More
>>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-14 22:34       ` Russ Dill
@ 2013-08-19  5:49         ` Gururaja Hebbar
  -1 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-19  5:49 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel

On 8/15/2013 4:04 AM, Russ Dill wrote:
> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>> Changes since v1:
>>> * Rebased onto new am335x PM branch
>>> * Changed to use 5th param register

>>

[snip]
[snip]

>>> +
>>> +     wkup_m3_reset_data_pos();
>>> +     if (am33xx_i2c_sleep_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>> +                                             i2c_sleep_sequence_sz);
>>
>> Why do we need to copy this data (same constant data) on every iteration?
> 
> Because the CM3 firmware is reset after each suspend/resume cycle. The
> firmware reset handler reinitializes the DMEM.

Well in that why can't the i2c payload be copied to UMEM?

Thanks & regards
Gururaja

> 
>>> +             /* Lower 16 bits stores offset to sleep sequence */
>>> +             param4 &= ~0xffff;
>>> +             param4 |= pos;
>>> +     }
>>> +
>>> +     if (am33xx_i2c_wake_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>>> +                                             i2c_wake_sequence_sz);
>>> +             /* Upper 16 bits stores offset to wake sequence */
>>> +             param4 &= ~0xffff0000;
>>> +             param4 |= pos << 16;
>>> +     }
>>> +
>>
>> Seems above entire change can be done only once.
>>
>>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>>> +     am33xx_pm->ipc.param4           = param4;
>>>
>>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>>
>>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>>       return 0;
>>>  }
>>>
>>> +static int __init am33xx_setup_sleep_sequence(void)
>>> +{
>>> +     int ret;
>>> +     int sz;
>>> +     const void *prop;
>>> +     struct device *dev;
>>> +     u32 freq_hz = 100000;
>>
>> Magic number?
> 
> It's taken from drivers/i2c/busses/i2c-omap.c
> 
>     u32 freq = 100000; /* default to 100000 Hz */
> 
> I'll add a comment to that effect.
> 
>>> +     unsigned short freq_khz;
>>> +
>>> +     /*
>>> +      * We put the device tree node in the I2C controller that will
>>> +      * be sending the sequence. i2c1 is the only controller that can
>>> +      * be accessed by the firmware as it is the only controller in the
>>> +      * WKUP domain.
>>
>> and on which the PMIC sits I believe?
> 
> Yes, but this code is designed not to be PMIC specific as one could
> chose to regulate VDD_CORE with any PMIC, or even with a standalone
> I2C controlled regulator.
> 
>>> +      */
>>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>>> +     if (IS_ERR(dev))
>>> +             return PTR_ERR(dev);
>>> +
>>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>>> +     freq_khz = freq_hz / 1000;
>>
>> Magic number?
> 
> Nah, converting between metric prefixes this way is pretty common in the kernel.
> 
>>> +
>>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>>> +     if (prop) {
>>> +             /*
>>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>>> +              * byte for terminator.
>>> +              */
>>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_sleep_sequence)
>>> +                     return -ENOMEM;
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>>
>> so, looking at entire code, it seems there is 3 memory space for same
>> data (or 1 original + 2 copy)
>>
>> 1. in DT
>> 2. in am33xx_i2c_[sleep/wake]_sequence
>> 3. in SRAm by call to wkup_m3_copy_data()
>>
>> why not directly copy to SRAM from DT?
> 
> As pointed out above, the firmware reset handler would wipe it out.
> 
>>> +             i2c_sleep_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>>> +     if (prop) {
>>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_wake_sequence) {
>>> +                     ret = -ENOMEM;
>>> +                     goto cleanup_sleep;
>>> +             }
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>>> +             i2c_wake_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     return 0;
>>> +
>>> +cleanup_sleep:
>>> +     kfree(am33xx_i2c_sleep_sequence);
>>> +     am33xx_i2c_sleep_sequence = NULL;
>>> +     return ret;
>>> +}
>>> +
>>>  int __init am33xx_pm_init(void)
>>>  {
>>>       int ret;
>>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>>               }
>>>       }
>>>
>>> +     ret = am33xx_setup_sleep_sequence();
>>> +     if (ret) {
>>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>>> +             goto err;
>>> +     }
>>> +
>>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>>
>>>       /* CEFUSE domain can be turned off post bootup */
>>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>>> index befdd11..d0f08a5 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.h
>>> +++ b/arch/arm/mach-omap2/pm33xx.h
>>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>>  };
>>>
>>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>>> +void wkup_m3_reset_data_pos(void);
>>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>>  int wkup_m3_prepare(void);
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>>
>>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>>> index 8eaa7f3..a541de9 100644
>>> --- a/arch/arm/mach-omap2/wkup_m3.c
>>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>>> @@ -35,6 +35,9 @@
>>>  struct wkup_m3_context {
>>>       struct device   *dev;
>>>       void __iomem    *code;
>>> +     void __iomem    *data;
>>> +     void __iomem    *data_end;
>>> +     size_t          data_size;
>>>       void (*txev_handler)(void);
>>>  };
>>>
>>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>>       return 0;
>>>  }
>>>
>>> +/*
>>> + * This pair of functions allows data to be stuffed into the end of the
>>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>>> + * sequences to the firmware.
>>> + */
>>> +
>>> +/* Clear out the pointer for data stored at the end of DMEM */
>>> +void wkup_m3_reset_data_pos(void)
>>> +{
>>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>>> +}
>>> +
>>> +/*
>>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>>> + * that the data is stored at, or -ENOMEM if the data did not fit
>>> + */
>>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>>> +{
>>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>>> +             return -ENOMEM;
>>> +     wkup_m3->data_end -= size;
>>> +     memcpy_toio(wkup_m3->data_end, data, size);
>>> +     return wkup_m3->data_end - wkup_m3->data;
>>> +}
>>>
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>>  {
>>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>>  static int wkup_m3_probe(struct platform_device *pdev)
>>>  {
>>>       int irq, ret = 0;
>>> -     struct resource *mem;
>>> +     struct resource *umem, *dmem;
>>>
>>>       pm_runtime_enable(&pdev->dev);
>>>
>>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       irq = platform_get_irq(pdev, 0);
>>>       if (!irq) {
>>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>>> +             dev_err(&pdev->dev, "no irq resource\n");
>>
>> unrelated change?. Better to mention this as code cleanup in commit.
> 
> Will add a comment to that effect, the underlying error should be
> fixed in the next suspend/resume patch though.
> 
>>> +             ret = -ENXIO;
>>> +             goto err;
>>> +     }
>>> +
>>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +     if (!umem) {
>>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>>
>>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> -     if (!mem) {
>>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>> +     if (!dmem) {
>>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       wkup_m3->dev = &pdev->dev;
>>>
>>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>>> +     if (!wkup_m3->code) {
>>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>>
>> why not use "pdev->dev" here?
> 
> Either one works
> 
>>> +             ret = -EADDRNOTAVAIL;
>>> +             goto err;
>>> +     }
>>> +
>>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>>       if (!wkup_m3->code) {
>>
>> I believe this is just a copy/paste error. s/code/data
> 
> Doh, thanks!
> 
>>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>>
>> same as above.
>>
>>>               ret = -EADDRNOTAVAIL;
>>>               goto err;
>>>       }
>>> +     wkup_m3->data_size = resource_size(dmem);
>>> +     wkup_m3_reset_data_pos();
>>>
>>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>>> linux-omap" in the body of a message to majordomo@vger.kernel.org More
>>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-19  5:49         ` Gururaja Hebbar
  0 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-19  5:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 8/15/2013 4:04 AM, Russ Dill wrote:
> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>> Changes since v1:
>>> * Rebased onto new am335x PM branch
>>> * Changed to use 5th param register

>>

[snip]
[snip]

>>> +
>>> +     wkup_m3_reset_data_pos();
>>> +     if (am33xx_i2c_sleep_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>> +                                             i2c_sleep_sequence_sz);
>>
>> Why do we need to copy this data (same constant data) on every iteration?
> 
> Because the CM3 firmware is reset after each suspend/resume cycle. The
> firmware reset handler reinitializes the DMEM.

Well in that why can't the i2c payload be copied to UMEM?

Thanks & regards
Gururaja

> 
>>> +             /* Lower 16 bits stores offset to sleep sequence */
>>> +             param4 &= ~0xffff;
>>> +             param4 |= pos;
>>> +     }
>>> +
>>> +     if (am33xx_i2c_wake_sequence) {
>>> +             pos = wkup_m3_copy_data(am33xx_i2c_wake_sequence,
>>> +                                             i2c_wake_sequence_sz);
>>> +             /* Upper 16 bits stores offset to wake sequence */
>>> +             param4 &= ~0xffff0000;
>>> +             param4 |= pos << 16;
>>> +     }
>>> +
>>
>> Seems above entire change can be done only once.
>>
>>>       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
>>>       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
>>>       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
>>> +     am33xx_pm->ipc.param4           = param4;
>>>
>>>       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
>>>
>>> @@ -386,6 +413,62 @@ static int __init am33xx_map_emif(void)
>>>       return 0;
>>>  }
>>>
>>> +static int __init am33xx_setup_sleep_sequence(void)
>>> +{
>>> +     int ret;
>>> +     int sz;
>>> +     const void *prop;
>>> +     struct device *dev;
>>> +     u32 freq_hz = 100000;
>>
>> Magic number?
> 
> It's taken from drivers/i2c/busses/i2c-omap.c
> 
>     u32 freq = 100000; /* default to 100000 Hz */
> 
> I'll add a comment to that effect.
> 
>>> +     unsigned short freq_khz;
>>> +
>>> +     /*
>>> +      * We put the device tree node in the I2C controller that will
>>> +      * be sending the sequence. i2c1 is the only controller that can
>>> +      * be accessed by the firmware as it is the only controller in the
>>> +      * WKUP domain.
>>
>> and on which the PMIC sits I believe?
> 
> Yes, but this code is designed not to be PMIC specific as one could
> chose to regulate VDD_CORE with any PMIC, or even with a standalone
> I2C controlled regulator.
> 
>>> +      */
>>> +     dev = omap_device_get_by_hwmod_name("i2c1");
>>> +     if (IS_ERR(dev))
>>> +             return PTR_ERR(dev);
>>> +
>>> +     of_property_read_u32(dev->of_node, "clock-frequency", &freq_hz);
>>> +     freq_khz = freq_hz / 1000;
>>
>> Magic number?
> 
> Nah, converting between metric prefixes this way is pretty common in the kernel.
> 
>>> +
>>> +     prop = of_get_property(dev->of_node, "sleep_sequence", &sz);
>>> +     if (prop) {
>>> +             /*
>>> +              * Length is sequence length + 2 bytes for freq_khz, and 1
>>> +              * byte for terminator.
>>> +              */
>>> +             am33xx_i2c_sleep_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_sleep_sequence)
>>> +                     return -ENOMEM;
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_sleep_sequence + 2, prop, sz);
>>
>> so, looking at entire code, it seems there is 3 memory space for same
>> data (or 1 original + 2 copy)
>>
>> 1. in DT
>> 2. in am33xx_i2c_[sleep/wake]_sequence
>> 3. in SRAm by call to wkup_m3_copy_data()
>>
>> why not directly copy to SRAM from DT?
> 
> As pointed out above, the firmware reset handler would wipe it out.
> 
>>> +             i2c_sleep_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     prop = of_get_property(dev->of_node, "wake_sequence", &sz);
>>> +     if (prop) {
>>> +             am33xx_i2c_wake_sequence = kzalloc(sz + 3, GFP_KERNEL);
>>> +             if (!am33xx_i2c_wake_sequence) {
>>> +                     ret = -ENOMEM;
>>> +                     goto cleanup_sleep;
>>> +             }
>>> +             put_unaligned_le16(freq_khz, am33xx_i2c_sleep_sequence);
>>> +             memcpy(am33xx_i2c_wake_sequence + 2, prop, sz);
>>> +             i2c_wake_sequence_sz = sz + 3;
>>> +     }
>>> +
>>> +     return 0;
>>> +
>>> +cleanup_sleep:
>>> +     kfree(am33xx_i2c_sleep_sequence);
>>> +     am33xx_i2c_sleep_sequence = NULL;
>>> +     return ret;
>>> +}
>>> +
>>>  int __init am33xx_pm_init(void)
>>>  {
>>>       int ret;
>>> @@ -451,6 +534,12 @@ int __init am33xx_pm_init(void)
>>>               }
>>>       }
>>>
>>> +     ret = am33xx_setup_sleep_sequence();
>>> +     if (ret) {
>>> +             pr_err("Error fetching I2C sleep/wake sequence\n");
>>> +             goto err;
>>> +     }
>>> +
>>>       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
>>>
>>>       /* CEFUSE domain can be turned off post bootup */
>>> diff --git a/arch/arm/mach-omap2/pm33xx.h b/arch/arm/mach-omap2/pm33xx.h
>>> index befdd11..d0f08a5 100644
>>> --- a/arch/arm/mach-omap2/pm33xx.h
>>> +++ b/arch/arm/mach-omap2/pm33xx.h
>>> @@ -52,6 +52,8 @@ struct forced_standby_module {
>>>  };
>>>
>>>  int wkup_m3_copy_code(const u8 *data, size_t size);
>>> +void wkup_m3_reset_data_pos(void);
>>> +int wkup_m3_copy_data(const u8 *data, size_t size);
>>>  int wkup_m3_prepare(void);
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void));
>>>
>>> diff --git a/arch/arm/mach-omap2/wkup_m3.c b/arch/arm/mach-omap2/wkup_m3.c
>>> index 8eaa7f3..a541de9 100644
>>> --- a/arch/arm/mach-omap2/wkup_m3.c
>>> +++ b/arch/arm/mach-omap2/wkup_m3.c
>>> @@ -35,6 +35,9 @@
>>>  struct wkup_m3_context {
>>>       struct device   *dev;
>>>       void __iomem    *code;
>>> +     void __iomem    *data;
>>> +     void __iomem    *data_end;
>>> +     size_t          data_size;
>>>       void (*txev_handler)(void);
>>>  };
>>>
>>> @@ -50,6 +53,30 @@ int wkup_m3_copy_code(const u8 *data, size_t size)
>>>       return 0;
>>>  }
>>>
>>> +/*
>>> + * This pair of functions allows data to be stuffed into the end of the
>>> + * CM3 data memory. This is currently used for passing the I2C sleep/wake
>>> + * sequences to the firmware.
>>> + */
>>> +
>>> +/* Clear out the pointer for data stored at the end of DMEM */
>>> +void wkup_m3_reset_data_pos(void)
>>> +{
>>> +     wkup_m3->data_end = wkup_m3->data + wkup_m3->data_size;
>>> +}
>>> +
>>> +/*
>>> + * Store a block of data at the end of DMEM, return the offset within DMEM
>>> + * that the data is stored at, or -ENOMEM if the data did not fit
>>> + */
>>> +int wkup_m3_copy_data(const u8 *data, size_t size)
>>> +{
>>> +     if (wkup_m3->data + size > wkup_m3->data_end)
>>> +             return -ENOMEM;
>>> +     wkup_m3->data_end -= size;
>>> +     memcpy_toio(wkup_m3->data_end, data, size);
>>> +     return wkup_m3->data_end - wkup_m3->data;
>>> +}
>>>
>>>  void wkup_m3_register_txev_handler(void (*txev_handler)(void))
>>>  {
>>> @@ -83,7 +110,7 @@ int wkup_m3_prepare(void)
>>>  static int wkup_m3_probe(struct platform_device *pdev)
>>>  {
>>>       int irq, ret = 0;
>>> -     struct resource *mem;
>>> +     struct resource *umem, *dmem;
>>>
>>>       pm_runtime_enable(&pdev->dev);
>>>
>>> @@ -95,14 +122,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       irq = platform_get_irq(pdev, 0);
>>>       if (!irq) {
>>> -             dev_err(wkup_m3->dev, "no irq resource\n");
>>> +             dev_err(&pdev->dev, "no irq resource\n");
>>
>> unrelated change?. Better to mention this as code cleanup in commit.
> 
> Will add a comment to that effect, the underlying error should be
> fixed in the next suspend/resume patch though.
> 
>>> +             ret = -ENXIO;
>>> +             goto err;
>>> +     }
>>> +
>>> +     umem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +     if (!umem) {
>>> +             dev_err(&pdev->dev, "no UMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>>
>>> -     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> -     if (!mem) {
>>> -             dev_err(wkup_m3->dev, "no memory resource\n");
>>> +     dmem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>> +     if (!dmem) {
>>> +             dev_err(&pdev->dev, "no DMEM resource\n");
>>>               ret = -ENXIO;
>>>               goto err;
>>>       }
>>> @@ -116,12 +150,21 @@ static int wkup_m3_probe(struct platform_device *pdev)
>>>
>>>       wkup_m3->dev = &pdev->dev;
>>>
>>> -     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
>>> +     wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, umem);
>>> +     if (!wkup_m3->code) {
>>> +             dev_err(wkup_m3->dev, "could not ioremap UMEM\n");
>>
>> why not use "pdev->dev" here?
> 
> Either one works
> 
>>> +             ret = -EADDRNOTAVAIL;
>>> +             goto err;
>>> +     }
>>> +
>>> +     wkup_m3->data = devm_request_and_ioremap(wkup_m3->dev, dmem);
>>>       if (!wkup_m3->code) {
>>
>> I believe this is just a copy/paste error. s/code/data
> 
> Doh, thanks!
> 
>>> -             dev_err(wkup_m3->dev, "could not ioremap\n");
>>> +             dev_err(wkup_m3->dev, "could not ioremap DMEM\n");
>>
>> same as above.
>>
>>>               ret = -EADDRNOTAVAIL;
>>>               goto err;
>>>       }
>>> +     wkup_m3->data_size = resource_size(dmem);
>>> +     wkup_m3_reset_data_pos();
>>>
>>>       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
>>>                 IRQF_DISABLED, "wkup_m3_txev", NULL);
>>> -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe
>>> linux-omap" in the body of a message to majordomo at vger.kernel.org More
>>> majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-19  5:49         ` Gururaja Hebbar
@ 2013-08-20 16:33           ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-20 16:33 UTC (permalink / raw)
  To: Gururaja Hebbar
  Cc: Kevin Hilman, devicetree, Devicetree Discuss, linux-omap,
	Linux ARM Kernel List

On Sun, Aug 18, 2013 at 10:49 PM, Gururaja Hebbar
<gururaja.hebbar@ti.com> wrote:
>
> On 8/15/2013 4:04 AM, Russ Dill wrote:
> > On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> >> On 8/14/2013 3:50 AM, Russ Dill wrote:
> >>> Changes since v1:
> >>> * Rebased onto new am335x PM branch
> >>> * Changed to use 5th param register
>
> >>
>
> [snip]
> [snip]
>
> >>> +
> >>> +     wkup_m3_reset_data_pos();
> >>> +     if (am33xx_i2c_sleep_sequence) {
> >>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
> >>> +                                             i2c_sleep_sequence_sz);
> >>
> >> Why do we need to copy this data (same constant data) on every iteration?
> >
> > Because the CM3 firmware is reset after each suspend/resume cycle. The
> > firmware reset handler reinitializes the DMEM.
>
> Well in that why can't the i2c payload be copied to UMEM?
>
> Thanks & regards
> Gururaja
>

I've given this some thought, and gone back and forth a bit. UMEM is a
bit more complicated because the linker decides what should go where.
Also, it may be that in the future, either the PM for am335x or am43xx
will be writing different sequences depending on the suspend
mode/options.

Is there a specific aspect of copying the data each suspend cycle that
you are trying to fix? Is it just that the data could only be copied
once? Or is it the latency of the copy?

Thanks!

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-20 16:33           ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-20 16:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Aug 18, 2013 at 10:49 PM, Gururaja Hebbar
<gururaja.hebbar@ti.com> wrote:
>
> On 8/15/2013 4:04 AM, Russ Dill wrote:
> > On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
> >> On 8/14/2013 3:50 AM, Russ Dill wrote:
> >>> Changes since v1:
> >>> * Rebased onto new am335x PM branch
> >>> * Changed to use 5th param register
>
> >>
>
> [snip]
> [snip]
>
> >>> +
> >>> +     wkup_m3_reset_data_pos();
> >>> +     if (am33xx_i2c_sleep_sequence) {
> >>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
> >>> +                                             i2c_sleep_sequence_sz);
> >>
> >> Why do we need to copy this data (same constant data) on every iteration?
> >
> > Because the CM3 firmware is reset after each suspend/resume cycle. The
> > firmware reset handler reinitializes the DMEM.
>
> Well in that why can't the i2c payload be copied to UMEM?
>
> Thanks & regards
> Gururaja
>

I've given this some thought, and gone back and forth a bit. UMEM is a
bit more complicated because the linker decides what should go where.
Also, it may be that in the future, either the PM for am335x or am43xx
will be writing different sequences depending on the suspend
mode/options.

Is there a specific aspect of copying the data each suspend cycle that
you are trying to fix? Is it just that the data could only be copied
once? Or is it the latency of the copy?

Thanks!

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
  2013-08-20 16:33           ` Russ Dill
@ 2013-08-21  8:29             ` Gururaja Hebbar
  -1 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-21  8:29 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, Devicetree Discuss, linux-omap,
	Linux ARM Kernel List

On 8/20/2013 10:03 PM, Russ Dill wrote:
> On Sun, Aug 18, 2013 at 10:49 PM, Gururaja Hebbar
> <gururaja.hebbar@ti.com> wrote:
>>
>> On 8/15/2013 4:04 AM, Russ Dill wrote:
>>> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>>>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>>>> Changes since v1:
>>>>> * Rebased onto new am335x PM branch
>>>>> * Changed to use 5th param register
>>
>>>>
>>
>> [snip]
>> [snip]
>>
>>>>> +
>>>>> +     wkup_m3_reset_data_pos();
>>>>> +     if (am33xx_i2c_sleep_sequence) {
>>>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>>>> +                                             i2c_sleep_sequence_sz);
>>>>
>>>> Why do we need to copy this data (same constant data) on every iteration?
>>>
>>> Because the CM3 firmware is reset after each suspend/resume cycle. The
>>> firmware reset handler reinitializes the DMEM.
>>
>> Well in that why can't the i2c payload be copied to UMEM?
>>
>> Thanks & regards
>> Gururaja
>>
> 
> I've given this some thought, and gone back and forth a bit. UMEM is a
> bit more complicated because the linker decides what should go where.

but linker doesn't know about the copy and the location we are doing at
runtime.

> Also, it may be that in the future, either the PM for am335x or am43xx
> will be writing different sequences depending on the suspend
> mode/options.

still these info will be coming from DT and can be copied to UMEM. only
issue could be space.

> 
> Is there a specific aspect of copying the data each suspend cycle that
> you are trying to fix? Is it just that the data could only be copied
> once? Or is it the latency of the copy?

Copy latency on every iterations is what worries me. it will surely add
a delay for suspend.

> 
> Thanks!
> 


^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support
@ 2013-08-21  8:29             ` Gururaja Hebbar
  0 siblings, 0 replies; 84+ messages in thread
From: Gururaja Hebbar @ 2013-08-21  8:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 8/20/2013 10:03 PM, Russ Dill wrote:
> On Sun, Aug 18, 2013 at 10:49 PM, Gururaja Hebbar
> <gururaja.hebbar@ti.com> wrote:
>>
>> On 8/15/2013 4:04 AM, Russ Dill wrote:
>>> On Wed, Aug 14, 2013 at 3:18 AM, Gururaja Hebbar <gururaja.hebbar@ti.com> wrote:
>>>> On 8/14/2013 3:50 AM, Russ Dill wrote:
>>>>> Changes since v1:
>>>>> * Rebased onto new am335x PM branch
>>>>> * Changed to use 5th param register
>>
>>>>
>>
>> [snip]
>> [snip]
>>
>>>>> +
>>>>> +     wkup_m3_reset_data_pos();
>>>>> +     if (am33xx_i2c_sleep_sequence) {
>>>>> +             pos = wkup_m3_copy_data(am33xx_i2c_sleep_sequence,
>>>>> +                                             i2c_sleep_sequence_sz);
>>>>
>>>> Why do we need to copy this data (same constant data) on every iteration?
>>>
>>> Because the CM3 firmware is reset after each suspend/resume cycle. The
>>> firmware reset handler reinitializes the DMEM.
>>
>> Well in that why can't the i2c payload be copied to UMEM?
>>
>> Thanks & regards
>> Gururaja
>>
> 
> I've given this some thought, and gone back and forth a bit. UMEM is a
> bit more complicated because the linker decides what should go where.

but linker doesn't know about the copy and the location we are doing at
runtime.

> Also, it may be that in the future, either the PM for am335x or am43xx
> will be writing different sequences depending on the suspend
> mode/options.

still these info will be coming from DT and can be copied to UMEM. only
issue could be space.

> 
> Is there a specific aspect of copying the data each suspend cycle that
> you are trying to fix? Is it just that the data could only be copied
> once? Or is it the latency of the copy?

Copy latency on every iterations is what worries me. it will surely add
a delay for suspend.

> 
> Thanks!
> 

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-14 22:21     ` Russ Dill
@ 2013-08-27 22:44       ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-27 22:44 UTC (permalink / raw)
  To: Russ Dill
  Cc: Jan Lübbe, devicetree, devicetree-discuss, linux-omap,
	linux-arm-kernel, Mark Brown

[+Mark Brown for regulator suspend sequence ideas]

Russ Dill <Russ.Dill@ti.com> writes:

> On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>>> The purpose and method of executing these sequences is left up to each
>>> platform. In the case of the am33xx, the CM3 firmware writes out the
>>> simple I2C sequences.
>>>
>>> Each sequence is a series of I2C write commands. The first byte is the
>>> length of the write, the second byte the I2C device to address, and
>>> the following bytes are the message.
>>
>>>         /* Set OPP100 (1.10V) for VDD core */
>>>         wake_sequence = /bits/ 8 <
>>>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>>>         >;
>>>
>>>         tps: tps@2d {
>>>                 reg = <0x2d>;
>>>         };
>>
>>> In the above example, the sequence "0x25 0x1f" is written to the I2C
>>> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
>>> as a write to a register at address 0x25.
>>
>>> I'd really like to get some feedback on the devicetree bindings.

Well the first comment (also made by others) is that the DT should be
describing the hardware, and by that rule, the wake/sleep sequences are
not properties of the i2c node but rather properties of the pmic.
You've pointed out the inconveniences caused by that, but I'm not sure
that those are enough to break the basic DT rules there.  I'll leave it
to the DT reviewers to make that decision.

>> Shouldn't the TPS driver know how to generate this sequence? It seems
>> fragile to do voltage adjustments behind the back of the regulator
>> framework and the TPS driver. The wake-sequence values should match the
>> (in-memory) regulator configuration on resume (which may have been
>> changed by DVFS).
>
> The sequence is both PMIC specific and board specific. Additionally,
> the PMICs used aren't am335x specific. It would be nice to have the
> regulator framework and the driver write all this out, but the
> sequence is written out by the Cortex-M3 processor running some PM
> firmware. Even if the code was changed to run on the A8, it'd have to
> run from a small piece of SRAM.

So, why/how was the decision made to use the M3 instead of the MPU
running from SRAM?

As a firmware minimalist, I obviously prefer to do this from the MPU
side.  But also, because the M3 is reset every suspend sequence, this
becomes rather heavy to do from the M3. 

Currently voltage scaling is only being proposed for suspend in this
series, but in theory it's possible from idle as well.  Doing this from
the MPU/SRAM seems much better suited for idle.

> As far as DVFS, I'm not aware of any DVFS implementations that muck
> with VDD CORE.
>
>> The CM3 driver needs to figure out where the core regulator is connected
>> using using either DT or the regulator framework and ask the TPS (via a
>> new interface) for register writes for sleep/wake sequences. Then those
>> sequences will actually match the correct voltages configured using
>> DT/DVFS.
>
> That seems like it'd add a lot of complexity to the regulator
> subsystem, as well as all the PMIC and other I2C regulators that any
> users of these device tree properties may end up using for not a lot
> of gain. There would be two separate code paths for any used
> I2C regulator or PMIC for setting voltages.

Added Mark for his thoughts on this, but seems like complexity that the
regulator framework might need to grow anyways.  

The framework already has a concept of suspend voltage, suspend mode
etc.  Maybe it needs some generalizing so low-level platform code could
query the framework for the sequence so it can be done late in platform
idle/suspend paths.  Especially for regmap drivers, this seems feasible.

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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-27 22:44       ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-27 22:44 UTC (permalink / raw)
  To: linux-arm-kernel

[+Mark Brown for regulator suspend sequence ideas]

Russ Dill <Russ.Dill@ti.com> writes:

> On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>>> The purpose and method of executing these sequences is left up to each
>>> platform. In the case of the am33xx, the CM3 firmware writes out the
>>> simple I2C sequences.
>>>
>>> Each sequence is a series of I2C write commands. The first byte is the
>>> length of the write, the second byte the I2C device to address, and
>>> the following bytes are the message.
>>
>>>         /* Set OPP100 (1.10V) for VDD core */
>>>         wake_sequence = /bits/ 8 <
>>>                 0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>>>         >;
>>>
>>>         tps: tps at 2d {
>>>                 reg = <0x2d>;
>>>         };
>>
>>> In the above example, the sequence "0x25 0x1f" is written to the I2C
>>> device at address 0x2d (the TPS65910 PMIC). The PMIC interprets that
>>> as a write to a register at address 0x25.
>>
>>> I'd really like to get some feedback on the devicetree bindings.

Well the first comment (also made by others) is that the DT should be
describing the hardware, and by that rule, the wake/sleep sequences are
not properties of the i2c node but rather properties of the pmic.
You've pointed out the inconveniences caused by that, but I'm not sure
that those are enough to break the basic DT rules there.  I'll leave it
to the DT reviewers to make that decision.

>> Shouldn't the TPS driver know how to generate this sequence? It seems
>> fragile to do voltage adjustments behind the back of the regulator
>> framework and the TPS driver. The wake-sequence values should match the
>> (in-memory) regulator configuration on resume (which may have been
>> changed by DVFS).
>
> The sequence is both PMIC specific and board specific. Additionally,
> the PMICs used aren't am335x specific. It would be nice to have the
> regulator framework and the driver write all this out, but the
> sequence is written out by the Cortex-M3 processor running some PM
> firmware. Even if the code was changed to run on the A8, it'd have to
> run from a small piece of SRAM.

So, why/how was the decision made to use the M3 instead of the MPU
running from SRAM?

As a firmware minimalist, I obviously prefer to do this from the MPU
side.  But also, because the M3 is reset every suspend sequence, this
becomes rather heavy to do from the M3. 

Currently voltage scaling is only being proposed for suspend in this
series, but in theory it's possible from idle as well.  Doing this from
the MPU/SRAM seems much better suited for idle.

> As far as DVFS, I'm not aware of any DVFS implementations that muck
> with VDD CORE.
>
>> The CM3 driver needs to figure out where the core regulator is connected
>> using using either DT or the regulator framework and ask the TPS (via a
>> new interface) for register writes for sleep/wake sequences. Then those
>> sequences will actually match the correct voltages configured using
>> DT/DVFS.
>
> That seems like it'd add a lot of complexity to the regulator
> subsystem, as well as all the PMIC and other I2C regulators that any
> users of these device tree properties may end up using for not a lot
> of gain. There would be two separate code paths for any used
> I2C regulator or PMIC for setting voltages.

Added Mark for his thoughts on this, but seems like complexity that the
regulator framework might need to grow anyways.  

The framework already has a concept of suspend voltage, suspend mode
etc.  Maybe it needs some generalizing so low-level platform code could
query the framework for the sequence so it can be done late in platform
idle/suspend paths.  Especially for regmap drivers, this seems feasible.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-27 22:44       ` Kevin Hilman
@ 2013-08-28  1:05         ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-28  1:05 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Jan Lübbe, devicetree, linux-omap, Linux ARM Kernel List,
	Mark Brown

On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
> [+Mark Brown for regulator suspend sequence ideas]
>
> Russ Dill <Russ.Dill@ti.com> writes:
>
>> On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
[snip]
>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>> fragile to do voltage adjustments behind the back of the regulator
>>> framework and the TPS driver. The wake-sequence values should match the
>>> (in-memory) regulator configuration on resume (which may have been
>>> changed by DVFS).
>>
>> The sequence is both PMIC specific and board specific. Additionally,
>> the PMICs used aren't am335x specific. It would be nice to have the
>> regulator framework and the driver write all this out, but the
>> sequence is written out by the Cortex-M3 processor running some PM
>> firmware. Even if the code was changed to run on the A8, it'd have to
>> run from a small piece of SRAM.
>
> So, why/how was the decision made to use the M3 instead of the MPU
> running from SRAM?
>
> As a firmware minimalist, I obviously prefer to do this from the MPU
> side.  But also, because the M3 is reset every suspend sequence, this
> becomes rather heavy to do from the M3.

After the feedback Vaibhav Bedia received on v2 of his suspend/resume
patchset for am335x, he decided to move many of the operations from
sleep33xx.S into the M3 firmware.

See the commit message here:
http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6

I need to wait until after the PLLs are put into bypass, which is now
done in the M3 firmware. It also ends up being a lot easier to write
the I2C writer code there in C rather than in assembly in sleep33xx.S.

> Currently voltage scaling is only being proposed for suspend in this
> series, but in theory it's possible from idle as well.  Doing this from
> the MPU/SRAM seems much better suited for idle.

The M3 firmware will also handle any cpuidle modes deeper than just
putting SDRAM into self refresh. This is actually the only way of
doing things like turning the MPU domain off on am335x.

>> As far as DVFS, I'm not aware of any DVFS implementations that muck
>> with VDD CORE.
>>
>>> The CM3 driver needs to figure out where the core regulator is connected
>>> using using either DT or the regulator framework and ask the TPS (via a
>>> new interface) for register writes for sleep/wake sequences. Then those
>>> sequences will actually match the correct voltages configured using
>>> DT/DVFS.
>>
>> That seems like it'd add a lot of complexity to the regulator
>> subsystem, as well as all the PMIC and other I2C regulators that any
>> users of these device tree properties may end up using for not a lot
>> of gain. There would be two separate code paths for any used
>> I2C regulator or PMIC for setting voltages.
>
> Added Mark for his thoughts on this, but seems like complexity that the
> regulator framework might need to grow anyways.
>
> The framework already has a concept of suspend voltage, suspend mode
> etc.  Maybe it needs some generalizing so low-level platform code could
> query the framework for the sequence so it can be done late in platform
> idle/suspend paths.  Especially for regmap drivers, this seems feasible.

Yes, my main hesitation for going down this path is possible lack of
support for such an interface upstream.

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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-28  1:05         ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-28  1:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
> [+Mark Brown for regulator suspend sequence ideas]
>
> Russ Dill <Russ.Dill@ti.com> writes:
>
>> On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
[snip]
>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>> fragile to do voltage adjustments behind the back of the regulator
>>> framework and the TPS driver. The wake-sequence values should match the
>>> (in-memory) regulator configuration on resume (which may have been
>>> changed by DVFS).
>>
>> The sequence is both PMIC specific and board specific. Additionally,
>> the PMICs used aren't am335x specific. It would be nice to have the
>> regulator framework and the driver write all this out, but the
>> sequence is written out by the Cortex-M3 processor running some PM
>> firmware. Even if the code was changed to run on the A8, it'd have to
>> run from a small piece of SRAM.
>
> So, why/how was the decision made to use the M3 instead of the MPU
> running from SRAM?
>
> As a firmware minimalist, I obviously prefer to do this from the MPU
> side.  But also, because the M3 is reset every suspend sequence, this
> becomes rather heavy to do from the M3.

After the feedback Vaibhav Bedia received on v2 of his suspend/resume
patchset for am335x, he decided to move many of the operations from
sleep33xx.S into the M3 firmware.

See the commit message here:
http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6

I need to wait until after the PLLs are put into bypass, which is now
done in the M3 firmware. It also ends up being a lot easier to write
the I2C writer code there in C rather than in assembly in sleep33xx.S.

> Currently voltage scaling is only being proposed for suspend in this
> series, but in theory it's possible from idle as well.  Doing this from
> the MPU/SRAM seems much better suited for idle.

The M3 firmware will also handle any cpuidle modes deeper than just
putting SDRAM into self refresh. This is actually the only way of
doing things like turning the MPU domain off on am335x.

>> As far as DVFS, I'm not aware of any DVFS implementations that muck
>> with VDD CORE.
>>
>>> The CM3 driver needs to figure out where the core regulator is connected
>>> using using either DT or the regulator framework and ask the TPS (via a
>>> new interface) for register writes for sleep/wake sequences. Then those
>>> sequences will actually match the correct voltages configured using
>>> DT/DVFS.
>>
>> That seems like it'd add a lot of complexity to the regulator
>> subsystem, as well as all the PMIC and other I2C regulators that any
>> users of these device tree properties may end up using for not a lot
>> of gain. There would be two separate code paths for any used
>> I2C regulator or PMIC for setting voltages.
>
> Added Mark for his thoughts on this, but seems like complexity that the
> regulator framework might need to grow anyways.
>
> The framework already has a concept of suspend voltage, suspend mode
> etc.  Maybe it needs some generalizing so low-level platform code could
> query the framework for the sequence so it can be done late in platform
> idle/suspend paths.  Especially for regmap drivers, this seems feasible.

Yes, my main hesitation for going down this path is possible lack of
support for such an interface upstream.

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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-28  1:05         ` Russ Dill
@ 2013-08-29 11:05           ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 11:05 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, Jan Lübbe, devicetree, linux-omap,
	Linux ARM Kernel List

[-- Attachment #1: Type: text/plain, Size: 1093 bytes --]

On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:

> > The framework already has a concept of suspend voltage, suspend mode
> > etc.  Maybe it needs some generalizing so low-level platform code could
> > query the framework for the sequence so it can be done late in platform
> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.

> Yes, my main hesitation for going down this path is possible lack of
> support for such an interface upstream.

Someone is going to have to walk me through the context for me to fully
understand what this is all about - what's the problem?

Generally for suspend if the sequencing is being done by the processor
it's been handled by the drivers for the components in question.  For
sequencing beyond that you're into hardware features which aren't all
that regular sadly and often aren't controllable either.  It sounds like
this is the latter case but the thing that manages some of the late
power down stages does so using a firmware we can rewrite?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 11:05           ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 11:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:

> > The framework already has a concept of suspend voltage, suspend mode
> > etc.  Maybe it needs some generalizing so low-level platform code could
> > query the framework for the sequence so it can be done late in platform
> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.

> Yes, my main hesitation for going down this path is possible lack of
> support for such an interface upstream.

Someone is going to have to walk me through the context for me to fully
understand what this is all about - what's the problem?

Generally for suspend if the sequencing is being done by the processor
it's been handled by the drivers for the components in question.  For
sequencing beyond that you're into hardware features which aren't all
that regular sadly and often aren't controllable either.  It sounds like
this is the latter case but the thing that manages some of the late
power down stages does so using a firmware we can rewrite?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/03182f12/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-28  1:05         ` Russ Dill
@ 2013-08-29 15:17           ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 15:17 UTC (permalink / raw)
  To: Russ Dill
  Cc: Jan Lübbe, devicetree, linux-omap, Linux ARM Kernel List,
	Mark Brown

Russ Dill <Russ.Dill@ti.com> writes:

> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>> [+Mark Brown for regulator suspend sequence ideas]
>>
>> Russ Dill <Russ.Dill@ti.com> writes:
>>
>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
> [snip]
>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>> fragile to do voltage adjustments behind the back of the regulator
>>>> framework and the TPS driver. The wake-sequence values should match the
>>>> (in-memory) regulator configuration on resume (which may have been
>>>> changed by DVFS).
>>>
>>> The sequence is both PMIC specific and board specific. Additionally,
>>> the PMICs used aren't am335x specific. It would be nice to have the
>>> regulator framework and the driver write all this out, but the
>>> sequence is written out by the Cortex-M3 processor running some PM
>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>> run from a small piece of SRAM.
>>
>> So, why/how was the decision made to use the M3 instead of the MPU
>> running from SRAM?
>>
>> As a firmware minimalist, I obviously prefer to do this from the MPU
>> side.  But also, because the M3 is reset every suspend sequence, this
>> becomes rather heavy to do from the M3.
>
> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
> patchset for am335x, he decided to move many of the operations from
> sleep33xx.S into the M3 firmware.
>
> See the commit message here:
> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6

Was this feedback on the public lists?  That patch has never been posted
to linux-omap AFAICT.

> I need to wait until after the PLLs are put into bypass, which is now
> done in the M3 firmware. It also ends up being a lot easier to write
> the I2C writer code there in C rather than in assembly in sleep33xx.S.

hmm, (carefully) written functions in C can still be copied to SRAM.  I
dont' see that as an obstacle.

>> Currently voltage scaling is only being proposed for suspend in this
>> series, but in theory it's possible from idle as well.  Doing this from
>> the MPU/SRAM seems much better suited for idle.
>
> The M3 firmware will also handle any cpuidle modes deeper than just
> putting SDRAM into self refresh. This is actually the only way of
> doing things like turning the MPU domain off on am335x.

Yes, it will have to handle the MPU/interconnect off parts but other
than that, that's the only thing it *has* to do (well, and handle wakeup
from the deep state.)  The rest of the stuff being piled into the M3 is
a result of software/firmware design decisions AFAICT.  As I predicted
when I first saw this SoC design, the firmware is getting bigger and
bigger.  Initially it was argued that it would be tiny, and only handle
the things it had to do.  Now it's growing due to "convenience".  IMO,
this is a bad trend, and one that will make this code more and more
difficult to maintain upstream (assuming that's a goal.)

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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 15:17           ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

Russ Dill <Russ.Dill@ti.com> writes:

> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>> [+Mark Brown for regulator suspend sequence ideas]
>>
>> Russ Dill <Russ.Dill@ti.com> writes:
>>
>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
> [snip]
>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>> fragile to do voltage adjustments behind the back of the regulator
>>>> framework and the TPS driver. The wake-sequence values should match the
>>>> (in-memory) regulator configuration on resume (which may have been
>>>> changed by DVFS).
>>>
>>> The sequence is both PMIC specific and board specific. Additionally,
>>> the PMICs used aren't am335x specific. It would be nice to have the
>>> regulator framework and the driver write all this out, but the
>>> sequence is written out by the Cortex-M3 processor running some PM
>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>> run from a small piece of SRAM.
>>
>> So, why/how was the decision made to use the M3 instead of the MPU
>> running from SRAM?
>>
>> As a firmware minimalist, I obviously prefer to do this from the MPU
>> side.  But also, because the M3 is reset every suspend sequence, this
>> becomes rather heavy to do from the M3.
>
> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
> patchset for am335x, he decided to move many of the operations from
> sleep33xx.S into the M3 firmware.
>
> See the commit message here:
> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6

Was this feedback on the public lists?  That patch has never been posted
to linux-omap AFAICT.

> I need to wait until after the PLLs are put into bypass, which is now
> done in the M3 firmware. It also ends up being a lot easier to write
> the I2C writer code there in C rather than in assembly in sleep33xx.S.

hmm, (carefully) written functions in C can still be copied to SRAM.  I
dont' see that as an obstacle.

>> Currently voltage scaling is only being proposed for suspend in this
>> series, but in theory it's possible from idle as well.  Doing this from
>> the MPU/SRAM seems much better suited for idle.
>
> The M3 firmware will also handle any cpuidle modes deeper than just
> putting SDRAM into self refresh. This is actually the only way of
> doing things like turning the MPU domain off on am335x.

Yes, it will have to handle the MPU/interconnect off parts but other
than that, that's the only thing it *has* to do (well, and handle wakeup
from the deep state.)  The rest of the stuff being piled into the M3 is
a result of software/firmware design decisions AFAICT.  As I predicted
when I first saw this SoC design, the firmware is getting bigger and
bigger.  Initially it was argued that it would be tiny, and only handle
the things it had to do.  Now it's growing due to "convenience".  IMO,
this is a bad trend, and one that will make this code more and more
difficult to maintain upstream (assuming that's a goal.)

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 11:05           ` Mark Brown
@ 2013-08-29 15:29             ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 15:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Russ Dill, Jan Lübbe, devicetree, linux-omap, Linux ARM Kernel List

On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>
>> > The framework already has a concept of suspend voltage, suspend mode
>> > etc.  Maybe it needs some generalizing so low-level platform code could
>> > query the framework for the sequence so it can be done late in platform
>> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.
>
>> Yes, my main hesitation for going down this path is possible lack of
>> support for such an interface upstream.
>
> Someone is going to have to walk me through the context for me to fully
> understand what this is all about - what's the problem?

The basic problem is how to have low-level platform code (or possibly
firmware) send commands to a regulator to scale voltage.  This has to
happen *very* late in the suspend process, so having the drivers do it
themselves is not feasible.

The proposal in this series is to define the i2c commands sequence to
be sent to the regulator in the i2c node of the DT.  The
platform-specific code then reads the sequence from the DT and sends
the commands (or in in the case of the current series, passes the
sequence to some firmware on a microcontroller which does the
sequence.)

> Generally for suspend if the sequencing is being done by the processor
> it's been handled by the drivers for the components in question.  For
> sequencing beyond that you're into hardware features which aren't all
> that regular sadly and often aren't controllable either.  It sounds like
> this is the latter case but the thing that manages some of the late
> power down stages does so using a firmware we can rewrite?

For the TI AM335x, the source for M3 firmware is available and
configurable[1].  However, I'd still rather see this done by the
low-level platform code in linux, not offloaded to the firmware, but
the linux vs. firmware decision orthogonal to how to define/probe the
sequences that need to be sent to the regulator.

Kevin

[1] git://arago-project.org/git/projects/am33x-cm3.git

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 15:29             ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 15:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>
>> > The framework already has a concept of suspend voltage, suspend mode
>> > etc.  Maybe it needs some generalizing so low-level platform code could
>> > query the framework for the sequence so it can be done late in platform
>> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.
>
>> Yes, my main hesitation for going down this path is possible lack of
>> support for such an interface upstream.
>
> Someone is going to have to walk me through the context for me to fully
> understand what this is all about - what's the problem?

The basic problem is how to have low-level platform code (or possibly
firmware) send commands to a regulator to scale voltage.  This has to
happen *very* late in the suspend process, so having the drivers do it
themselves is not feasible.

The proposal in this series is to define the i2c commands sequence to
be sent to the regulator in the i2c node of the DT.  The
platform-specific code then reads the sequence from the DT and sends
the commands (or in in the case of the current series, passes the
sequence to some firmware on a microcontroller which does the
sequence.)

> Generally for suspend if the sequencing is being done by the processor
> it's been handled by the drivers for the components in question.  For
> sequencing beyond that you're into hardware features which aren't all
> that regular sadly and often aren't controllable either.  It sounds like
> this is the latter case but the thing that manages some of the late
> power down stages does so using a firmware we can rewrite?

For the TI AM335x, the source for M3 firmware is available and
configurable[1].  However, I'd still rather see this done by the
low-level platform code in linux, not offloaded to the firmware, but
the linux vs. firmware decision orthogonal to how to define/probe the
sequences that need to be sent to the regulator.

Kevin

[1] git://arago-project.org/git/projects/am33x-cm3.git

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 11:05           ` Mark Brown
@ 2013-08-29 15:42             ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 15:42 UTC (permalink / raw)
  To: Mark Brown
  Cc: devicetree, linux-omap, Kevin Hilman, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>
>> > The framework already has a concept of suspend voltage, suspend mode
>> > etc.  Maybe it needs some generalizing so low-level platform code could
>> > query the framework for the sequence so it can be done late in platform
>> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.
>
>> Yes, my main hesitation for going down this path is possible lack of
>> support for such an interface upstream.
>
> Someone is going to have to walk me through the context for me to fully
> understand what this is all about - what's the problem?
>
> Generally for suspend if the sequencing is being done by the processor
> it's been handled by the drivers for the components in question.  For
> sequencing beyond that you're into hardware features which aren't all
> that regular sadly and often aren't controllable either.  It sounds like
> this is the latter case but the thing that manages some of the late
> power down stages does so using a firmware we can rewrite?

So the AM335X processor has a small M3 coprocessor attached to it. The
M3 coprocessor is in charge of performing many of the sleep and resume
transition steps. It has a 16k code space for firmware. The CM3
coprocessor has access to most of the same registers the primary
AM335X processor has access to (PM registers, clock registers, I2C
controller, etc).

For the deepest sleep modes, the core power supply can have its
voltage reduced, but only after several steps by the CM3 coprocessor
have been performed. The core power supply voltage must be reduced by
the CM3 coprocessor. The core regulator is controlled by I2C on all
the AM335X platforms that I am aware of, but different platforms have
different I2C regulators.

The path I'm taking in this patchset is to just put the board specific
I2C sequences necessary for the CM3 coprocessor to write out into the
devicetree. I've made it as generic as I can so that other platforms
with similar issues can reuse the bindings. Because of the limitations
of the firmware size and the desire not to have some sort of byte
code, this is a write only sequence.

Kevin Hilman is suggesting some way to query the regulator framework
for this sequence. There would be some call to the regulator framework
that would return a series of I2C commands that would be necessary to
program a regulator to a specific voltage. It would be called twice,
once for the suspend voltage, once for the resume voltage. The
regulator framework would then call into the driver that sets that
voltage, and by some method query the driver for the necessary I2C
sequence, either by some special new call, or some regmap magic.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 15:42             ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
> On Tue, Aug 27, 2013 at 06:05:34PM -0700, Russ Dill wrote:
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>
>> > The framework already has a concept of suspend voltage, suspend mode
>> > etc.  Maybe it needs some generalizing so low-level platform code could
>> > query the framework for the sequence so it can be done late in platform
>> > idle/suspend paths.  Especially for regmap drivers, this seems feasible.
>
>> Yes, my main hesitation for going down this path is possible lack of
>> support for such an interface upstream.
>
> Someone is going to have to walk me through the context for me to fully
> understand what this is all about - what's the problem?
>
> Generally for suspend if the sequencing is being done by the processor
> it's been handled by the drivers for the components in question.  For
> sequencing beyond that you're into hardware features which aren't all
> that regular sadly and often aren't controllable either.  It sounds like
> this is the latter case but the thing that manages some of the late
> power down stages does so using a firmware we can rewrite?

So the AM335X processor has a small M3 coprocessor attached to it. The
M3 coprocessor is in charge of performing many of the sleep and resume
transition steps. It has a 16k code space for firmware. The CM3
coprocessor has access to most of the same registers the primary
AM335X processor has access to (PM registers, clock registers, I2C
controller, etc).

For the deepest sleep modes, the core power supply can have its
voltage reduced, but only after several steps by the CM3 coprocessor
have been performed. The core power supply voltage must be reduced by
the CM3 coprocessor. The core regulator is controlled by I2C on all
the AM335X platforms that I am aware of, but different platforms have
different I2C regulators.

The path I'm taking in this patchset is to just put the board specific
I2C sequences necessary for the CM3 coprocessor to write out into the
devicetree. I've made it as generic as I can so that other platforms
with similar issues can reuse the bindings. Because of the limitations
of the firmware size and the desire not to have some sort of byte
code, this is a write only sequence.

Kevin Hilman is suggesting some way to query the regulator framework
for this sequence. There would be some call to the regulator framework
that would return a series of I2C commands that would be necessary to
program a regulator to a specific voltage. It would be called twice,
once for the suspend voltage, once for the resume voltage. The
regulator framework would then call into the driver that sets that
voltage, and by some method query the driver for the necessary I2C
sequence, either by some special new call, or some regmap magic.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 15:29             ` Kevin Hilman
@ 2013-08-29 15:49               ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 15:49 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Russ Dill, Jan Lübbe, devicetree, linux-omap, Linux ARM Kernel List

[-- Attachment #1: Type: text/plain, Size: 1352 bytes --]

On Thu, Aug 29, 2013 at 08:29:37AM -0700, Kevin Hilman wrote:
> On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:

> > Someone is going to have to walk me through the context for me to fully
> > understand what this is all about - what's the problem?

> The basic problem is how to have low-level platform code (or possibly
> firmware) send commands to a regulator to scale voltage.  This has to
> happen *very* late in the suspend process, so having the drivers do it
> themselves is not feasible.

Why does it have to happen this late and are the sequences definitely
fixed ones not ones that could depend on the system state at the time
we suspend?  It'd help to know what exactly is being controlled here...

> The proposal in this series is to define the i2c commands sequence to
> be sent to the regulator in the i2c node of the DT.  The
> platform-specific code then reads the sequence from the DT and sends
> the commands (or in in the case of the current series, passes the
> sequence to some firmware on a microcontroller which does the
> sequence.)

Surely specifying things in terms of the actual sequence would be better
than trying to specify the I2C commands if you want this to be done from
Linux?  If the firmware has to cope directly then this would require the
firmware to understand what it's doing of course.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 15:49               ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 08:29:37AM -0700, Kevin Hilman wrote:
> On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:

> > Someone is going to have to walk me through the context for me to fully
> > understand what this is all about - what's the problem?

> The basic problem is how to have low-level platform code (or possibly
> firmware) send commands to a regulator to scale voltage.  This has to
> happen *very* late in the suspend process, so having the drivers do it
> themselves is not feasible.

Why does it have to happen this late and are the sequences definitely
fixed ones not ones that could depend on the system state at the time
we suspend?  It'd help to know what exactly is being controlled here...

> The proposal in this series is to define the i2c commands sequence to
> be sent to the regulator in the i2c node of the DT.  The
> platform-specific code then reads the sequence from the DT and sends
> the commands (or in in the case of the current series, passes the
> sequence to some firmware on a microcontroller which does the
> sequence.)

Surely specifying things in terms of the actual sequence would be better
than trying to specify the I2C commands if you want this to be done from
Linux?  If the firmware has to cope directly then this would require the
firmware to understand what it's doing of course.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/36460f8a/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 15:17           ` Kevin Hilman
@ 2013-08-29 16:10             ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 16:10 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: devicetree, Mark Brown, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 8:17 AM, Kevin Hilman <khilman@linaro.org> wrote:
> Russ Dill <Russ.Dill@ti.com> writes:
>
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>>> [+Mark Brown for regulator suspend sequence ideas]
>>>
>>> Russ Dill <Russ.Dill@ti.com> writes:
>>>
>>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
>>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>> [snip]
>>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>>> fragile to do voltage adjustments behind the back of the regulator
>>>>> framework and the TPS driver. The wake-sequence values should match the
>>>>> (in-memory) regulator configuration on resume (which may have been
>>>>> changed by DVFS).
>>>>
>>>> The sequence is both PMIC specific and board specific. Additionally,
>>>> the PMICs used aren't am335x specific. It would be nice to have the
>>>> regulator framework and the driver write all this out, but the
>>>> sequence is written out by the Cortex-M3 processor running some PM
>>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>>> run from a small piece of SRAM.
>>>
>>> So, why/how was the decision made to use the M3 instead of the MPU
>>> running from SRAM?
>>>
>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>> side.  But also, because the M3 is reset every suspend sequence, this
>>> becomes rather heavy to do from the M3.
>>
>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>> patchset for am335x, he decided to move many of the operations from
>> sleep33xx.S into the M3 firmware.
>>
>> See the commit message here:
>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>
> Was this feedback on the public lists?  That patch has never been posted
> to linux-omap AFAICT.
>
>> I need to wait until after the PLLs are put into bypass, which is now
>> done in the M3 firmware. It also ends up being a lot easier to write
>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>
> hmm, (carefully) written functions in C can still be copied to SRAM.  I
> dont' see that as an obstacle.
>
>>> Currently voltage scaling is only being proposed for suspend in this
>>> series, but in theory it's possible from idle as well.  Doing this from
>>> the MPU/SRAM seems much better suited for idle.
>>
>> The M3 firmware will also handle any cpuidle modes deeper than just
>> putting SDRAM into self refresh. This is actually the only way of
>> doing things like turning the MPU domain off on am335x.
>
> Yes, it will have to handle the MPU/interconnect off parts but other
> than that, that's the only thing it *has* to do (well, and handle wakeup
> from the deep state.)  The rest of the stuff being piled into the M3 is
> a result of software/firmware design decisions AFAICT.  As I predicted
> when I first saw this SoC design, the firmware is getting bigger and
> bigger.  Initially it was argued that it would be tiny, and only handle
> the things it had to do.  Now it's growing due to "convenience".  IMO,
> this is a bad trend, and one that will make this code more and more
> difficult to maintain upstream (assuming that's a goal.)

Do you mean upstream as in the firmware upstream, or upstream as in
the kernel upstream? Upstream kernel is really easy to maintain
because sleep33xx.S just puts the SDRAM into self-refresh.

The code to perform these transitions is going to exist, either in
kernel or in firmware. If you are looking for this to be maintainable
C code that is copied into SRAM, it will need to be built much like a
firmware, with it's elf sections being copied into SRAM properly. I'm
not sure how much it complicates things, but the code needs to be able
to run with the MMU on and MMU off. The C code would be a minimalized
duplication of much of what is already in mach-omap2. Because you are
proposing to split this up between A8 and M3, much of that code would
then be duplicated again within the M3 firmware.

And don't forget that am335x is just the first platform with such a PM scheme.

Because the M3 firmware already has to manage power domains, hwmods,
plls, and clockdomains, adding or removing which ones it handles
doesn't really change the size or complexity of the firmware. In fact,
because so much of the code is common code, moving this into kernel
would just mean making two copies of the firmware with different steps
to be run, one for the A8 SRAM, one for the M3.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 16:10             ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 16:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 8:17 AM, Kevin Hilman <khilman@linaro.org> wrote:
> Russ Dill <Russ.Dill@ti.com> writes:
>
>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>>> [+Mark Brown for regulator suspend sequence ideas]
>>>
>>> Russ Dill <Russ.Dill@ti.com> writes:
>>>
>>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
>>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>> [snip]
>>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>>> fragile to do voltage adjustments behind the back of the regulator
>>>>> framework and the TPS driver. The wake-sequence values should match the
>>>>> (in-memory) regulator configuration on resume (which may have been
>>>>> changed by DVFS).
>>>>
>>>> The sequence is both PMIC specific and board specific. Additionally,
>>>> the PMICs used aren't am335x specific. It would be nice to have the
>>>> regulator framework and the driver write all this out, but the
>>>> sequence is written out by the Cortex-M3 processor running some PM
>>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>>> run from a small piece of SRAM.
>>>
>>> So, why/how was the decision made to use the M3 instead of the MPU
>>> running from SRAM?
>>>
>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>> side.  But also, because the M3 is reset every suspend sequence, this
>>> becomes rather heavy to do from the M3.
>>
>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>> patchset for am335x, he decided to move many of the operations from
>> sleep33xx.S into the M3 firmware.
>>
>> See the commit message here:
>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>
> Was this feedback on the public lists?  That patch has never been posted
> to linux-omap AFAICT.
>
>> I need to wait until after the PLLs are put into bypass, which is now
>> done in the M3 firmware. It also ends up being a lot easier to write
>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>
> hmm, (carefully) written functions in C can still be copied to SRAM.  I
> dont' see that as an obstacle.
>
>>> Currently voltage scaling is only being proposed for suspend in this
>>> series, but in theory it's possible from idle as well.  Doing this from
>>> the MPU/SRAM seems much better suited for idle.
>>
>> The M3 firmware will also handle any cpuidle modes deeper than just
>> putting SDRAM into self refresh. This is actually the only way of
>> doing things like turning the MPU domain off on am335x.
>
> Yes, it will have to handle the MPU/interconnect off parts but other
> than that, that's the only thing it *has* to do (well, and handle wakeup
> from the deep state.)  The rest of the stuff being piled into the M3 is
> a result of software/firmware design decisions AFAICT.  As I predicted
> when I first saw this SoC design, the firmware is getting bigger and
> bigger.  Initially it was argued that it would be tiny, and only handle
> the things it had to do.  Now it's growing due to "convenience".  IMO,
> this is a bad trend, and one that will make this code more and more
> difficult to maintain upstream (assuming that's a goal.)

Do you mean upstream as in the firmware upstream, or upstream as in
the kernel upstream? Upstream kernel is really easy to maintain
because sleep33xx.S just puts the SDRAM into self-refresh.

The code to perform these transitions is going to exist, either in
kernel or in firmware. If you are looking for this to be maintainable
C code that is copied into SRAM, it will need to be built much like a
firmware, with it's elf sections being copied into SRAM properly. I'm
not sure how much it complicates things, but the code needs to be able
to run with the MMU on and MMU off. The C code would be a minimalized
duplication of much of what is already in mach-omap2. Because you are
proposing to split this up between A8 and M3, much of that code would
then be duplicated again within the M3 firmware.

And don't forget that am335x is just the first platform with such a PM scheme.

Because the M3 firmware already has to manage power domains, hwmods,
plls, and clockdomains, adding or removing which ones it handles
doesn't really change the size or complexity of the firmware. In fact,
because so much of the code is common code, moving this into kernel
would just mean making two copies of the firmware with different steps
to be run, one for the A8 SRAM, one for the M3.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 15:49               ` Mark Brown
@ 2013-08-29 16:31                 ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 16:31 UTC (permalink / raw)
  To: Mark Brown
  Cc: Kevin Hilman, devicetree, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 08:29:37AM -0700, Kevin Hilman wrote:
>> On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Someone is going to have to walk me through the context for me to fully
>> > understand what this is all about - what's the problem?
>
>> The basic problem is how to have low-level platform code (or possibly
>> firmware) send commands to a regulator to scale voltage.  This has to
>> happen *very* late in the suspend process, so having the drivers do it
>> themselves is not feasible.
>
> Why does it have to happen this late and are the sequences definitely
> fixed ones not ones that could depend on the system state at the time
> we suspend?  It'd help to know what exactly is being controlled here...

On all am335x platforms, the lower operating point for core voltage
cannot be reached without first disabling the DDR controller, and
programming it into a lower power mode. For DDR3 platforms, no such
lower power mode is available and the lower operating point for core
voltage can only be reached with the memory controller disabled.

It certainly is possible that some bizarre I2C regulator may mix in
regulator voltage and some other state into one I2C register. In the
case of such a platform, setting the lower operating point would not
be supported.

>> The proposal in this series is to define the i2c commands sequence to
>> be sent to the regulator in the i2c node of the DT.  The
>> platform-specific code then reads the sequence from the DT and sends
>> the commands (or in in the case of the current series, passes the
>> sequence to some firmware on a microcontroller which does the
>> sequence.)
>
> Surely specifying things in terms of the actual sequence would be better
> than trying to specify the I2C commands if you want this to be done from
> Linux?  If the firmware has to cope directly then this would require the
> firmware to understand what it's doing of course.

I'm not sure what you mean by "actual sequence". Maybe if I show you a
couple examples, it will be more clear:

This is for the AM335X-EVM which has a TPS65910. The first byte is the
number of bytes to write, the second byte is the I2C device to write
those bytes to, the third byte happens to be a register address on the
TPS65910, and the 4th byte happens to be the value for 0.95V and 1.1V
respectively.

/* Set OPP50 (0.95V) for VDD core on TPS65910 */
sleep_sequence = /bits/ 8 <
        0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
>;

/* Set OPP100 (1.10V) for VDD core on TPS65910 */
wake_sequence = /bits/ 8 <
        0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>;

These next sequences are for the Beaglebone which has a different
PMIC. The format is the same, but the PMIC requires an unlock sequence
to be performed for certain registers and it also requires an
additional step to apply DCDC changes:

/* Set OPP50 (0.95V) for VDD core on TPS65217 */
sleep_sequence = /bits/ 8 <
        0x02 0x24 0x0b 0x6d /* Password unlock 1 */
        0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
        0x02 0x24 0x0b 0x6d /* Password unlock 2 */
        0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
        0x02 0x24 0x0b 0x6c /* Password unlock 1 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
        0x02 0x24 0x0b 0x6c /* Password unlock 2 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>;

/* Set OPP100 (1.10V) for VDD core on TPS65217 */
wake_sequence = /bits/ 8 <
        0x02 0x24 0x0b 0x6d /* Password unlock 1 */
        0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
        0x02 0x24 0x0b 0x6d /* Password unlock 2 */
        0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
        0x02 0x24 0x0b 0x6c /* Password unlock 1 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
        0x02 0x24 0x0b 0x6c /* Password unlock 2 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>;

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 16:31                 ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 16:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 08:29:37AM -0700, Kevin Hilman wrote:
>> On Thu, Aug 29, 2013 at 4:05 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Someone is going to have to walk me through the context for me to fully
>> > understand what this is all about - what's the problem?
>
>> The basic problem is how to have low-level platform code (or possibly
>> firmware) send commands to a regulator to scale voltage.  This has to
>> happen *very* late in the suspend process, so having the drivers do it
>> themselves is not feasible.
>
> Why does it have to happen this late and are the sequences definitely
> fixed ones not ones that could depend on the system state at the time
> we suspend?  It'd help to know what exactly is being controlled here...

On all am335x platforms, the lower operating point for core voltage
cannot be reached without first disabling the DDR controller, and
programming it into a lower power mode. For DDR3 platforms, no such
lower power mode is available and the lower operating point for core
voltage can only be reached with the memory controller disabled.

It certainly is possible that some bizarre I2C regulator may mix in
regulator voltage and some other state into one I2C register. In the
case of such a platform, setting the lower operating point would not
be supported.

>> The proposal in this series is to define the i2c commands sequence to
>> be sent to the regulator in the i2c node of the DT.  The
>> platform-specific code then reads the sequence from the DT and sends
>> the commands (or in in the case of the current series, passes the
>> sequence to some firmware on a microcontroller which does the
>> sequence.)
>
> Surely specifying things in terms of the actual sequence would be better
> than trying to specify the I2C commands if you want this to be done from
> Linux?  If the firmware has to cope directly then this would require the
> firmware to understand what it's doing of course.

I'm not sure what you mean by "actual sequence". Maybe if I show you a
couple examples, it will be more clear:

This is for the AM335X-EVM which has a TPS65910. The first byte is the
number of bytes to write, the second byte is the I2C device to write
those bytes to, the third byte happens to be a register address on the
TPS65910, and the 4th byte happens to be the value for 0.95V and 1.1V
respectively.

/* Set OPP50 (0.95V) for VDD core on TPS65910 */
sleep_sequence = /bits/ 8 <
        0x02 0x2d 0x25 0x1f /* Set VDD2 to 0.95V */
>;

/* Set OPP100 (1.10V) for VDD core on TPS65910 */
wake_sequence = /bits/ 8 <
        0x02 0x2d 0x25 0x2b /* Set VDD2 to 1.1V */
>;

These next sequences are for the Beaglebone which has a different
PMIC. The format is the same, but the PMIC requires an unlock sequence
to be performed for certain registers and it also requires an
additional step to apply DCDC changes:

/* Set OPP50 (0.95V) for VDD core on TPS65217 */
sleep_sequence = /bits/ 8 <
        0x02 0x24 0x0b 0x6d /* Password unlock 1 */
        0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
        0x02 0x24 0x0b 0x6d /* Password unlock 2 */
        0x02 0x24 0x10 0x02 /* Set DCDC3 to 0.95V */
        0x02 0x24 0x0b 0x6c /* Password unlock 1 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
        0x02 0x24 0x0b 0x6c /* Password unlock 2 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>;

/* Set OPP100 (1.10V) for VDD core on TPS65217 */
wake_sequence = /bits/ 8 <
        0x02 0x24 0x0b 0x6d /* Password unlock 1 */
        0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
        0x02 0x24 0x0b 0x6d /* Password unlock 2 */
        0x02 0x24 0x10 0x08 /* Set DCDC3 to 1.1V */
        0x02 0x24 0x0b 0x6c /* Password unlock 1 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
        0x02 0x24 0x0b 0x6c /* Password unlock 2 */
        0x02 0x24 0x11 0x86 /* Apply DCDC changes */
>;

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 16:31                 ` Russ Dill
@ 2013-08-29 17:30                   ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 17:30 UTC (permalink / raw)
  To: Russ Dill
  Cc: Kevin Hilman, devicetree, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

[-- Attachment #1: Type: text/plain, Size: 1842 bytes --]

On Thu, Aug 29, 2013 at 09:31:55AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:

> > Why does it have to happen this late and are the sequences definitely
> > fixed ones not ones that could depend on the system state at the time
> > we suspend?  It'd help to know what exactly is being controlled here...

> On all am335x platforms, the lower operating point for core voltage
> cannot be reached without first disabling the DDR controller, and
> programming it into a lower power mode. For DDR3 platforms, no such
> lower power mode is available and the lower operating point for core
> voltage can only be reached with the memory controller disabled.

So this is done from cpuidle rather than system suspend.

> It certainly is possible that some bizarre I2C regulator may mix in
> regulator voltage and some other state into one I2C register. In the
> case of such a platform, setting the lower operating point would not
> be supported.

This isn't particularly bizzare, there is no technical reason why a
register in the PMIC has to be given over completely to setting the
voltage and indeed there are PMICs in mainline right now which don't do
that - if you've got 16 bit registers it's probably not going to take
the entire 16 bits to encode the voltage range.

> > Surely specifying things in terms of the actual sequence would be better
> > than trying to specify the I2C commands if you want this to be done from
> > Linux?  If the firmware has to cope directly then this would require the
> > firmware to understand what it's doing of course.

> I'm not sure what you mean by "actual sequence". Maybe if I show you a
> couple examples, it will be more clear:

I mean describe the intended sequence of events in the system rather
than the raw register commands to accomplish them.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 17:30                   ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 17:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 09:31:55AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:

> > Why does it have to happen this late and are the sequences definitely
> > fixed ones not ones that could depend on the system state at the time
> > we suspend?  It'd help to know what exactly is being controlled here...

> On all am335x platforms, the lower operating point for core voltage
> cannot be reached without first disabling the DDR controller, and
> programming it into a lower power mode. For DDR3 platforms, no such
> lower power mode is available and the lower operating point for core
> voltage can only be reached with the memory controller disabled.

So this is done from cpuidle rather than system suspend.

> It certainly is possible that some bizarre I2C regulator may mix in
> regulator voltage and some other state into one I2C register. In the
> case of such a platform, setting the lower operating point would not
> be supported.

This isn't particularly bizzare, there is no technical reason why a
register in the PMIC has to be given over completely to setting the
voltage and indeed there are PMICs in mainline right now which don't do
that - if you've got 16 bit registers it's probably not going to take
the entire 16 bits to encode the voltage range.

> > Surely specifying things in terms of the actual sequence would be better
> > than trying to specify the I2C commands if you want this to be done from
> > Linux?  If the firmware has to cope directly then this would require the
> > firmware to understand what it's doing of course.

> I'm not sure what you mean by "actual sequence". Maybe if I show you a
> couple examples, it will be more clear:

I mean describe the intended sequence of events in the system rather
than the raw register commands to accomplish them.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/10787a1f/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 17:30                   ` Mark Brown
@ 2013-08-29 17:47                     ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 17:47 UTC (permalink / raw)
  To: Mark Brown
  Cc: devicetree, linux-omap, Kevin Hilman, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 09:31:55AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Why does it have to happen this late and are the sequences definitely
>> > fixed ones not ones that could depend on the system state at the time
>> > we suspend?  It'd help to know what exactly is being controlled here...
>
>> On all am335x platforms, the lower operating point for core voltage
>> cannot be reached without first disabling the DDR controller, and
>> programming it into a lower power mode. For DDR3 platforms, no such
>> lower power mode is available and the lower operating point for core
>> voltage can only be reached with the memory controller disabled.
>
> So this is done from cpuidle rather than system suspend.

It is done for system suspend. It isn't possible to do this in a
cpuidle use case as the memory controller would need to come out of
idle automatically to service DMA requests.

>> It certainly is possible that some bizarre I2C regulator may mix in
>> regulator voltage and some other state into one I2C register. In the
>> case of such a platform, setting the lower operating point would not
>> be supported.
>
> This isn't particularly bizzare, there is no technical reason why a
> register in the PMIC has to be given over completely to setting the
> voltage and indeed there are PMICs in mainline right now which don't do
> that - if you've got 16 bit registers it's probably not going to take
> the entire 16 bits to encode the voltage range.
>
>> > Surely specifying things in terms of the actual sequence would be better
>> > than trying to specify the I2C commands if you want this to be done from
>> > Linux?  If the firmware has to cope directly then this would require the
>> > firmware to understand what it's doing of course.
>
>> I'm not sure what you mean by "actual sequence". Maybe if I show you a
>> couple examples, it will be more clear:
>
> I mean describe the intended sequence of events in the system rather
> than the raw register commands to accomplish them.

I'm still not sure what you mean.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 17:47                     ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 17:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 09:31:55AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 8:49 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Why does it have to happen this late and are the sequences definitely
>> > fixed ones not ones that could depend on the system state at the time
>> > we suspend?  It'd help to know what exactly is being controlled here...
>
>> On all am335x platforms, the lower operating point for core voltage
>> cannot be reached without first disabling the DDR controller, and
>> programming it into a lower power mode. For DDR3 platforms, no such
>> lower power mode is available and the lower operating point for core
>> voltage can only be reached with the memory controller disabled.
>
> So this is done from cpuidle rather than system suspend.

It is done for system suspend. It isn't possible to do this in a
cpuidle use case as the memory controller would need to come out of
idle automatically to service DMA requests.

>> It certainly is possible that some bizarre I2C regulator may mix in
>> regulator voltage and some other state into one I2C register. In the
>> case of such a platform, setting the lower operating point would not
>> be supported.
>
> This isn't particularly bizzare, there is no technical reason why a
> register in the PMIC has to be given over completely to setting the
> voltage and indeed there are PMICs in mainline right now which don't do
> that - if you've got 16 bit registers it's probably not going to take
> the entire 16 bits to encode the voltage range.
>
>> > Surely specifying things in terms of the actual sequence would be better
>> > than trying to specify the I2C commands if you want this to be done from
>> > Linux?  If the firmware has to cope directly then this would require the
>> > firmware to understand what it's doing of course.
>
>> I'm not sure what you mean by "actual sequence". Maybe if I show you a
>> couple examples, it will be more clear:
>
> I mean describe the intended sequence of events in the system rather
> than the raw register commands to accomplish them.

I'm still not sure what you mean.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 15:42             ` Russ Dill
@ 2013-08-29 18:01               ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 18:01 UTC (permalink / raw)
  To: Russ Dill
  Cc: Linux ARM Kernel List, devicetree, linux-omap, Jan Lübbe,
	Kevin Hilman


[-- Attachment #1.1: Type: text/plain, Size: 1582 bytes --]

On Thu, Aug 29, 2013 at 08:42:11AM -0700, Russ Dill wrote:

> The path I'm taking in this patchset is to just put the board specific
> I2C sequences necessary for the CM3 coprocessor to write out into the
> devicetree. I've made it as generic as I can so that other platforms
> with similar issues can reuse the bindings. Because of the limitations
> of the firmware size and the desire not to have some sort of byte
> code, this is a write only sequence.

Making it write only seems to be a mistake - like I said in my other
mail I'd expect you'd want bitfield updates here.  The read and modify
could be done earlier by Linux though.

> Kevin Hilman is suggesting some way to query the regulator framework
> for this sequence. There would be some call to the regulator framework
> that would return a series of I2C commands that would be necessary to
> program a regulator to a specific voltage. It would be called twice,
> once for the suspend voltage, once for the resume voltage. The
> regulator framework would then call into the driver that sets that
> voltage, and by some method query the driver for the necessary I2C
> sequence, either by some special new call, or some regmap magic.

If it's just setting a single voltage then extracting the bitfield to
update shouldn't be too hard for regmap based regulators.  Off the top
of my head I'd expect either the driver for the M3 or the cpuidle driver
that talks to it to be a consumer of the regulator and then go from
there.

Just putting the sequence directly into the device tree doesn't feel
like the right abstraction.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 18:01               ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 18:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 08:42:11AM -0700, Russ Dill wrote:

> The path I'm taking in this patchset is to just put the board specific
> I2C sequences necessary for the CM3 coprocessor to write out into the
> devicetree. I've made it as generic as I can so that other platforms
> with similar issues can reuse the bindings. Because of the limitations
> of the firmware size and the desire not to have some sort of byte
> code, this is a write only sequence.

Making it write only seems to be a mistake - like I said in my other
mail I'd expect you'd want bitfield updates here.  The read and modify
could be done earlier by Linux though.

> Kevin Hilman is suggesting some way to query the regulator framework
> for this sequence. There would be some call to the regulator framework
> that would return a series of I2C commands that would be necessary to
> program a regulator to a specific voltage. It would be called twice,
> once for the suspend voltage, once for the resume voltage. The
> regulator framework would then call into the driver that sets that
> voltage, and by some method query the driver for the necessary I2C
> sequence, either by some special new call, or some regmap magic.

If it's just setting a single voltage then extracting the bitfield to
update shouldn't be too hard for regmap based regulators.  Off the top
of my head I'd expect either the driver for the M3 or the cpuidle driver
that talks to it to be a consumer of the regulator and then go from
there.

Just putting the sequence directly into the device tree doesn't feel
like the right abstraction.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/c308dfaa/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 17:47                     ` Russ Dill
@ 2013-08-29 18:03                       ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 18:03 UTC (permalink / raw)
  To: Russ Dill
  Cc: devicetree, linux-omap, Kevin Hilman, Jan Lübbe,
	Linux ARM Kernel List

[-- Attachment #1: Type: text/plain, Size: 831 bytes --]

On Thu, Aug 29, 2013 at 10:47:04AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:

> > So this is done from cpuidle rather than system suspend.

> It is done for system suspend. It isn't possible to do this in a
> cpuidle use case as the memory controller would need to come out of
> idle automatically to service DMA requests.

OK, so it's all part of the core power down sequence for the SoC?  I'm
not sure that makes a big difference but it at least means that there
are fewer runtime interactions to worry about.

> > I mean describe the intended sequence of events in the system rather
> > than the raw register commands to accomplish them.

> I'm still not sure what you mean.

Say "set voltage X" or even "regulator X supplies Y" not "send this
bytestream to the device".

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 18:03                       ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 18:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 10:47:04AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:

> > So this is done from cpuidle rather than system suspend.

> It is done for system suspend. It isn't possible to do this in a
> cpuidle use case as the memory controller would need to come out of
> idle automatically to service DMA requests.

OK, so it's all part of the core power down sequence for the SoC?  I'm
not sure that makes a big difference but it at least means that there
are fewer runtime interactions to worry about.

> > I mean describe the intended sequence of events in the system rather
> > than the raw register commands to accomplish them.

> I'm still not sure what you mean.

Say "set voltage X" or even "regulator X supplies Y" not "send this
bytestream to the device".
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/047e1eca/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 18:01               ` Mark Brown
@ 2013-08-29 18:25                 ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 18:25 UTC (permalink / raw)
  To: Mark Brown
  Cc: Linux ARM Kernel List, devicetree, linux-omap, Jan Lübbe,
	Kevin Hilman

On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 08:42:11AM -0700, Russ Dill wrote:
>
>> The path I'm taking in this patchset is to just put the board specific
>> I2C sequences necessary for the CM3 coprocessor to write out into the
>> devicetree. I've made it as generic as I can so that other platforms
>> with similar issues can reuse the bindings. Because of the limitations
>> of the firmware size and the desire not to have some sort of byte
>> code, this is a write only sequence.
>
> Making it write only seems to be a mistake - like I said in my other
> mail I'd expect you'd want bitfield updates here.  The read and modify
> could be done earlier by Linux though.

Updating bitfields in memory is pretty basic, but with I2C, each
device has its own register sizes and methods of accessing registers.
The first byte of an I2C sequence being a register address is pretty
common though. You'd need a method of defining in the device tree
piece how to modify bitfields.

>> Kevin Hilman is suggesting some way to query the regulator framework
>> for this sequence. There would be some call to the regulator framework
>> that would return a series of I2C commands that would be necessary to
>> program a regulator to a specific voltage. It would be called twice,
>> once for the suspend voltage, once for the resume voltage. The
>> regulator framework would then call into the driver that sets that
>> voltage, and by some method query the driver for the necessary I2C
>> sequence, either by some special new call, or some regmap magic.
>
> If it's just setting a single voltage then extracting the bitfield to
> update shouldn't be too hard for regmap based regulators.  Off the top
> of my head I'd expect either the driver for the M3 or the cpuidle driver
> that talks to it to be a consumer of the regulator and then go from
> there.

It'd be a list of bitfields. So are you suggesting a regulator_ops
call that would return a list of bitfield updates along with an I2C
controller, an I2C device address, I2C register addressing scheme (8
bit, 16 bit, or other) and the info for each bitfield (register size)?
And then each regulator driver would be updated as needed with this
code. Would this be a way forward? Would regmap actually tie into this
at all?

This is VDD core, so its not related to cpuidle or the M3.

> Just putting the sequence directly into the device tree doesn't feel
> like the right abstraction.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 18:25                 ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 18:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 08:42:11AM -0700, Russ Dill wrote:
>
>> The path I'm taking in this patchset is to just put the board specific
>> I2C sequences necessary for the CM3 coprocessor to write out into the
>> devicetree. I've made it as generic as I can so that other platforms
>> with similar issues can reuse the bindings. Because of the limitations
>> of the firmware size and the desire not to have some sort of byte
>> code, this is a write only sequence.
>
> Making it write only seems to be a mistake - like I said in my other
> mail I'd expect you'd want bitfield updates here.  The read and modify
> could be done earlier by Linux though.

Updating bitfields in memory is pretty basic, but with I2C, each
device has its own register sizes and methods of accessing registers.
The first byte of an I2C sequence being a register address is pretty
common though. You'd need a method of defining in the device tree
piece how to modify bitfields.

>> Kevin Hilman is suggesting some way to query the regulator framework
>> for this sequence. There would be some call to the regulator framework
>> that would return a series of I2C commands that would be necessary to
>> program a regulator to a specific voltage. It would be called twice,
>> once for the suspend voltage, once for the resume voltage. The
>> regulator framework would then call into the driver that sets that
>> voltage, and by some method query the driver for the necessary I2C
>> sequence, either by some special new call, or some regmap magic.
>
> If it's just setting a single voltage then extracting the bitfield to
> update shouldn't be too hard for regmap based regulators.  Off the top
> of my head I'd expect either the driver for the M3 or the cpuidle driver
> that talks to it to be a consumer of the regulator and then go from
> there.

It'd be a list of bitfields. So are you suggesting a regulator_ops
call that would return a list of bitfield updates along with an I2C
controller, an I2C device address, I2C register addressing scheme (8
bit, 16 bit, or other) and the info for each bitfield (register size)?
And then each regulator driver would be updated as needed with this
code. Would this be a way forward? Would regmap actually tie into this
at all?

This is VDD core, so its not related to cpuidle or the M3.

> Just putting the sequence directly into the device tree doesn't feel
> like the right abstraction.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 18:03                       ` Mark Brown
@ 2013-08-29 18:28                         ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 18:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Linux ARM Kernel List, devicetree, linux-omap, Jan Lübbe,
	Kevin Hilman

On Thu, Aug 29, 2013 at 11:03 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 10:47:04AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > So this is done from cpuidle rather than system suspend.
>
>> It is done for system suspend. It isn't possible to do this in a
>> cpuidle use case as the memory controller would need to come out of
>> idle automatically to service DMA requests.
>
> OK, so it's all part of the core power down sequence for the SoC?  I'm
> not sure that makes a big difference but it at least means that there
> are fewer runtime interactions to worry about.

 Well, core suspend sequence for the SoC.

>> > I mean describe the intended sequence of events in the system rather
>> > than the raw register commands to accomplish them.
>
>> I'm still not sure what you mean.
>
> Say "set voltage X" or even "regulator X supplies Y" not "send this
> bytestream to the device".

That's already known at the SoC level, "set the vdd core regulator to
0.95V". What isn't known is how to do that for each board.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 18:28                         ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-29 18:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 11:03 AM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 10:47:04AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 10:30 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > So this is done from cpuidle rather than system suspend.
>
>> It is done for system suspend. It isn't possible to do this in a
>> cpuidle use case as the memory controller would need to come out of
>> idle automatically to service DMA requests.
>
> OK, so it's all part of the core power down sequence for the SoC?  I'm
> not sure that makes a big difference but it at least means that there
> are fewer runtime interactions to worry about.

 Well, core suspend sequence for the SoC.

>> > I mean describe the intended sequence of events in the system rather
>> > than the raw register commands to accomplish them.
>
>> I'm still not sure what you mean.
>
> Say "set voltage X" or even "regulator X supplies Y" not "send this
> bytestream to the device".

That's already known at the SoC level, "set the vdd core regulator to
0.95V". What isn't known is how to do that for each board.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 18:25                 ` Russ Dill
@ 2013-08-29 19:10                   ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 19:10 UTC (permalink / raw)
  To: Russ Dill
  Cc: devicetree, Kevin Hilman, linux-omap, Jan Lübbe,
	Linux ARM Kernel List


[-- Attachment #1.1: Type: text/plain, Size: 2579 bytes --]

On Thu, Aug 29, 2013 at 11:25:43AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:

> > Making it write only seems to be a mistake - like I said in my other
> > mail I'd expect you'd want bitfield updates here.  The read and modify
> > could be done earlier by Linux though.

> Updating bitfields in memory is pretty basic, but with I2C, each
> device has its own register sizes and methods of accessing registers.
> The first byte of an I2C sequence being a register address is pretty
> common though. You'd need a method of defining in the device tree
> piece how to modify bitfields.

I'd not assume byte based addressing for a PMIC, it's very common but
not universal.  The difficulties here assume putting this in the device
tree as explicit register I/O - I do tend to agree with Kevin that this
doesn't seem like the right abstraction.

> > If it's just setting a single voltage then extracting the bitfield to
> > update shouldn't be too hard for regmap based regulators.  Off the top
> > of my head I'd expect either the driver for the M3 or the cpuidle driver
> > that talks to it to be a consumer of the regulator and then go from
> > there.

> It'd be a list of bitfields. So are you suggesting a regulator_ops
> call that would return a list of bitfield updates along with an I2C
> controller, an I2C device address, I2C register addressing scheme (8
> bit, 16 bit, or other) and the info for each bitfield (register size)?
> And then each regulator driver would be updated as needed with this
> code. Would this be a way forward? Would regmap actually tie into this
> at all?

I was thinking about the majority of regulators where setting a voltage
would be a single bitfield update (plus ramp delay, which is going to
need to be accounted for in the power on case).  If we need to do longer
sequences things get a bit more tricky in terms of interface but it
seems doable.

regmap would tie in in that it already has a way of describing the
format for interactions with the device so we could just reuse the same
description, and with some work we can probably reuse the code that
generates the bitstreams for sending to the devices too (though I don't
immediately see a nice way of doing that).

Not sure if this is worth the effort or not though, but then there's the
whole DT as ABI thing to worry about...

> This is VDD core, so its not related to cpuidle or the M3.

It's related to the M3 if the M3 is managing it; you can have multiple
consumers for a regulator so it doesn't need to be one or the other.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 19:10                   ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-08-29 19:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 11:25:43AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:

> > Making it write only seems to be a mistake - like I said in my other
> > mail I'd expect you'd want bitfield updates here.  The read and modify
> > could be done earlier by Linux though.

> Updating bitfields in memory is pretty basic, but with I2C, each
> device has its own register sizes and methods of accessing registers.
> The first byte of an I2C sequence being a register address is pretty
> common though. You'd need a method of defining in the device tree
> piece how to modify bitfields.

I'd not assume byte based addressing for a PMIC, it's very common but
not universal.  The difficulties here assume putting this in the device
tree as explicit register I/O - I do tend to agree with Kevin that this
doesn't seem like the right abstraction.

> > If it's just setting a single voltage then extracting the bitfield to
> > update shouldn't be too hard for regmap based regulators.  Off the top
> > of my head I'd expect either the driver for the M3 or the cpuidle driver
> > that talks to it to be a consumer of the regulator and then go from
> > there.

> It'd be a list of bitfields. So are you suggesting a regulator_ops
> call that would return a list of bitfield updates along with an I2C
> controller, an I2C device address, I2C register addressing scheme (8
> bit, 16 bit, or other) and the info for each bitfield (register size)?
> And then each regulator driver would be updated as needed with this
> code. Would this be a way forward? Would regmap actually tie into this
> at all?

I was thinking about the majority of regulators where setting a voltage
would be a single bitfield update (plus ramp delay, which is going to
need to be accounted for in the power on case).  If we need to do longer
sequences things get a bit more tricky in terms of interface but it
seems doable.

regmap would tie in in that it already has a way of describing the
format for interactions with the device so we could just reuse the same
description, and with some work we can probably reuse the code that
generates the bitstreams for sending to the devices too (though I don't
immediately see a nice way of doing that).

Not sure if this is worth the effort or not though, but then there's the
whole DT as ABI thing to worry about...

> This is VDD core, so its not related to cpuidle or the M3.

It's related to the M3 if the M3 is managing it; you can have multiple
consumers for a regulator so it doesn't need to be one or the other.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/606d058c/attachment.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 16:10             ` Russ Dill
@ 2013-08-29 19:11               ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 19:11 UTC (permalink / raw)
  To: Russ Dill
  Cc: devicetree, Mark Brown, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

Russ Dill <Russ.Dill@ti.com> writes:

> On Thu, Aug 29, 2013 at 8:17 AM, Kevin Hilman <khilman@linaro.org> wrote:
>> Russ Dill <Russ.Dill@ti.com> writes:
>>
>>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>>>> [+Mark Brown for regulator suspend sequence ideas]
>>>>
>>>> Russ Dill <Russ.Dill@ti.com> writes:
>>>>
>>>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan Lübbe <jlu@pengutronix.de> wrote:
>>>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>>> [snip]
>>>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>>>> fragile to do voltage adjustments behind the back of the regulator
>>>>>> framework and the TPS driver. The wake-sequence values should match the
>>>>>> (in-memory) regulator configuration on resume (which may have been
>>>>>> changed by DVFS).
>>>>>
>>>>> The sequence is both PMIC specific and board specific. Additionally,
>>>>> the PMICs used aren't am335x specific. It would be nice to have the
>>>>> regulator framework and the driver write all this out, but the
>>>>> sequence is written out by the Cortex-M3 processor running some PM
>>>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>>>> run from a small piece of SRAM.
>>>>
>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>> running from SRAM?
>>>>
>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>> becomes rather heavy to do from the M3.
>>>
>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>> patchset for am335x, he decided to move many of the operations from
>>> sleep33xx.S into the M3 firmware.
>>>
>>> See the commit message here:
>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>
>> Was this feedback on the public lists?  That patch has never been posted
>> to linux-omap AFAICT.
>>
>>> I need to wait until after the PLLs are put into bypass, which is now
>>> done in the M3 firmware. It also ends up being a lot easier to write
>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>
>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>> dont' see that as an obstacle.
>>
>>>> Currently voltage scaling is only being proposed for suspend in this
>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>> the MPU/SRAM seems much better suited for idle.
>>>
>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>> putting SDRAM into self refresh. This is actually the only way of
>>> doing things like turning the MPU domain off on am335x.
>>
>> Yes, it will have to handle the MPU/interconnect off parts but other
>> than that, that's the only thing it *has* to do (well, and handle wakeup
>> from the deep state.)  The rest of the stuff being piled into the M3 is
>> a result of software/firmware design decisions AFAICT.  As I predicted
>> when I first saw this SoC design, the firmware is getting bigger and
>> bigger.  Initially it was argued that it would be tiny, and only handle
>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>> this is a bad trend, and one that will make this code more and more
>> difficult to maintain upstream (assuming that's a goal.)
>
> Do you mean upstream as in the firmware upstream, or upstream as in
> the kernel upstream? Upstream kernel is really easy to maintain
> because sleep33xx.S just puts the SDRAM into self-refresh.

I mean making the kernel "simple" at the price of more complicated (and
much less reviewed) firmware code is a bad trend.  I understand the
desire to move this stuff into firmware and bypass the kernel review
process, but I predict it will backfire.

> The code to perform these transitions is going to exist, either in
> kernel or in firmware. If you are looking for this to be maintainable
> C code that is copied into SRAM, it will need to be built much like a
> firmware, with it's elf sections being copied into SRAM properly. 

You're making it too complicated.  No need for ELF, etc.

So the argument for moving much of the stuff from the kernel (in the
patch you referenced above) was that the "assembly code is quite big and
folks have found it hard to review and fixup issues in this dense piece
of code."  (interestingly, it was moved to firmware where it will see
even less review, but that's off topic.)

My idea was that if reviewing assembly is the issue, why not carefully
write a self-contained C function that can be copied to SRAM.  It might
need a little stub in SRAM to setup the stack etc., but it should be
quite doable.  That eliminates the problem cited as the reason for the
move to M3.

> I'm not sure how much it complicates things, but the code needs to be
> able to run with the MMU on and MMU off. The C code would be a
> minimalized duplication of much of what is already in
> mach-omap2. Because you are proposing to split this up between A8 and
> M3, much of that code would then be duplicated again within the M3
> firmware.
>
> And don't forget that am335x is just the first platform with such a PM scheme.

IMO, all the more reason to handle it in Linux, not in platform-specific firmware.

> Because the M3 firmware already has to manage power domains, hwmods,
> plls, and clockdomains, adding or removing which ones it handles
> doesn't really change the size or complexity of the firmware. 

No, but it significantly complicates its interaction with Linux, which
also has to know about all these things already.  IMO, as I've stated
from the very beginning of this SoC, there should be a very clean split.
M3 should only handle the minimum, what the MPU simply cannot do
(MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.

> In fact, because so much of the code is common code, moving this into
> kernel would just mean making two copies of the firmware with
> different steps to be run, one for the A8 SRAM, one for the M3.

Maybe I'm getting confused, but the more you talk about the linux and
the firmware doing the same code, the more I think the firmware is
(trying) to do too much.  If this is going to be understandable (and
maintainable), there needs to be a clean split of roles between the MPU
and the M3.

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

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 19:11               ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 19:11 UTC (permalink / raw)
  To: linux-arm-kernel

Russ Dill <Russ.Dill@ti.com> writes:

> On Thu, Aug 29, 2013 at 8:17 AM, Kevin Hilman <khilman@linaro.org> wrote:
>> Russ Dill <Russ.Dill@ti.com> writes:
>>
>>> On Tue, Aug 27, 2013 at 3:44 PM, Kevin Hilman <khilman@linaro.org> wrote:
>>>> [+Mark Brown for regulator suspend sequence ideas]
>>>>
>>>> Russ Dill <Russ.Dill@ti.com> writes:
>>>>
>>>>> On Wed, Aug 14, 2013 at 6:38 AM, Jan L?bbe <jlu@pengutronix.de> wrote:
>>>>>> On Tue, 2013-08-13 at 15:20 -0700, Russ Dill wrote:
>>> [snip]
>>>>>> Shouldn't the TPS driver know how to generate this sequence? It seems
>>>>>> fragile to do voltage adjustments behind the back of the regulator
>>>>>> framework and the TPS driver. The wake-sequence values should match the
>>>>>> (in-memory) regulator configuration on resume (which may have been
>>>>>> changed by DVFS).
>>>>>
>>>>> The sequence is both PMIC specific and board specific. Additionally,
>>>>> the PMICs used aren't am335x specific. It would be nice to have the
>>>>> regulator framework and the driver write all this out, but the
>>>>> sequence is written out by the Cortex-M3 processor running some PM
>>>>> firmware. Even if the code was changed to run on the A8, it'd have to
>>>>> run from a small piece of SRAM.
>>>>
>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>> running from SRAM?
>>>>
>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>> becomes rather heavy to do from the M3.
>>>
>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>> patchset for am335x, he decided to move many of the operations from
>>> sleep33xx.S into the M3 firmware.
>>>
>>> See the commit message here:
>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>
>> Was this feedback on the public lists?  That patch has never been posted
>> to linux-omap AFAICT.
>>
>>> I need to wait until after the PLLs are put into bypass, which is now
>>> done in the M3 firmware. It also ends up being a lot easier to write
>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>
>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>> dont' see that as an obstacle.
>>
>>>> Currently voltage scaling is only being proposed for suspend in this
>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>> the MPU/SRAM seems much better suited for idle.
>>>
>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>> putting SDRAM into self refresh. This is actually the only way of
>>> doing things like turning the MPU domain off on am335x.
>>
>> Yes, it will have to handle the MPU/interconnect off parts but other
>> than that, that's the only thing it *has* to do (well, and handle wakeup
>> from the deep state.)  The rest of the stuff being piled into the M3 is
>> a result of software/firmware design decisions AFAICT.  As I predicted
>> when I first saw this SoC design, the firmware is getting bigger and
>> bigger.  Initially it was argued that it would be tiny, and only handle
>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>> this is a bad trend, and one that will make this code more and more
>> difficult to maintain upstream (assuming that's a goal.)
>
> Do you mean upstream as in the firmware upstream, or upstream as in
> the kernel upstream? Upstream kernel is really easy to maintain
> because sleep33xx.S just puts the SDRAM into self-refresh.

I mean making the kernel "simple" at the price of more complicated (and
much less reviewed) firmware code is a bad trend.  I understand the
desire to move this stuff into firmware and bypass the kernel review
process, but I predict it will backfire.

> The code to perform these transitions is going to exist, either in
> kernel or in firmware. If you are looking for this to be maintainable
> C code that is copied into SRAM, it will need to be built much like a
> firmware, with it's elf sections being copied into SRAM properly. 

You're making it too complicated.  No need for ELF, etc.

So the argument for moving much of the stuff from the kernel (in the
patch you referenced above) was that the "assembly code is quite big and
folks have found it hard to review and fixup issues in this dense piece
of code."  (interestingly, it was moved to firmware where it will see
even less review, but that's off topic.)

My idea was that if reviewing assembly is the issue, why not carefully
write a self-contained C function that can be copied to SRAM.  It might
need a little stub in SRAM to setup the stack etc., but it should be
quite doable.  That eliminates the problem cited as the reason for the
move to M3.

> I'm not sure how much it complicates things, but the code needs to be
> able to run with the MMU on and MMU off. The C code would be a
> minimalized duplication of much of what is already in
> mach-omap2. Because you are proposing to split this up between A8 and
> M3, much of that code would then be duplicated again within the M3
> firmware.
>
> And don't forget that am335x is just the first platform with such a PM scheme.

IMO, all the more reason to handle it in Linux, not in platform-specific firmware.

> Because the M3 firmware already has to manage power domains, hwmods,
> plls, and clockdomains, adding or removing which ones it handles
> doesn't really change the size or complexity of the firmware. 

No, but it significantly complicates its interaction with Linux, which
also has to know about all these things already.  IMO, as I've stated
from the very beginning of this SoC, there should be a very clean split.
M3 should only handle the minimum, what the MPU simply cannot do
(MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.

> In fact, because so much of the code is common code, moving this into
> kernel would just mean making two copies of the firmware with
> different steps to be run, one for the A8 SRAM, one for the M3.

Maybe I'm getting confused, but the more you talk about the linux and
the firmware doing the same code, the more I think the firmware is
(trying) to do too much.  If this is going to be understandable (and
maintainable), there needs to be a clean split of roles between the MPU
and the M3.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 19:11               ` Kevin Hilman
@ 2013-08-29 20:09                 ` Vaibhav Bedia
  -1 siblings, 0 replies; 84+ messages in thread
From: Vaibhav Bedia @ 2013-08-29 20:09 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Russ Dill, devicetree, linux-omap, Mark Brown, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 3:11 PM, Kevin Hilman <khilman@linaro.org> wrote:
[...]

First of all, apologies for jumping in here. Now that i am not
actively involved in
AM335x/AM437x stuff i wasn't actively following all the discussion here.

Looking at the lists now i just wanted to mention a few things so that we can
agree on the approach to be taken here.

>>>>>
>>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>>> running from SRAM?
>>>>>
>>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>>> becomes rather heavy to do from the M3.
>>>>
>>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>>> patchset for am335x, he decided to move many of the operations from
>>>> sleep33xx.S into the M3 firmware.
>>>>
>>>> See the commit message here:
>>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>>
>>> Was this feedback on the public lists?  That patch has never been posted
>>> to linux-omap AFAICT.
>>>
>>>> I need to wait until after the PLLs are put into bypass, which is now
>>>> done in the M3 firmware. It also ends up being a lot easier to write
>>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>>
>>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>>> dont' see that as an obstacle.
>>>
>>>>> Currently voltage scaling is only being proposed for suspend in this
>>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>>> the MPU/SRAM seems much better suited for idle.
>>>>
>>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>>> putting SDRAM into self refresh. This is actually the only way of
>>>> doing things like turning the MPU domain off on am335x.
>>>
>>> Yes, it will have to handle the MPU/interconnect off parts but other
>>> than that, that's the only thing it *has* to do (well, and handle wakeup
>>> from the deep state.)  The rest of the stuff being piled into the M3 is
>>> a result of software/firmware design decisions AFAICT.  As I predicted
>>> when I first saw this SoC design, the firmware is getting bigger and
>>> bigger.  Initially it was argued that it would be tiny, and only handle
>>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>>> this is a bad trend, and one that will make this code more and more
>>> difficult to maintain upstream (assuming that's a goal.)
>>
>> Do you mean upstream as in the firmware upstream, or upstream as in
>> the kernel upstream? Upstream kernel is really easy to maintain
>> because sleep33xx.S just puts the SDRAM into self-refresh.
>
> I mean making the kernel "simple" at the price of more complicated (and
> much less reviewed) firmware code is a bad trend.  I understand the
> desire to move this stuff into firmware and bypass the kernel review
> process, but I predict it will backfire.
>
>> The code to perform these transitions is going to exist, either in
>> kernel or in firmware. If you are looking for this to be maintainable
>> C code that is copied into SRAM, it will need to be built much like a
>> firmware, with it's elf sections being copied into SRAM properly.
>
> You're making it too complicated.  No need for ELF, etc.
>
> So the argument for moving much of the stuff from the kernel (in the
> patch you referenced above) was that the "assembly code is quite big and
> folks have found it hard to review and fixup issues in this dense piece
> of code."  (interestingly, it was moved to firmware where it will see
> even less review, but that's off topic.)
>
> My idea was that if reviewing assembly is the issue, why not carefully
> write a self-contained C function that can be copied to SRAM.  It might
> need a little stub in SRAM to setup the stack etc., but it should be
> quite doable.  That eliminates the problem cited as the reason for the
> move to M3.
>
>> I'm not sure how much it complicates things, but the code needs to be
>> able to run with the MMU on and MMU off. The C code would be a
>> minimalized duplication of much of what is already in
>> mach-omap2. Because you are proposing to split this up between A8 and
>> M3, much of that code would then be duplicated again within the M3
>> firmware.
>>
>> And don't forget that am335x is just the first platform with such a PM scheme.
>
> IMO, all the more reason to handle it in Linux, not in platform-specific firmware.
>
>> Because the M3 firmware already has to manage power domains, hwmods,
>> plls, and clockdomains, adding or removing which ones it handles
>> doesn't really change the size or complexity of the firmware.
>
> No, but it significantly complicates its interaction with Linux, which
> also has to know about all these things already.  IMO, as I've stated
> from the very beginning of this SoC, there should be a very clean split.
> M3 should only handle the minimum, what the MPU simply cannot do
> (MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.
>
>> In fact, because so much of the code is common code, moving this into
>> kernel would just mean making two copies of the firmware with
>> different steps to be run, one for the A8 SRAM, one for the M3.
>
> Maybe I'm getting confused, but the more you talk about the linux and
> the firmware doing the same code, the more I think the firmware is
> (trying) to do too much.  If this is going to be understandable (and
> maintainable), there needs to be a clean split of roles between the MPU
> and the M3.
>

In the past i tried to keep the firmware as minimal as possible and pushed
back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
the opinion that we need to do whatever's possible in the kernel.

Sadly, things just got a point where it made much more sense (technically
as well as non-technically) to just put the low level stuff in the M3.

1. In addition to the Linux support, we have non-OS based code for AM335x
(and AM437x) which in the past just had to duplicate whatever was done
in the Linux. Being a different codebase the non-OS guys have their own
set of challenges and we had to at times sit through and debug issues in
one codebase while the other was working fine. Ideally these things should
never come up but sadly they do and we need to solve them.

We also have people trying to implement this thing on different sort of
OS environments and they also end up debugging the same set of issues.

With only a handful of folks able to spend time debugging issues 'do everything
in Linux and expect others to copy it' model doesn't scale up. Keeping
things in the
firmware with the code available online helps do away with the
'developer scalability'
problem and if one looks at things differently enables code-reuse at
the same time.

Moreover, when the code was finally moved to M3, AFAICT we had validated
all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
control) that TI hardware guys could throw at us.Yes there could be stupid bugs
lurking in the code since it wasn't reviewed as much as i would have
liked but we
have something which proves the functionality to be used as the base.

2. As has been already been pointed out by Russ, on AM335x this step needs
to be done very late in the suspend process (the last stage actually). On the
next SoC there are other complications related to security which enforce this
step must be done from the M3. So trying to keep it in M3 for both AM335x
and AM437x helps avoid the code churn that will happen if we were to do
this differently on two SoCs which have similar PM architectures.

Morevoer, all the suggestions on how to keep the code in Linux working
around the
complications due to the main memory not being accessible will need to
be replicated
on the non-Linux s/w stacks and that's just make it more difficult for them.

3. Moving this to M3 leaves the option open to try out some crazy stuff for
power optimizations wherein the CORE voltage is lowered even below OPP50.
This is yet to be proved in h/w so one can ignore this for now but yes it's a
possibility.

Regards,
Vaibhav

[1] http://www.ti.com/tool/starterware-sitara

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 20:09                 ` Vaibhav Bedia
  0 siblings, 0 replies; 84+ messages in thread
From: Vaibhav Bedia @ 2013-08-29 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 3:11 PM, Kevin Hilman <khilman@linaro.org> wrote:
[...]

First of all, apologies for jumping in here. Now that i am not
actively involved in
AM335x/AM437x stuff i wasn't actively following all the discussion here.

Looking at the lists now i just wanted to mention a few things so that we can
agree on the approach to be taken here.

>>>>>
>>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>>> running from SRAM?
>>>>>
>>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>>> becomes rather heavy to do from the M3.
>>>>
>>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>>> patchset for am335x, he decided to move many of the operations from
>>>> sleep33xx.S into the M3 firmware.
>>>>
>>>> See the commit message here:
>>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>>
>>> Was this feedback on the public lists?  That patch has never been posted
>>> to linux-omap AFAICT.
>>>
>>>> I need to wait until after the PLLs are put into bypass, which is now
>>>> done in the M3 firmware. It also ends up being a lot easier to write
>>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>>
>>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>>> dont' see that as an obstacle.
>>>
>>>>> Currently voltage scaling is only being proposed for suspend in this
>>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>>> the MPU/SRAM seems much better suited for idle.
>>>>
>>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>>> putting SDRAM into self refresh. This is actually the only way of
>>>> doing things like turning the MPU domain off on am335x.
>>>
>>> Yes, it will have to handle the MPU/interconnect off parts but other
>>> than that, that's the only thing it *has* to do (well, and handle wakeup
>>> from the deep state.)  The rest of the stuff being piled into the M3 is
>>> a result of software/firmware design decisions AFAICT.  As I predicted
>>> when I first saw this SoC design, the firmware is getting bigger and
>>> bigger.  Initially it was argued that it would be tiny, and only handle
>>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>>> this is a bad trend, and one that will make this code more and more
>>> difficult to maintain upstream (assuming that's a goal.)
>>
>> Do you mean upstream as in the firmware upstream, or upstream as in
>> the kernel upstream? Upstream kernel is really easy to maintain
>> because sleep33xx.S just puts the SDRAM into self-refresh.
>
> I mean making the kernel "simple" at the price of more complicated (and
> much less reviewed) firmware code is a bad trend.  I understand the
> desire to move this stuff into firmware and bypass the kernel review
> process, but I predict it will backfire.
>
>> The code to perform these transitions is going to exist, either in
>> kernel or in firmware. If you are looking for this to be maintainable
>> C code that is copied into SRAM, it will need to be built much like a
>> firmware, with it's elf sections being copied into SRAM properly.
>
> You're making it too complicated.  No need for ELF, etc.
>
> So the argument for moving much of the stuff from the kernel (in the
> patch you referenced above) was that the "assembly code is quite big and
> folks have found it hard to review and fixup issues in this dense piece
> of code."  (interestingly, it was moved to firmware where it will see
> even less review, but that's off topic.)
>
> My idea was that if reviewing assembly is the issue, why not carefully
> write a self-contained C function that can be copied to SRAM.  It might
> need a little stub in SRAM to setup the stack etc., but it should be
> quite doable.  That eliminates the problem cited as the reason for the
> move to M3.
>
>> I'm not sure how much it complicates things, but the code needs to be
>> able to run with the MMU on and MMU off. The C code would be a
>> minimalized duplication of much of what is already in
>> mach-omap2. Because you are proposing to split this up between A8 and
>> M3, much of that code would then be duplicated again within the M3
>> firmware.
>>
>> And don't forget that am335x is just the first platform with such a PM scheme.
>
> IMO, all the more reason to handle it in Linux, not in platform-specific firmware.
>
>> Because the M3 firmware already has to manage power domains, hwmods,
>> plls, and clockdomains, adding or removing which ones it handles
>> doesn't really change the size or complexity of the firmware.
>
> No, but it significantly complicates its interaction with Linux, which
> also has to know about all these things already.  IMO, as I've stated
> from the very beginning of this SoC, there should be a very clean split.
> M3 should only handle the minimum, what the MPU simply cannot do
> (MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.
>
>> In fact, because so much of the code is common code, moving this into
>> kernel would just mean making two copies of the firmware with
>> different steps to be run, one for the A8 SRAM, one for the M3.
>
> Maybe I'm getting confused, but the more you talk about the linux and
> the firmware doing the same code, the more I think the firmware is
> (trying) to do too much.  If this is going to be understandable (and
> maintainable), there needs to be a clean split of roles between the MPU
> and the M3.
>

In the past i tried to keep the firmware as minimal as possible and pushed
back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
the opinion that we need to do whatever's possible in the kernel.

Sadly, things just got a point where it made much more sense (technically
as well as non-technically) to just put the low level stuff in the M3.

1. In addition to the Linux support, we have non-OS based code for AM335x
(and AM437x) which in the past just had to duplicate whatever was done
in the Linux. Being a different codebase the non-OS guys have their own
set of challenges and we had to at times sit through and debug issues in
one codebase while the other was working fine. Ideally these things should
never come up but sadly they do and we need to solve them.

We also have people trying to implement this thing on different sort of
OS environments and they also end up debugging the same set of issues.

With only a handful of folks able to spend time debugging issues 'do everything
in Linux and expect others to copy it' model doesn't scale up. Keeping
things in the
firmware with the code available online helps do away with the
'developer scalability'
problem and if one looks at things differently enables code-reuse at
the same time.

Moreover, when the code was finally moved to M3, AFAICT we had validated
all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
control) that TI hardware guys could throw at us.Yes there could be stupid bugs
lurking in the code since it wasn't reviewed as much as i would have
liked but we
have something which proves the functionality to be used as the base.

2. As has been already been pointed out by Russ, on AM335x this step needs
to be done very late in the suspend process (the last stage actually). On the
next SoC there are other complications related to security which enforce this
step must be done from the M3. So trying to keep it in M3 for both AM335x
and AM437x helps avoid the code churn that will happen if we were to do
this differently on two SoCs which have similar PM architectures.

Morevoer, all the suggestions on how to keep the code in Linux working
around the
complications due to the main memory not being accessible will need to
be replicated
on the non-Linux s/w stacks and that's just make it more difficult for them.

3. Moving this to M3 leaves the option open to try out some crazy stuff for
power optimizations wherein the CORE voltage is lowered even below OPP50.
This is yet to be proved in h/w so one can ignore this for now but yes it's a
possibility.

Regards,
Vaibhav

[1] http://www.ti.com/tool/starterware-sitara

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 20:09                 ` Vaibhav Bedia
@ 2013-08-29 21:33                   ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 21:33 UTC (permalink / raw)
  To: Vaibhav Bedia
  Cc: Russ Dill, devicetree, linux-omap, Mark Brown, Jan Lübbe,
	Linux ARM Kernel List

Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:

> On Thu, Aug 29, 2013 at 3:11 PM, Kevin Hilman <khilman@linaro.org> wrote:
> [...]
>
> First of all, apologies for jumping in here. Now that i am not
> actively involved in AM335x/AM437x stuff i wasn't actively following
> all the discussion here.

No apologies needed, I was hoping you would jump in here.  Thanks for
sharing your experience and insight.

> Looking at the lists now i just wanted to mention a few things so that we can
> agree on the approach to be taken here.
>
>>>>>>
>>>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>>>> running from SRAM?
>>>>>>
>>>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>>>> becomes rather heavy to do from the M3.
>>>>>
>>>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>>>> patchset for am335x, he decided to move many of the operations from
>>>>> sleep33xx.S into the M3 firmware.
>>>>>
>>>>> See the commit message here:
>>>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>>>
>>>> Was this feedback on the public lists?  That patch has never been posted
>>>> to linux-omap AFAICT.
>>>>
>>>>> I need to wait until after the PLLs are put into bypass, which is now
>>>>> done in the M3 firmware. It also ends up being a lot easier to write
>>>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>>>
>>>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>>>> dont' see that as an obstacle.
>>>>
>>>>>> Currently voltage scaling is only being proposed for suspend in this
>>>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>>>> the MPU/SRAM seems much better suited for idle.
>>>>>
>>>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>>>> putting SDRAM into self refresh. This is actually the only way of
>>>>> doing things like turning the MPU domain off on am335x.
>>>>
>>>> Yes, it will have to handle the MPU/interconnect off parts but other
>>>> than that, that's the only thing it *has* to do (well, and handle wakeup
>>>> from the deep state.)  The rest of the stuff being piled into the M3 is
>>>> a result of software/firmware design decisions AFAICT.  As I predicted
>>>> when I first saw this SoC design, the firmware is getting bigger and
>>>> bigger.  Initially it was argued that it would be tiny, and only handle
>>>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>>>> this is a bad trend, and one that will make this code more and more
>>>> difficult to maintain upstream (assuming that's a goal.)
>>>
>>> Do you mean upstream as in the firmware upstream, or upstream as in
>>> the kernel upstream? Upstream kernel is really easy to maintain
>>> because sleep33xx.S just puts the SDRAM into self-refresh.
>>
>> I mean making the kernel "simple" at the price of more complicated (and
>> much less reviewed) firmware code is a bad trend.  I understand the
>> desire to move this stuff into firmware and bypass the kernel review
>> process, but I predict it will backfire.
>>
>>> The code to perform these transitions is going to exist, either in
>>> kernel or in firmware. If you are looking for this to be maintainable
>>> C code that is copied into SRAM, it will need to be built much like a
>>> firmware, with it's elf sections being copied into SRAM properly.
>>
>> You're making it too complicated.  No need for ELF, etc.
>>
>> So the argument for moving much of the stuff from the kernel (in the
>> patch you referenced above) was that the "assembly code is quite big and
>> folks have found it hard to review and fixup issues in this dense piece
>> of code."  (interestingly, it was moved to firmware where it will see
>> even less review, but that's off topic.)
>>
>> My idea was that if reviewing assembly is the issue, why not carefully
>> write a self-contained C function that can be copied to SRAM.  It might
>> need a little stub in SRAM to setup the stack etc., but it should be
>> quite doable.  That eliminates the problem cited as the reason for the
>> move to M3.
>>
>>> I'm not sure how much it complicates things, but the code needs to be
>>> able to run with the MMU on and MMU off. The C code would be a
>>> minimalized duplication of much of what is already in
>>> mach-omap2. Because you are proposing to split this up between A8 and
>>> M3, much of that code would then be duplicated again within the M3
>>> firmware.
>>>
>>> And don't forget that am335x is just the first platform with such a PM scheme.
>>
>> IMO, all the more reason to handle it in Linux, not in platform-specific firmware.
>>
>>> Because the M3 firmware already has to manage power domains, hwmods,
>>> plls, and clockdomains, adding or removing which ones it handles
>>> doesn't really change the size or complexity of the firmware.
>>
>> No, but it significantly complicates its interaction with Linux, which
>> also has to know about all these things already.  IMO, as I've stated
>> from the very beginning of this SoC, there should be a very clean split.
>> M3 should only handle the minimum, what the MPU simply cannot do
>> (MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.
>>
>>> In fact, because so much of the code is common code, moving this into
>>> kernel would just mean making two copies of the firmware with
>>> different steps to be run, one for the A8 SRAM, one for the M3.
>>
>> Maybe I'm getting confused, but the more you talk about the linux and
>> the firmware doing the same code, the more I think the firmware is
>> (trying) to do too much.  If this is going to be understandable (and
>> maintainable), there needs to be a clean split of roles between the MPU
>> and the M3.
>>
>
> In the past i tried to keep the firmware as minimal as possible and pushed
> back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
> the opinion that we need to do whatever's possible in the kernel.
>
> Sadly, things just got a point where it made much more sense (technically
> as well as non-technically) to just put the low level stuff in the M3.
>
> 1. In addition to the Linux support, we have non-OS based code for AM335x
> (and AM437x) which in the past just had to duplicate whatever was done
> in the Linux. Being a different codebase the non-OS guys have their own
> set of challenges and we had to at times sit through and debug issues in
> one codebase while the other was working fine. Ideally these things should
> never come up but sadly they do and we need to solve them.
>
> We also have people trying to implement this thing on different sort of
> OS environments and they also end up debugging the same set of issues.
>
> With only a handful of folks able to spend time debugging issues 'do everything
> in Linux and expect others to copy it' model doesn't scale up. Keeping
> things in the
> firmware with the code available online helps do away with the
> 'developer scalability'
> problem and if one looks at things differently enables code-reuse at
> the same time.

Yes, yes, this is the classic argument for a HAL, and making that case has always
gone over well in the kernel. ;)

> Moreover, when the code was finally moved to M3, AFAICT we had validated
> all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
> control) that TI hardware guys could throw at us.Yes there could be stupid bugs
> lurking in the code since it wasn't reviewed as much as i would have
> liked but we
> have something which proves the functionality to be used as the base.

I don't follow the argument here.  You mean it was validated *before*
moving it to the M3, or after?  Either way, I'm how that makes a case
for moving it to the M3.  Surely if it was on the MPU, it would also
have been validated, no?

> 2. As has been already been pointed out by Russ, on AM335x this step needs
> to be done very late in the suspend process (the last stage
> actually). 

late, yes.  But *technically*, it can still be done from the MPU.

> On the next SoC there are other complications related to security
> which enforce this step must be done from the M3.

Aha!  So far, the first technical reason I've seen.  Can you elaborate?
Exactly which step has to be done from the M3, and why can't the MPU do
it?  And could it be done more simply by putting *only* the parts needed
on the M3 and not letting it snowball into a pile of stuff?

> So trying to keep it in M3 for both AM335x and AM437x helps avoid the
> code churn that will happen if we were to do this differently on two
> SoCs which have similar PM architectures.

I'm not conviced it has to be done so differently between the two.
Let's have some more details about the security differences before
making that decision.

> Morevoer, all the suggestions on how to keep the code in Linux working
> around the complications due to the main memory not being accessible
> will need to be replicated on the non-Linux s/w stacks and that's just
> make it more difficult for them.

The linux code has to be very self-contained (in assembler or C), so I'm
not sure how it's difficult to replicated in any other OS (or non-OS.)

> 3. Moving this to M3 leaves the option open to try out some crazy stuff for
> power optimizations wherein the CORE voltage is lowered even below OPP50.
> This is yet to be proved in h/w so one can ignore this for now but yes it's a
> possibility.

All interesting reasons, but other than the security one, all boil down
to non-technical arguments about what's easier.  But as you well know,
"the easy way" usually isn't the same thing as "the right way" when it
comes to getting things into the upstream linux kernel.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-29 21:33                   ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-29 21:33 UTC (permalink / raw)
  To: linux-arm-kernel

Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:

> On Thu, Aug 29, 2013 at 3:11 PM, Kevin Hilman <khilman@linaro.org> wrote:
> [...]
>
> First of all, apologies for jumping in here. Now that i am not
> actively involved in AM335x/AM437x stuff i wasn't actively following
> all the discussion here.

No apologies needed, I was hoping you would jump in here.  Thanks for
sharing your experience and insight.

> Looking at the lists now i just wanted to mention a few things so that we can
> agree on the approach to be taken here.
>
>>>>>>
>>>>>> So, why/how was the decision made to use the M3 instead of the MPU
>>>>>> running from SRAM?
>>>>>>
>>>>>> As a firmware minimalist, I obviously prefer to do this from the MPU
>>>>>> side.  But also, because the M3 is reset every suspend sequence, this
>>>>>> becomes rather heavy to do from the M3.
>>>>>
>>>>> After the feedback Vaibhav Bedia received on v2 of his suspend/resume
>>>>> patchset for am335x, he decided to move many of the operations from
>>>>> sleep33xx.S into the M3 firmware.
>>>>>
>>>>> See the commit message here:
>>>>> http://arago-project.org/git/projects/?p=am33x-cm3.git;a=commit;h=a972ce2f6
>>>>
>>>> Was this feedback on the public lists?  That patch has never been posted
>>>> to linux-omap AFAICT.
>>>>
>>>>> I need to wait until after the PLLs are put into bypass, which is now
>>>>> done in the M3 firmware. It also ends up being a lot easier to write
>>>>> the I2C writer code there in C rather than in assembly in sleep33xx.S.
>>>>
>>>> hmm, (carefully) written functions in C can still be copied to SRAM.  I
>>>> dont' see that as an obstacle.
>>>>
>>>>>> Currently voltage scaling is only being proposed for suspend in this
>>>>>> series, but in theory it's possible from idle as well.  Doing this from
>>>>>> the MPU/SRAM seems much better suited for idle.
>>>>>
>>>>> The M3 firmware will also handle any cpuidle modes deeper than just
>>>>> putting SDRAM into self refresh. This is actually the only way of
>>>>> doing things like turning the MPU domain off on am335x.
>>>>
>>>> Yes, it will have to handle the MPU/interconnect off parts but other
>>>> than that, that's the only thing it *has* to do (well, and handle wakeup
>>>> from the deep state.)  The rest of the stuff being piled into the M3 is
>>>> a result of software/firmware design decisions AFAICT.  As I predicted
>>>> when I first saw this SoC design, the firmware is getting bigger and
>>>> bigger.  Initially it was argued that it would be tiny, and only handle
>>>> the things it had to do.  Now it's growing due to "convenience".  IMO,
>>>> this is a bad trend, and one that will make this code more and more
>>>> difficult to maintain upstream (assuming that's a goal.)
>>>
>>> Do you mean upstream as in the firmware upstream, or upstream as in
>>> the kernel upstream? Upstream kernel is really easy to maintain
>>> because sleep33xx.S just puts the SDRAM into self-refresh.
>>
>> I mean making the kernel "simple" at the price of more complicated (and
>> much less reviewed) firmware code is a bad trend.  I understand the
>> desire to move this stuff into firmware and bypass the kernel review
>> process, but I predict it will backfire.
>>
>>> The code to perform these transitions is going to exist, either in
>>> kernel or in firmware. If you are looking for this to be maintainable
>>> C code that is copied into SRAM, it will need to be built much like a
>>> firmware, with it's elf sections being copied into SRAM properly.
>>
>> You're making it too complicated.  No need for ELF, etc.
>>
>> So the argument for moving much of the stuff from the kernel (in the
>> patch you referenced above) was that the "assembly code is quite big and
>> folks have found it hard to review and fixup issues in this dense piece
>> of code."  (interestingly, it was moved to firmware where it will see
>> even less review, but that's off topic.)
>>
>> My idea was that if reviewing assembly is the issue, why not carefully
>> write a self-contained C function that can be copied to SRAM.  It might
>> need a little stub in SRAM to setup the stack etc., but it should be
>> quite doable.  That eliminates the problem cited as the reason for the
>> move to M3.
>>
>>> I'm not sure how much it complicates things, but the code needs to be
>>> able to run with the MMU on and MMU off. The C code would be a
>>> minimalized duplication of much of what is already in
>>> mach-omap2. Because you are proposing to split this up between A8 and
>>> M3, much of that code would then be duplicated again within the M3
>>> firmware.
>>>
>>> And don't forget that am335x is just the first platform with such a PM scheme.
>>
>> IMO, all the more reason to handle it in Linux, not in platform-specific firmware.
>>
>>> Because the M3 firmware already has to manage power domains, hwmods,
>>> plls, and clockdomains, adding or removing which ones it handles
>>> doesn't really change the size or complexity of the firmware.
>>
>> No, but it significantly complicates its interaction with Linux, which
>> also has to know about all these things already.  IMO, as I've stated
>> from the very beginning of this SoC, there should be a very clean split.
>> M3 should only handle the minimum, what the MPU simply cannot do
>> (MPU/interconnect off, wakeup).  MPU/Linux should handle the rest.
>>
>>> In fact, because so much of the code is common code, moving this into
>>> kernel would just mean making two copies of the firmware with
>>> different steps to be run, one for the A8 SRAM, one for the M3.
>>
>> Maybe I'm getting confused, but the more you talk about the linux and
>> the firmware doing the same code, the more I think the firmware is
>> (trying) to do too much.  If this is going to be understandable (and
>> maintainable), there needs to be a clean split of roles between the MPU
>> and the M3.
>>
>
> In the past i tried to keep the firmware as minimal as possible and pushed
> back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
> the opinion that we need to do whatever's possible in the kernel.
>
> Sadly, things just got a point where it made much more sense (technically
> as well as non-technically) to just put the low level stuff in the M3.
>
> 1. In addition to the Linux support, we have non-OS based code for AM335x
> (and AM437x) which in the past just had to duplicate whatever was done
> in the Linux. Being a different codebase the non-OS guys have their own
> set of challenges and we had to at times sit through and debug issues in
> one codebase while the other was working fine. Ideally these things should
> never come up but sadly they do and we need to solve them.
>
> We also have people trying to implement this thing on different sort of
> OS environments and they also end up debugging the same set of issues.
>
> With only a handful of folks able to spend time debugging issues 'do everything
> in Linux and expect others to copy it' model doesn't scale up. Keeping
> things in the
> firmware with the code available online helps do away with the
> 'developer scalability'
> problem and if one looks at things differently enables code-reuse at
> the same time.

Yes, yes, this is the classic argument for a HAL, and making that case has always
gone over well in the kernel. ;)

> Moreover, when the code was finally moved to M3, AFAICT we had validated
> all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
> control) that TI hardware guys could throw at us.Yes there could be stupid bugs
> lurking in the code since it wasn't reviewed as much as i would have
> liked but we
> have something which proves the functionality to be used as the base.

I don't follow the argument here.  You mean it was validated *before*
moving it to the M3, or after?  Either way, I'm how that makes a case
for moving it to the M3.  Surely if it was on the MPU, it would also
have been validated, no?

> 2. As has been already been pointed out by Russ, on AM335x this step needs
> to be done very late in the suspend process (the last stage
> actually). 

late, yes.  But *technically*, it can still be done from the MPU.

> On the next SoC there are other complications related to security
> which enforce this step must be done from the M3.

Aha!  So far, the first technical reason I've seen.  Can you elaborate?
Exactly which step has to be done from the M3, and why can't the MPU do
it?  And could it be done more simply by putting *only* the parts needed
on the M3 and not letting it snowball into a pile of stuff?

> So trying to keep it in M3 for both AM335x and AM437x helps avoid the
> code churn that will happen if we were to do this differently on two
> SoCs which have similar PM architectures.

I'm not conviced it has to be done so differently between the two.
Let's have some more details about the security differences before
making that decision.

> Morevoer, all the suggestions on how to keep the code in Linux working
> around the complications due to the main memory not being accessible
> will need to be replicated on the non-Linux s/w stacks and that's just
> make it more difficult for them.

The linux code has to be very self-contained (in assembler or C), so I'm
not sure how it's difficult to replicated in any other OS (or non-OS.)

> 3. Moving this to M3 leaves the option open to try out some crazy stuff for
> power optimizations wherein the CORE voltage is lowered even below OPP50.
> This is yet to be proved in h/w so one can ignore this for now but yes it's a
> possibility.

All interesting reasons, but other than the security one, all boil down
to non-technical arguments about what's easier.  But as you well know,
"the easy way" usually isn't the same thing as "the right way" when it
comes to getting things into the upstream linux kernel.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 21:33                   ` Kevin Hilman
@ 2013-08-30  0:25                     ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-30  0:25 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Vaibhav Bedia, devicetree, Jan Lübbe, Mark Brown,
	linux-omap, Linux ARM Kernel List

On Thu, Aug 29, 2013 at 2:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
> Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:
[snip]
>> Morevoer, all the suggestions on how to keep the code in Linux working
>> around the complications due to the main memory not being accessible
>> will need to be replicated on the non-Linux s/w stacks and that's just
>> make it more difficult for them.
>
> The linux code has to be very self-contained (in assembler or C), so I'm
> not sure how it's difficult to replicated in any other OS (or non-OS.)

Let me pull on this thread a little bit. Would this involve defining a
bunch of different sections for each arch so that I could do:

void __sram_am33xx am33xx_some_pm_function(args....)
{
}

static struct am33xx_foo_dyn *blargity __sramdata_am33xx = { ...};

static const struct am33xx_foo_const *blarg __sramconst_am33xx = { ... };

The sram push code could then push these sections into sram. There
would then be a set of inlines or macros for converting addresses
within these sections to SRAM addresses, maybe also inlines or macros
for calling code that has been pushed into sram by wrapping the
original function pointer. The macros or inlines that call SRAM code
could perform the trampoline as well.

Would there be much general interest in a scheme like this? Is there
already I scheme like this I haven't noticed. Would such an explosion
of sections be a problem if all platforms started using this for SRAM
code?

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-30  0:25                     ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-08-30  0:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 2:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
> Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:
[snip]
>> Morevoer, all the suggestions on how to keep the code in Linux working
>> around the complications due to the main memory not being accessible
>> will need to be replicated on the non-Linux s/w stacks and that's just
>> make it more difficult for them.
>
> The linux code has to be very self-contained (in assembler or C), so I'm
> not sure how it's difficult to replicated in any other OS (or non-OS.)

Let me pull on this thread a little bit. Would this involve defining a
bunch of different sections for each arch so that I could do:

void __sram_am33xx am33xx_some_pm_function(args....)
{
}

static struct am33xx_foo_dyn *blargity __sramdata_am33xx = { ...};

static const struct am33xx_foo_const *blarg __sramconst_am33xx = { ... };

The sram push code could then push these sections into sram. There
would then be a set of inlines or macros for converting addresses
within these sections to SRAM addresses, maybe also inlines or macros
for calling code that has been pushed into sram by wrapping the
original function pointer. The macros or inlines that call SRAM code
could perform the trampoline as well.

Would there be much general interest in a scheme like this? Is there
already I scheme like this I haven't noticed. Would such an explosion
of sections be a problem if all platforms started using this for SRAM
code?

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-30  0:25                     ` Russ Dill
@ 2013-08-30 16:06                       ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-30 16:06 UTC (permalink / raw)
  To: Russ Dill
  Cc: Vaibhav Bedia, devicetree, Jan Lübbe, Mark Brown,
	linux-omap, Linux ARM Kernel List

Russ Dill <Russ.Dill@ti.com> writes:

> On Thu, Aug 29, 2013 at 2:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
>> Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:
> [snip]
>>> Morevoer, all the suggestions on how to keep the code in Linux working
>>> around the complications due to the main memory not being accessible
>>> will need to be replicated on the non-Linux s/w stacks and that's just
>>> make it more difficult for them.
>>
>> The linux code has to be very self-contained (in assembler or C), so I'm
>> not sure how it's difficult to replicated in any other OS (or non-OS.)
>
> Let me pull on this thread a little bit. Would this involve defining a
> bunch of different sections for each arch so that I could do:
>
> void __sram_am33xx am33xx_some_pm_function(args....)
> {
> }
>
> static struct am33xx_foo_dyn *blargity __sramdata_am33xx = { ...};
>
> static const struct am33xx_foo_const *blarg __sramconst_am33xx = { ... };
>
> The sram push code could then push these sections into sram. There
> would then be a set of inlines or macros for converting addresses
> within these sections to SRAM addresses, maybe also inlines or macros
> for calling code that has been pushed into sram by wrapping the
> original function pointer. The macros or inlines that call SRAM code
> could perform the trampoline as well.

Well, I was thinking of something much dumber.

I was thinking about just _carefully_ writing a single, self-contained C
function, with all of its data on the stack (and consts as #defines).
Think of it is a step up in readability from straight assembly (which
was the stated reason for moving the code to the M3 in the first place.)

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-30 16:06                       ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-08-30 16:06 UTC (permalink / raw)
  To: linux-arm-kernel

Russ Dill <Russ.Dill@ti.com> writes:

> On Thu, Aug 29, 2013 at 2:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
>> Vaibhav Bedia <vaibhav.bedia@gmail.com> writes:
> [snip]
>>> Morevoer, all the suggestions on how to keep the code in Linux working
>>> around the complications due to the main memory not being accessible
>>> will need to be replicated on the non-Linux s/w stacks and that's just
>>> make it more difficult for them.
>>
>> The linux code has to be very self-contained (in assembler or C), so I'm
>> not sure how it's difficult to replicated in any other OS (or non-OS.)
>
> Let me pull on this thread a little bit. Would this involve defining a
> bunch of different sections for each arch so that I could do:
>
> void __sram_am33xx am33xx_some_pm_function(args....)
> {
> }
>
> static struct am33xx_foo_dyn *blargity __sramdata_am33xx = { ...};
>
> static const struct am33xx_foo_const *blarg __sramconst_am33xx = { ... };
>
> The sram push code could then push these sections into sram. There
> would then be a set of inlines or macros for converting addresses
> within these sections to SRAM addresses, maybe also inlines or macros
> for calling code that has been pushed into sram by wrapping the
> original function pointer. The macros or inlines that call SRAM code
> could perform the trampoline as well.

Well, I was thinking of something much dumber.

I was thinking about just _carefully_ writing a single, self-contained C
function, with all of its data on the stack (and consts as #defines).
Think of it is a step up in readability from straight assembly (which
was the stated reason for moving the code to the M3 in the first place.)

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 21:33                   ` Kevin Hilman
@ 2013-08-30 17:57                     ` Vaibhav Bedia
  -1 siblings, 0 replies; 84+ messages in thread
From: Vaibhav Bedia @ 2013-08-30 17:57 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Russ Dill, devicetree, linux-omap, Mark Brown, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 5:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
[...]
>>>
>>> Maybe I'm getting confused, but the more you talk about the linux and
>>> the firmware doing the same code, the more I think the firmware is
>>> (trying) to do too much.  If this is going to be understandable (and
>>> maintainable), there needs to be a clean split of roles between the MPU
>>> and the M3.
>>>
>>
>> In the past i tried to keep the firmware as minimal as possible and pushed
>> back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
>> the opinion that we need to do whatever's possible in the kernel.
>>
>> Sadly, things just got a point where it made much more sense (technically
>> as well as non-technically) to just put the low level stuff in the M3.
>>
>> 1. In addition to the Linux support, we have non-OS based code for AM335x
>> (and AM437x) which in the past just had to duplicate whatever was done
>> in the Linux. Being a different codebase the non-OS guys have their own
>> set of challenges and we had to at times sit through and debug issues in
>> one codebase while the other was working fine. Ideally these things should
>> never come up but sadly they do and we need to solve them.
>>
>> We also have people trying to implement this thing on different sort of
>> OS environments and they also end up debugging the same set of issues.
>>
>> With only a handful of folks able to spend time debugging issues 'do everything
>> in Linux and expect others to copy it' model doesn't scale up. Keeping
>> things in the
>> firmware with the code available online helps do away with the
>> 'developer scalability'
>> problem and if one looks at things differently enables code-reuse at
>> the same time.
>
> Yes, yes, this is the classic argument for a HAL, and making that case has always
> gone over well in the kernel. ;)
>

If the carefully crafted C code with a bit of linker magic thrown in
works, that's great
but for anyone without the generic Linux code in general and the Linux community
to go to with queries will have a tough time getting it done. TI
non-OS code has been
implemented from scratch and one of the purposes is to keep things as simple
as possible for folks. I know it's all non-technical stuff and most
likely i am a bit
biased but just a different POV from someone who spent hours debugging
'this works
and that doesn't' kind of issues. Trying to wrap your head around
random s/w stacks
and figuring out what needs to be changed is not pretty IMHO :\

>> Moreover, when the code was finally moved to M3, AFAICT we had validated
>> all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
>> control) that TI hardware guys could throw at us.Yes there could be stupid bugs
>> lurking in the code since it wasn't reviewed as much as i would have
>> liked but we
>> have something which proves the functionality to be used as the base.
>
> I don't follow the argument here.  You mean it was validated *before*
> moving it to the M3, or after?  Either way, I'm how that makes a case
> for moving it to the M3.  Surely if it was on the MPU, it would also
> have been validated, no?
>

At least i did all the validation without the VDD_CORE changes. The point i was
trying to make is that we are not trying to hide bugs in there, if
that's one of the
concerns. Just trying to make it simple (subjective, i know) for others to use.

>> 2. As has been already been pointed out by Russ, on AM335x this step needs
>> to be done very late in the suspend process (the last stage
>> actually).
>
> late, yes.  But *technically*, it can still be done from the MPU.
>
>> On the next SoC there are other complications related to security
>> which enforce this step must be done from the M3.
>
> Aha!  So far, the first technical reason I've seen.  Can you elaborate?
> Exactly which step has to be done from the M3, and why can't the MPU do
> it?  And could it be done more simply by putting *only* the parts needed
> on the M3 and not letting it snowball into a pile of stuff?
>

Sent out another mail for this.

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-08-30 17:57                     ` Vaibhav Bedia
  0 siblings, 0 replies; 84+ messages in thread
From: Vaibhav Bedia @ 2013-08-30 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 5:33 PM, Kevin Hilman <khilman@linaro.org> wrote:
[...]
>>>
>>> Maybe I'm getting confused, but the more you talk about the linux and
>>> the firmware doing the same code, the more I think the firmware is
>>> (trying) to do too much.  If this is going to be understandable (and
>>> maintainable), there needs to be a clean split of roles between the MPU
>>> and the M3.
>>>
>>
>> In the past i tried to keep the firmware as minimal as possible and pushed
>> back all efforts to push unnecessary stuff in there. Like Kevin, i too was of
>> the opinion that we need to do whatever's possible in the kernel.
>>
>> Sadly, things just got a point where it made much more sense (technically
>> as well as non-technically) to just put the low level stuff in the M3.
>>
>> 1. In addition to the Linux support, we have non-OS based code for AM335x
>> (and AM437x) which in the past just had to duplicate whatever was done
>> in the Linux. Being a different codebase the non-OS guys have their own
>> set of challenges and we had to at times sit through and debug issues in
>> one codebase while the other was working fine. Ideally these things should
>> never come up but sadly they do and we need to solve them.
>>
>> We also have people trying to implement this thing on different sort of
>> OS environments and they also end up debugging the same set of issues.
>>
>> With only a handful of folks able to spend time debugging issues 'do everything
>> in Linux and expect others to copy it' model doesn't scale up. Keeping
>> things in the
>> firmware with the code available online helps do away with the
>> 'developer scalability'
>> problem and if one looks at things differently enables code-reuse at
>> the same time.
>
> Yes, yes, this is the classic argument for a HAL, and making that case has always
> gone over well in the kernel. ;)
>

If the carefully crafted C code with a bit of linker magic thrown in
works, that's great
but for anyone without the generic Linux code in general and the Linux community
to go to with queries will have a tough time getting it done. TI
non-OS code has been
implemented from scratch and one of the purposes is to keep things as simple
as possible for folks. I know it's all non-technical stuff and most
likely i am a bit
biased but just a different POV from someone who spent hours debugging
'this works
and that doesn't' kind of issues. Trying to wrap your head around
random s/w stacks
and figuring out what needs to be changed is not pretty IMHO :\

>> Moreover, when the code was finally moved to M3, AFAICT we had validated
>> all supported combinations (DDR2, DDR3, DDR3 with VTT, DDR3 without VTT
>> control) that TI hardware guys could throw at us.Yes there could be stupid bugs
>> lurking in the code since it wasn't reviewed as much as i would have
>> liked but we
>> have something which proves the functionality to be used as the base.
>
> I don't follow the argument here.  You mean it was validated *before*
> moving it to the M3, or after?  Either way, I'm how that makes a case
> for moving it to the M3.  Surely if it was on the MPU, it would also
> have been validated, no?
>

At least i did all the validation without the VDD_CORE changes. The point i was
trying to make is that we are not trying to hide bugs in there, if
that's one of the
concerns. Just trying to make it simple (subjective, i know) for others to use.

>> 2. As has been already been pointed out by Russ, on AM335x this step needs
>> to be done very late in the suspend process (the last stage
>> actually).
>
> late, yes.  But *technically*, it can still be done from the MPU.
>
>> On the next SoC there are other complications related to security
>> which enforce this step must be done from the M3.
>
> Aha!  So far, the first technical reason I've seen.  Can you elaborate?
> Exactly which step has to be done from the M3, and why can't the MPU do
> it?  And could it be done more simply by putting *only* the parts needed
> on the M3 and not letting it snowball into a pile of stuff?
>

Sent out another mail for this.

Regards,
Vaibhav

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-29 19:10                   ` Mark Brown
@ 2013-09-03 14:06                     ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-09-03 14:06 UTC (permalink / raw)
  To: Mark Brown
  Cc: devicetree, Kevin Hilman, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

On Thu, Aug 29, 2013 at 12:10 PM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 11:25:43AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Making it write only seems to be a mistake - like I said in my other
>> > mail I'd expect you'd want bitfield updates here.  The read and modify
>> > could be done earlier by Linux though.
>
>> Updating bitfields in memory is pretty basic, but with I2C, each
>> device has its own register sizes and methods of accessing registers.
>> The first byte of an I2C sequence being a register address is pretty
>> common though. You'd need a method of defining in the device tree
>> piece how to modify bitfields.
>
> I'd not assume byte based addressing for a PMIC, it's very common but
> not universal.  The difficulties here assume putting this in the device
> tree as explicit register I/O - I do tend to agree with Kevin that this
> doesn't seem like the right abstraction.
>
>> > If it's just setting a single voltage then extracting the bitfield to
>> > update shouldn't be too hard for regmap based regulators.  Off the top
>> > of my head I'd expect either the driver for the M3 or the cpuidle driver
>> > that talks to it to be a consumer of the regulator and then go from
>> > there.
>
>> It'd be a list of bitfields. So are you suggesting a regulator_ops
>> call that would return a list of bitfield updates along with an I2C
>> controller, an I2C device address, I2C register addressing scheme (8
>> bit, 16 bit, or other) and the info for each bitfield (register size)?
>> And then each regulator driver would be updated as needed with this
>> code. Would this be a way forward? Would regmap actually tie into this
>> at all?
>
> I was thinking about the majority of regulators where setting a voltage
> would be a single bitfield update (plus ramp delay, which is going to
> need to be accounted for in the power on case).  If we need to do longer
> sequences things get a bit more tricky in terms of interface but it
> seems doable.

The sequence for TPS65217 on beaglebone is rather long, it's 8
register writes. It has to write the new value to the DCDC3 register
and the apply bit to the DCDC register, but both registers are
password locked registers. The password sequence is to write the
password register, then the register, then the password register
again, then the register again.

> regmap would tie in in that it already has a way of describing the
> format for interactions with the device so we could just reuse the same
> description, and with some work we can probably reuse the code that
> generates the bitstreams for sending to the devices too (though I don't
> immediately see a nice way of doing that).
>
> Not sure if this is worth the effort or not though, but then there's the
> whole DT as ABI thing to worry about...
>
>> This is VDD core, so its not related to cpuidle or the M3.
>
> It's related to the M3 if the M3 is managing it; you can have multiple
> consumers for a regulator so it doesn't need to be one or the other.

Ah.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-09-03 14:06                     ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-09-03 14:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 29, 2013 at 12:10 PM, Mark Brown <broonie@kernel.org> wrote:
> On Thu, Aug 29, 2013 at 11:25:43AM -0700, Russ Dill wrote:
>> On Thu, Aug 29, 2013 at 11:01 AM, Mark Brown <broonie@kernel.org> wrote:
>
>> > Making it write only seems to be a mistake - like I said in my other
>> > mail I'd expect you'd want bitfield updates here.  The read and modify
>> > could be done earlier by Linux though.
>
>> Updating bitfields in memory is pretty basic, but with I2C, each
>> device has its own register sizes and methods of accessing registers.
>> The first byte of an I2C sequence being a register address is pretty
>> common though. You'd need a method of defining in the device tree
>> piece how to modify bitfields.
>
> I'd not assume byte based addressing for a PMIC, it's very common but
> not universal.  The difficulties here assume putting this in the device
> tree as explicit register I/O - I do tend to agree with Kevin that this
> doesn't seem like the right abstraction.
>
>> > If it's just setting a single voltage then extracting the bitfield to
>> > update shouldn't be too hard for regmap based regulators.  Off the top
>> > of my head I'd expect either the driver for the M3 or the cpuidle driver
>> > that talks to it to be a consumer of the regulator and then go from
>> > there.
>
>> It'd be a list of bitfields. So are you suggesting a regulator_ops
>> call that would return a list of bitfield updates along with an I2C
>> controller, an I2C device address, I2C register addressing scheme (8
>> bit, 16 bit, or other) and the info for each bitfield (register size)?
>> And then each regulator driver would be updated as needed with this
>> code. Would this be a way forward? Would regmap actually tie into this
>> at all?
>
> I was thinking about the majority of regulators where setting a voltage
> would be a single bitfield update (plus ramp delay, which is going to
> need to be accounted for in the power on case).  If we need to do longer
> sequences things get a bit more tricky in terms of interface but it
> seems doable.

The sequence for TPS65217 on beaglebone is rather long, it's 8
register writes. It has to write the new value to the DCDC3 register
and the apply bit to the DCDC register, but both registers are
password locked registers. The password sequence is to write the
password register, then the register, then the password register
again, then the register again.

> regmap would tie in in that it already has a way of describing the
> format for interactions with the device so we could just reuse the same
> description, and with some work we can probably reuse the code that
> generates the bitstreams for sending to the devices too (though I don't
> immediately see a nice way of doing that).
>
> Not sure if this is worth the effort or not though, but then there's the
> whole DT as ABI thing to worry about...
>
>> This is VDD core, so its not related to cpuidle or the M3.
>
> It's related to the M3 if the M3 is managing it; you can have multiple
> consumers for a regulator so it doesn't need to be one or the other.

Ah.

> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-09-03 14:06                     ` Russ Dill
@ 2013-09-03 14:39                       ` Mark Brown
  -1 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-09-03 14:39 UTC (permalink / raw)
  To: Russ Dill
  Cc: devicetree, Kevin Hilman, linux-omap, Jan Lübbe,
	Linux ARM Kernel List

[-- Attachment #1: Type: text/plain, Size: 965 bytes --]

On Tue, Sep 03, 2013 at 07:06:01AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 12:10 PM, Mark Brown <broonie@kernel.org> wrote:

> > I was thinking about the majority of regulators where setting a voltage
> > would be a single bitfield update (plus ramp delay, which is going to
> > need to be accounted for in the power on case).  If we need to do longer
> > sequences things get a bit more tricky in terms of interface but it
> > seems doable.

> The sequence for TPS65217 on beaglebone is rather long, it's 8
> register writes. It has to write the new value to the DCDC3 register
> and the apply bit to the DCDC register, but both registers are
> password locked registers. The password sequence is to write the
> password register, then the register, then the password register
> again, then the register again.

Oh dear, that's a bit annoying.  It's doable obviously if people decide
to go down that route but it's work and this is a very common system.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-09-03 14:39                       ` Mark Brown
  0 siblings, 0 replies; 84+ messages in thread
From: Mark Brown @ 2013-09-03 14:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 03, 2013 at 07:06:01AM -0700, Russ Dill wrote:
> On Thu, Aug 29, 2013 at 12:10 PM, Mark Brown <broonie@kernel.org> wrote:

> > I was thinking about the majority of regulators where setting a voltage
> > would be a single bitfield update (plus ramp delay, which is going to
> > need to be accounted for in the power on case).  If we need to do longer
> > sequences things get a bit more tricky in terms of interface but it
> > seems doable.

> The sequence for TPS65217 on beaglebone is rather long, it's 8
> register writes. It has to write the new value to the DCDC3 register
> and the apply bit to the DCDC register, but both registers are
> password locked registers. The password sequence is to write the
> password register, then the register, then the password register
> again, then the register again.

Oh dear, that's a bit annoying.  It's doable obviously if people decide
to go down that route but it's work and this is a very common system.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130903/76f33bcf/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-08-30 16:06                       ` Kevin Hilman
@ 2013-09-03 18:55                         ` Russ Dill
  -1 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-09-03 18:55 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: devicetree, Jan Lübbe, Mark Brown, Vaibhav Bedia,
	linux-omap, Linux ARM Kernel List

On Fri, Aug 30, 2013 at 9:06 AM, Kevin Hilman <khilman@linaro.org> wrote:
> Well, I was thinking of something much dumber.
>
> I was thinking about just _carefully_ writing a single, self-contained C
> function, with all of its data on the stack (and consts as #defines).
> Think of it is a step up in readability from straight assembly (which
> was the stated reason for moving the code to the M3 in the first place.)
>
> Kevin

That can only give you your suspend function. You need a resume
function to undo everything before calling cpu_resume, and the resume
function needs access to the data that was in the suspend function.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-09-03 18:55                         ` Russ Dill
  0 siblings, 0 replies; 84+ messages in thread
From: Russ Dill @ 2013-09-03 18:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Aug 30, 2013 at 9:06 AM, Kevin Hilman <khilman@linaro.org> wrote:
> Well, I was thinking of something much dumber.
>
> I was thinking about just _carefully_ writing a single, self-contained C
> function, with all of its data on the stack (and consts as #defines).
> Think of it is a step up in readability from straight assembly (which
> was the stated reason for moving the code to the M3 in the first place.)
>
> Kevin

That can only give you your suspend function. You need a resume
function to undo everything before calling cpu_resume, and the resume
function needs access to the data that was in the suspend function.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
  2013-09-03 18:55                         ` Russ Dill
@ 2013-09-03 19:07                           ` Kevin Hilman
  -1 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-09-03 19:07 UTC (permalink / raw)
  To: Russ Dill
  Cc: devicetree, Jan Lübbe, Mark Brown, Vaibhav Bedia,
	linux-omap, Linux ARM Kernel List

On Tue, Sep 3, 2013 at 11:55 AM, Russ Dill <Russ.Dill@ti.com> wrote:
> On Fri, Aug 30, 2013 at 9:06 AM, Kevin Hilman <khilman@linaro.org> wrote:
>> Well, I was thinking of something much dumber.
>>
>> I was thinking about just _carefully_ writing a single, self-contained C
>> function, with all of its data on the stack (and consts as #defines).
>> Think of it is a step up in readability from straight assembly (which
>> was the stated reason for moving the code to the M3 in the first place.)
>>
>> Kevin
>
> That can only give you your suspend function. You need a resume
> function to undo everything before calling cpu_resume, and the resume
> function needs access to the data that was in the suspend function.

Well, it can be done (and I've seen it done) with various hacks, but I
agree it's not pretty, but it is at least slightly prettier than piles
of asm.  That being said, I saw you posted a more generic solution
that looks like a real solution that can scale.  I'll have a closer
look at that.  Thanks for working on it.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support
@ 2013-09-03 19:07                           ` Kevin Hilman
  0 siblings, 0 replies; 84+ messages in thread
From: Kevin Hilman @ 2013-09-03 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 3, 2013 at 11:55 AM, Russ Dill <Russ.Dill@ti.com> wrote:
> On Fri, Aug 30, 2013 at 9:06 AM, Kevin Hilman <khilman@linaro.org> wrote:
>> Well, I was thinking of something much dumber.
>>
>> I was thinking about just _carefully_ writing a single, self-contained C
>> function, with all of its data on the stack (and consts as #defines).
>> Think of it is a step up in readability from straight assembly (which
>> was the stated reason for moving the code to the M3 in the first place.)
>>
>> Kevin
>
> That can only give you your suspend function. You need a resume
> function to undo everything before calling cpu_resume, and the resume
> function needs access to the data that was in the suspend function.

Well, it can be done (and I've seen it done) with various hacks, but I
agree it's not pretty, but it is at least slightly prettier than piles
of asm.  That being said, I saw you posted a more generic solution
that looks like a real solution that can scale.  I'll have a closer
look at that.  Thanks for working on it.

Kevin

^ permalink raw reply	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2013-09-03 19:07 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-13 22:20 [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support Russ Dill
2013-08-13 22:20 ` Russ Dill
2013-08-13 22:20 ` [PATCH v4 1/4] ARM: OMAP2+: AM33XX: I2C Sleep/wake sequence support Russ Dill
2013-08-13 22:20   ` Russ Dill
2013-08-14 10:18   ` Gururaja Hebbar
2013-08-14 10:18     ` Gururaja Hebbar
2013-08-14 22:34     ` Russ Dill
2013-08-14 22:34       ` Russ Dill
2013-08-16  7:16       ` Gururaja Hebbar
2013-08-16  7:16         ` Gururaja Hebbar
2013-08-19  5:49       ` Gururaja Hebbar
2013-08-19  5:49         ` Gururaja Hebbar
2013-08-20 16:33         ` Russ Dill
2013-08-20 16:33           ` Russ Dill
2013-08-21  8:29           ` Gururaja Hebbar
2013-08-21  8:29             ` Gururaja Hebbar
2013-08-13 22:20 ` [PATCH v4 2/4] ARM: dts: add AM33XX vdd core opp50 suspend for Beaglebone Russ Dill
2013-08-13 22:20   ` Russ Dill
2013-08-14  8:59   ` Gururaja Hebbar
2013-08-14  8:59     ` Gururaja Hebbar
2013-08-14 22:21     ` Russ Dill
2013-08-14 22:21       ` Russ Dill
2013-08-13 22:20 ` [PATCH v4 3/4] ARM: dts: add AM33XX vdd core opp50 suspend for AM335X GP EVM Russ Dill
2013-08-13 22:20   ` Russ Dill
2013-08-13 22:20 ` [PATCH v4 4/4] ARM: dts: AM33XX vdd core opp50 suspend for EVM-SK Russ Dill
2013-08-13 22:20   ` Russ Dill
2013-08-14 13:38 ` [PATCH v4 0/4] ARM: OMAP2+: AM33XX: VDD CORE OPP50 support Jan Lübbe
2013-08-14 13:38   ` Jan Lübbe
2013-08-14 22:21   ` Russ Dill
2013-08-14 22:21     ` Russ Dill
2013-08-15  8:00     ` Jan Lübbe
2013-08-15  8:00       ` Jan Lübbe
2013-08-27 22:44     ` Kevin Hilman
2013-08-27 22:44       ` Kevin Hilman
2013-08-28  1:05       ` Russ Dill
2013-08-28  1:05         ` Russ Dill
2013-08-29 11:05         ` Mark Brown
2013-08-29 11:05           ` Mark Brown
2013-08-29 15:29           ` Kevin Hilman
2013-08-29 15:29             ` Kevin Hilman
2013-08-29 15:49             ` Mark Brown
2013-08-29 15:49               ` Mark Brown
2013-08-29 16:31               ` Russ Dill
2013-08-29 16:31                 ` Russ Dill
2013-08-29 17:30                 ` Mark Brown
2013-08-29 17:30                   ` Mark Brown
2013-08-29 17:47                   ` Russ Dill
2013-08-29 17:47                     ` Russ Dill
2013-08-29 18:03                     ` Mark Brown
2013-08-29 18:03                       ` Mark Brown
2013-08-29 18:28                       ` Russ Dill
2013-08-29 18:28                         ` Russ Dill
2013-08-29 15:42           ` Russ Dill
2013-08-29 15:42             ` Russ Dill
2013-08-29 18:01             ` Mark Brown
2013-08-29 18:01               ` Mark Brown
2013-08-29 18:25               ` Russ Dill
2013-08-29 18:25                 ` Russ Dill
2013-08-29 19:10                 ` Mark Brown
2013-08-29 19:10                   ` Mark Brown
2013-09-03 14:06                   ` Russ Dill
2013-09-03 14:06                     ` Russ Dill
2013-09-03 14:39                     ` Mark Brown
2013-09-03 14:39                       ` Mark Brown
2013-08-29 15:17         ` Kevin Hilman
2013-08-29 15:17           ` Kevin Hilman
2013-08-29 16:10           ` Russ Dill
2013-08-29 16:10             ` Russ Dill
2013-08-29 19:11             ` Kevin Hilman
2013-08-29 19:11               ` Kevin Hilman
2013-08-29 20:09               ` Vaibhav Bedia
2013-08-29 20:09                 ` Vaibhav Bedia
2013-08-29 21:33                 ` Kevin Hilman
2013-08-29 21:33                   ` Kevin Hilman
2013-08-30  0:25                   ` Russ Dill
2013-08-30  0:25                     ` Russ Dill
2013-08-30 16:06                     ` Kevin Hilman
2013-08-30 16:06                       ` Kevin Hilman
2013-09-03 18:55                       ` Russ Dill
2013-09-03 18:55                         ` Russ Dill
2013-09-03 19:07                         ` Kevin Hilman
2013-09-03 19:07                           ` Kevin Hilman
2013-08-30 17:57                   ` Vaibhav Bedia
2013-08-30 17:57                     ` Vaibhav Bedia

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.