From patchwork Tue Aug 19 22:15:33 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 35674 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qg0-f71.google.com (mail-qg0-f71.google.com [209.85.192.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1D8A72034C for ; Tue, 19 Aug 2014 22:16:06 +0000 (UTC) Received: by mail-qg0-f71.google.com with SMTP id f51sf21702034qge.2 for ; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=XLJICH5W2/c2XAmrndwJG8IF8DZ6+KHZantJDeSY9Zc=; b=DCuB28OUO3b5vCAyVY70AgqzW3RZLShMLi+DhxDIHUqn/3hIrVb90S8xgxnpCoixGo qhcgj7T1c+uhYU4lnJsQggVyyM/8IfrN9wXpMq/QENK7I+4e5x8CdlUwD6MkhQvasY1D jUrJN+2tO7U67YZGmRKR3qge4PZQp9CzHvrQfo7MpSBKddsuRRlFfXT3+S504VEWVt4S 8Ys8r5fMVIiidMmnJ9YrrtEvTB9eGZCc0yMuA/yvED3b7yoHrtreUW02JUxve+pxtogt apoSpZn0JbdJzoGDe7r6dscNj9ormUSmGQ82INeiH1Q5daplUoSQb3qhEQJTfi3JPEQ+ IO/g== X-Gm-Message-State: ALoCoQl05q3aLST+mNyoSWYSDN6gq6/rOEd9ljVnzbHTVoaeMiwgYw0kPM841EEPZOXkNBo5Fy/d X-Received: by 10.236.15.167 with SMTP id f27mr20080053yhf.37.1408486565956; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.36.105 with SMTP id o96ls37737qgo.35.gmail; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) X-Received: by 10.52.239.108 with SMTP id vr12mr5224977vdc.30.1408486565858; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) Received: from mail-vc0-f174.google.com (mail-vc0-f174.google.com [209.85.220.174]) by mx.google.com with ESMTPS id sd9si9682679vdb.25.2014.08.19.15.16.05 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 19 Aug 2014 15:16:05 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.174 as permitted sender) client-ip=209.85.220.174; Received: by mail-vc0-f174.google.com with SMTP id la4so8103983vcb.5 for ; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) X-Received: by 10.52.120.51 with SMTP id kz19mr1784469vdb.95.1408486565773; Tue, 19 Aug 2014 15:16:05 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.45.67 with SMTP id uj3csp3352vcb; Tue, 19 Aug 2014 15:16:04 -0700 (PDT) X-Received: by 10.68.250.3 with SMTP id yy3mr48106469pbc.56.1408486564450; Tue, 19 Aug 2014 15:16:04 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id df3si28839804pbc.99.2014.08.19.15.16.03 for ; Tue, 19 Aug 2014 15:16:04 -0700 (PDT) Received-SPF: none (google.com: linux-arm-msm-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751922AbaHSWQC (ORCPT + 5 others); Tue, 19 Aug 2014 18:16:02 -0400 Received: from mail-pa0-f48.google.com ([209.85.220.48]:45068 "EHLO mail-pa0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751710AbaHSWQB (ORCPT ); Tue, 19 Aug 2014 18:16:01 -0400 Received: by mail-pa0-f48.google.com with SMTP id et14so10791686pad.7 for ; Tue, 19 Aug 2014 15:16:01 -0700 (PDT) X-Received: by 10.68.201.68 with SMTP id jy4mr47968553pbc.64.1408486560964; Tue, 19 Aug 2014 15:16:00 -0700 (PDT) Received: from ubuntu.localdomain (proxy6-global253.qualcomm.com. [199.106.103.253]) by mx.google.com with ESMTPSA id zq5sm20305897pbb.37.2014.08.19.15.15.59 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 19 Aug 2014 15:16:00 -0700 (PDT) From: Lina Iyer To: daniel.lezcano@linaro.org, khilman@linaro.org, sboyd@codeaurora.org, davidb@codeaurora.org, galak@codeaurora.org, linux-arm-msm@vger.kernel.org, lorenzo.pieralisi@arm.com Cc: msivasub@codeaurora.org, Lina Iyer , Praveen Chidamabram , Murali Nalajala Subject: [PATCH v4 4/8] qcom: spm-devices: Add SPM device manager for the SoC Date: Tue, 19 Aug 2014 16:15:33 -0600 Message-Id: <1408486537-6358-5-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1408486537-6358-1-git-send-email-lina.iyer@linaro.org> References: <1408486537-6358-1-git-send-email-lina.iyer@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: lina.iyer@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.174 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Each cpu or an L2$ has an SPM device. They are identical instances of the same SPM block. This allows for multiple instances be grouped and managed collectively. spm-devices.c is the SPM device manager managing multiple SPM devices on top of the driver layer. Device configuration of each SPM is picked up from the DTS. The hardware configuration of each of the SPM is handled by the spm.c driver. Signed-off-by: Praveen Chidamabram Signed-off-by: Murali Nalajala Signed-off-by: Lina Iyer --- Documentation/devicetree/bindings/arm/msm/spm.txt | 47 +++++ drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/spm-devices.c | 198 ++++++++++++++++++++++ include/soc/qcom/spm.h | 34 ++++ 5 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/spm.txt create mode 100644 drivers/soc/qcom/spm-devices.c create mode 100644 include/soc/qcom/spm.h diff --git a/Documentation/devicetree/bindings/arm/msm/spm.txt b/Documentation/devicetree/bindings/arm/msm/spm.txt new file mode 100644 index 0000000..318e024 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/spm.txt @@ -0,0 +1,47 @@ +* Subsystem Power Manager (SAW2) + +S4 generation of MSMs have SPM hardware blocks to control the Application +Processor Sub-System power. These SPM blocks run individual state machine +to determine what the core (L2 or Krait/Scorpion) would do when the WFI +instruction is executed by the core. + +The devicetree representation of the SPM block should be: + +Required properties + +- compatible: Could be one of - + "qcom,spm-v2.1" + "qcom,spm-v3.0" +- reg: The physical address and the size of the SPM's memory mapped registers +- qcom,cpu: phandle for the CPU that the SPM block is attached to. + This field is required on only for SPMs that control the CPU. +- qcom,saw2-cfg: SAW2 configuration register +- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM + sequence +- qcom,saw2-spm-ctl: The SPM control register + +Optional properties + +- qcom,saw2-spm-cmd-wfi: The WFI command sequence +- qcom,saw2-spm-cmd-ret: The Retention command sequence +- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence +- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence. This sequence may + turn off other SoC components. +- qcom,saw2-spm-cmd-gdhs: GDHS (Globally Distributed Head Switch) command + sequence. This sequence will retain the memory but turn off the logic. +- +Example: + spm@f9089000 { + compatible = "qcom,spm-v2.1"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf9089000 0x1000>; + qcom,cpu = <&CPU0>; + qcom,saw2-cfg = <0x1>; + qcom,saw2-spm-dly= <0x20000400>; + qcom,saw2-spm-ctl = <0x1>; + qcom,saw2-spm-cmd-wfi = [03 0b 0f]; + qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92 + a0 b0 03 68 70 3b 92 a0 b0 + 82 2b 50 10 30 02 22 30 0f]; + }; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 7dcd554..d467767 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -11,3 +11,11 @@ config QCOM_GSBI config QCOM_SCM bool + +config QCOM_PM + bool "Qualcomm Power Management" + depends on PM && ARCH_QCOM && OF + help + QCOM Platform specific power driver to manage cores and L2 low power + modes. It interface with various system drivers to put the cores in + low power modes. diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 20b329f..9457b2a 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o -obj-$(CONFIG_QCOM_PM) += spm.o +obj-$(CONFIG_QCOM_PM) += spm.o spm-devices.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/spm-devices.c b/drivers/soc/qcom/spm-devices.c new file mode 100644 index 0000000..2175a81 --- /dev/null +++ b/drivers/soc/qcom/spm-devices.c @@ -0,0 +1,198 @@ +/* Copyright (c) 2011-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 +#include + +#include + +#include "spm-drv.h" + +/** + * All related information for an SPM device + * Helps manage the collective. + */ +struct msm_spm_device { + bool initialized; + struct msm_spm_driver_data drv; +}; + +static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device); + +/** + * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode + * @mode: SPM LPM mode to enter + */ +int msm_spm_set_low_power_mode(unsigned int mode) +{ + struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device); + int ret = -EINVAL; + + if (!dev->initialized) + return -ENXIO; + + if (mode == MSM_SPM_MODE_DISABLED) + ret = msm_spm_drv_set_spm_enable(&dev->drv, false); + else if (!msm_spm_drv_set_spm_enable(&dev->drv, true)) + ret = msm_spm_drv_set_low_power_mode(&dev->drv, mode); + + return ret; +} +EXPORT_SYMBOL(msm_spm_set_low_power_mode); + +static int get_cpu_id(struct device_node *node) +{ + struct device_node *cpu_node; + u32 cpu; + int ret = -EINVAL; + char *key = "qcom,cpu"; + + cpu_node = of_parse_phandle(node, key, 0); + if (cpu_node) { + for_each_possible_cpu(cpu) { + if (of_get_cpu_node(cpu, NULL) == cpu_node) + return cpu; + } + } + return ret; +} + +static struct msm_spm_device *msm_spm_get_device(struct platform_device *pdev) +{ + struct msm_spm_device *dev = NULL; + int cpu = get_cpu_id(pdev->dev.of_node); + + if ((cpu >= 0) && cpu < num_possible_cpus()) + dev = &per_cpu(msm_cpu_spm_device, cpu); + + return dev; +} + +static int msm_spm_dev_probe(struct platform_device *pdev) +{ + int ret; + int i; + struct device_node *node = pdev->dev.of_node; + char *key; + uint32_t val; + struct msm_spm_mode modes[MSM_SPM_MODE_NR]; + struct msm_spm_device *spm_dev; + struct resource *res; + uint32_t mode_count = 0; + + struct spm_of { + char *key; + uint32_t id; + }; + + /* SPM Configuration registers */ + struct spm_of spm_of_data[] = { + {"qcom,saw2-clk-div", MSM_SPM_REG_SAW2_CFG}, + {"qcom,saw2-enable", MSM_SPM_REG_SAW2_SPM_CTL}, + {"qcom,saw2-delays", MSM_SPM_REG_SAW2_SPM_DLY}, + }; + + /* SPM sleep sequences */ + struct spm_of mode_of_data[] = { + {"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING}, + {"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE}, + {"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_RETENTION}, + }; + + /* Get the right SPM device */ + spm_dev = msm_spm_get_device(pdev); + if (IS_ERR_OR_NULL(spm_dev)) + return -EINVAL; + + /* Get the SAW start address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -EINVAL; + goto fail; + } + spm_dev->drv.reg_base_addr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!spm_dev->drv.reg_base_addr) { + ret = -ENOMEM; + goto fail; + } + + /* Read the SPM configuration register values */ + for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) { + ret = of_property_read_u32(node, spm_of_data[i].key, &val); + if (ret) + continue; + spm_dev->drv.reg_shadow[spm_of_data[i].id] = val; + } + + /* Read the byte arrays for the SPM sleep sequences */ + for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) { + modes[mode_count].start_addr = 0; + key = mode_of_data[i].key; + modes[mode_count].cmd = + (uint8_t *)of_get_property(node, key, &val); + if (!modes[mode_count].cmd) + continue; + modes[mode_count].mode = mode_of_data[i].id; + mode_count++; + } + + spm_dev->drv.modes = devm_kcalloc(&pdev->dev, mode_count, + sizeof(modes[0]), GFP_KERNEL); + if (!spm_dev->drv.modes) + return -ENOMEM; + spm_dev->drv.num_modes = mode_count; + memcpy(spm_dev->drv.modes, &modes[0], sizeof(modes[0]) * mode_count); + + /* Initialize the hardware */ + ret = msm_spm_drv_init(&spm_dev->drv); + if (ret) { + kfree(spm_dev->drv.modes); + return ret; + } + + spm_dev->initialized = true; + return ret; + +fail: + dev_err(&pdev->dev, "SPM device probe failed: %d\n", ret); + return ret; +} + +static struct of_device_id msm_spm_match_table[] = { + {.compatible = "qcom,spm-v2.1"}, + {}, +}; + +static struct platform_driver msm_spm_device_driver = { + .probe = msm_spm_dev_probe, + .driver = { + .name = "spm-v2", + .owner = THIS_MODULE, + .of_match_table = msm_spm_match_table, + }, +}; + +static int __init msm_spm_device_init(void) +{ + return platform_driver_register(&msm_spm_device_driver); +} +device_initcall(msm_spm_device_init); diff --git a/include/soc/qcom/spm.h b/include/soc/qcom/spm.h new file mode 100644 index 0000000..99a1d12 --- /dev/null +++ b/include/soc/qcom/spm.h @@ -0,0 +1,34 @@ +/* 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. + */ + +#ifndef __QCOM_SPM_H +#define __QCOM_SPM_H + +enum { + MSM_SPM_MODE_DISABLED, + MSM_SPM_MODE_CLOCK_GATING, + MSM_SPM_MODE_RETENTION, + MSM_SPM_MODE_GDHS, + MSM_SPM_MODE_POWER_COLLAPSE, + MSM_SPM_MODE_NR +}; + +struct msm_spm_device; + +#if defined(CONFIG_QCOM_PM) +int msm_spm_set_low_power_mode(unsigned int mode); +#else /* defined(CONFIG_QCOM_PM) */ +static inline int msm_spm_set_low_power_mode(unsigned int mode) +{ return -ENOSYS; } +#endif /* defined (CONFIG_QCOM_PM) */ + +#endif /* __QCOM_SPM_H */