From patchwork Fri Aug 8 04:05:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 4693581 Return-Path: X-Original-To: patchwork-linux-arm-msm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id F3D99C0338 for ; Fri, 8 Aug 2014 04:05:49 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C59FE2017D for ; Fri, 8 Aug 2014 04:05:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A364820145 for ; Fri, 8 Aug 2014 04:05:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752831AbaHHEFq (ORCPT ); Fri, 8 Aug 2014 00:05:46 -0400 Received: from mail-pa0-f50.google.com ([209.85.220.50]:57435 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752761AbaHHEFp (ORCPT ); Fri, 8 Aug 2014 00:05:45 -0400 Received: by mail-pa0-f50.google.com with SMTP id et14so6482540pad.23 for ; Thu, 07 Aug 2014 21:05:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=l1o24ASnLAvSJSCnL/DAzREfyl/2beXMW1Efbt2H3UE=; b=JuR52ExX9NkwjytySFTGZw5ccpyaXK7SOmSNnFxiJ7H3D+7pbx7rbc5bsSjlgRxZ7D CDfxnlJRAhRE4pfRhXNXdC0Alm4vs4QPFKZ+YM6lRHch71XceR+eUFsTmE+fl89OgMDH bwwA0xITQHyhRudL9KE5ihUnPB0EGRz6JA08WxioBnShw47mgS9rGar45Rydz1glII+G oyF+y7YU79iJ+2x7OYmfrKl2rZ0uOvGVMvJ+ArjyO1uv7lIi3f9wxutxf10+Xc2/TSwz jG1+wpVc4Hz3AN4FZ7xOMnd1InccQ0WAGFV8Lnxo4SqY6IdCf2hUPHsB8pC3CZBBXPLG ITEw== X-Gm-Message-State: ALoCoQmCMFbRg8U53AGGJcLVBuLmGU1jjegRgO1ePyo1B1aXpYK0a6v/KKBCXl3ot4BnQJrKMdpM X-Received: by 10.70.108.194 with SMTP id hm2mr21923727pdb.115.1407470745154; Thu, 07 Aug 2014 21:05:45 -0700 (PDT) Received: from localhost.localdomain (c-24-8-37-141.hsd1.co.comcast.net. [24.8.37.141]) by mx.google.com with ESMTPSA id n8sm2163342pdm.22.2014.08.07.21.05.43 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Aug 2014 21:05:44 -0700 (PDT) From: Lina Iyer To: daniel.lezcano@linaro.org, khilman@linaro.org, amit.kucheria@linaro.org, sboyd@codeaurora.org, davidb@codeaurora.org, galak@codeaurora.org, linux-arm-msm@vger.kernel.org Cc: msivasub@codeaurora.org, bryanh@codeaurora.org, Lina Iyer Subject: [RFC] [PATCH 07/13] qcom: sleep-status: Add ability to recognize cpu power down state Date: Thu, 7 Aug 2014 22:05:16 -0600 Message-Id: <1407470722-23015-8-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1407470722-23015-1-git-send-email-lina.iyer@linaro.org> References: <1407470722-23015-1-git-send-email-lina.iyer@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 QCOM processors get notified by the processor subsystem logic that recognizes when a processor has entered the low power state. This is used by PM to guarantee that the processor is indeed in its low power state, before powering down the associated resources. Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Lina Iyer --- .../bindings/arm/msm/qcom,cpu-sleep-status.txt | 41 +++++ drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/sleep-status.c | 178 +++++++++++++++++++++ include/soc/qcom/pm.h | 2 + 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt create mode 100644 drivers/soc/qcom/sleep-status.c diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt b/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt new file mode 100644 index 0000000..3d2974e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qcom,cpu-sleep-status.txt @@ -0,0 +1,41 @@ +* MSM Sleep Status + +MSM Sleep status device is used to check the power collapsed status of a +offlined core. The core that initiates the hotplug would wait on the +sleep status device before CPU_DEAD notifications are sent out. Some hardware +devices require that the offlined core is power collapsed before turning off +the resources that are used by the offlined core. + + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,cpu-sleep-status" + +- reg: + Usage: required + Value type: + Definition: The physical address of the sleep status register for + core0, the second element is the size of the register. + +- qcom,cpu-alias-addr: + Usage: required + Value type: + Definition: On MSM chipset, the each cores registers are at a + fixed offset each other. + +- qcom,cpu-sleep-status-mask: + Usage: required + Value type: + Definition: The bit mask within the status register that + indicates the Core's sleep state. + +Example: + qcom,cpu-sleep-status@f9088008 { + compatible = "qcom,cpu-sleep-status"; + reg = <0xf9088008 0x4>; + qcom,cpu-alias-addr = <0x10000>; + qcom,sleep-status-mask = <0x80000>; + }; diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 87c3b9704..d2cc9c0 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o -obj-$(CONFIG_QCOM_PM) += spm_devices.o spm.o msm-pm.o +obj-$(CONFIG_QCOM_PM) += spm_devices.o spm.o msm-pm.o sleep-status.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o diff --git a/drivers/soc/qcom/sleep-status.c b/drivers/soc/qcom/sleep-status.c new file mode 100644 index 0000000..aa6340c --- /dev/null +++ b/drivers/soc/qcom/sleep-status.c @@ -0,0 +1,178 @@ +/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct msm_pm_sleep_status_data { + void *base_addr; + uint32_t cpu_offset; + uint32_t mask; +}; + +static struct msm_pm_sleep_status_data *msm_pm_slp_sts; + +/** + * msm_pm_wait_cpu_shutdown() - Wait for a core to be power collapsed during + * hotplug + * + * @ cpu - cpu to wait on. + * + * Blocking function call that waits on the core to be power collapsed. This + * function is called from platform_cpu_die to ensure that a core is power + * collapsed before sending the CPU_DEAD notification so the drivers could + * remove the resource votes for this CPU(regulator and clock) + */ +int msm_pm_wait_cpu_shutdown(unsigned int cpu) +{ + int timeout = 0; + + if (!msm_pm_slp_sts) + return 0; + + if (!msm_pm_slp_sts[cpu].base_addr) + return 0; + + while (1) { + /* + * Check for the SPM of the core being hotplugged to set + * its sleep state.The SPM sleep state indicates that the + * core has been power collapsed. + */ + int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr); + + if (acc_sts & msm_pm_slp_sts[cpu].mask) + return 0; + + udelay(100); + /* + * Dump spm registers for debugging + */ + if (++timeout == 20) { + msm_spm_dump_regs(cpu); + __WARN_printf( + "CPU%u didn't collapse in 2ms, sleep status: 0x%x\n", + cpu, acc_sts); + } + } + + return -EBUSY; +} + +static int msm_cpu_status_probe(struct platform_device *pdev) +{ + struct msm_pm_sleep_status_data *pdata; + char *key; + u32 cpu; + + if (!pdev) + return -EFAULT; + + msm_pm_slp_sts = devm_kcalloc(&pdev->dev, num_possible_cpus(), + sizeof(*msm_pm_slp_sts), GFP_KERNEL); + + if (!msm_pm_slp_sts) + return -ENOMEM; + + if (pdev->dev.of_node) { + struct resource *res; + u32 offset; + int rc; + u32 mask; + bool offset_available = true; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + key = "qcom,cpu-alias-addr"; + rc = of_property_read_u32(pdev->dev.of_node, key, &offset); + + if (rc) + offset_available = false; + + key = "qcom,sleep-status-mask"; + rc = of_property_read_u32(pdev->dev.of_node, key, &mask); + + if (rc) + return -ENODEV; + + for_each_possible_cpu(cpu) { + phys_addr_t base_c; + + if (offset_available) + base_c = res->start + cpu * offset; + else { + res = platform_get_resource(pdev, + IORESOURCE_MEM, cpu); + if (!res) + return -ENODEV; + base_c = res->start; + } + + msm_pm_slp_sts[cpu].base_addr = + devm_ioremap(&pdev->dev, base_c, + resource_size(res)); + msm_pm_slp_sts[cpu].mask = mask; + + if (!msm_pm_slp_sts[cpu].base_addr) + return -ENOMEM; + } + } else { + pdata = pdev->dev.platform_data; + if (!pdev->dev.platform_data) + return -EINVAL; + + for_each_possible_cpu(cpu) { + msm_pm_slp_sts[cpu].base_addr = + pdata->base_addr + cpu * pdata->cpu_offset; + msm_pm_slp_sts[cpu].mask = pdata->mask; + } + } + + return 0; +}; + +static struct of_device_id msm_slp_sts_match_tbl[] = { + {.compatible = "qcom,cpu-sleep-status"}, + {}, +}; + +static struct platform_driver msm_cpu_status_driver = { + .probe = msm_cpu_status_probe, + .driver = { + .name = "qcom,cpu-sleep-status", + .owner = THIS_MODULE, + .of_match_table = msm_slp_sts_match_tbl, + }, +}; + +int __init msm_pm_sleep_status_init(void) +{ + static bool registered; + + if (registered) + return 0; + registered = true; + + return platform_driver_register(&msm_cpu_status_driver); +} +arch_initcall(msm_pm_sleep_status_init); diff --git a/include/soc/qcom/pm.h b/include/soc/qcom/pm.h index ed6124a..3de04b8 100644 --- a/include/soc/qcom/pm.h +++ b/include/soc/qcom/pm.h @@ -32,12 +32,14 @@ enum msm_pm_l2_scm_flag { bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle); int msm_pm_cpu_hotplug_enter(unsigned int cpu); int msm_pm_secondary_startup(unsigned int cpu); +int msm_pm_wait_cpu_shutdown(unsigned int cpu); #else static inline bool msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle) { return true; } static inline int msm_pm_cpu_hotplug_enter(unsigned int cpu) { return 0; } static inline int msm_pm_secondary_startup(unsigned int cpu) { return 0; } +static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; } #endif #endif /* __QCOM_PM_H */