* [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
* 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 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 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
* [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
* 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 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
* [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 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 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 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-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 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: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 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: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 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: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 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: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 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-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 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 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-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
* 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
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.