From patchwork Fri Feb 16 21:40:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Gerlach X-Patchwork-Id: 10225781 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 68201603EE for ; Fri, 16 Feb 2018 21:42:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5459B29330 for ; Fri, 16 Feb 2018 21:42:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 471A3296C0; Fri, 16 Feb 2018 21:42:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 48DF229330 for ; Fri, 16 Feb 2018 21:42:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751054AbeBPVl5 (ORCPT ); Fri, 16 Feb 2018 16:41:57 -0500 Received: from lelnx194.ext.ti.com ([198.47.27.80]:40451 "EHLO lelnx194.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750914AbeBPVl3 (ORCPT ); Fri, 16 Feb 2018 16:41:29 -0500 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by lelnx194.ext.ti.com (8.15.1/8.15.1) with ESMTP id w1GLf6UN013590; Fri, 16 Feb 2018 15:41:06 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com; s=ti-com-17Q1; t=1518817266; bh=D1tTwOAcMRlT90geS50rQ95j9GSqdeHcwvzR6lPS2EM=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=G86zd1NHtvVOiapIFdylskIi0SmbgzuL8OCB4Y77z3kIoCOW1XBWgSC+kCHI4TfMY EnbR9vvg56obZAADZ8eBdPFhLZcJgKOUH44memmNAe8qaSWICxFe0pOvz6omlwxA8n TU2+rNDRaMKHEdcTtM8OG/RVpPE/C0onqPElQJI8= Received: from DFLE107.ent.ti.com (dfle107.ent.ti.com [10.64.6.28]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id w1GLf6vq023449; Fri, 16 Feb 2018 15:41:06 -0600 Received: from DFLE104.ent.ti.com (10.64.6.25) by DFLE107.ent.ti.com (10.64.6.28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1261.35; Fri, 16 Feb 2018 15:41:06 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE104.ent.ti.com (10.64.6.25) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1261.35 via Frontend Transport; Fri, 16 Feb 2018 15:41:05 -0600 Received: from legion.dal.design.ti.com (legion.dal.design.ti.com [128.247.22.53]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id w1GLf5PL009595; Fri, 16 Feb 2018 15:41:05 -0600 Received: from localhost (uda0274052.dhcp.ti.com [128.247.59.203]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id w1GLf5x12292; Fri, 16 Feb 2018 15:41:05 -0600 (CST) From: Dave Gerlach To: Tony Lindgren , Santosh Shilimkar CC: , , , Dave Gerlach , Keerthy J , Johan Hovold Subject: [PATCH 3/4] ARM: OMAP2+: pm33xx-core: Add platform code needed for PM Date: Fri, 16 Feb 2018 15:40:01 -0600 Message-ID: <20180216214002.6209-4-d-gerlach@ti.com> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180216214002.6209-1-d-gerlach@ti.com> References: <20180216214002.6209-1-d-gerlach@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Most of the PM code needed for am335x and am437x can be moved into a module under drivers but some core code must remain in mach-omap2 at the moment. This includes some internal clockdomain APIs and low-level ARM APIs which are also not exported for use by modules. Implement a few functions that handle these low-level platform operations can be passed to the pm33xx module through the use of platform data. In addition to this, to be able to share data structures between C and the sleep33xx and sleep43xx assembly code, we can automatically generate all of the C struct member offsets and sizes as macros by processing pm-asm-offsets.c into assembly code and then extracting the relevant data as is done for the generated platform asm-offsets.h files. Finally, add amx3_common_pm_init to create a dummy platform_device for pm33xx so that our soon to be introduced pm33xx module can probe on am335x and am437x platforms to enable basic suspend to mem and standby support. Signed-off-by: Dave Gerlach --- arch/arm/mach-omap2/Kconfig | 1 + arch/arm/mach-omap2/Makefile | 16 +++ arch/arm/mach-omap2/common.h | 7 ++ arch/arm/mach-omap2/io.c | 2 + arch/arm/mach-omap2/pm-asm-offsets.c | 38 +++++++ arch/arm/mach-omap2/pm.h | 3 + arch/arm/mach-omap2/pm33xx-core.c | 197 +++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/sleep33xx.S | 2 + arch/arm/mach-omap2/sleep43xx.S | 2 + include/linux/platform_data/pm33xx.h | 50 +++++++++ 10 files changed, 318 insertions(+) create mode 100644 arch/arm/mach-omap2/pm-asm-offsets.c create mode 100644 arch/arm/mach-omap2/pm33xx-core.c create mode 100644 include/linux/platform_data/pm33xx.h diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 00b1f17f8d44..9f27b486a536 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -72,6 +72,7 @@ config SOC_AM43XX select ARM_ERRATA_754322 select ARM_ERRATA_775420 select OMAP_INTERCONNECT + select ARM_CPU_SUSPEND if PM config SOC_DRA7XX bool "TI DRA7XX" diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index c15bbcad5f67..4603c30fef73 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -88,6 +88,8 @@ omap-4-5-pm-common += pm44xx.o obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-pm-common) obj-$(CONFIG_SOC_OMAP5) += $(omap-4-5-pm-common) obj-$(CONFIG_SOC_DRA7XX) += $(omap-4-5-pm-common) +obj-$(CONFIG_SOC_AM33XX) += pm33xx-core.o sleep33xx.o +obj-$(CONFIG_SOC_AM43XX) += pm33xx-core.o sleep43xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o @@ -95,6 +97,8 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o AFLAGS_sleep24xx.o :=-Wa,-march=armv6 AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep33xx.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep43xx.o :=-Wa,-march=armv7-a$(plus_sec) endif @@ -232,3 +236,15 @@ obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y) obj-y += omap_phy_internal.o obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o + +arch/arm/mach-omap2/pm-asm-offsets.s: arch/arm/mach-omap2/pm-asm-offsets.c + $(call if_changed_dep,cc_s_c) + +include/generated/ti-pm-asm-offsets.h: arch/arm/mach-omap2/pm-asm-offsets.s FORCE + $(call filechk,offsets,__TI_PM_ASM_OFFSETS_H__) + +# For rule to generate ti-emif-asm-offsets.h dependency +include drivers/memory/Makefile.asm-offsets + +arch/arm/mach-omap2/sleep33xx.o: include/generated/ti-pm-asm-offsets.h include/generated/ti-emif-asm-offsets.h +arch/arm/mach-omap2/sleep43xx.o: include/generated/ti-pm-asm-offsets.h include/generated/ti-emif-asm-offsets.h diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index bc202835371b..fbe0b78bf489 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -77,6 +77,13 @@ static inline int omap4_pm_init_early(void) } #endif +#if defined(CONFIG_PM) && (defined(CONFIG_SOC_AM33XX) || \ + defined(CONFIG_SOC_AM43XX)) +void amx3_common_pm_init(void); +#else +static inline void amx3_common_pm_init(void) { } +#endif + extern void omap2_init_common_infrastructure(void); extern void omap_init_time(void); diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index cb5d7314cf99..cf546dfe3b32 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -622,6 +622,7 @@ void __init am33xx_init_early(void) void __init am33xx_init_late(void) { omap_common_late_init(); + amx3_common_pm_init(); } #endif @@ -646,6 +647,7 @@ void __init am43xx_init_late(void) { omap_common_late_init(); omap2_clk_enable_autoidle_all(); + amx3_common_pm_init(); } #endif diff --git a/arch/arm/mach-omap2/pm-asm-offsets.c b/arch/arm/mach-omap2/pm-asm-offsets.c new file mode 100644 index 000000000000..8c4be13e1f52 --- /dev/null +++ b/arch/arm/mach-omap2/pm-asm-offsets.c @@ -0,0 +1,38 @@ +/* + * TI AM33XX and AM43XX PM Assembly Offsets + * + * Copyright (C) 2017-2018 Texas Instruments Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include + +int main(void) +{ + DEFINE(AMX3_PM_WFI_FLAGS_OFFSET, + offsetof(struct am33xx_pm_sram_data, wfi_flags)); + DEFINE(AMX3_PM_L2_AUX_CTRL_VAL_OFFSET, + offsetof(struct am33xx_pm_sram_data, l2_aux_ctrl_val)); + DEFINE(AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET, + offsetof(struct am33xx_pm_sram_data, l2_prefetch_ctrl_val)); + DEFINE(AMX3_PM_SRAM_DATA_SIZE, sizeof(struct am33xx_pm_sram_data)); + + BLANK(); + + DEFINE(AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET, + offsetof(struct am33xx_pm_ro_sram_data, amx3_pm_sram_data_virt)); + DEFINE(AMX3_PM_RO_SRAM_DATA_PHYS_OFFSET, + offsetof(struct am33xx_pm_ro_sram_data, amx3_pm_sram_data_phys)); + DEFINE(AMX3_PM_RO_SRAM_DATA_SIZE, + sizeof(struct am33xx_pm_ro_sram_data)); + + return 0; +} diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 8e30772cfe32..c73776b82348 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -81,6 +81,9 @@ extern unsigned int omap3_do_wfi_sz; /* ... and its pointer from SRAM after copy */ extern void (*omap3_do_wfi_sram)(void); +extern struct am33xx_pm_sram_addr am33xx_pm_sram; +extern struct am33xx_pm_sram_addr am43xx_pm_sram; + extern void omap3_save_scratchpad_contents(void); #define PM_RTA_ERRATUM_i608 (1 << 0) diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c new file mode 100644 index 000000000000..b06907908975 --- /dev/null +++ b/arch/arm/mach-omap2/pm33xx-core.c @@ -0,0 +1,197 @@ +/* + * AM33XX Arch Power Management Routines + * + * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ + * Dave Gerlach + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "cm33xx.h" +#include "common.h" +#include "control.h" +#include "clockdomain.h" +#include "iomap.h" +#include "omap_hwmod.h" +#include "pm.h" +#include "powerdomain.h" +#include "prm33xx.h" +#include "soc.h" +#include "sram.h" + +static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm; +static struct clockdomain *gfx_l4ls_clkdm; +static void __iomem *scu_base; + +static int __init am43xx_map_scu(void) +{ + scu_base = ioremap(scu_a9_get_base(), SZ_256); + + if (!scu_base) + return -ENOMEM; + + return 0; +} + +static int amx3_common_init(void) +{ + gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); + per_pwrdm = pwrdm_lookup("per_pwrdm"); + mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); + + if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm)) + return -ENODEV; + + (void)clkdm_for_each(omap_pm_clkdms_setup, NULL); + + /* CEFUSE domain can be turned off post bootup */ + cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm"); + if (cefuse_pwrdm) + omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF); + else + pr_err("PM: Failed to get cefuse_pwrdm\n"); + + return 0; +} + +static int am33xx_suspend_init(void) +{ + int ret; + + gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm"); + + if (!gfx_l4ls_clkdm) { + pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n"); + return -ENODEV; + } + + ret = amx3_common_init(); + + return ret; +} + +static int am43xx_suspend_init(void) +{ + int ret = 0; + + ret = am43xx_map_scu(); + if (ret) { + pr_err("PM: Could not ioremap SCU\n"); + return ret; + } + + ret = amx3_common_init(); + + return ret; +} + +static void amx3_pre_suspend_common(void) +{ + omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF); +} + +static void amx3_post_suspend_common(void) +{ + int status; + /* + * Because gfx_pwrdm is the only one under MPU control, + * comment on transition status + */ + status = pwrdm_read_pwrst(gfx_pwrdm); + if (status != PWRDM_POWER_OFF) + pr_err("PM: GFX domain did not transition: %x\n", status); +} + +static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long)) +{ + int ret = 0; + + amx3_pre_suspend_common(); + ret = cpu_suspend(0, fn); + amx3_post_suspend_common(); + + /* + * BUG: GFX_L4LS clock domain needs to be woken up to + * ensure thet L4LS clock domain does not get stuck in + * transition. If that happens L3 module does not get + * disabled, thereby leading to PER power domain + * transition failing + */ + + clkdm_wakeup(gfx_l4ls_clkdm); + clkdm_sleep(gfx_l4ls_clkdm); + + return ret; +} + +static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long)) +{ + int ret = 0; + + amx3_pre_suspend_common(); + scu_power_mode(scu_base, SCU_PM_POWEROFF); + ret = cpu_suspend(0, fn); + scu_power_mode(scu_base, SCU_PM_NORMAL); + amx3_post_suspend_common(); + + return ret; +} + +static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void) +{ + if (soc_is_am33xx()) + return &am33xx_pm_sram; + else if (soc_is_am437x()) + return &am43xx_pm_sram; + else + return NULL; +} + +static struct am33xx_pm_platform_data am33xx_ops = { + .init = am33xx_suspend_init, + .soc_suspend = am33xx_suspend, + .get_sram_addrs = amx3_get_sram_addrs, +}; + +static struct am33xx_pm_platform_data am43xx_ops = { + .init = am43xx_suspend_init, + .soc_suspend = am43xx_suspend, + .get_sram_addrs = amx3_get_sram_addrs, +}; + +static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) +{ + if (soc_is_am33xx()) + return &am33xx_ops; + else if (soc_is_am437x()) + return &am43xx_ops; + else + return NULL; +} + +void __init amx3_common_pm_init(void) +{ + struct am33xx_pm_platform_data *pdata; + struct platform_device_info devinfo; + + pdata = am33xx_pm_get_pdata(); + + memset(&devinfo, 0, sizeof(devinfo)); + devinfo.name = "pm33xx"; + devinfo.data = pdata; + devinfo.size_data = sizeof(*pdata); + devinfo.id = -1; + platform_device_register_full(&devinfo); +} diff --git a/arch/arm/mach-omap2/sleep33xx.S b/arch/arm/mach-omap2/sleep33xx.S index 481833c6be94..dbbe6665f7a5 100644 --- a/arch/arm/mach-omap2/sleep33xx.S +++ b/arch/arm/mach-omap2/sleep33xx.S @@ -14,6 +14,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include #include diff --git a/arch/arm/mach-omap2/sleep43xx.S b/arch/arm/mach-omap2/sleep43xx.S index 3a8bfd62a33c..9452eeadf221 100644 --- a/arch/arm/mach-omap2/sleep43xx.S +++ b/arch/arm/mach-omap2/sleep43xx.S @@ -14,6 +14,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include diff --git a/include/linux/platform_data/pm33xx.h b/include/linux/platform_data/pm33xx.h new file mode 100644 index 000000000000..12378abc94ee --- /dev/null +++ b/include/linux/platform_data/pm33xx.h @@ -0,0 +1,50 @@ +/* + * TI pm33xx platform data + * + * Copyright (C) 2016-2018 Texas Instruments, Inc. + * Dave Gerlach + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_PLATFORM_DATA_PM33XX_H +#define _LINUX_PLATFORM_DATA_PM33XX_H + +#include +#include + +#ifndef __ASSEMBLER__ +struct am33xx_pm_sram_addr { + void (*do_wfi)(void); + unsigned long *do_wfi_sz; + unsigned long *resume_offset; + unsigned long *emif_sram_table; + unsigned long *ro_sram_data; +}; + +struct am33xx_pm_platform_data { + int (*init)(void); + int (*soc_suspend)(unsigned int state, int (*fn)(unsigned long)); + struct am33xx_pm_sram_addr *(*get_sram_addrs)(void); +}; + +struct am33xx_pm_sram_data { + u32 wfi_flags; + u32 l2_aux_ctrl_val; + u32 l2_prefetch_ctrl_val; +} __packed __aligned(8); + +struct am33xx_pm_ro_sram_data { + u32 amx3_pm_sram_data_virt; + u32 amx3_pm_sram_data_phys; +} __packed __aligned(8); + +#endif /* __ASSEMBLER__ */ +#endif /* _LINUX_PLATFORM_DATA_PM33XX_H */