From patchwork Mon Feb 12 18:45:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128165 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3489033ljc; Mon, 12 Feb 2018 10:51:26 -0800 (PST) X-Google-Smtp-Source: AH8x226Z/+lDKWVxGuMza5PRrBXF++a3yauR7zbFliqVAw/pWAhbzBzJK93Uu40LC5bgjn95AAcq X-Received: by 2002:a17:902:a9ca:: with SMTP id b10-v6mr11708860plr.223.1518461486311; Mon, 12 Feb 2018 10:51:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461486; cv=none; d=google.com; s=arc-20160816; b=Sp60Vnp5d70sqJ+oW2ln/2x5kLZ83PViCQqGXAL3MuV5VKOT1iUIfPbgXhYlkCzolU +JXykqnz+OyvBmMcdkrpPPfT/6BpWjxpziKCHJ/xFEBvbW+sbNtyIhoJbPg4sextef+h AfBdOGw8easgO69BHr+hqPlWAB/daZXeTP3ZR2I6LLbBPz+c1/QsiQNhr+M3HUROlc0G Gwsw/XbmaFUGrJm/ViLsawTR9T4csxKUy+8CIaaDl5u58W2FyxEIC4Hh/APMpLRhbqRG 35kat5LHqMlaZFfyXSK+CQKxjXRaXxdipEfYDMoBEOhfGr6V4XQKJd9SCSG9syaV3Ls3 3l2A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=X794D4Td2R/AAgr3Bmk6KHWliSyHumLI64r6OV5HHQY=; b=arh0nfedUyy9RdDl57Qux4VqnQeOdQyNOIMRtwtkYIBo1LC4ReI/f8RDvhv/Ybp7iI Sc0jgSrFr1MsxJfGlT6SGmiZ4qZZk08SqzXFLxbyVKNs6f9Wlirr3+/mAL/vJyxiVn4/ bsVJxFA863N3tXUFksnvNwJxohG4zl4hZRopUsJ9ft0YDP8AxNwYCGtaUHQ3cHZdSH7W CBmRkzTpBNubTPkHOjXySWBUZQOIymqTBPpHKIy0ZUona0no/kv6MQSDcw3cGewOh3/d jp8jWKtk78M81QWhWpnf4TIZIqJeAl1RdBQJRqGt7neB3SFOvlC+QmcZp24ISPAig8N9 qZag== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c19-v6si4124730plo.278.2018.02.12.10.51.26; Mon, 12 Feb 2018 10:51:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753287AbeBLSvY (ORCPT + 6 others); Mon, 12 Feb 2018 13:51:24 -0500 Received: from foss.arm.com ([217.140.101.70]:47160 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753979AbeBLSpu (ORCPT ); Mon, 12 Feb 2018 13:45:50 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 74B231688; Mon, 12 Feb 2018 10:45:50 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 1F3FB3F24D; Mon, 12 Feb 2018 10:45:48 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 05/20] firmware: arm_scmi: add scmi protocol bus to enumerate protocol devices Date: Mon, 12 Feb 2018 18:45:09 +0000 Message-Id: <1518461124-17371-6-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The SCMI specification encompasses various protocols. However, not every protocol has to be present on a given platform/implementation as not every protocol is relevant for it. Furthermore, the platform chooses which protocols it exposes to a given agent. The only protocol that must be implemented is the base protocol. The base protocol is used by an agent to discover which protocols are available to it. In order to enumerate the discovered implemented protocols, this patch adds support for a separate scmi protocol bus. It also adds mechanism to register support for different protocols. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 3 +- drivers/firmware/arm_scmi/bus.c | 232 +++++++++++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/common.h | 1 + include/linux/scmi_protocol.h | 62 ++++++++++ 4 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/bus.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 5d9c7ef35f0f..5f4ec2613db6 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,3 +1,4 @@ -obj-y = scmi-driver.o scmi-protocols.o +obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o +scmi-bus-y = bus.o scmi-driver-y = driver.o scmi-protocols-y = base.o diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c new file mode 100644 index 000000000000..cf1c2464cb0f --- /dev/null +++ b/drivers/firmware/arm_scmi/bus.c @@ -0,0 +1,232 @@ +/* + * System Control and Management Interface (SCMI) Message Protocol bus layer + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "common.h" + +static DEFINE_IDA(scmi_bus_id); +static DEFINE_IDR(scmi_protocols); +static DEFINE_SPINLOCK(protocol_lock); + +static const struct scmi_device_id * +scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv) +{ + const struct scmi_device_id *id = scmi_drv->id_table; + + if (!id) + return NULL; + + for (; id->protocol_id; id++) + if (id->protocol_id == scmi_dev->protocol_id) + return id; + + return NULL; +} + +static int scmi_dev_match(struct device *dev, struct device_driver *drv) +{ + struct scmi_driver *scmi_drv = to_scmi_driver(drv); + struct scmi_device *scmi_dev = to_scmi_dev(dev); + const struct scmi_device_id *id; + + id = scmi_dev_match_id(scmi_dev, scmi_drv); + if (id) + return 1; + + return 0; +} + +static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle) +{ + scmi_prot_init_fn_t fn = idr_find(&scmi_protocols, protocol_id); + + if (unlikely(!fn)) + return -EINVAL; + return fn(handle); +} + +static int scmi_dev_probe(struct device *dev) +{ + struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); + struct scmi_device *scmi_dev = to_scmi_dev(dev); + const struct scmi_device_id *id; + int ret; + + id = scmi_dev_match_id(scmi_dev, scmi_drv); + if (!id) + return -ENODEV; + + if (!scmi_dev->handle) + return -EPROBE_DEFER; + + ret = scmi_protocol_init(scmi_dev->protocol_id, scmi_dev->handle); + if (ret) + return ret; + + return scmi_drv->probe(scmi_dev); +} + +static int scmi_dev_remove(struct device *dev) +{ + struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); + struct scmi_device *scmi_dev = to_scmi_dev(dev); + + if (scmi_drv->remove) + scmi_drv->remove(scmi_dev); + + return 0; +} + +static struct bus_type scmi_bus_type = { + .name = "scmi_protocol", + .match = scmi_dev_match, + .probe = scmi_dev_probe, + .remove = scmi_dev_remove, +}; + +int scmi_driver_register(struct scmi_driver *driver, struct module *owner, + const char *mod_name) +{ + int retval; + + driver->driver.bus = &scmi_bus_type; + driver->driver.name = driver->name; + driver->driver.owner = owner; + driver->driver.mod_name = mod_name; + + retval = driver_register(&driver->driver); + if (!retval) + pr_debug("registered new scmi driver %s\n", driver->name); + + return retval; +} +EXPORT_SYMBOL_GPL(scmi_driver_register); + +void scmi_driver_unregister(struct scmi_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL_GPL(scmi_driver_unregister); + +struct scmi_device * +scmi_device_create(struct device_node *np, struct device *parent, int protocol) +{ + int id, retval; + struct scmi_device *scmi_dev; + + id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL); + if (id < 0) + return NULL; + + scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL); + if (!scmi_dev) + goto no_mem; + + scmi_dev->id = id; + scmi_dev->protocol_id = protocol; + scmi_dev->dev.parent = parent; + scmi_dev->dev.of_node = np; + scmi_dev->dev.bus = &scmi_bus_type; + dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id); + + retval = device_register(&scmi_dev->dev); + if (!retval) + return scmi_dev; + + put_device(&scmi_dev->dev); + kfree(scmi_dev); +no_mem: + ida_simple_remove(&scmi_bus_id, id); + return NULL; +} + +void scmi_device_destroy(struct scmi_device *scmi_dev) +{ + scmi_handle_put(scmi_dev->handle); + device_unregister(&scmi_dev->dev); + ida_simple_remove(&scmi_bus_id, scmi_dev->id); + kfree(scmi_dev); +} + +void scmi_set_handle(struct scmi_device *scmi_dev) +{ + scmi_dev->handle = scmi_handle_get(&scmi_dev->dev); +} + +int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn) +{ + int ret; + + spin_lock(&protocol_lock); + ret = idr_alloc(&scmi_protocols, fn, protocol_id, protocol_id + 1, + GFP_KERNEL); + if (ret != protocol_id) + pr_err("unable to allocate SCMI idr slot, err %d\n", ret); + spin_unlock(&protocol_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(scmi_protocol_register); + +void scmi_protocol_unregister(int protocol_id) +{ + spin_lock(&protocol_lock); + idr_remove(&scmi_protocols, protocol_id); + spin_unlock(&protocol_lock); +} +EXPORT_SYMBOL_GPL(scmi_protocol_unregister); + +static int __scmi_devices_unregister(struct device *dev, void *data) +{ + struct scmi_device *scmi_dev = to_scmi_dev(dev); + + scmi_device_destroy(scmi_dev); + return 0; +} + +static void scmi_devices_unregister(void) +{ + bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister); +} + +static int __init scmi_bus_init(void) +{ + int retval; + + retval = bus_register(&scmi_bus_type); + if (retval) + pr_err("scmi protocol bus register failed (%d)\n", retval); + + return retval; +} +subsys_initcall(scmi_bus_init); + +static void __exit scmi_bus_exit(void) +{ + scmi_devices_unregister(); + bus_unregister(&scmi_bus_type); + ida_destroy(&scmi_bus_id); +} +module_exit(scmi_bus_exit); diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index bc767f4997e0..f1eeacaef57b 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -107,6 +107,7 @@ int scmi_one_xfer_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, size_t tx_size, size_t rx_size, struct scmi_xfer **p); int scmi_handle_put(const struct scmi_handle *handle); struct scmi_handle *scmi_handle_get(struct device *dev); +void scmi_set_handle(struct scmi_device *scmi_dev); int scmi_version_get(const struct scmi_handle *h, u8 protocol, u32 *version); void scmi_setup_protocol_implemented(const struct scmi_handle *handle, u8 *prot_imp); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 664da3d763f2..7b72c75cb560 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include #include #define SCMI_MAX_STR_SIZE 16 @@ -62,3 +63,64 @@ enum scmi_std_protocol { SCMI_PROTOCOL_CLOCK = 0x14, SCMI_PROTOCOL_SENSOR = 0x15, }; + +struct scmi_device { + u32 id; + u8 protocol_id; + struct device dev; + struct scmi_handle *handle; +}; + +#define to_scmi_dev(d) container_of(d, struct scmi_device, dev) + +struct scmi_device * +scmi_device_create(struct device_node *np, struct device *parent, int protocol); +void scmi_device_destroy(struct scmi_device *scmi_dev); + +struct scmi_device_id { + u8 protocol_id; +}; + +struct scmi_driver { + const char *name; + int (*probe)(struct scmi_device *); + void (*remove)(struct scmi_device *); + const struct scmi_device_id *id_table; + + struct device_driver driver; +}; + +#define to_scmi_driver(d) container_of(d, struct scmi_driver, driver) + +#ifdef CONFIG_ARM_SCMI_PROTOCOL +int scmi_driver_register(struct scmi_driver *driver, + struct module *owner, const char *mod_name); +void scmi_driver_unregister(struct scmi_driver *driver); +#else +static int scmi_driver_register(struct scmi_driver *driver, + struct module *owner, const char *mod_name) +{ + return -EINVAL; +} +static void scmi_driver_unregister(struct scmi_driver *driver) {} +#endif /* CONFIG_ARM_SCMI_PROTOCOL */ + +#define scmi_register(driver) \ + scmi_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) +#define scmi_unregister(driver) \ + scmi_driver_unregister(driver) + +/** + * module_scmi_driver() - Helper macro for registering a scmi driver + * @__scmi_driver: scmi_driver structure + * + * Helper macro for scmi drivers to set up proper module init / exit + * functions. Replaces module_init() and module_exit() and keeps people from + * printing pointless things to the kernel log when their driver is loaded. + */ +#define module_scmi_driver(__scmi_driver) \ + module_driver(__scmi_driver, scmi_register, scmi_unregister) + +typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *); +int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn); +void scmi_protocol_unregister(int protocol_id); From patchwork Mon Feb 12 18:45:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128148 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485250ljc; Mon, 12 Feb 2018 10:45:59 -0800 (PST) X-Google-Smtp-Source: AH8x224co3sXrRym1NcWq4deEzg7cCKWHC4uWizt/jELpuTfx+Ah154PaQUG9hxQOW5u//4DF1qV X-Received: by 10.101.73.197 with SMTP id t5mr10195674pgs.48.1518461159458; Mon, 12 Feb 2018 10:45:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461159; cv=none; d=google.com; s=arc-20160816; b=VfrnQbnZTn2Gpl4v88ZfQidTpcQqLJmIEZB1UxUo5bKpux26x9x6c0fs0e5vQae3le IazL3ArmDvpTVLSt7LVniZsOq4tDlff1yIUTuj6WUx8sac/JMnDMkcPilv8a+gEe9Sth c70MoA9PZWBaqWKw7A7B8w+9q38zwRZdZybSSA9fRR9MNQJo+QY82lCbCy86Xx1z1NN9 gnaVGCg+XQCMsnew0hLvn5HcHBLIS1BrcPnHNew0d7ZdMTi/vSNEn07HSwLODmPjzeaO 48oOOi8slO1k0FB0nSIKdm7ZIBZ4ONcEtSzWkXUq2J5rCstBg431NzruneNS79A+ZVzf Ixvg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=7YXydwEwKVfQFrORlZdfIMqtd12iHN92AUghmjPbWd8=; b=C1RSZahmTENXPOlN+XlhvNYgnQdiLOcg/yQtNi5Ekr1wexOIlfFiCqW/qmXzUFiGxx k+xnHSrE1zW3a2krbEdCjSMXRitEZKAPAzRAgQFk7vAoyQvuVCTj1n8B2IDXJ4c1fjiv YkVh+ETFoLHQqM2nayoUkbT6icWTrPrdKtoiOeUT8kxRLvlNB4e5cI1j7Y2aBzclcEaL B1srupieBBTs90zAhGUy3ISULW/F4xvvIhyBLOhHkR/zhNRgxf5/0Akpq5He8BRuGY6E +TFo0hTrqIlojT/6zmMC1LdgTLKY0wvYkqmz95xyHdvCDvCc8RqN/nwcp1LWi7ck6Seq ycEg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q73si4808976pfj.270.2018.02.12.10.45.59; Mon, 12 Feb 2018 10:45:59 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753380AbeBLSp6 (ORCPT + 6 others); Mon, 12 Feb 2018 13:45:58 -0500 Received: from foss.arm.com ([217.140.101.70]:47190 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754052AbeBLSpz (ORCPT ); Mon, 12 Feb 2018 13:45:55 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4A25E164F; Mon, 12 Feb 2018 10:45:55 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id E8EC13F24D; Mon, 12 Feb 2018 10:45:53 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 08/20] firmware: arm_scmi: add initial support for power protocol Date: Mon, 12 Feb 2018 18:45:12 +0000 Message-Id: <1518461124-17371-9-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The power protocol is intended for management of power states of various power domains. The power domain management protocol provides commands to describe the protocol version, discover the implementation specific attributes, set and get the power state of a domain. This patch adds support for the above mention features of the protocol. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla -- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 242 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 28 +++++ 3 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 232 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 26 +++++ 3 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 2130ee9ac825..420c761ced94 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,4 +1,4 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-protocols-y = base.o clock.o perf.o +scmi-protocols-y = base.o clock.o perf.o power.o diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c new file mode 100644 index 000000000000..baf92a15b7e9 --- /dev/null +++ b/drivers/firmware/arm_scmi/power.c @@ -0,0 +1,232 @@ +/* + * System Control and Management Interface (SCMI) Power Protocol + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "common.h" + +enum scmi_power_protocol_cmd { + POWER_DOMAIN_ATTRIBUTES = 0x3, + POWER_STATE_SET = 0x4, + POWER_STATE_GET = 0x5, + POWER_STATE_NOTIFY = 0x6, +}; + +struct scmi_msg_resp_power_attributes { + __le16 num_domains; + __le16 reserved; + __le32 stats_addr_low; + __le32 stats_addr_high; + __le32 stats_size; +}; + +struct scmi_msg_resp_power_domain_attributes { + __le32 flags; +#define SUPPORTS_STATE_SET_NOTIFY(x) ((x) & BIT(31)) +#define SUPPORTS_STATE_SET_ASYNC(x) ((x) & BIT(30)) +#define SUPPORTS_STATE_SET_SYNC(x) ((x) & BIT(29)) + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_set_state { + __le32 flags; +#define STATE_SET_ASYNC BIT(0) + __le32 domain; + __le32 state; +}; + +struct scmi_power_state_notify { + __le32 domain; + __le32 notify_enable; +}; + +struct power_dom_info { + bool state_set_sync; + bool state_set_async; + bool state_set_notify; + char name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_info { + int num_domains; + u64 stats_addr; + u32 stats_size; + struct power_dom_info *dom_info; +}; + +static int scmi_power_attributes_get(const struct scmi_handle *handle, + struct scmi_power_info *pi) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + pi->num_domains = le16_to_cpu(attr->num_domains); + pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | + (u64)le32_to_cpu(attr->stats_addr_high) << 32; + pi->stats_size = le32_to_cpu(attr->stats_size); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, + struct power_dom_info *dom_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_domain_attributes *attr; + + ret = scmi_one_xfer_init(handle, POWER_DOMAIN_ATTRIBUTES, + SCMI_PROTOCOL_POWER, sizeof(domain), + sizeof(*attr), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + u32 flags = le32_to_cpu(attr->flags); + + dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags); + dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags); + dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags); + memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) +{ + int ret; + struct scmi_xfer *t; + struct scmi_power_set_state *st; + + ret = scmi_one_xfer_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, + sizeof(*st), 0, &t); + if (ret) + return ret; + + st = t->tx.buf; + st->flags = cpu_to_le32(0); + st->domain = cpu_to_le32(domain); + st->state = cpu_to_le32(state); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, + sizeof(u32), sizeof(u32), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + + ret = scmi_do_xfer(handle, t); + if (!ret) + *state = le32_to_cpu(*(__le32 *)t->rx.buf); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_power_num_domains_get(const struct scmi_handle *handle) +{ + struct scmi_power_info *pi = handle->power_priv; + + return pi->num_domains; +} + +static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain) +{ + struct scmi_power_info *pi = handle->power_priv; + struct power_dom_info *dom = pi->dom_info + domain; + + return dom->name; +} + +static struct scmi_power_ops power_ops = { + .num_domains_get = scmi_power_num_domains_get, + .name_get = scmi_power_name_get, + .state_set = scmi_power_state_set, + .state_get = scmi_power_state_get, +}; + +static int scmi_power_protocol_init(struct scmi_handle *handle) +{ + int domain; + u32 version; + struct scmi_power_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version); + + dev_dbg(handle->dev, "Power Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + scmi_power_attributes_get(handle, pinfo); + + pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + sizeof(*pinfo->dom_info), GFP_KERNEL); + if (!pinfo->dom_info) + return -ENOMEM; + + for (domain = 0; domain < pinfo->num_domains; domain++) { + struct power_dom_info *dom = pinfo->dom_info + domain; + + scmi_power_domain_attributes_get(handle, domain, dom); + } + + handle->power_ops = &power_ops; + handle->power_priv = pinfo; + + return 0; +} + +static int __init scmi_power_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_POWER, + &scmi_power_protocol_init); +} +subsys_initcall(scmi_power_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index cfdc8967e5d9..b853ac56940d 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -114,10 +114,34 @@ struct scmi_perf_ops { }; /** + * struct scmi_power_ops - represents the various operations provided + * by SCMI Power Protocol + * + * @num_domains_get: get the count of power domains provided by SCMI + * @name_get: gets the name of a power domain + * @state_set: sets the power state of a power domain + * @state_get: gets the power state of a power domain + */ +struct scmi_power_ops { + int (*num_domains_get)(const struct scmi_handle *); + char *(*name_get)(const struct scmi_handle *, u32); +#define SCMI_POWER_STATE_TYPE_SHIFT 30 +#define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1) +#define SCMI_POWER_STATE_PARAM(type, id) \ + ((((type) & BIT(0)) << SCMI_POWER_STATE_TYPE_SHIFT) | \ + ((id) & SCMI_POWER_STATE_ID_MASK)) +#define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0) +#define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0) + int (*state_set)(const struct scmi_handle *, u32, u32); + int (*state_get)(const struct scmi_handle *, u32, u32 *); +}; + +/** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information + * @power_ops: pointer to set of power protocol operations * @perf_ops: pointer to set of performance protocol operations * @clk_ops: pointer to set of clock protocol operations */ @@ -126,9 +150,11 @@ struct scmi_handle { struct scmi_revision_info *version; struct scmi_perf_ops *perf_ops; struct scmi_clk_ops *clk_ops; + struct scmi_power_ops *power_ops; /* for protocol internal use */ void *perf_priv; void *clk_priv; + void *power_priv; }; enum scmi_std_protocol { From patchwork Mon Feb 12 18:45:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128161 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3488267ljc; Mon, 12 Feb 2018 10:50:18 -0800 (PST) X-Google-Smtp-Source: AH8x224wFD5Mba6o7vP8oYmE96sbW7MYi0yPHqHIPARe+ag3Kagmes8g+th/SkFGSJRFVIhb2y1u X-Received: by 2002:a17:902:8c86:: with SMTP id t6-v6mr11749254plo.400.1518461418024; Mon, 12 Feb 2018 10:50:18 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461418; cv=none; d=google.com; s=arc-20160816; b=ITqxJmIVQrOa1xJD0kh/MPHzUah2P37TqHygUT2K94CF3nfrzh7/lG3HDiv51ROOED qnaI0gJVI0Z2pVcM1fSVZVPyw+g8X9U0Hp9af8XsolQ0/t7+khv/ph5q4JZW0OfTCJ6Y uam3rJ+wx3RNC9H2+3evpneyyNfOQX39NpUOVXNQEGk8qyyCjKzRQ8iW91Lg4ZqP+m7g bB1UH48F7akH+x8Gi6QkQ0wriZR7cuHWM71Fr+041RkEB+ltFMi7yS1SSzbrY6XuCd8s Sbz8cXzvFUTgtdFqUzpW3XCoLmiStm0aZCt6mdTn1D6U2Aw/GaJhjGA/xJAZhfjJiqw8 4vIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=GhSQtP7uZZdyzYH0IarQwJii7VKie6tNVfOOK5Zx414=; b=EOEnwqXj1PHaqTIqycroz9/vkuVjhx8v3Nhd4bJQZp61cXFH54/yDsJgIfWiVE52TM 71OG8vj+OR4AEJLCa8vT+jwQ98u6aZrdSzPsbeeGSy+Xsm/xdKxQojJob/ocv0pq2/+q Dy7kHnAn3mplVxsxBkj8sTdibOU2B94dhTEffNObcdPoP3iMoQ7lDn2ikuvL0uAzvXb2 ILNxqXV6uSq9P1Kwj1CCCs0QYnBN/t+7QcubBz87zuwn+RanIqbsJ72In21+aJ4/3blg i1pXTyES4jLAL0amf4yI+4KZHUhzVHezTbhGGcd/Vn6tj8RqXQ0Hn5Ic1hLtqXOi/bE6 5MdA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t27si1003621pfe.283.2018.02.12.10.50.17; Mon, 12 Feb 2018 10:50:18 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753801AbeBLSuQ (ORCPT + 6 others); Mon, 12 Feb 2018 13:50:16 -0500 Received: from foss.arm.com ([217.140.101.70]:47200 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753460AbeBLSp5 (ORCPT ); Mon, 12 Feb 2018 13:45:57 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DEB4A1435; Mon, 12 Feb 2018 10:45:56 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 8951F3F24D; Mon, 12 Feb 2018 10:45:55 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 09/20] firmware: arm_scmi: add initial support for sensor protocol Date: Mon, 12 Feb 2018 18:45:13 +0000 Message-Id: <1518461124-17371-10-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The sensor protocol provides functions to manage platform sensors, and provides the commands to describe the protocol version and the various attribute flags. It also provides commands to discover various sensors implemented and managed by the platform, read any sensor synchronously or asynchronously as allowed by the platform, program sensor attributes and/or configurations, if applicable. This patch adds support for most of the above features. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/sensors.c | 302 ++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 42 +++++ 3 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/sensors.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 420c761ced94..3236890905b9 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,4 +1,4 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-protocols-y = base.o clock.o perf.o power.o +scmi-protocols-y = base.o clock.o perf.o power.o sensors.o diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c new file mode 100644 index 000000000000..aee38d3d1c2d --- /dev/null +++ b/drivers/firmware/arm_scmi/sensors.c @@ -0,0 +1,302 @@ +/* + * System Control and Management Interface (SCMI) Sensor Protocol + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "common.h" + +enum scmi_sensor_protocol_cmd { + SENSOR_DESCRIPTION_GET = 0x3, + SENSOR_CONFIG_SET = 0x4, + SENSOR_TRIP_POINT_SET = 0x5, + SENSOR_READING_GET = 0x6, +}; + +struct scmi_msg_resp_sensor_attributes { + __le16 num_sensors; + u8 max_requests; + u8 reserved; + __le32 reg_addr_low; + __le32 reg_addr_high; + __le32 reg_size; +}; + +struct scmi_msg_resp_sensor_description { + __le16 num_returned; + __le16 num_remaining; + struct { + __le32 id; + __le32 attributes_low; +#define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31)) +#define NUM_TRIP_POINTS(x) (((x) >> 4) & 0xff) + __le32 attributes_high; +#define SENSOR_TYPE(x) ((x) & 0xff) +#define SENSOR_SCALE(x) (((x) >> 11) & 0x3f) +#define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f) +#define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f) + u8 name[SCMI_MAX_STR_SIZE]; + } desc[0]; +}; + +struct scmi_msg_set_sensor_config { + __le32 id; + __le32 event_control; +}; + +struct scmi_msg_set_sensor_trip_point { + __le32 id; + __le32 event_control; +#define SENSOR_TP_EVENT_MASK (0x3) +#define SENSOR_TP_DISABLED 0x0 +#define SENSOR_TP_POSITIVE 0x1 +#define SENSOR_TP_NEGATIVE 0x2 +#define SENSOR_TP_BOTH 0x3 +#define SENSOR_TP_ID(x) (((x) & 0xff) << 4) + __le32 value_low; + __le32 value_high; +}; + +struct scmi_msg_sensor_reading_get { + __le32 id; + __le32 flags; +#define SENSOR_READ_ASYNC BIT(0) +}; + +struct sensors_info { + int num_sensors; + int max_requests; + u64 reg_addr; + u32 reg_size; + struct scmi_sensor_info *sensors; +}; + +static int scmi_sensor_attributes_get(const struct scmi_handle *handle, + struct sensors_info *si) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_sensor_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + si->num_sensors = le16_to_cpu(attr->num_sensors); + si->max_requests = attr->max_requests; + si->reg_addr = le32_to_cpu(attr->reg_addr_low) | + (u64)le32_to_cpu(attr->reg_addr_high) << 32; + si->reg_size = le32_to_cpu(attr->reg_size); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_description_get(const struct scmi_handle *handle, + struct sensors_info *si) +{ + int ret, cnt; + u32 desc_index = 0; + u16 num_returned, num_remaining; + struct scmi_xfer *t; + struct scmi_msg_resp_sensor_description *buf; + + ret = scmi_one_xfer_init(handle, SENSOR_DESCRIPTION_GET, + SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t); + if (ret) + return ret; + + buf = t->rx.buf; + + do { + /* Set the number of sensors to be skipped/already read */ + *(__le32 *)t->tx.buf = cpu_to_le32(desc_index); + + ret = scmi_do_xfer(handle, t); + if (ret) + break; + + num_returned = le16_to_cpu(buf->num_returned); + num_remaining = le16_to_cpu(buf->num_remaining); + + if (desc_index + num_returned > si->num_sensors) { + dev_err(handle->dev, "No. of sensors can't exceed %d", + si->num_sensors); + break; + } + + for (cnt = 0; cnt < num_returned; cnt++) { + u32 attrh; + struct scmi_sensor_info *s; + + attrh = le32_to_cpu(buf->desc[cnt].attributes_high); + s = &si->sensors[desc_index + cnt]; + s->id = le32_to_cpu(buf->desc[cnt].id); + s->type = SENSOR_TYPE(attrh); + memcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); + } + + desc_index += num_returned; + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) +{ + int ret; + u32 evt_cntl = BIT(0); + struct scmi_xfer *t; + struct scmi_msg_set_sensor_config *cfg; + + ret = scmi_one_xfer_init(handle, SENSOR_CONFIG_SET, + SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(sensor_id); + cfg->event_control = cpu_to_le32(evt_cntl); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, + u32 sensor_id, u8 trip_id, u64 trip_value) +{ + int ret; + u32 evt_cntl = SENSOR_TP_BOTH; + struct scmi_xfer *t; + struct scmi_msg_set_sensor_trip_point *trip; + + ret = scmi_one_xfer_init(handle, SENSOR_TRIP_POINT_SET, + SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t); + if (ret) + return ret; + + trip = t->tx.buf; + trip->id = cpu_to_le32(sensor_id); + trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id)); + trip->value_low = cpu_to_le32(trip_value & 0xffffffff); + trip->value_high = cpu_to_le32(trip_value >> 32); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_reading_get(const struct scmi_handle *handle, + u32 sensor_id, bool async, u64 *value) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_sensor_reading_get *sensor; + + ret = scmi_one_xfer_init(handle, SENSOR_READING_GET, + SCMI_PROTOCOL_SENSOR, sizeof(*sensor), + sizeof(u64), &t); + if (ret) + return ret; + + sensor = t->tx.buf; + sensor->id = cpu_to_le32(sensor_id); + sensor->flags = cpu_to_le32(async ? SENSOR_READ_ASYNC : 0); + + ret = scmi_do_xfer(handle, t); + if (!ret) { + __le32 *pval = t->rx.buf; + + *value = le32_to_cpu(*pval); + *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static const struct scmi_sensor_info * +scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id) +{ + struct sensors_info *si = handle->sensor_priv; + + return si->sensors + sensor_id; +} + +static int scmi_sensor_count_get(const struct scmi_handle *handle) +{ + struct sensors_info *si = handle->sensor_priv; + + return si->num_sensors; +} + +static struct scmi_sensor_ops sensor_ops = { + .count_get = scmi_sensor_count_get, + .info_get = scmi_sensor_info_get, + .configuration_set = scmi_sensor_configuration_set, + .trip_point_set = scmi_sensor_trip_point_set, + .reading_get = scmi_sensor_reading_get, +}; + +static int scmi_sensors_protocol_init(struct scmi_handle *handle) +{ + u32 version; + struct sensors_info *sinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version); + + dev_dbg(handle->dev, "Sensor Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + + scmi_sensor_attributes_get(handle, sinfo); + + sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors, + sizeof(*sinfo->sensors), GFP_KERNEL); + if (!sinfo->sensors) + return -ENOMEM; + + scmi_sensor_description_get(handle, sinfo); + + handle->sensor_ops = &sensor_ops; + handle->sensor_priv = sinfo; + + return 0; +} + +static int __init scmi_sensors_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_SENSOR, + &scmi_sensors_protocol_init); +} +subsys_initcall(scmi_sensors_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index b853ac56940d..6785dd9f61e3 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -136,6 +136,45 @@ struct scmi_power_ops { int (*state_get)(const struct scmi_handle *, u32, u32 *); }; +struct scmi_sensor_info { + u32 id; + u8 type; + char name[SCMI_MAX_STR_SIZE]; +}; + +/* + * Partial list from Distributed Management Task Force (DMTF) specification: + * DSP0249 (Platform Level Data Model specification) + */ +enum scmi_sensor_class { + NONE = 0x0, + TEMPERATURE_C = 0x2, + VOLTAGE = 0x5, + CURRENT = 0x6, + POWER = 0x7, + ENERGY = 0x8, +}; + +/** + * struct scmi_sensor_ops - represents the various operations provided + * by SCMI Sensor Protocol + * + * @count_get: get the count of sensors provided by SCMI + * @info_get: get the information of the specified sensor + * @configuration_set: control notifications on cross-over events for + * the trip-points + * @trip_point_set: selects and configures a trip-point of interest + * @reading_get: gets the current value of the sensor + */ +struct scmi_sensor_ops { + int (*count_get)(const struct scmi_handle *); + const struct scmi_sensor_info *(*info_get)(const struct scmi_handle *, + u32); + int (*configuration_set)(const struct scmi_handle *, u32); + int (*trip_point_set)(const struct scmi_handle *, u32, u8, u64); + int (*reading_get)(const struct scmi_handle *, u32, bool, u64 *); +}; + /** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * @@ -144,6 +183,7 @@ struct scmi_power_ops { * @power_ops: pointer to set of power protocol operations * @perf_ops: pointer to set of performance protocol operations * @clk_ops: pointer to set of clock protocol operations + * @sensor_ops: pointer to set of sensor protocol operations */ struct scmi_handle { struct device *dev; @@ -151,10 +191,12 @@ struct scmi_handle { struct scmi_perf_ops *perf_ops; struct scmi_clk_ops *clk_ops; struct scmi_power_ops *power_ops; + struct scmi_sensor_ops *sensor_ops; /* for protocol internal use */ void *perf_priv; void *clk_priv; void *power_priv; + void *sensor_priv; }; enum scmi_std_protocol { From patchwork Mon Feb 12 18:45:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128158 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3487636ljc; Mon, 12 Feb 2018 10:49:21 -0800 (PST) X-Google-Smtp-Source: AH8x226fItTtlUMjhrfgWjQ4vf3MRr7E1l9zhYlCkUAI9MMH9ce+07lh0mYUoI6OhWcC5x9g0h2M X-Received: by 10.98.141.208 with SMTP id p77mr12461882pfk.5.1518461361359; Mon, 12 Feb 2018 10:49:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461361; cv=none; d=google.com; s=arc-20160816; b=tigzH8QNLZc9+frB0DEPP1G+2QifzzsgBzWoybainrWsJMVWr7A4rknsnswwgoq7gH GXHQ0OKxmkGxidrVO2bVC62L2rYkE8grIrJr6C8+HEQle1PE5SCTNXCJ/UVW5wGpD9mP 7ROR7hjxnY//JMkzSuRLI6wOFp81Vdc2a9diijrE1FP8VO/P12yvN26JDKByk/NKUbdB di86u4raPDXPPm7SuisgHj7g3hB4/DEgBGnJS97Qc0gj7quHe02gknw71tcIc4B9CEg2 lg8ef4qzmDbrOf+Hj2ZsUmGqlMvrLhHRlettraW4/QVWYGPCkfSWFRYs0KXoMJLGg/Jp CKZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=Z3v4yQIczR8Jiguzo4qmaSg/sFKDaPP4TXXU2nycRBk=; b=d6f+XQdvJ0WPi/8GbhrsuuDvysmXBekoGaJ9nQvI6+zngXAmBxsM2oJ/n2KUy1BO/C dEN6Jv8n+EFPzxqMKIHtRo7R6fkh+aSrpFmPtYQGEc6RlEEi4B9NK6Ww/Zc75zklkPw8 o8PbAjYOlr+jc21TiFnd50BcKmPjEOVVaNtEQJv0RHTqW/o7gmGQA9sHfkgu4kXLPVCi yeWCNkPTUKQP9pFsvTpLLO36xPlF982cpuM5C7y3sLVkwjAye03kiiXoDE0VKYgTkmvp nq9I0vLO6XXAtksYSnmSBSeKuwf5C3biz6418cmG64DM5c74A/xAFivgbLF2z7byteNa xrgw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g24si3785399pfd.140.2018.02.12.10.49.21; Mon, 12 Feb 2018 10:49:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932247AbeBLStT (ORCPT + 6 others); Mon, 12 Feb 2018 13:49:19 -0500 Received: from foss.arm.com ([217.140.101.70]:47254 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754085AbeBLSqD (ORCPT ); Mon, 12 Feb 2018 13:46:03 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 54D5116A3; Mon, 12 Feb 2018 10:46:03 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id F34083F24D; Mon, 12 Feb 2018 10:46:01 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 13/20] firmware: arm_scmi: refactor in preparation to support per-protocol channels Date: Mon, 12 Feb 2018 18:45:17 +0000 Message-Id: <1518461124-17371-14-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In order to support per-protocol channels if available, we need to factor out all the mailbox channel information(Tx/Rx payload and channel handle) out of the main SCMI instance information structure. This patch refactors the existing channel information into a separate chan_info structure. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 86 ++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 32 deletions(-) -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 0108bb39d0f6..5dd54f72b587 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -102,6 +102,22 @@ struct scmi_desc { }; /** + * struct scmi_chan_info - Structure representing a SCMI channel informfation + * + * @cl: Mailbox Client + * @chan: Transmit/Receive mailbox channel + * @payload: Transmit/Receive mailbox channel payload area + * @dev: Reference to device in the SCMI hierarchy corresponding to this + * channel + */ +struct scmi_chan_info { + struct mbox_client cl; + struct mbox_chan *chan; + void __iomem *payload; + struct device *dev; +}; + +/** * struct scmi_info - Structure representing a SCMI instance * * @dev: Device pointer @@ -109,10 +125,8 @@ struct scmi_desc { * @handle: Instance of SCMI handle to send to clients * @version: SCMI revision information containing protocol version, * implementation version and (sub-)vendor identification. - * @cl: Mailbox Client - * @tx_chan: Transmit mailbox channel - * @tx_payload: Transmit mailbox channel payload area * @minfo: Message info + * @tx_cinfo: Reference to SCMI channel information * @protocols_imp: list of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: list head @@ -123,16 +137,14 @@ struct scmi_info { const struct scmi_desc *desc; struct scmi_revision_info version; struct scmi_handle handle; - struct mbox_client cl; - struct mbox_chan *tx_chan; - void __iomem *tx_payload; struct scmi_xfers_info minfo; + struct scmi_chan_info *tx_cinfo; u8 *protocols_imp; struct list_head node; int users; }; -#define client_to_scmi_info(c) container_of(c, struct scmi_info, cl) +#define client_to_scmi_chan_info(c) container_of(c, struct scmi_chan_info, cl) #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) /* @@ -215,10 +227,11 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) { u16 xfer_id; struct scmi_xfer *xfer; - struct scmi_info *info = client_to_scmi_info(cl); + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + struct device *dev = cinfo->dev; + struct scmi_info *info = dev_get_drvdata(dev); struct scmi_xfers_info *minfo = &info->minfo; - struct device *dev = info->dev; - struct scmi_shared_mem __iomem *mem = info->tx_payload; + struct scmi_shared_mem __iomem *mem = cinfo->payload; xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); @@ -269,8 +282,8 @@ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) static void scmi_tx_prepare(struct mbox_client *cl, void *m) { struct scmi_xfer *t = m; - struct scmi_info *info = client_to_scmi_info(cl); - struct scmi_shared_mem __iomem *mem = info->tx_payload; + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + struct scmi_shared_mem __iomem *mem = cinfo->payload; /* Mark channel busy + clear error */ iowrite32(0x0, &mem->channel_status); @@ -349,15 +362,15 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) } static bool -scmi_xfer_poll_done(const struct scmi_info *info, struct scmi_xfer *xfer) +scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { - struct scmi_shared_mem *mem = info->tx_payload; - u16 xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); + struct scmi_shared_mem __iomem *mem = cinfo->payload; + u16 xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); if (xfer->hdr.seq != xfer_id) return false; - return le32_to_cpu(mem->channel_status) & + return ioread32(&mem->channel_status) & (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } @@ -379,8 +392,9 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) int timeout; struct scmi_info *info = handle_to_scmi_info(handle); struct device *dev = info->dev; + struct scmi_chan_info *cinfo = info->tx_cinfo; - ret = mbox_send_message(info->tx_chan, xfer); + ret = mbox_send_message(cinfo->chan, xfer); if (ret < 0) { dev_dbg(dev, "mbox send fail %d\n", ret); return ret; @@ -396,11 +410,11 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) do { udelay(5); cur = ktime_get(); - } while (!scmi_xfer_poll_done(info, xfer) && + } while (!scmi_xfer_poll_done(cinfo, xfer) && ktime_before(cur, stop)); if (ktime_before(cur, stop)) - scmi_fetch_response(xfer, info->tx_payload); + scmi_fetch_response(xfer, cinfo->payload); else ret = -ETIMEDOUT; } else { @@ -420,7 +434,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) * Unfortunately, we have to kick the mailbox framework after we have * received our message. */ - mbox_client_txdone(info->tx_chan, ret); + mbox_client_txdone(cinfo->chan, ret); return ret; } @@ -648,11 +662,11 @@ static int scmi_mailbox_check(struct device_node *np) return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); } -static int scmi_mbox_free_channel(struct scmi_info *info) +static int scmi_mbox_free_channel(struct scmi_chan_info *cinfo) { - if (!IS_ERR_OR_NULL(info->tx_chan)) { - mbox_free_channel(info->tx_chan); - info->tx_chan = NULL; + if (!IS_ERR_OR_NULL(cinfo->chan)) { + mbox_free_channel(cinfo->chan); + cinfo->chan = NULL; } return 0; @@ -672,7 +686,7 @@ static int scmi_remove(struct platform_device *pdev) if (!ret) /* Safe to free channels since no more users */ - return scmi_mbox_free_channel(info); + return scmi_mbox_free_channel(info->tx_cinfo); return ret; } @@ -684,9 +698,17 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) resource_size_t size; struct device *dev = info->dev; struct device_node *shmem, *np = dev->of_node; + struct scmi_chan_info *cinfo; struct mbox_client *cl; - cl = &info->cl; + cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + + info->tx_cinfo = cinfo; + cinfo->dev = dev; + + cl = &cinfo->cl; cl->dev = dev; cl->rx_callback = scmi_rx_callback; cl->tx_prepare = scmi_tx_prepare; @@ -702,16 +724,16 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) } size = resource_size(&res); - info->tx_payload = devm_ioremap(dev, res.start, size); - if (!info->tx_payload) { + cinfo->payload = devm_ioremap(info->dev, res.start, size); + if (!cinfo->payload) { dev_err(dev, "failed to ioremap SCMI Tx payload\n"); return -EADDRNOTAVAIL; } /* Transmit channel is first entry i.e. index 0 */ - info->tx_chan = mbox_request_channel(cl, 0); - if (IS_ERR(info->tx_chan)) { - ret = PTR_ERR(info->tx_chan); + cinfo->chan = mbox_request_channel(cl, 0); + if (IS_ERR(cinfo->chan)) { + ret = PTR_ERR(cinfo->chan); if (ret != -EPROBE_DEFER) dev_err(dev, "failed to request SCMI Tx mailbox\n"); return ret; @@ -779,7 +801,7 @@ static int scmi_probe(struct platform_device *pdev) ret = scmi_base_protocol_init(handle); if (ret) { dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); - scmi_mbox_free_channel(info); + scmi_mbox_free_channel(info->tx_cinfo); return ret; } From patchwork Mon Feb 12 18:45:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128150 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485401ljc; Mon, 12 Feb 2018 10:46:10 -0800 (PST) X-Google-Smtp-Source: AH8x225xE2iIRyCTpMQij15hyCVldv8AKqldV4cyj8w0UEgFBYTLAaN+ndgdI9+4kdMIuAknDf9y X-Received: by 2002:a17:902:9895:: with SMTP id s21-v6mr11405554plp.297.1518461170262; Mon, 12 Feb 2018 10:46:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461170; cv=none; d=google.com; s=arc-20160816; b=uEPvNuhauqtYTLHWbHWIN1eW0MDIN1CV8/2r67+iBzYjsZ1L2ox9mYshTptw0WHScp +W1hI7Hfm0XznvglVgYKwsOiHSSZKQ0DdUmCM+9cWGoLyYlj+AiwsH064sCDh/uJfedX hG364Y2o6pQZOZHvpf7u2A+f123U8EytIZ8u9A/s5/Z3LatBvhGyLpayZuWn6p6IcnLd uXZacMTHnfFkgVFr6Ussfdb5tuOmsyH+6EVZ7ojGLAATdLyDpiJYhvHqkbdLPQ93iCOB xVlrSENNlz9zNrJRGxKFKLxZffO1JTfbMSALp/TPtvWY9gA2YmuCSeOYfb3tKEyzdlrq SFCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=xYQbNrGEONISLjZ+srArLbTd41n8xqu4ioAduZjgdNk=; b=VQDjtFtHsw/rul0E55jQr2H2G/wnr0AiADgKl2zsregzJqxUUE3yMjC10hJlbQiz1Q gFBPTPzG0dIuOFhvdRKvIN4dmpj6tQYOxg0fCGVMkm3wUsR9XNTYWJKq9zeVX+qXoA6M UlBVQ96rIUka/J90I2upyaglrHcCo6QUGV0MtohXIkh8M9pp2aGB3yzmZqqtFFCZ8VWo T8RYCyPQ4OhM7W2jzjObR3KCOppZEhmP29GOettrRujLBItN37gLBB6L9wU3PuwuvWLX y37eSKgPIBXoHAvLNjt8lsKLD1Oa7+tQp/bH8YdJSrj0bhYdUQ30ydK60BsKsV/3e0d9 K3hg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s86si6665056pfd.327.2018.02.12.10.46.10; Mon, 12 Feb 2018 10:46:10 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754111AbeBLSqI (ORCPT + 6 others); Mon, 12 Feb 2018 13:46:08 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47278 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754052AbeBLSqH (ORCPT ); Mon, 12 Feb 2018 13:46:07 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id ACEFA1715; Mon, 12 Feb 2018 10:46:06 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 33F203F24D; Mon, 12 Feb 2018 10:46:05 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , Kevin Hilman Subject: [PATCH v5 15/20] firmware: arm_scmi: add device power domain support using genpd Date: Mon, 12 Feb 2018 18:45:19 +0000 Message-Id: <1518461124-17371-16-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This patch hooks up the support for device power domain provided by SCMI using the Linux generic power domain infrastructure. Cc: Kevin Hilman Reviewed-by: Ulf Hansson Signed-off-by: Sudeep Holla --- drivers/firmware/Kconfig | 13 +++ drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/scmi_pm_domain.c | 140 +++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 drivers/firmware/arm_scmi/scmi_pm_domain.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 704961e0473a..6e83880046d7 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -40,6 +40,19 @@ config ARM_SCMI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCMI. +config ARM_SCMI_POWER_DOMAIN + tristate "SCMI power domain driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCMI power domains which can be + enabled or disabled via the SCP firmware + + This driver can also be built as a module. If so, the module + will be called scmi_pm_domain. Note this may needed early in boot + before rootfs may be available. + config ARM_SCPI_PROTOCOL tristate "ARM System Control and Power Interface (SCPI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 3236890905b9..99e36c580fbc 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -2,3 +2,4 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-bus-y = bus.o scmi-driver-y = driver.o scmi-protocols-y = base.o clock.o perf.o power.o sensors.o +obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c new file mode 100644 index 000000000000..c03c06d3840a --- /dev/null +++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c @@ -0,0 +1,140 @@ +/* + * SCMI Generic power domain support. + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +struct scmi_pm_domain { + struct generic_pm_domain genpd; + const struct scmi_handle *handle; + const char *name; + u32 domain; +}; + +#define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd) + +static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + int ret; + u32 state, ret_state; + struct scmi_pm_domain *pd = to_scmi_pd(domain); + const struct scmi_power_ops *ops = pd->handle->power_ops; + + if (power_on) + state = SCMI_POWER_STATE_GENERIC_ON; + else + state = SCMI_POWER_STATE_GENERIC_OFF; + + ret = ops->state_set(pd->handle, pd->domain, state); + if (!ret) + ret = ops->state_get(pd->handle, pd->domain, &ret_state); + if (!ret && state != ret_state) + return -EIO; + + return ret; +} + +static int scmi_pd_power_on(struct generic_pm_domain *domain) +{ + return scmi_pd_power(domain, true); +} + +static int scmi_pd_power_off(struct generic_pm_domain *domain) +{ + return scmi_pd_power(domain, false); +} + +static int scmi_pm_domain_probe(struct scmi_device *sdev) +{ + int num_domains, i; + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + struct scmi_pm_domain *scmi_pd; + struct genpd_onecell_data *scmi_pd_data; + struct generic_pm_domain **domains; + const struct scmi_handle *handle = sdev->handle; + + if (!handle || !handle->power_ops) + return -ENODEV; + + num_domains = handle->power_ops->num_domains_get(handle); + if (num_domains < 0) { + dev_err(dev, "number of domains not found\n"); + return num_domains; + } + + scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL); + if (!scmi_pd) + return -ENOMEM; + + scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL); + if (!scmi_pd_data) + return -ENOMEM; + + domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + for (i = 0; i < num_domains; i++, scmi_pd++) { + u32 state; + + domains[i] = &scmi_pd->genpd; + + scmi_pd->domain = i; + scmi_pd->handle = handle; + scmi_pd->name = handle->power_ops->name_get(handle, i); + scmi_pd->genpd.name = scmi_pd->name; + scmi_pd->genpd.power_off = scmi_pd_power_off; + scmi_pd->genpd.power_on = scmi_pd_power_on; + + if (handle->power_ops->state_get(handle, i, &state)) { + dev_warn(dev, "failed to get state for domain %d\n", i); + continue; + } + + pm_genpd_init(&scmi_pd->genpd, NULL, + state == SCMI_POWER_STATE_GENERIC_OFF); + } + + scmi_pd_data->domains = domains; + scmi_pd_data->num_domains = num_domains; + + of_genpd_add_provider_onecell(np, scmi_pd_data); + + return 0; +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_POWER }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_power_domain_driver = { + .name = "scmi-power-domain", + .probe = scmi_pm_domain_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_power_domain_driver); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI power domain driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Feb 12 18:45:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128154 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485865ljc; Mon, 12 Feb 2018 10:46:53 -0800 (PST) X-Google-Smtp-Source: AH8x225ROOMgVFidZWfpK+D2G0zXeXE6LtEneecU8l/CuGVQFyJmWgaE231JRPp+JpM/XWboE2F0 X-Received: by 10.101.72.136 with SMTP id n8mr4413341pgs.201.1518461213232; Mon, 12 Feb 2018 10:46:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461213; cv=none; d=google.com; s=arc-20160816; b=DXjbhuLST/ZOZl0zDEHl1lhz7B9vFhATu+ZMGMzq11NC5oWmGN0uzgknOUyEX1KViU Pa7wQG29+cIMsi8yiG3Qtu5rifrQiM7i9tC4QExkezWWSHBuZcDCQD6f3vZGUgfg+Cy6 B25OeFnnfdJb1qvoJ9+27TQrV4Ur1HpFwCEgM8F6B/nR9G3DXLH3V5KdqmfKCicEgHbd i6hLsfeNXZBlRhyM/yF+A5aN3ZKSq7NpFVrh6bN5h9fzdZduuiiFcCiiar2I4hnF5Tmg WGhLwXSc9YlzaCF51eCC3OXvMq5f0XclUEfI0N7sqfqRdd5IBTKbj2KdUPLox9wD0E+N KjEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=n/5Y8o5aKCve4Ek3r64gByLgV8t3lh+DmpTKBEEQ3AY=; b=DnREX67mg84VCjHEc2OnpRwPmBzi7fRwbBURX9ot2E1c71s6BLm2pN3JoIRBtF6OyS 4VnK6uvvUIguDxz++5xwJdEugoSEyFFrnf0F3ID7xGEjDBr7Yoa6cF2bfEHC6W0d092x 3u6AB37Mu1FH79ONjnxHaH+mTfcr1ywe58/Lc71S/3RKdQZkP6EvXJUwckWo6zPK1zFr xGwWEsnXakfQBOWIg704B+eE6TpAHhNHZ8JabkchQ+u5B1CrOoESNH3u/Dbo+NeYL4Ql tuTf/1+voQtW6vr2jBXGUfXf31yhe08gY3YYv4G9Xqku//nbZPWXKYZXzRsspdNqTFPb 6vGQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c6si5464442pgn.681.2018.02.12.10.46.53; Mon, 12 Feb 2018 10:46:53 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932210AbeBLSqv (ORCPT + 6 others); Mon, 12 Feb 2018 13:46:51 -0500 Received: from foss.arm.com ([217.140.101.70]:47318 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754166AbeBLSqO (ORCPT ); Mon, 12 Feb 2018 13:46:14 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DD0391682; Mon, 12 Feb 2018 10:46:13 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (e107155-lin.cambridge.arm.com [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6403F3F24D; Mon, 12 Feb 2018 10:46:12 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , linux-pm@vger.kernel.org Subject: [PATCH v5 19/20] cpufreq: add support for CPU DVFS based on SCMI message protocol Date: Mon, 12 Feb 2018 18:45:23 +0000 Message-Id: <1518461124-17371-20-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> References: <1518461124-17371-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org On some ARM based systems, a separate Cortex-M based System Control Processor(SCP) provides the overall power, clock, reset and system control including CPU DVFS. SCMI Message Protocol is used to communicate with the SCP. This patch adds a cpufreq driver for such systems using SCMI interface to drive CPU DVFS. Cc: linux-pm@vger.kernel.org Acked-by: Rafael J. Wysocki Acked-by: Viresh Kumar Signed-off-by: Sudeep Holla --- MAINTAINERS | 2 +- drivers/cpufreq/Kconfig.arm | 21 ++++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/scmi-cpufreq.c | 249 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/scmi-cpufreq.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/MAINTAINERS b/MAINTAINERS index d6e9e3eae5ac..ef766eb17f8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13385,7 +13385,7 @@ L: linux-arm-kernel@lists.infradead.org S: Maintained F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt F: drivers/clk/clk-sc[mp]i.c -F: drivers/cpufreq/scpi-cpufreq.c +F: drivers/cpufreq/sc[mp]i-cpufreq.c F: drivers/firmware/arm_scpi.c F: drivers/firmware/arm_scmi/ F: include/linux/sc[mp]i_protocol.h diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 3a88e33b0cfe..4e1104b99f8b 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -238,6 +238,27 @@ config ARM_SA1100_CPUFREQ config ARM_SA1110_CPUFREQ bool +config ARM_SCMI_CPUFREQ + tristate "SCMI based CPUfreq driver" + depends on ARM_SCMI_PROTOCOL || COMPILE_TEST + select PM_OPP + help + This adds the CPUfreq driver support for ARM platforms using SCMI + protocol for CPU power management. + + This driver uses SCMI Message Protocol driver to interact with the + firmware providing the CPU DVFS functionality. + +config ARM_SCPI_CPUFREQ + tristate "SCPI based CPUfreq driver" + depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + help + This adds the CPUfreq driver support for ARM big.LITTLE platforms + using SCPI protocol for CPU power management. + + This driver uses SCPI Message Protocol driver to interact with the + firmware providing the CPU DVFS functionality. + config ARM_SPEAR_CPUFREQ bool "SPEAr CPUFreq support" depends on PLAT_SPEAR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index c60c1e141d9d..4987227b67df 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o +obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c new file mode 100644 index 000000000000..d6d35f7692b3 --- /dev/null +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -0,0 +1,249 @@ +/* + * System Control and Power Interface (SCMI) based CPUFreq Interface driver + * + * Copyright (C) 2017 ARM Ltd. + * Sudeep Holla + * + * 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 "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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct scmi_data { + int domain_id; + struct device *cpu_dev; + struct thermal_cooling_device *cdev; +}; + +static const struct scmi_handle *handle; + +static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct scmi_perf_ops *perf_ops = handle->perf_ops; + struct scmi_data *priv = policy->driver_data; + unsigned long rate; + int ret; + + ret = perf_ops->freq_get(handle, priv->domain_id, &rate, false); + if (ret) + return 0; + return rate / 1000; +} + +/* + * perf_ops->freq_set is not a synchronous, the actual OPP change will + * happen asynchronously and can get notified if the events are + * subscribed for by the SCMI firmware + */ +static int +scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + struct scmi_data *priv = policy->driver_data; + struct scmi_perf_ops *perf_ops = handle->perf_ops; + u64 freq = policy->freq_table[index].frequency * 1000; + + return perf_ops->freq_set(handle, priv->domain_id, freq, false); +} + +static int +scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) +{ + int cpu, domain, tdomain; + struct device *tcpu_dev; + + domain = handle->perf_ops->device_domain_id(cpu_dev); + if (domain < 0) + return domain; + + for_each_possible_cpu(cpu) { + if (cpu == cpu_dev->id) + continue; + + tcpu_dev = get_cpu_device(cpu); + if (!tcpu_dev) + continue; + + tdomain = handle->perf_ops->device_domain_id(tcpu_dev); + if (tdomain == domain) + cpumask_set_cpu(cpu, cpumask); + } + + return 0; +} + +static int scmi_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + unsigned int latency; + struct device *cpu_dev; + struct scmi_data *priv; + struct cpufreq_frequency_table *freq_table; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", policy->cpu); + return -ENODEV; + } + + ret = handle->perf_ops->add_opps_to_device(handle, cpu_dev); + if (ret) { + dev_warn(cpu_dev, "failed to add opps to the device\n"); + return ret; + } + + ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_warn(cpu_dev, "failed to get sharing cpumask\n"); + return ret; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); + return ret; + } + + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_free_opp; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out_free_priv; + } + + priv->cpu_dev = cpu_dev; + priv->domain_id = handle->perf_ops->device_domain_id(cpu_dev); + + policy->driver_data = priv; + + ret = cpufreq_table_validate_and_show(policy, freq_table); + if (ret) { + dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, + ret); + goto out_free_cpufreq_table; + } + + /* SCMI allows DVFS request for any domain from any CPU */ + policy->dvfs_possible_from_any_cpu = true; + + latency = handle->perf_ops->get_transition_latency(handle, cpu_dev); + if (!latency) + latency = CPUFREQ_ETERNAL; + + policy->cpuinfo.transition_latency = latency; + + return 0; + +out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); +out_free_priv: + kfree(priv); +out_free_opp: + dev_pm_opp_cpumask_remove_table(policy->cpus); + + return ret; +} + +static int scmi_cpufreq_exit(struct cpufreq_policy *policy) +{ + struct scmi_data *priv = policy->driver_data; + + cpufreq_cooling_unregister(priv->cdev); + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); + kfree(priv); + dev_pm_opp_cpumask_remove_table(policy->related_cpus); + + return 0; +} + +static void scmi_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct scmi_data *priv = policy->driver_data; + + priv->cdev = of_cpufreq_cooling_register(policy); +} + +static struct cpufreq_driver scmi_cpufreq_driver = { + .name = "scmi", + .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .attr = cpufreq_generic_attr, + .target_index = scmi_cpufreq_set_target, + .get = scmi_cpufreq_get_rate, + .init = scmi_cpufreq_init, + .exit = scmi_cpufreq_exit, + .ready = scmi_cpufreq_ready, +}; + +static int scmi_cpufreq_probe(struct scmi_device *sdev) +{ + int ret; + + handle = sdev->handle; + + if (!handle || !handle->perf_ops) + return -ENODEV; + + ret = cpufreq_register_driver(&scmi_cpufreq_driver); + if (ret) { + dev_err(&sdev->dev, "%s: registering cpufreq failed, err: %d\n", + __func__, ret); + } + + return ret; +} + +static void scmi_cpufreq_remove(struct scmi_device *sdev) +{ + cpufreq_unregister_driver(&scmi_cpufreq_driver); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_PERF }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_cpufreq_drv = { + .name = "scmi-cpufreq", + .probe = scmi_cpufreq_probe, + .remove = scmi_cpufreq_remove, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_cpufreq_drv); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI CPUFreq interface driver"); +MODULE_LICENSE("GPL v2");