From patchwork Thu May 14 06:10:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chen-Yu Tsai X-Patchwork-Id: 6402811 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 510139F374 for ; Thu, 14 May 2015 06:15:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 60D8B203DA for ; Thu, 14 May 2015 06:15:17 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 54003203F7 for ; Thu, 14 May 2015 06:15:16 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YsmNq-0002MC-59; Thu, 14 May 2015 06:12:38 +0000 Received: from smtp.csie.ntu.edu.tw ([140.112.30.61]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YsmMP-0001gy-DF for linux-arm-kernel@lists.infradead.org; Thu, 14 May 2015 06:11:11 +0000 Received: from mirror2.csie.ntu.edu.tw (mirror2.csie.ntu.edu.tw [140.112.30.76]) (Authenticated sender: b93043) by smtp.csie.ntu.edu.tw (Postfix) with ESMTPSA id BE508203C3; Thu, 14 May 2015 14:10:21 +0800 (CST) Received: by mirror2.csie.ntu.edu.tw (Postfix, from userid 1000) id A104F5F8DF; Thu, 14 May 2015 14:10:21 +0800 (CST) From: Chen-Yu Tsai To: Maxime Ripard Subject: [RFC 5/7] ARM: sunxi: mcpm: Support CPU/cluster power down and hotplugging for cpu1~7 Date: Thu, 14 May 2015 14:10:09 +0800 Message-Id: <1431583811-25780-6-git-send-email-wens@csie.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1431583811-25780-1-git-send-email-wens@csie.org> References: <1431583811-25780-1-git-send-email-wens@csie.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150513_231109_957800_BC3CD595 X-CRM114-Status: GOOD ( 13.26 ) X-Spam-Score: -2.3 (--) Cc: Nicolas Pitre , linux-sunxi@googlegroups.com, linux-kernel@vger.kernel.org, Chen-Yu Tsai , Dave Martin , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The primary core (cpu0) requires setting flags to have the BROM bounce execution to the SMP software entry code. Signed-off-by: Chen-Yu Tsai --- arch/arm/mach-sunxi/mcpm.c | 103 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-sunxi/mcpm.c b/arch/arm/mach-sunxi/mcpm.c index cf9cbf268d29..5ea4b488890c 100644 --- a/arch/arm/mach-sunxi/mcpm.c +++ b/arch/arm/mach-sunxi/mcpm.c @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include @@ -33,6 +35,9 @@ #define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15 BIT(0) #define CPUCFG_CX_CTRL_REG1(c) (0x10 * (c) + 0x4) #define CPUCFG_CX_CTRL_REG1_ACINACTM BIT(0) +#define CPUCFG_CX_STATUS(c) (0x30 * (c) + 0x4) +#define CPUCFG_CX_STATUS_STANDBYWFI(n) BIT(16 + (n)) +#define CPUCFG_CX_STATUS_STANDBYWFIL2 BIT(0) #define CPUCFG_CX_RST_CTRL(c) (0x80 + 0x4 * (c)) #define CPUCFG_CX_RST_CTRL_DBG_SOC_RST BIT(24) #define CPUCFG_CX_RST_CTRL_ETM_RST(n) BIT(20 + (n)) @@ -221,6 +226,15 @@ static int sunxi_cluster_powerup(unsigned int cluster) return 0; } +static void sunxi_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) +{ + gic_cpu_if_down(); +} + +static void sunxi_cluster_powerdown_prepare(unsigned int cluster) +{ +} + static void sunxi_cpu_cache_disable(void) { /* Disable and flush the local CPU cache. */ @@ -253,11 +267,92 @@ static void sunxi_cluster_cache_disable(void) cci_disable_port_by_cpu(read_cpuid_mpidr()); } +static int sunxi_cpu_powerdown(unsigned int cpu, unsigned int cluster) +{ + u32 reg; + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS) + return -EINVAL; + + /* gate processor power */ + reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); + reg |= PRCM_PWROFF_GATING_REG_CORE(cpu); + writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); + udelay(20); + + /* close power switch */ + sunxi_cpu_power_switch_set(cpu, cluster, false); + + return 0; +} + +static int sunxi_cluster_powerdown(unsigned int cluster) +{ + u32 reg; + + pr_debug("%s: cluster %u\n", __func__, cluster); + if (cluster >= SUNXI_NR_CLUSTERS) + return -EINVAL; + + /* clear cluster power gate */ + reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); + reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER; + writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); + udelay(20); + + return 0; +} + +static int sunxi_wait_for_powerdown(unsigned int cpu, unsigned int cluster) +{ + int ret; + u32 reg; + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + + /* wait for CPU core to enter WFI */ + ret = readl_poll_timeout(cpucfg_base + CPUCFG_CX_STATUS(cluster), reg, + reg & CPUCFG_CX_STATUS_STANDBYWFI(cpu), + 1000, 100000); + + if (ret) + return ret; + + /* power down CPU core */ + sunxi_cpu_powerdown(cpu, cluster); + + if (__mcpm_cluster_state(cluster) != CLUSTER_DOWN) + return 0; + + /* last man standing, assert ACINACTM */ + reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster)); + reg |= CPUCFG_CX_CTRL_REG1_ACINACTM; + writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster)); + + /* wait for cluster L2 WFI */ + ret = readl_poll_timeout(cpucfg_base + CPUCFG_CX_STATUS(cluster), reg, + reg & CPUCFG_CX_STATUS_STANDBYWFIL2, + 1000, 100000); + if (ret) { + pr_warn("%s: cluster %u time out waiting for STANDBYWFIL2\n", + __func__, cluster); + return ret; + } + + sunxi_cluster_powerdown(cluster); + + return 0; +} + static const struct mcpm_platform_ops sunxi_power_ops = { - .cpu_powerup = sunxi_cpu_powerup, - .cluster_powerup = sunxi_cluster_powerup, - .cpu_cache_disable = sunxi_cpu_cache_disable, - .cluster_cache_disable = sunxi_cluster_cache_disable, + .cpu_powerup = sunxi_cpu_powerup, + .cpu_powerdown_prepare = sunxi_cpu_powerdown_prepare, + .cluster_powerup = sunxi_cluster_powerup, + .cluster_powerdown_prepare = sunxi_cluster_powerdown_prepare, + .cpu_cache_disable = sunxi_cpu_cache_disable, + .cluster_cache_disable = sunxi_cluster_cache_disable, + .wait_for_powerdown = sunxi_wait_for_powerdown, }; /*