From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.1 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D00C2C10F03 for ; Fri, 22 Mar 2019 17:17:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8E7D721900 for ; Fri, 22 Mar 2019 17:17:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="BgZCXa7W" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728560AbfCVRRy (ORCPT ); Fri, 22 Mar 2019 13:17:54 -0400 Received: from fllv0016.ext.ti.com ([198.47.19.142]:55176 "EHLO fllv0016.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727105AbfCVRRy (ORCPT ); Fri, 22 Mar 2019 13:17:54 -0400 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id x2MHGb4v041015; Fri, 22 Mar 2019 12:16:37 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1553274997; bh=dAxkXO7uX9xemqVnUq/O5k+/6gUH3zu+WTXA9y14s9U=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=BgZCXa7W2U8BLyPn95fovmbvIWUzZ4+zfxPrI0WVGO/RJDPhbMauvb6H0juHRmGDh 7WDVyJ2LJ70saKQR8+k/EeM/YGIVm3nxECvW+4HZk2FnEpbVXoH2TQOrxBC599/7m8 QA+W6XecfWsx8T4bYSrzqBFoT2PjYmE5s6zNz8Jo= Received: from DLEE106.ent.ti.com (dlee106.ent.ti.com [157.170.170.36]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x2MHGa95041149 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Mar 2019 12:16:36 -0500 Received: from DLEE102.ent.ti.com (157.170.170.32) by DLEE106.ent.ti.com (157.170.170.36) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5; Fri, 22 Mar 2019 12:16:36 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE102.ent.ti.com (157.170.170.32) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1713.5 via Frontend Transport; Fri, 22 Mar 2019 12:16:36 -0500 Received: from a0393675ula.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x2MHGHYO006487; Fri, 22 Mar 2019 12:16:33 -0500 From: Keerthy To: , , , CC: , , , , , Subject: [PATCH 5/5] soc: ti: pm33xx: AM437X: Add rtc_only with ddr in self-refresh support Date: Fri, 22 Mar 2019 22:46:19 +0530 Message-ID: <20190322171619.4180-6-j-keerthy@ti.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190322171619.4180-1-j-keerthy@ti.com> References: <20190322171619.4180-1-j-keerthy@ti.com> MIME-Version: 1.0 Content-Type: text/plain X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-rtc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rtc@vger.kernel.org During RTC-only suspend, power is lost to the wkup domain, so we need to save and restore the state of that domain. We also need to store some information within the RTC registers so that u-boot can do the right thing at powerup. The state is entered by getting the RTC to bring the pmic_power_en line low which will instruct the PMIC to disable the appropriate power rails after putting DDR into self-refresh mode. To bring pmic_power_en low, we need to get an ALARM2 event. Since we are running from SRAM at that point, it means calculating what the next second is (via ASM) and programming that into the RTC. This patch also adds support for wake up source detection. Signed-off-by: Keerthy Signed-off-by: Dave Gerlach --- drivers/soc/ti/Kconfig | 5 +- drivers/soc/ti/pm33xx.c | 190 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index be4570baad96..57960e92ebe0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA config AMX3_PM tristate "AMx3 Power Management" depends on SOC_AM33XX || SOC_AM43XX - depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM + depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP help Enable power management on AM335x and AM437x. Required for suspend to mem and standby states on both AM335x and AM437x platforms and for deeper cpuidle - c-states on AM335x. + c-states on AM335x. Also required for rtc and ddr in self-refresh low + power mode on AM437x platforms. config WKUP_M3_IPC tristate "TI AMx3 Wkup-M3 IPC Driver" diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 69128993776d..15b1414d3465 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -6,6 +6,7 @@ * Vaibhav Bedia, Dave Gerlach */ +#include #include #include #include @@ -13,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -29,20 +32,47 @@ #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ (unsigned long)pm_sram->do_wfi) +#define RTC_SCRATCH_RESUME_REG 0 +#define RTC_SCRATCH_MAGIC_REG 1 +#define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ +#define GIC_INT_SET_PENDING_BASE 0x200 +#define AM43XX_GIC_DIST_BASE 0x48241000 + +static u32 rtc_magic_val; + static int (*am33xx_do_wfi_sram)(unsigned long unused); static phys_addr_t am33xx_do_wfi_sram_phys; static struct gen_pool *sram_pool, *sram_pool_data; static unsigned long ocmcram_location, ocmcram_location_data; +static struct rtc_device *omap_rtc; +static void __iomem *gic_dist_base; + static struct am33xx_pm_platform_data *pm_ops; static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +#ifdef CONFIG_SUSPEND +static int rtc_only_idle; +static int retrigger_irq; static unsigned long suspend_wfi_flags; +static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, + .src = "Unknown", +}; + +static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { + .irq_nr = 108, .src = "RTC Alarm", +}; + +static struct wkup_m3_wakeup_src rtc_ext_wakeup = { + .irq_nr = 0, .src = "Ext wakeup", +}; +#endif + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -99,13 +129,65 @@ static int am33xx_push_sram_idle(void) return 0; } +static int __init am43xx_map_gic(void) +{ + gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); + + if (!gic_dist_base) + return -ENOMEM; + + return 0; +} + #ifdef CONFIG_SUSPEND +struct wkup_m3_wakeup_src rtc_wake_src(void) +{ + u32 i; + + i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; + + if (i) { + retrigger_irq = rtc_alarm_wakeup.irq_nr; + return rtc_alarm_wakeup; + } + + retrigger_irq = rtc_ext_wakeup.irq_nr; + + return rtc_ext_wakeup; +} + +int am33xx_rtc_only_idle(unsigned long wfi_flags) +{ + rtc_power_off_program(omap_rtc); + am33xx_do_wfi_sram(wfi_flags); + return 0; +} + static int am33xx_pm_suspend(suspend_state_t suspend_state) { int i, ret = 0; - ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram, suspend_wfi_flags); + if (suspend_state == PM_SUSPEND_MEM && + pm_ops->check_off_mode_enable()) { + pm_ops->prepare_rtc_suspend(); + pm_ops->save_context(); + suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; + clk_save_context(); + ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, + suspend_wfi_flags); + + suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; + + if (!ret) { + clk_restore_context(); + pm_ops->restore_context(); + m3_ipc->ops->set_rtc_only(m3_ipc); + am33xx_push_sram_idle(); + } + } else { + ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, + suspend_wfi_flags); + } if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -127,8 +209,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) "PM: CM3 returned unknown result = %d\n", i); ret = -1; } + + /* print the wakeup reason */ + if (rtc_only_idle) { + wakeup_src = rtc_wake_src(); + pr_info("PM: Wakeup source %s\n", wakeup_src.src); + } else { + pr_info("PM: Wakeup source %s\n", + m3_ipc->ops->request_wake_src(m3_ipc)); + } } + if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) + pm_ops->prepare_rtc_resume(); + return ret; } @@ -151,6 +245,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state) static int am33xx_pm_begin(suspend_state_t state) { int ret = -EINVAL; + struct nvmem_device *nvmem; + + if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&rtc_magic_val); + rtc_only_idle = 1; + } else { + rtc_only_idle = 0; + } switch (state) { case PM_SUSPEND_MEM: @@ -166,7 +272,28 @@ static int am33xx_pm_begin(suspend_state_t state) static void am33xx_pm_end(void) { + u32 val = 0; + struct nvmem_device *nvmem; + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); m3_ipc->ops->finish_low_power(m3_ipc); + if (rtc_only_idle) { + if (retrigger_irq) + /* + * 32 bits of Interrupt Set-Pending correspond to 32 + * 32 interrupts. Compute the bit offset of the + * Interrupt and set that particular bit + * Compute the register offset by dividing interrupt + * number by 32 and mutiplying by 4 + */ + writel_relaxed(1 << (retrigger_irq & 31), + gic_dist_base + GIC_INT_SET_PENDING_BASE + + retrigger_irq / 32 * 4); + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&val); + } + + rtc_only_idle = 0; } static int am33xx_pm_valid(suspend_state_t state) @@ -269,6 +396,42 @@ static int am33xx_pm_alloc_sram(void) return ret; } +static int am33xx_pm_rtc_setup(void) +{ + struct device_node *np; + unsigned long val = 0; + struct nvmem_device *nvmem; + + np = of_find_node_by_name(NULL, "rtc"); + + if (of_device_is_available(np)) { + omap_rtc = rtc_class_open("rtc0"); + if (!omap_rtc) { + pr_warn("PM: rtc0 not available"); + return -EPROBE_DEFER; + } + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) { + nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&rtc_magic_val); + if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) + pr_warn("PM: bootloader does not support rtc-only!\n"); + + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&val); + val = pm_sram->resume_address; + nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, + 4, (void *)&val); + } + } else { + pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); + } + + return 0; +} + static int am33xx_pm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -284,34 +447,42 @@ static int am33xx_pm_probe(struct platform_device *pdev) return -ENODEV; } + ret = am43xx_map_gic(); + if (ret) { + pr_err("PM: Could not ioremap GIC base\n"); + return ret; + } + pm_sram = pm_ops->get_sram_addrs(); if (!pm_sram) { dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); return -ENODEV; } + m3_ipc = wkup_m3_ipc_get(); + if (!m3_ipc) { + pr_err("PM: Cannot get wkup_m3_ipc handle\n"); + return -EPROBE_DEFER; + } + pm33xx_dev = dev; ret = am33xx_pm_alloc_sram(); if (ret) return ret; - ret = am33xx_push_sram_idle(); + ret = am33xx_pm_rtc_setup(); if (ret) goto err_free_sram; - m3_ipc = wkup_m3_ipc_get(); - if (!m3_ipc) { - dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n"); - ret = -EPROBE_DEFER; + ret = am33xx_push_sram_idle(); + if (ret) goto err_free_sram; - } am33xx_pm_set_ipc_ops(); #ifdef CONFIG_SUSPEND suspend_set_ops(&am33xx_pm_ops); -#endif /* CONFIG_SUSPEND */ /* * For a system suspend we must flush the caches, we want @@ -323,6 +494,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; suspend_wfi_flags |= WFI_FLAG_WAKE_M3; +#endif /* CONFIG_SUSPEND */ ret = pm_ops->init(); if (ret) { -- 2.17.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Keerthy Subject: [PATCH 5/5] soc: ti: pm33xx: AM437X: Add rtc_only with ddr in self-refresh support Date: Fri, 22 Mar 2019 22:46:19 +0530 Message-ID: <20190322171619.4180-6-j-keerthy@ti.com> References: <20190322171619.4180-1-j-keerthy@ti.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20190322171619.4180-1-j-keerthy@ti.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: tony@atomide.com, alexandre.belloni@bootlin.com, a.zummo@towertech.it, t-kristo@ti.com Cc: linux-rtc@vger.kernel.org, d-gerlach@ti.com, j-keerthy@ti.com, ssantosh@kernel.org, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org List-Id: linux-omap@vger.kernel.org During RTC-only suspend, power is lost to the wkup domain, so we need to save and restore the state of that domain. We also need to store some information within the RTC registers so that u-boot can do the right thing at powerup. The state is entered by getting the RTC to bring the pmic_power_en line low which will instruct the PMIC to disable the appropriate power rails after putting DDR into self-refresh mode. To bring pmic_power_en low, we need to get an ALARM2 event. Since we are running from SRAM at that point, it means calculating what the next second is (via ASM) and programming that into the RTC. This patch also adds support for wake up source detection. Signed-off-by: Keerthy Signed-off-by: Dave Gerlach --- drivers/soc/ti/Kconfig | 5 +- drivers/soc/ti/pm33xx.c | 190 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index be4570baad96..57960e92ebe0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA config AMX3_PM tristate "AMx3 Power Management" depends on SOC_AM33XX || SOC_AM43XX - depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM + depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP help Enable power management on AM335x and AM437x. Required for suspend to mem and standby states on both AM335x and AM437x platforms and for deeper cpuidle - c-states on AM335x. + c-states on AM335x. Also required for rtc and ddr in self-refresh low + power mode on AM437x platforms. config WKUP_M3_IPC tristate "TI AMx3 Wkup-M3 IPC Driver" diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 69128993776d..15b1414d3465 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -6,6 +6,7 @@ * Vaibhav Bedia, Dave Gerlach */ +#include #include #include #include @@ -13,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -29,20 +32,47 @@ #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ (unsigned long)pm_sram->do_wfi) +#define RTC_SCRATCH_RESUME_REG 0 +#define RTC_SCRATCH_MAGIC_REG 1 +#define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ +#define GIC_INT_SET_PENDING_BASE 0x200 +#define AM43XX_GIC_DIST_BASE 0x48241000 + +static u32 rtc_magic_val; + static int (*am33xx_do_wfi_sram)(unsigned long unused); static phys_addr_t am33xx_do_wfi_sram_phys; static struct gen_pool *sram_pool, *sram_pool_data; static unsigned long ocmcram_location, ocmcram_location_data; +static struct rtc_device *omap_rtc; +static void __iomem *gic_dist_base; + static struct am33xx_pm_platform_data *pm_ops; static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +#ifdef CONFIG_SUSPEND +static int rtc_only_idle; +static int retrigger_irq; static unsigned long suspend_wfi_flags; +static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, + .src = "Unknown", +}; + +static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { + .irq_nr = 108, .src = "RTC Alarm", +}; + +static struct wkup_m3_wakeup_src rtc_ext_wakeup = { + .irq_nr = 0, .src = "Ext wakeup", +}; +#endif + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -99,13 +129,65 @@ static int am33xx_push_sram_idle(void) return 0; } +static int __init am43xx_map_gic(void) +{ + gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); + + if (!gic_dist_base) + return -ENOMEM; + + return 0; +} + #ifdef CONFIG_SUSPEND +struct wkup_m3_wakeup_src rtc_wake_src(void) +{ + u32 i; + + i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; + + if (i) { + retrigger_irq = rtc_alarm_wakeup.irq_nr; + return rtc_alarm_wakeup; + } + + retrigger_irq = rtc_ext_wakeup.irq_nr; + + return rtc_ext_wakeup; +} + +int am33xx_rtc_only_idle(unsigned long wfi_flags) +{ + rtc_power_off_program(omap_rtc); + am33xx_do_wfi_sram(wfi_flags); + return 0; +} + static int am33xx_pm_suspend(suspend_state_t suspend_state) { int i, ret = 0; - ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram, suspend_wfi_flags); + if (suspend_state == PM_SUSPEND_MEM && + pm_ops->check_off_mode_enable()) { + pm_ops->prepare_rtc_suspend(); + pm_ops->save_context(); + suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; + clk_save_context(); + ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, + suspend_wfi_flags); + + suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; + + if (!ret) { + clk_restore_context(); + pm_ops->restore_context(); + m3_ipc->ops->set_rtc_only(m3_ipc); + am33xx_push_sram_idle(); + } + } else { + ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, + suspend_wfi_flags); + } if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -127,8 +209,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) "PM: CM3 returned unknown result = %d\n", i); ret = -1; } + + /* print the wakeup reason */ + if (rtc_only_idle) { + wakeup_src = rtc_wake_src(); + pr_info("PM: Wakeup source %s\n", wakeup_src.src); + } else { + pr_info("PM: Wakeup source %s\n", + m3_ipc->ops->request_wake_src(m3_ipc)); + } } + if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) + pm_ops->prepare_rtc_resume(); + return ret; } @@ -151,6 +245,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state) static int am33xx_pm_begin(suspend_state_t state) { int ret = -EINVAL; + struct nvmem_device *nvmem; + + if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&rtc_magic_val); + rtc_only_idle = 1; + } else { + rtc_only_idle = 0; + } switch (state) { case PM_SUSPEND_MEM: @@ -166,7 +272,28 @@ static int am33xx_pm_begin(suspend_state_t state) static void am33xx_pm_end(void) { + u32 val = 0; + struct nvmem_device *nvmem; + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); m3_ipc->ops->finish_low_power(m3_ipc); + if (rtc_only_idle) { + if (retrigger_irq) + /* + * 32 bits of Interrupt Set-Pending correspond to 32 + * 32 interrupts. Compute the bit offset of the + * Interrupt and set that particular bit + * Compute the register offset by dividing interrupt + * number by 32 and mutiplying by 4 + */ + writel_relaxed(1 << (retrigger_irq & 31), + gic_dist_base + GIC_INT_SET_PENDING_BASE + + retrigger_irq / 32 * 4); + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&val); + } + + rtc_only_idle = 0; } static int am33xx_pm_valid(suspend_state_t state) @@ -269,6 +396,42 @@ static int am33xx_pm_alloc_sram(void) return ret; } +static int am33xx_pm_rtc_setup(void) +{ + struct device_node *np; + unsigned long val = 0; + struct nvmem_device *nvmem; + + np = of_find_node_by_name(NULL, "rtc"); + + if (of_device_is_available(np)) { + omap_rtc = rtc_class_open("rtc0"); + if (!omap_rtc) { + pr_warn("PM: rtc0 not available"); + return -EPROBE_DEFER; + } + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) { + nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&rtc_magic_val); + if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) + pr_warn("PM: bootloader does not support rtc-only!\n"); + + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&val); + val = pm_sram->resume_address; + nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, + 4, (void *)&val); + } + } else { + pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); + } + + return 0; +} + static int am33xx_pm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -284,34 +447,42 @@ static int am33xx_pm_probe(struct platform_device *pdev) return -ENODEV; } + ret = am43xx_map_gic(); + if (ret) { + pr_err("PM: Could not ioremap GIC base\n"); + return ret; + } + pm_sram = pm_ops->get_sram_addrs(); if (!pm_sram) { dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); return -ENODEV; } + m3_ipc = wkup_m3_ipc_get(); + if (!m3_ipc) { + pr_err("PM: Cannot get wkup_m3_ipc handle\n"); + return -EPROBE_DEFER; + } + pm33xx_dev = dev; ret = am33xx_pm_alloc_sram(); if (ret) return ret; - ret = am33xx_push_sram_idle(); + ret = am33xx_pm_rtc_setup(); if (ret) goto err_free_sram; - m3_ipc = wkup_m3_ipc_get(); - if (!m3_ipc) { - dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n"); - ret = -EPROBE_DEFER; + ret = am33xx_push_sram_idle(); + if (ret) goto err_free_sram; - } am33xx_pm_set_ipc_ops(); #ifdef CONFIG_SUSPEND suspend_set_ops(&am33xx_pm_ops); -#endif /* CONFIG_SUSPEND */ /* * For a system suspend we must flush the caches, we want @@ -323,6 +494,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; suspend_wfi_flags |= WFI_FLAG_WAKE_M3; +#endif /* CONFIG_SUSPEND */ ret = pm_ops->init(); if (ret) { -- 2.17.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.2 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,UNWANTED_LANGUAGE_BODY,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4DAD9C43381 for ; Fri, 22 Mar 2019 17:17:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1216E21900 for ; Fri, 22 Mar 2019 17:17:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="LC+P5ZJ6"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=ti.com header.i=@ti.com header.b="BgZCXa7W" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1216E21900 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=s6v/w7dgljpvq0zqdg5nd6/HHj5009wiI236YQbYwuw=; b=LC+P5ZJ6oY9bSm KlLGbJ1ga6KkZYihWO96cJdbEJP6+WBfw/5flllNT++hmwTUnlCvBah/zDG1NPKKJuoVomODaLMTk 7m+0tS76Juu8y06FXY2/MS5qguLpfqhy/paU9nyOMtSFQA8hHqgw0Pn+Vk235hEZqI/VUvsVirOJn UPSJhDffVOcn3PbtfP4hBGe8ddm+UvgopAhZDqv81vdLm12H4uzK6dhZ85ZQDBXyx5dzuAEBmtlFQ i8CjLOyJxYClbPhxyNh8JJyjmwMgSLlfWmU3q76g647q5sTz1MMiWypdw2qn1K+sHa4wlSSD3FFaI k5cMycBBwb7sbQRDZ6cQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1h7NnB-0002wx-Tx; Fri, 22 Mar 2019 17:17:17 +0000 Received: from fllv0016.ext.ti.com ([198.47.19.142]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1h7Nmc-0002DB-9y for linux-arm-kernel@lists.infradead.org; Fri, 22 Mar 2019 17:16:44 +0000 Received: from lelv0266.itg.ti.com ([10.180.67.225]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id x2MHGb4v041015; Fri, 22 Mar 2019 12:16:37 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1553274997; bh=dAxkXO7uX9xemqVnUq/O5k+/6gUH3zu+WTXA9y14s9U=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=BgZCXa7W2U8BLyPn95fovmbvIWUzZ4+zfxPrI0WVGO/RJDPhbMauvb6H0juHRmGDh 7WDVyJ2LJ70saKQR8+k/EeM/YGIVm3nxECvW+4HZk2FnEpbVXoH2TQOrxBC599/7m8 QA+W6XecfWsx8T4bYSrzqBFoT2PjYmE5s6zNz8Jo= Received: from DLEE106.ent.ti.com (dlee106.ent.ti.com [157.170.170.36]) by lelv0266.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x2MHGa95041149 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 22 Mar 2019 12:16:36 -0500 Received: from DLEE102.ent.ti.com (157.170.170.32) by DLEE106.ent.ti.com (157.170.170.36) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1713.5; Fri, 22 Mar 2019 12:16:36 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE102.ent.ti.com (157.170.170.32) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1713.5 via Frontend Transport; Fri, 22 Mar 2019 12:16:36 -0500 Received: from a0393675ula.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x2MHGHYO006487; Fri, 22 Mar 2019 12:16:33 -0500 From: Keerthy To: , , , Subject: [PATCH 5/5] soc: ti: pm33xx: AM437X: Add rtc_only with ddr in self-refresh support Date: Fri, 22 Mar 2019 22:46:19 +0530 Message-ID: <20190322171619.4180-6-j-keerthy@ti.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190322171619.4180-1-j-keerthy@ti.com> References: <20190322171619.4180-1-j-keerthy@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190322_101642_441522_F04F18A7 X-CRM114-Status: GOOD ( 25.18 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-rtc@vger.kernel.org, d-gerlach@ti.com, j-keerthy@ti.com, ssantosh@kernel.org, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org During RTC-only suspend, power is lost to the wkup domain, so we need to save and restore the state of that domain. We also need to store some information within the RTC registers so that u-boot can do the right thing at powerup. The state is entered by getting the RTC to bring the pmic_power_en line low which will instruct the PMIC to disable the appropriate power rails after putting DDR into self-refresh mode. To bring pmic_power_en low, we need to get an ALARM2 event. Since we are running from SRAM at that point, it means calculating what the next second is (via ASM) and programming that into the RTC. This patch also adds support for wake up source detection. Signed-off-by: Keerthy Signed-off-by: Dave Gerlach --- drivers/soc/ti/Kconfig | 5 +- drivers/soc/ti/pm33xx.c | 190 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index be4570baad96..57960e92ebe0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA config AMX3_PM tristate "AMx3 Power Management" depends on SOC_AM33XX || SOC_AM43XX - depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM + depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP help Enable power management on AM335x and AM437x. Required for suspend to mem and standby states on both AM335x and AM437x platforms and for deeper cpuidle - c-states on AM335x. + c-states on AM335x. Also required for rtc and ddr in self-refresh low + power mode on AM437x platforms. config WKUP_M3_IPC tristate "TI AMx3 Wkup-M3 IPC Driver" diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 69128993776d..15b1414d3465 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -6,6 +6,7 @@ * Vaibhav Bedia, Dave Gerlach */ +#include #include #include #include @@ -13,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -29,20 +32,47 @@ #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ (unsigned long)pm_sram->do_wfi) +#define RTC_SCRATCH_RESUME_REG 0 +#define RTC_SCRATCH_MAGIC_REG 1 +#define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ +#define GIC_INT_SET_PENDING_BASE 0x200 +#define AM43XX_GIC_DIST_BASE 0x48241000 + +static u32 rtc_magic_val; + static int (*am33xx_do_wfi_sram)(unsigned long unused); static phys_addr_t am33xx_do_wfi_sram_phys; static struct gen_pool *sram_pool, *sram_pool_data; static unsigned long ocmcram_location, ocmcram_location_data; +static struct rtc_device *omap_rtc; +static void __iomem *gic_dist_base; + static struct am33xx_pm_platform_data *pm_ops; static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +#ifdef CONFIG_SUSPEND +static int rtc_only_idle; +static int retrigger_irq; static unsigned long suspend_wfi_flags; +static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, + .src = "Unknown", +}; + +static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { + .irq_nr = 108, .src = "RTC Alarm", +}; + +static struct wkup_m3_wakeup_src rtc_ext_wakeup = { + .irq_nr = 0, .src = "Ext wakeup", +}; +#endif + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -99,13 +129,65 @@ static int am33xx_push_sram_idle(void) return 0; } +static int __init am43xx_map_gic(void) +{ + gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); + + if (!gic_dist_base) + return -ENOMEM; + + return 0; +} + #ifdef CONFIG_SUSPEND +struct wkup_m3_wakeup_src rtc_wake_src(void) +{ + u32 i; + + i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; + + if (i) { + retrigger_irq = rtc_alarm_wakeup.irq_nr; + return rtc_alarm_wakeup; + } + + retrigger_irq = rtc_ext_wakeup.irq_nr; + + return rtc_ext_wakeup; +} + +int am33xx_rtc_only_idle(unsigned long wfi_flags) +{ + rtc_power_off_program(omap_rtc); + am33xx_do_wfi_sram(wfi_flags); + return 0; +} + static int am33xx_pm_suspend(suspend_state_t suspend_state) { int i, ret = 0; - ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram, suspend_wfi_flags); + if (suspend_state == PM_SUSPEND_MEM && + pm_ops->check_off_mode_enable()) { + pm_ops->prepare_rtc_suspend(); + pm_ops->save_context(); + suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; + clk_save_context(); + ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, + suspend_wfi_flags); + + suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; + + if (!ret) { + clk_restore_context(); + pm_ops->restore_context(); + m3_ipc->ops->set_rtc_only(m3_ipc); + am33xx_push_sram_idle(); + } + } else { + ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, + suspend_wfi_flags); + } if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -127,8 +209,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) "PM: CM3 returned unknown result = %d\n", i); ret = -1; } + + /* print the wakeup reason */ + if (rtc_only_idle) { + wakeup_src = rtc_wake_src(); + pr_info("PM: Wakeup source %s\n", wakeup_src.src); + } else { + pr_info("PM: Wakeup source %s\n", + m3_ipc->ops->request_wake_src(m3_ipc)); + } } + if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) + pm_ops->prepare_rtc_resume(); + return ret; } @@ -151,6 +245,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state) static int am33xx_pm_begin(suspend_state_t state) { int ret = -EINVAL; + struct nvmem_device *nvmem; + + if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&rtc_magic_val); + rtc_only_idle = 1; + } else { + rtc_only_idle = 0; + } switch (state) { case PM_SUSPEND_MEM: @@ -166,7 +272,28 @@ static int am33xx_pm_begin(suspend_state_t state) static void am33xx_pm_end(void) { + u32 val = 0; + struct nvmem_device *nvmem; + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); m3_ipc->ops->finish_low_power(m3_ipc); + if (rtc_only_idle) { + if (retrigger_irq) + /* + * 32 bits of Interrupt Set-Pending correspond to 32 + * 32 interrupts. Compute the bit offset of the + * Interrupt and set that particular bit + * Compute the register offset by dividing interrupt + * number by 32 and mutiplying by 4 + */ + writel_relaxed(1 << (retrigger_irq & 31), + gic_dist_base + GIC_INT_SET_PENDING_BASE + + retrigger_irq / 32 * 4); + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&val); + } + + rtc_only_idle = 0; } static int am33xx_pm_valid(suspend_state_t state) @@ -269,6 +396,42 @@ static int am33xx_pm_alloc_sram(void) return ret; } +static int am33xx_pm_rtc_setup(void) +{ + struct device_node *np; + unsigned long val = 0; + struct nvmem_device *nvmem; + + np = of_find_node_by_name(NULL, "rtc"); + + if (of_device_is_available(np)) { + omap_rtc = rtc_class_open("rtc0"); + if (!omap_rtc) { + pr_warn("PM: rtc0 not available"); + return -EPROBE_DEFER; + } + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) { + nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&rtc_magic_val); + if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) + pr_warn("PM: bootloader does not support rtc-only!\n"); + + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&val); + val = pm_sram->resume_address; + nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, + 4, (void *)&val); + } + } else { + pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); + } + + return 0; +} + static int am33xx_pm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -284,34 +447,42 @@ static int am33xx_pm_probe(struct platform_device *pdev) return -ENODEV; } + ret = am43xx_map_gic(); + if (ret) { + pr_err("PM: Could not ioremap GIC base\n"); + return ret; + } + pm_sram = pm_ops->get_sram_addrs(); if (!pm_sram) { dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); return -ENODEV; } + m3_ipc = wkup_m3_ipc_get(); + if (!m3_ipc) { + pr_err("PM: Cannot get wkup_m3_ipc handle\n"); + return -EPROBE_DEFER; + } + pm33xx_dev = dev; ret = am33xx_pm_alloc_sram(); if (ret) return ret; - ret = am33xx_push_sram_idle(); + ret = am33xx_pm_rtc_setup(); if (ret) goto err_free_sram; - m3_ipc = wkup_m3_ipc_get(); - if (!m3_ipc) { - dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n"); - ret = -EPROBE_DEFER; + ret = am33xx_push_sram_idle(); + if (ret) goto err_free_sram; - } am33xx_pm_set_ipc_ops(); #ifdef CONFIG_SUSPEND suspend_set_ops(&am33xx_pm_ops); -#endif /* CONFIG_SUSPEND */ /* * For a system suspend we must flush the caches, we want @@ -323,6 +494,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; suspend_wfi_flags |= WFI_FLAG_WAKE_M3; +#endif /* CONFIG_SUSPEND */ ret = pm_ops->init(); if (ret) { -- 2.17.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel