From patchwork Mon Feb 12 18:45:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128147 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485187ljc; Mon, 12 Feb 2018 10:45:54 -0800 (PST) X-Google-Smtp-Source: AH8x227nkH1T7h8rrxINk9/BvJwZ8whCw0B34S4kg67t0x5K+gCL7QqFa3YzymMsGVIWySYVK7XZ X-Received: by 2002:a17:902:5305:: with SMTP id b5-v6mr11280150pli.61.1518461154226; Mon, 12 Feb 2018 10:45:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461154; cv=none; d=google.com; s=arc-20160816; b=RI5ox+cw5lZGKvXmEbKGiruDW7AZfoUOK+BSjT67NTqU8h5JpwBhCRTa5/YeBzVn4K FOjr9CpDj2ff94HpU6M/41gfTdaDxNxRWmfIv1SIQn6HQN2V5/78CjxGNclVOeZXbZ3V rzRuVMb1tBwlHm3ahPDrssDljj/L5FBQgDK7nSvLlfCHj6x+bvbpd4al2tR6Vs4eX6Tu rwOGnLN/F6HaukNKfFQszSkkPnO0rIJ+e/+65TRmhHG4vt1cHZE600PQHku4RHKRoY46 x/8nGO1xnggy1y04pvwOyrzCUvuMEqaYFsgVyuxblpeYEEV2Tfvf8n6Lvk1BqzQWKAcd jcfQ== 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=q3UXyp+tnqviAHY2DeuyyRpdyMaApC+pjq/q5ocp9lw=; b=kVduTnt2UxRm+E7KOxoUMmUnI4BElTzxu7MBaAycxYQ8N51whffb1PtuW9X1qBmdwv XZHYfDBBbuZz2ncQSos8FxCt42BmNRoupoXSREvDHuL+XlehFgc1lrvzI8V7N27/LLJf 9H7V8DIH+a7WDBf4Mc3vqZu1XLIxtsdQgCyTvLS5WkLsAcn79wkWKwpqfo9t4TzaaN16 AThWytrLVaSeKoNEHGz2QJ04mf1MFFpS7FpKgE9l3YZ7jXZ9+kNy/a27O6XX8c2076og znWlUY65nB+T3k0zNnM821oZwQE8S9iySDagJdvKDGhm2ZjMIUPIZ0EkMI18sO48/Kwp v2nw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.53; Mon, 12 Feb 2018 10:45:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753971AbeBLSpq (ORCPT + 26 others); Mon, 12 Feb 2018 13:45:46 -0500 Received: from foss.arm.com ([217.140.101.70]:47106 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753588AbeBLSpo (ORCPT ); Mon, 12 Feb 2018 13:45:44 -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 B7E5E164F; Mon, 12 Feb 2018 10:45:43 -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 3ED713F24D; Mon, 12 Feb 2018 10:45:42 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , Mark Rutland Subject: [PATCH v5 01/20] dt-bindings: mailbox: add support for mailbox client shared memory Date: Mon, 12 Feb 2018 18:45:05 +0000 Message-Id: <1518461124-17371-2-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Many users of the mailbox controllers depend on the shared memory between the two end points to exchange the main data while using simple doorbell mechanism to alert the end points of the presence of a message. This patch defines device tree bindings to represent such shared memory in a generic way. Cc: Mark Rutland Acked-by: Rob Herring Signed-off-by: Sudeep Holla --- .../devicetree/bindings/mailbox/mailbox.txt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) -- 2.7.4 diff --git a/Documentation/devicetree/bindings/mailbox/mailbox.txt b/Documentation/devicetree/bindings/mailbox/mailbox.txt index be05b9746c69..af8ecee2ac68 100644 --- a/Documentation/devicetree/bindings/mailbox/mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/mailbox.txt @@ -23,6 +23,11 @@ assign appropriate mailbox channel to client drivers. Optional property: - mbox-names: List of identifier strings for each mailbox channel. +- shmem : List of phandle pointing to the shared memory(SHM) area between the + users of these mailboxes for IPC, one for each mailbox. This shared + memory can be part of any memory reserved for the purpose of this + communication between the mailbox client and the remote. + Example: pwr_cntrl: power { @@ -30,3 +35,26 @@ assign appropriate mailbox channel to client drivers. mbox-names = "pwr-ctrl", "rpc"; mboxes = <&mailbox 0 &mailbox 1>; }; + +Example with shared memory(shmem): + + sram: sram@50000000 { + compatible = "mmio-sram"; + reg = <0x50000000 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x50000000 0x10000>; + + cl_shmem: shmem@0 { + compatible = "client-shmem"; + reg = <0x0 0x200>; + }; + }; + + client@2e000000 { + ... + mboxes = <&mailbox 0>; + shmem = <&cl_shmem>; + .. + }; From patchwork Mon Feb 12 18:45:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128166 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3489271ljc; Mon, 12 Feb 2018 10:51:49 -0800 (PST) X-Google-Smtp-Source: AH8x227uhxOjK6LZtxdYnRgb8DEn0HOTh9nYtDxUDabzaYXlG2oKKZ4by8UMJkM3UE1dszB5dOi2 X-Received: by 10.101.91.66 with SMTP id y2mr10298380pgr.11.1518461509381; Mon, 12 Feb 2018 10:51:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461509; cv=none; d=google.com; s=arc-20160816; b=qW8RUGzdBLhURlqruap1pK7F6ZQU9s1szEormLweBpyHmkKAg/IfC6OuW9koQ4Rpqp yNtFF5nQjzeuEQM8LvUoYJL1c6hC+3C8p9tKfyiqKytGXZIOmVEGxltqGYJqzCohlni5 F5/OwJcULZtxidgDnSyqdb8wDqzQ6oXlCLSkVP5+7PThrnio1u6qlBonTMbymvNMY6cj Np1bCGRaiW2WQeghxTC9Itwe6HSkeYuF4a9NcmJE3fqP0OQZb9Ggy29yGhQgTI8ycnI/ o4TeuSmJe8xLGIhi3hKd1P+piO9CLDfh6WgN3vvT/M2slKe0YGx8vlMGoDcIF0xhqklp 9f/w== 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=iZDiToIH9Y2S2yJlposRe/FLeOXW3XNTrNYPD4PRUOM=; b=1A+V+u1DZMaNZ7Kd4tezpVtdbKWQuKairCg+28H+0NGyPyfAfQnD6tmP82ORniO+wn xUiNHuhobcGppyPjGVpxTu504TtB7aYUclDxs3enR9OL//XELzEfu1h6EZhLLsln/nrq rO6Lpok/MB6/75BDAs/8Cf7cfKvZj63yR2BvCxH/T/Duu/d40fQRu8SlHkW9MBS43mGv YQiqT1Kec8D00BsiEgYpa9RoC1RPWECIPGGEUp/cVxmFrsuPNg3iUMJRXtiEZ/jR+tK+ SY8K/y1Z3mw5DaBuZKPjTyRdAM43H1rqE7rRpa4ah9HuxoJ1stebfiE5d44xMe4Zo++p P5ig== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 k12si5443871pgt.734.2018.02.12.10.51.49; Mon, 12 Feb 2018 10:51:49 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754097AbeBLSvq (ORCPT + 26 others); Mon, 12 Feb 2018 13:51:46 -0500 Received: from foss.arm.com ([217.140.101.70]:47108 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753920AbeBLSpp (ORCPT ); Mon, 12 Feb 2018 13:45:45 -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 7BCB9165C; Mon, 12 Feb 2018 10:45:45 -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 02C533F24D; Mon, 12 Feb 2018 10:45:43 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , Mark Rutland Subject: [PATCH v5 02/20] dt-bindings: arm: add support for ARM System Control and Management Interface(SCMI) protocol Date: Mon, 12 Feb 2018 18:45:06 +0000 Message-Id: <1518461124-17371-3-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds devicetree binding for System Control and Management Interface (SCMI) Message Protocol used between the Application Cores(AP) and the System Control Processor(SCP). The MHU peripheral provides a mechanism for inter-processor communication between SCP's M3 processor and AP. SCP offers control and management of the core/cluster power states, various power domain DVFS including the core/cluster, certain system clocks configuration, thermal sensors and many others. SCMI protocol is developed as better replacement to the existing SCPI which is not flexible and easily extensible. Cc: Mark Rutland Acked-by: Rob Herring Signed-off-by: Sudeep Holla --- Documentation/devicetree/bindings/arm/arm,scmi.txt | 179 +++++++++++++++++++++ MAINTAINERS | 4 +- 2 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/arm,scmi.txt -- 2.7.4 diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt new file mode 100644 index 000000000000..5f3719ab7075 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -0,0 +1,179 @@ +System Control and Management Interface (SCMI) Message Protocol +---------------------------------------------------------- + +The SCMI is intended to allow agents such as OSPM to manage various functions +that are provided by the hardware platform it is running on, including power +and performance functions. + +This binding is intended to define the interface the firmware implementing +the SCMI as described in ARM document number ARM DUI 0922B ("ARM System Control +and Management Interface Platform Design Document")[0] provide for OSPM in +the device tree. + +Required properties: + +The scmi node with the following properties shall be under the /firmware/ node. + +- compatible : shall be "arm,scmi" +- mboxes: List of phandle and mailbox channel specifiers. It should contain + exactly one or two mailboxes, one for transmitting messages("tx") + and another optional for receiving the notifications("rx") if + supported. +- shmem : List of phandle pointing to the shared memory(SHM) area as per + generic mailbox client binding. +- #address-cells : should be '1' if the device has sub-nodes, maps to + protocol identifier for a given sub-node. +- #size-cells : should be '0' as 'reg' property doesn't have any size + associated with it. + +Optional properties: + +- mbox-names: shall be "tx" or "rx" depending on mboxes entries. + +See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details +about the generic mailbox controller and client driver bindings. + +The mailbox is the only permitted method of calling the SCMI firmware. +Mailbox doorbell is used as a mechanism to alert the presence of a +messages and/or notification. + +Each protocol supported shall have a sub-node with corresponding compatible +as described in the following sections. If the platform supports dedicated +communication channel for a particular protocol, the 3 properties namely: +mboxes, mbox-names and shmem shall be present in the sub-node corresponding +to that protocol. + +Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol +------------------------------------------------------------ + +This binding uses the common clock binding[1]. + +Required properties: +- #clock-cells : Should be 1. Contains the Clock ID value used by SCMI commands. + +Power domain bindings for the power domains based on SCMI Message Protocol +------------------------------------------------------------ + +This binding for the SCMI power domain providers uses the generic power +domain binding[2]. + +Required properties: + - #power-domain-cells : Should be 1. Contains the device or the power + domain ID value used by SCMI commands. + +Sensor bindings for the sensors based on SCMI Message Protocol +-------------------------------------------------------------- +SCMI provides an API to access the various sensors on the SoC. + +Required properties: +- #thermal-sensor-cells: should be set to 1. This property follows the + thermal device tree bindings[3]. + + Valid cell values are raw identifiers (Sensor ID) + as used by the firmware. Refer to platform details + for your implementation for the IDs to use. + +SRAM and Shared Memory for SCMI +------------------------------- + +A small area of SRAM is reserved for SCMI communication between application +processors and SCP. + +The properties should follow the generic mmio-sram description found in [4] + +Each sub-node represents the reserved area for SCMI. + +Required sub-node properties: +- reg : The base offset and size of the reserved area with the SRAM +- compatible : should be "arm,scmi-shmem" for Non-secure SRAM based + shared memory + +[0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/power/power_domain.txt +[3] Documentation/devicetree/bindings/thermal/thermal.txt +[4] Documentation/devicetree/bindings/sram/sram.txt + +Example: + +sram@50000000 { + compatible = "mmio-sram"; + reg = <0x0 0x50000000 0x0 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x50000000 0x10000>; + + cpu_scp_lpri: scp-shmem@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x200>; + }; + + cpu_scp_hpri: scp-shmem@200 { + compatible = "arm,scmi-shmem"; + reg = <0x200 0x200>; + }; +}; + +mailbox@40000000 { + .... + #mbox-cells = <1>; + reg = <0x0 0x40000000 0x0 0x10000>; +}; + +firmware { + + ... + + scmi { + compatible = "arm,scmi"; + mboxes = <&mailbox 0 &mailbox 1>; + mbox-names = "tx", "rx"; + shmem = <&cpu_scp_lpri &cpu_scp_hpri>; + #address-cells = <1>; + #size-cells = <0>; + + scmi_devpd: protocol@11 { + reg = <0x11>; + #power-domain-cells = <1>; + }; + + scmi_dvfs: protocol@13 { + reg = <0x13>; + #clock-cells = <1>; + }; + + scmi_clk: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + + scmi_sensors0: protocol@15 { + reg = <0x15>; + #thermal-sensor-cells = <1>; + }; + }; +}; + +cpu@0 { + ... + reg = <0 0>; + clocks = <&scmi_dvfs 0>; +}; + +hdlcd@7ff60000 { + ... + reg = <0 0x7ff60000 0 0x1000>; + clocks = <&scmi_clk 4>; + power-domains = <&scmi_devpd 1>; +}; + +thermal-zones { + soc_thermal { + polling-delay-passive = <100>; + polling-delay = <1000>; + /* sensor ID */ + thermal-sensors = <&scmi_sensors0 3>; + ... + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..5c8c55ba22a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13379,11 +13379,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git S: Supported F: drivers/mfd/syscon.c -SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers +SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers M: Sudeep Holla L: linux-arm-kernel@lists.infradead.org S: Maintained -F: Documentation/devicetree/bindings/arm/arm,scpi.txt +F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt F: drivers/clk/clk-scpi.c F: drivers/cpufreq/scpi-cpufreq.c F: drivers/firmware/arm_scpi.c From patchwork Mon Feb 12 18:45:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128149 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485268ljc; Mon, 12 Feb 2018 10:46:01 -0800 (PST) X-Google-Smtp-Source: AH8x2254/3Vmh1cMjsx1MRrRjMC2Gz8oM3CsTw9iRtK36E2FMzyhBgbG2CsmYTMFjZ0gyjxzXysT X-Received: by 10.98.227.8 with SMTP id g8mr12509585pfh.200.1518461161176; Mon, 12 Feb 2018 10:46:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461161; cv=none; d=google.com; s=arc-20160816; b=oekztVwqxbIiOzcy5kmGwi8jOQOLDXt19xBwLmaJftMHL+nhReKovbDuOQ0jqpuTJO msaru6EObUrg78dXmw7oD+ncuKDVz9bviN1J6AJVa+DeL7NaA3RldZ+wI3kCaKCfe8V5 DFE9FiAoEZzrxpoqoPA/er38r57yH3/0X+fo3AC+34Y5ufdtkjCYrCS8h8KnV0dFi5Gb dQwt1EvtY8gHogH5rLgbmtb0UFb1rmVOrQyxd3MZY5nTuqAo1/GYuKDq+CD4rcgCogIs gyoLlO74fC0qazBmGLx6eYytcProCPnmssZW1reexeC5F4tz2omjm5M6s0gfsUlKcxQb FPfw== 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=BkI01S+MxWv+toIUy47AtXAmZuye9kZuVbTR9mZGsnk=; b=QDiJTyetpgDCgdIl5kyd8nW5FPImvVGH2o+zapKB8963/EVVyi82I7OMD2ejzQ7Fpp lQCWApy0CahcbxMjQTQBGwCuHPqNETkii3O+MnDs/gmGKsIdRBpL6H9NCo0J5d99hnpP DPBK+NODyiIq9esbMvDs2zSXO8tNJgpSPzlnqi/Z2GKroqoPb8Qvcr5uhvIlCPGhd8Yi eMlgThUv3boiVfa1XHHrh0IeDpIWGNnobDKObwsws6PbuJPzetGl1rO03tMJrNvzmdjr BSFE1SHAH2Jy/MDn8KvpR8lI9XdkrLGjYhILhzHIpORYZDXAHHg9F0i456yjjJwNojEm Fssw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 r69si2513064pgr.678.2018.02.12.10.46.00; Mon, 12 Feb 2018 10:46:01 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754060AbeBLSpz (ORCPT + 26 others); Mon, 12 Feb 2018 13:45:55 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47134 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753588AbeBLSpr (ORCPT ); Mon, 12 Feb 2018 13:45:47 -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 4007C165D; Mon, 12 Feb 2018 10:45:47 -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 BAD833F24D; Mon, 12 Feb 2018 10:45:45 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 03/20] firmware: arm_scmi: add basic driver infrastructure for SCMI Date: Mon, 12 Feb 2018 18:45:07 +0000 Message-Id: <1518461124-17371-4-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The SCMI is intended to allow OSPM to manage various functions that are provided by the hardware platform it is running on, including power and performance functions. SCMI provides two levels of abstraction, protocols and transports. Protocols define individual groups of system control and management messages. A protocol specification describes the messages that it supports. Transports describe the method by which protocol messages are communicated between agents and the platform. This patch adds basic infrastructure to manage the message allocation, initialisation, packing/unpacking and shared memory management. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- MAINTAINERS | 3 +- drivers/firmware/Kconfig | 21 ++ drivers/firmware/Makefile | 1 + drivers/firmware/arm_scmi/Makefile | 2 + drivers/firmware/arm_scmi/common.h | 77 +++++ drivers/firmware/arm_scmi/driver.c | 689 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 27 ++ 7 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/Makefile create mode 100644 drivers/firmware/arm_scmi/common.h create mode 100644 drivers/firmware/arm_scmi/driver.c create mode 100644 include/linux/scmi_protocol.h -- 2.7.4 diff --git a/MAINTAINERS b/MAINTAINERS index 5c8c55ba22a3..7cede6e7dfed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13387,7 +13387,8 @@ F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt F: drivers/clk/clk-scpi.c F: drivers/cpufreq/scpi-cpufreq.c F: drivers/firmware/arm_scpi.c -F: include/linux/scpi_protocol.h +F: drivers/firmware/arm_scmi/ +F: include/linux/sc[mp]i_protocol.h SYSTEM RESET/SHUTDOWN DRIVERS M: Sebastian Reichel diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b7c748248e53..704961e0473a 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -19,6 +19,27 @@ config ARM_PSCI_CHECKER on and off through hotplug, so for now torture tests and PSCI checker are mutually exclusive. +config ARM_SCMI_PROTOCOL + bool "ARM System Control and Management Interface (SCMI) Message Protocol" + depends on ARM || ARM64 || COMPILE_TEST + depends on MAILBOX + help + ARM System Control and Management Interface (SCMI) protocol is a + set of operating system-independent software interfaces that are + used in system management. SCMI is extensible and currently provides + interfaces for: Discovery and self-description of the interfaces + it supports, Power domain management which is the ability to place + a given device or domain into the various power-saving states that + it supports, Performance management which is the ability to control + the performance of a domain that is composed of compute engines + such as application processors and other accelerators, Clock + management which is the ability to set and inquire rates on platform + managed clocks and Sensor management which is the ability to read + sensor data, and be notified of sensor value. + + This protocol library provides interface for all the client drivers + making use of the features offered by the SCMI. + 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/Makefile b/drivers/firmware/Makefile index b248238ddc6a..e18a041cfc53 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o +obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/ obj-y += broadcom/ obj-y += meson/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile new file mode 100644 index 000000000000..b2a24ba2b636 --- /dev/null +++ b/drivers/firmware/arm_scmi/Makefile @@ -0,0 +1,2 @@ +obj-y = scmi-driver.o +scmi-driver-y = driver.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h new file mode 100644 index 000000000000..cdfc43427c3c --- /dev/null +++ b/drivers/firmware/arm_scmi/common.h @@ -0,0 +1,77 @@ +/* + * System Control and Management Interface (SCMI) Message Protocol + * driver common header file containing some definitions, structures + * and function prototypes used in all the different SCMI protocols. + * + * 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 + +/** + * struct scmi_msg_hdr - Message(Tx/Rx) header + * + * @id: The identifier of the command being sent + * @protocol_id: The identifier of the protocol used to send @id command + * @seq: The token to identify the message. when a message/command returns, + * the platform returns the whole message header unmodified including + * the token. + */ +struct scmi_msg_hdr { + u8 id; + u8 protocol_id; + u16 seq; + u32 status; + bool poll_completion; +}; + +/** + * struct scmi_msg - Message(Tx/Rx) structure + * + * @buf: Buffer pointer + * @len: Length of data in the Buffer + */ +struct scmi_msg { + void *buf; + size_t len; +}; + +/** + * struct scmi_xfer - Structure representing a message flow + * + * @hdr: Transmit message header + * @tx: Transmit message + * @rx: Receive message, the buffer should be pre-allocated to store + * message. If request-ACK protocol is used, we can reuse the same + * buffer for the rx path as we use for the tx path. + * @done: completion event + */ + +struct scmi_xfer { + void *con_priv; + struct scmi_msg_hdr hdr; + struct scmi_msg tx; + struct scmi_msg rx; + struct completion done; +}; + +void scmi_one_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer); +int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer); +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); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c new file mode 100644 index 000000000000..37472a9a1c8b --- /dev/null +++ b/drivers/firmware/arm_scmi/driver.c @@ -0,0 +1,689 @@ +/* + * System Control and Management Interface (SCMI) Message Protocol driver + * + * SCMI Message Protocol is used between the System Control Processor(SCP) + * and the Application Processors(AP). The Message Handling Unit(MHU) + * provides a mechanism for inter-processor communication between SCP's + * Cortex M3 and AP. + * + * SCP offers control and management of the core/cluster power states, + * various power domain DVFS including the core/cluster, certain system + * clocks configuration, thermal sensors and many others. + * + * 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 +#include +#include +#include +#include +#include + +#include "common.h" + +#define MSG_ID_SHIFT 0 +#define MSG_ID_MASK 0xff +#define MSG_TYPE_SHIFT 8 +#define MSG_TYPE_MASK 0x3 +#define MSG_PROTOCOL_ID_SHIFT 10 +#define MSG_PROTOCOL_ID_MASK 0xff +#define MSG_TOKEN_ID_SHIFT 18 +#define MSG_TOKEN_ID_MASK 0x3ff +#define MSG_XTRACT_TOKEN(header) \ + (((header) >> MSG_TOKEN_ID_SHIFT) & MSG_TOKEN_ID_MASK) + +enum scmi_error_codes { + SCMI_SUCCESS = 0, /* Success */ + SCMI_ERR_SUPPORT = -1, /* Not supported */ + SCMI_ERR_PARAMS = -2, /* Invalid Parameters */ + SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */ + SCMI_ERR_ENTRY = -4, /* Not found */ + SCMI_ERR_RANGE = -5, /* Value out of range */ + SCMI_ERR_BUSY = -6, /* Device busy */ + SCMI_ERR_COMMS = -7, /* Communication Error */ + SCMI_ERR_GENERIC = -8, /* Generic Error */ + SCMI_ERR_HARDWARE = -9, /* Hardware Error */ + SCMI_ERR_PROTOCOL = -10,/* Protocol Error */ + SCMI_ERR_MAX +}; + +/* List of all SCMI devices active in system */ +static LIST_HEAD(scmi_list); +/* Protection for the entire list */ +static DEFINE_MUTEX(scmi_list_mutex); + +/** + * struct scmi_xfers_info - Structure to manage transfer information + * + * @xfer_block: Preallocated Message array + * @xfer_alloc_table: Bitmap table for allocated messages. + * Index of this bitmap table is also used for message + * sequence identifier. + * @xfer_lock: Protection for message allocation + */ +struct scmi_xfers_info { + struct scmi_xfer *xfer_block; + unsigned long *xfer_alloc_table; + /* protect transfer allocation */ + spinlock_t xfer_lock; +}; + +/** + * struct scmi_desc - Description of SoC integration + * + * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) + * @max_msg: Maximum number of messages that can be pending + * simultaneously in the system + * @max_msg_size: Maximum size of data per message that can be handled. + */ +struct scmi_desc { + int max_rx_timeout_ms; + int max_msg; + int max_msg_size; +}; + +/** + * struct scmi_info - Structure representing a SCMI instance + * + * @dev: Device pointer + * @desc: SoC description for this instance + * @handle: Instance of SCMI handle to send to clients + * @cl: Mailbox Client + * @tx_chan: Transmit mailbox channel + * @tx_payload: Transmit mailbox channel payload area + * @minfo: Message info + * @node: list head + * @users: Number of users of this instance + */ +struct scmi_info { + struct device *dev; + const struct scmi_desc *desc; + struct scmi_handle handle; + struct mbox_client cl; + struct mbox_chan *tx_chan; + void __iomem *tx_payload; + struct scmi_xfers_info minfo; + struct list_head node; + int users; +}; + +#define client_to_scmi_info(c) container_of(c, struct scmi_info, cl) +#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) + +/* + * SCMI specification requires all parameters, message headers, return + * arguments or any protocol data to be expressed in little endian + * format only. + */ +struct scmi_shared_mem { + __le32 reserved; + __le32 channel_status; +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) +#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) + __le32 reserved1[2]; + __le32 flags; +#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) + __le32 length; + __le32 msg_header; + u8 msg_payload[0]; +}; + +static const int scmi_linux_errmap[] = { + /* better than switch case as long as return value is continuous */ + 0, /* SCMI_SUCCESS */ + -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */ + -EINVAL, /* SCMI_ERR_PARAM */ + -EACCES, /* SCMI_ERR_ACCESS */ + -ENOENT, /* SCMI_ERR_ENTRY */ + -ERANGE, /* SCMI_ERR_RANGE */ + -EBUSY, /* SCMI_ERR_BUSY */ + -ECOMM, /* SCMI_ERR_COMMS */ + -EIO, /* SCMI_ERR_GENERIC */ + -EREMOTEIO, /* SCMI_ERR_HARDWARE */ + -EPROTO, /* SCMI_ERR_PROTOCOL */ +}; + +static inline int scmi_to_linux_errno(int errno) +{ + if (errno < SCMI_SUCCESS && errno > SCMI_ERR_MAX) + return scmi_linux_errmap[-errno]; + return -EIO; +} + +/** + * scmi_dump_header_dbg() - Helper to dump a message header. + * + * @dev: Device pointer corresponding to the SCMI entity + * @hdr: pointer to header. + */ +static inline void scmi_dump_header_dbg(struct device *dev, + struct scmi_msg_hdr *hdr) +{ + dev_dbg(dev, "Command ID: %x Sequence ID: %x Protocol: %x\n", + hdr->id, hdr->seq, hdr->protocol_id); +} + +static void scmi_fetch_response(struct scmi_xfer *xfer, + struct scmi_shared_mem __iomem *mem) +{ + xfer->hdr.status = ioread32(mem->msg_payload); + /* Skip the length of header and statues in payload area i.e 8 bytes*/ + xfer->rx.len = min_t(size_t, xfer->rx.len, ioread32(&mem->length) - 8); + + /* Take a copy to the rx buffer.. */ + memcpy_fromio(xfer->rx.buf, mem->msg_payload + 4, xfer->rx.len); +} + +/** + * scmi_rx_callback() - mailbox client callback for receive messages + * + * @cl: client pointer + * @m: mailbox message + * + * Processes one received message to appropriate transfer information and + * signals completion of the transfer. + * + * NOTE: This function will be invoked in IRQ context, hence should be + * as optimal as possible. + */ +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_xfers_info *minfo = &info->minfo; + struct device *dev = info->dev; + struct scmi_shared_mem __iomem *mem = info->tx_payload; + + xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); + + /* + * Are we even expecting this? + */ + if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { + dev_err(dev, "message for %d is not expected!\n", xfer_id); + return; + } + + xfer = &minfo->xfer_block[xfer_id]; + + scmi_dump_header_dbg(dev, &xfer->hdr); + /* Is the message of valid length? */ + if (xfer->rx.len > info->desc->max_msg_size) { + dev_err(dev, "unable to handle %zu xfer(max %d)\n", + xfer->rx.len, info->desc->max_msg_size); + return; + } + + scmi_fetch_response(xfer, mem); + complete(&xfer->done); +} + +/** + * pack_scmi_header() - packs and returns 32-bit header + * + * @hdr: pointer to header containing all the information on message id, + * protocol id and sequence id. + */ +static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) +{ + return ((hdr->id & MSG_ID_MASK) << MSG_ID_SHIFT) | + ((hdr->seq & MSG_TOKEN_ID_MASK) << MSG_TOKEN_ID_SHIFT) | + ((hdr->protocol_id & MSG_PROTOCOL_ID_MASK) << MSG_PROTOCOL_ID_SHIFT); +} + +/** + * scmi_tx_prepare() - mailbox client callback to prepare for the transfer + * + * @cl: client pointer + * @m: mailbox message + * + * This function prepares the shared memory which contains the header and the + * payload. + */ +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; + + /* Mark channel busy + clear error */ + iowrite32(0x0, &mem->channel_status); + iowrite32(t->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, + &mem->flags); + iowrite32(sizeof(mem->msg_header) + t->tx.len, &mem->length); + iowrite32(pack_scmi_header(&t->hdr), &mem->msg_header); + if (t->tx.buf) + memcpy_toio(mem->msg_payload, t->tx.buf, t->tx.len); +} + +/** + * scmi_one_xfer_get() - Allocate one message + * + * @handle: SCMI entity handle + * + * Helper function which is used by various command functions that are + * exposed to clients of this driver for allocating a message traffic event. + * + * This function can sleep depending on pending requests already in the system + * for the SCMI entity. Further, this also holds a spinlock to maintain + * integrity of internal data structures. + * + * Return: 0 if all went fine, else corresponding error. + */ +static struct scmi_xfer *scmi_one_xfer_get(const struct scmi_handle *handle) +{ + u16 xfer_id; + struct scmi_xfer *xfer; + unsigned long flags, bit_pos; + struct scmi_info *info = handle_to_scmi_info(handle); + struct scmi_xfers_info *minfo = &info->minfo; + + /* Keep the locked section as small as possible */ + spin_lock_irqsave(&minfo->xfer_lock, flags); + bit_pos = find_first_zero_bit(minfo->xfer_alloc_table, + info->desc->max_msg); + if (bit_pos == info->desc->max_msg) { + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + return ERR_PTR(-ENOMEM); + } + set_bit(bit_pos, minfo->xfer_alloc_table); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + + xfer_id = bit_pos; + + xfer = &minfo->xfer_block[xfer_id]; + xfer->hdr.seq = xfer_id; + reinit_completion(&xfer->done); + + return xfer; +} + +/** + * scmi_one_xfer_put() - Release a message + * + * @minfo: transfer info pointer + * @xfer: message that was reserved by scmi_one_xfer_get + * + * This holds a spinlock to maintain integrity of internal data structures. + */ +void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +{ + unsigned long flags; + struct scmi_info *info = handle_to_scmi_info(handle); + struct scmi_xfers_info *minfo = &info->minfo; + + /* + * Keep the locked section as small as possible + * NOTE: we might escape with smp_mb and no lock here.. + * but just be conservative and symmetric. + */ + spin_lock_irqsave(&minfo->xfer_lock, flags); + clear_bit(xfer->hdr.seq, minfo->xfer_alloc_table); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); +} + +/** + * scmi_do_xfer() - Do one transfer + * + * @info: Pointer to SCMI entity information + * @xfer: Transfer to initiate and wait for response + * + * Return: -ETIMEDOUT in case of no response, if transmit error, + * return corresponding error, else if all goes well, + * return 0. + */ +int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) +{ + int ret; + int timeout; + struct scmi_info *info = handle_to_scmi_info(handle); + struct device *dev = info->dev; + + ret = mbox_send_message(info->tx_chan, xfer); + if (ret < 0) { + dev_dbg(dev, "mbox send fail %d\n", ret); + return ret; + } + + /* mbox_send_message returns non-negative value on success, so reset */ + ret = 0; + + /* And we wait for the response. */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); + if (!wait_for_completion_timeout(&xfer->done, timeout)) { + dev_err(dev, "mbox timed out in resp(caller: %pF)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; + } else if (xfer->hdr.status) { + ret = scmi_to_linux_errno(xfer->hdr.status); + } + /* + * NOTE: we might prefer not to need the mailbox ticker to manage the + * transfer queueing since the protocol layer queues things by itself. + * Unfortunately, we have to kick the mailbox framework after we have + * received our message. + */ + mbox_client_txdone(info->tx_chan, ret); + + return ret; +} + +/** + * scmi_one_xfer_init() - Allocate and initialise one message + * + * @handle: SCMI entity handle + * @msg_id: Message identifier + * @msg_prot_id: Protocol identifier for the message + * @tx_size: transmit message size + * @rx_size: receive message size + * @p: pointer to the allocated and initialised message + * + * This function allocates the message using @scmi_one_xfer_get and + * initialise the header. + * + * Return: 0 if all went fine with @p pointing to message, else + * corresponding error. + */ +int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, + size_t tx_size, size_t rx_size, struct scmi_xfer **p) +{ + int ret; + struct scmi_xfer *xfer; + struct scmi_info *info = handle_to_scmi_info(handle); + struct device *dev = info->dev; + + /* Ensure we have sane transfer sizes */ + if (rx_size > info->desc->max_msg_size || + tx_size > info->desc->max_msg_size) + return -ERANGE; + + xfer = scmi_one_xfer_get(handle); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "failed to get free message slot(%d)\n", ret); + return ret; + } + + xfer->tx.len = tx_size; + xfer->rx.len = rx_size ? : info->desc->max_msg_size; + xfer->hdr.id = msg_id; + xfer->hdr.protocol_id = prot_id; + xfer->hdr.poll_completion = false; + + *p = xfer; + return 0; +} + +/** + * scmi_handle_get() - Get the SCMI handle for a device + * + * @dev: pointer to device for which we want SCMI handle + * + * NOTE: The function does not track individual clients of the framework + * and is expected to be maintained by caller of SCMI protocol library. + * scmi_handle_put must be balanced with successful scmi_handle_get + * + * Return: pointer to handle if successful, NULL on error + */ +struct scmi_handle *scmi_handle_get(struct device *dev) +{ + struct list_head *p; + struct scmi_info *info; + struct scmi_handle *handle = NULL; + + mutex_lock(&scmi_list_mutex); + list_for_each(p, &scmi_list) { + info = list_entry(p, struct scmi_info, node); + if (dev->parent == info->dev) { + handle = &info->handle; + info->users++; + break; + } + } + mutex_unlock(&scmi_list_mutex); + + return handle; +} + +/** + * scmi_handle_put() - Release the handle acquired by scmi_handle_get + * + * @handle: handle acquired by scmi_handle_get + * + * NOTE: The function does not track individual clients of the framework + * and is expected to be maintained by caller of SCMI protocol library. + * scmi_handle_put must be balanced with successful scmi_handle_get + * + * Return: 0 is successfully released + * if null was passed, it returns -EINVAL; + */ +int scmi_handle_put(const struct scmi_handle *handle) +{ + struct scmi_info *info; + + if (!handle) + return -EINVAL; + + info = handle_to_scmi_info(handle); + mutex_lock(&scmi_list_mutex); + if (!WARN_ON(!info->users)) + info->users--; + mutex_unlock(&scmi_list_mutex); + + return 0; +} + +static const struct scmi_desc scmi_generic_desc = { + .max_rx_timeout_ms = 30, /* we may increase this if required */ + .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ + .max_msg_size = 128, +}; + +/* Each compatible listed below must have descriptor associated with it */ +static const struct of_device_id scmi_of_match[] = { + { .compatible = "arm,scmi", .data = &scmi_generic_desc }, + { /* Sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, scmi_of_match); + +static int scmi_xfer_info_init(struct scmi_info *sinfo) +{ + int i; + struct scmi_xfer *xfer; + struct device *dev = sinfo->dev; + const struct scmi_desc *desc = sinfo->desc; + struct scmi_xfers_info *info = &sinfo->minfo; + + /* Pre-allocated messages, no more than what hdr.seq can support */ + if (WARN_ON(desc->max_msg >= (MSG_TOKEN_ID_MASK + 1))) { + dev_err(dev, "Maximum message of %d exceeds supported %d\n", + desc->max_msg, MSG_TOKEN_ID_MASK + 1); + return -EINVAL; + } + + info->xfer_block = devm_kcalloc(dev, desc->max_msg, + sizeof(*info->xfer_block), GFP_KERNEL); + if (!info->xfer_block) + return -ENOMEM; + + info->xfer_alloc_table = devm_kcalloc(dev, BITS_TO_LONGS(desc->max_msg), + sizeof(long), GFP_KERNEL); + if (!info->xfer_alloc_table) + return -ENOMEM; + + bitmap_zero(info->xfer_alloc_table, desc->max_msg); + + /* Pre-initialize the buffer pointer to pre-allocated buffers */ + for (i = 0, xfer = info->xfer_block; i < desc->max_msg; i++, xfer++) { + xfer->rx.buf = devm_kcalloc(dev, sizeof(u8), desc->max_msg_size, + GFP_KERNEL); + if (!xfer->rx.buf) + return -ENOMEM; + + xfer->tx.buf = xfer->rx.buf; + init_completion(&xfer->done); + } + + spin_lock_init(&info->xfer_lock); + + return 0; +} + +static int scmi_mailbox_check(struct device_node *np) +{ + struct of_phandle_args arg; + + return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); +} + +static int scmi_mbox_free_channel(struct scmi_info *info) +{ + if (!IS_ERR_OR_NULL(info->tx_chan)) { + mbox_free_channel(info->tx_chan); + info->tx_chan = NULL; + } + + return 0; +} + +static int scmi_remove(struct platform_device *pdev) +{ + int ret = 0; + struct scmi_info *info = platform_get_drvdata(pdev); + + mutex_lock(&scmi_list_mutex); + if (info->users) + ret = -EBUSY; + else + list_del(&info->node); + mutex_unlock(&scmi_list_mutex); + + if (!ret) + /* Safe to free channels since no more users */ + return scmi_mbox_free_channel(info); + + return ret; +} + +static inline int scmi_mbox_chan_setup(struct scmi_info *info) +{ + int ret; + struct resource res; + resource_size_t size; + struct device *dev = info->dev; + struct device_node *shmem, *np = dev->of_node; + struct mbox_client *cl; + + cl = &info->cl; + cl->dev = dev; + cl->rx_callback = scmi_rx_callback; + cl->tx_prepare = scmi_tx_prepare; + cl->tx_block = false; + cl->knows_txdone = true; + + shmem = of_parse_phandle(np, "shmem", 0); + ret = of_address_to_resource(shmem, 0, &res); + of_node_put(shmem); + if (ret) { + dev_err(dev, "failed to get SCMI Tx payload mem resource\n"); + return ret; + } + + size = resource_size(&res); + info->tx_payload = devm_ioremap(dev, res.start, size); + if (!info->tx_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); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to request SCMI Tx mailbox\n"); + return ret; + } + + return 0; +} + +static int scmi_probe(struct platform_device *pdev) +{ + int ret; + struct scmi_handle *handle; + const struct scmi_desc *desc; + struct scmi_info *info; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + /* Only mailbox method supported, check for the presence of one */ + if (scmi_mailbox_check(np)) { + dev_err(dev, "no mailbox found in %pOF\n", np); + return -EINVAL; + } + + desc = of_match_device(scmi_of_match, dev)->data; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = dev; + info->desc = desc; + INIT_LIST_HEAD(&info->node); + + ret = scmi_xfer_info_init(info); + if (ret) + return ret; + + platform_set_drvdata(pdev, info); + + handle = &info->handle; + handle->dev = info->dev; + + ret = scmi_mbox_chan_setup(info); + if (ret) + return ret; + + mutex_lock(&scmi_list_mutex); + list_add_tail(&info->node, &scmi_list); + mutex_unlock(&scmi_list_mutex); + + return 0; +} + +static struct platform_driver scmi_driver = { + .driver = { + .name = "arm-scmi", + .of_match_table = scmi_of_match, + }, + .probe = scmi_probe, + .remove = scmi_remove, +}; + +module_platform_driver(scmi_driver); + +MODULE_ALIAS("platform: arm-scmi"); +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI protocol driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h new file mode 100644 index 000000000000..854ed2479993 --- /dev/null +++ b/include/linux/scmi_protocol.h @@ -0,0 +1,27 @@ +/* + * SCMI Message Protocol driver header + * + * 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 + +/** + * struct scmi_handle - Handle returned to ARM SCMI clients for usage. + * + * @dev: pointer to the SCMI device + */ +struct scmi_handle { + struct device *dev; +}; From patchwork Mon Feb 12 18:45:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128163 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3488649ljc; Mon, 12 Feb 2018 10:50:56 -0800 (PST) X-Google-Smtp-Source: AH8x224vpQ5seNlU9bfQjwCBskHkZXdf+P+nN65HlXyFhdOLHheKkY+Xl7UITIeYdxhOG5GWggUt X-Received: by 2002:a17:902:6849:: with SMTP id f9-v6mr11840396pln.113.1518461455991; Mon, 12 Feb 2018 10:50:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461455; cv=none; d=google.com; s=arc-20160816; b=yGKW+0Y0FNbN6hAjD9M2zoca7U9vnmokGLCBaBZw9fv5x7MSn082f0CMWj+IbwCA8f CRKTRZ18kh4hKCxq65IVGTcdAZuHtN0lFDKXd0Iti83w0mnIY3Uv+T0S/rDrJqGnYA0r yFd0NPWco5d46wIcqa0RJeTp7sR9YrcxyiJTnH2/Zi/Z+mrwoS9TPV6xGOu8/J9ocXVU Kz17ymPO6RPQz3JvhNraKQPE6N0NmCwL14n79rUP/NiZD7NZUy0hTO3cdwKyOIe9iuD+ z566lwc/nxMn1fh3uZ5xWHMwMRAKYEmuKf6kBUAaBfNBTsWZMRKu2AG8sMBXsFeY/aR0 lWIw== 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=lC65S1pNhNQiESKT2GCDpEuE8Jm+7bRcmQyBTl3pWHo=; b=JX6Z4E29h2ctQxwjMzMMHI379FwKl4wFRkx2RvcDghakodyDuXHxhkuWkcsOPv5XrV Yre+Bi+nChCVEGYAmdGceC2/V3X7NJ/ZfxAWRmQ3ghtxjrT3syi+vX+6vuK6IvN0nwnX JNqlG1LMZfqXSZFfkRCrjjgRTqvv530lHCbVY8C4XVJgtczdhYCyQExxMTmycABI4ktW AsldXtz2i0TCc+vREjJyWln1xF+83Abp3E1j44Rtwqror5V03Ndz9Y/lrwFh+OkJLazH 5UDa8+ktBj+Kzp26sx0uVEzn2EHvZxsnH7Hd4FJIO5/QnR423+UBzhzX2xovAF3/abcb RztQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.55; Mon, 12 Feb 2018 10:50:55 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754032AbeBLSpx (ORCPT + 26 others); Mon, 12 Feb 2018 13:45:53 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47140 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753977AbeBLSpt (ORCPT ); Mon, 12 Feb 2018 13:45:49 -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 D542C1682; Mon, 12 Feb 2018 10:45:48 -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 7EDF43F24D; Mon, 12 Feb 2018 10:45:47 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 04/20] firmware: arm_scmi: add common infrastructure and support for base protocol Date: Mon, 12 Feb 2018 18:45:08 +0000 Message-Id: <1518461124-17371-5-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The base protocol describes the properties of the implementation and provide generic error management. The base protocol provides commands to describe protocol version, discover implementation specific attributes and vendor/sub-vendor identification, list of protocols implemented and the various agents are in the system including OSPM and the platform. It also supports registering for notifications of platform errors. This protocol is mandatory. This patch adds support for the same along with some basic infrastructure to add support for other protocols. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 3 +- drivers/firmware/arm_scmi/base.c | 264 +++++++++++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/common.h | 37 ++++++ drivers/firmware/arm_scmi/driver.c | 53 ++++++++ include/linux/scmi_protocol.h | 37 ++++++ 5 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/base.c -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index b2a24ba2b636..5d9c7ef35f0f 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,3 @@ -obj-y = scmi-driver.o +obj-y = scmi-driver.o scmi-protocols.o scmi-driver-y = driver.o +scmi-protocols-y = base.o diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c new file mode 100644 index 000000000000..57e6913988f1 --- /dev/null +++ b/drivers/firmware/arm_scmi/base.c @@ -0,0 +1,264 @@ +/* + * System Control and Management Interface (SCMI) Base 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_base_protocol_cmd { + BASE_DISCOVER_VENDOR = 0x3, + BASE_DISCOVER_SUB_VENDOR = 0x4, + BASE_DISCOVER_IMPLEMENT_VERSION = 0x5, + BASE_DISCOVER_LIST_PROTOCOLS = 0x6, + BASE_DISCOVER_AGENT = 0x7, + BASE_NOTIFY_ERRORS = 0x8, +}; + +struct scmi_msg_resp_base_attributes { + u8 num_protocols; + u8 num_agents; + __le16 reserved; +}; + +/** + * scmi_base_attributes_get() - gets the implementation details + * that are associated with the base protocol. + * + * @handle - SCMI entity handle + * + * Return: 0 on success, else appropriate SCMI error. + */ +static int scmi_base_attributes_get(const struct scmi_handle *handle) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_base_attributes *attr_info; + struct scmi_revision_info *rev = handle->version; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_BASE, 0, sizeof(*attr_info), &t); + if (ret) + return ret; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + attr_info = t->rx.buf; + rev->num_protocols = attr_info->num_protocols; + rev->num_agents = attr_info->num_agents; + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +/** + * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string. + * + * @handle - SCMI entity handle + * @sub_vendor - specify true if sub-vendor ID is needed + * + * Return: 0 on success, else appropriate SCMI error. + */ +static int +scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) +{ + u8 cmd; + int ret, size; + char *vendor_id; + struct scmi_xfer *t; + struct scmi_revision_info *rev = handle->version; + + if (sub_vendor) { + cmd = BASE_DISCOVER_SUB_VENDOR; + vendor_id = rev->sub_vendor_id; + size = ARRAY_SIZE(rev->sub_vendor_id); + } else { + cmd = BASE_DISCOVER_VENDOR; + vendor_id = rev->vendor_id; + size = ARRAY_SIZE(rev->vendor_id); + } + + ret = scmi_one_xfer_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t); + if (ret) + return ret; + + ret = scmi_do_xfer(handle, t); + if (!ret) + memcpy(vendor_id, t->rx.buf, size); + + scmi_one_xfer_put(handle, t); + return ret; +} + +/** + * scmi_base_implementation_version_get() - gets a vendor-specific + * implementation 32-bit version. The format of the version number is + * vendor-specific + * + * @handle - SCMI entity handle + * + * Return: 0 on success, else appropriate SCMI error. + */ +static int +scmi_base_implementation_version_get(const struct scmi_handle *handle) +{ + int ret; + __le32 *impl_ver; + struct scmi_xfer *t; + struct scmi_revision_info *rev = handle->version; + + ret = scmi_one_xfer_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION, + SCMI_PROTOCOL_BASE, 0, sizeof(*impl_ver), &t); + if (ret) + return ret; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + impl_ver = t->rx.buf; + rev->impl_ver = le32_to_cpu(*impl_ver); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +/** + * scmi_base_implementation_list_get() - gets the list of protocols it is + * OSPM is allowed to access + * + * @handle - SCMI entity handle + * @protocols_imp - pointer to hold the list of protocol identifiers + * + * Return: 0 on success, else appropriate SCMI error. + */ +static int scmi_base_implementation_list_get(const struct scmi_handle *handle, + u8 *protocols_imp) +{ + u8 *list; + int ret, loop; + struct scmi_xfer *t; + __le32 *num_skip, *num_ret; + u32 tot_num_ret = 0, loop_num_ret; + struct device *dev = handle->dev; + + ret = scmi_one_xfer_init(handle, BASE_DISCOVER_LIST_PROTOCOLS, + SCMI_PROTOCOL_BASE, sizeof(*num_skip), 0, &t); + if (ret) + return ret; + + num_skip = t->tx.buf; + num_ret = t->rx.buf; + list = t->rx.buf + sizeof(*num_ret); + + do { + /* Set the number of protocols to be skipped/already read */ + *num_skip = cpu_to_le32(tot_num_ret); + + ret = scmi_do_xfer(handle, t); + if (ret) + break; + + loop_num_ret = le32_to_cpu(*num_ret); + if (tot_num_ret + loop_num_ret > MAX_PROTOCOLS_IMP) { + dev_err(dev, "No. of Protocol > MAX_PROTOCOLS_IMP"); + break; + } + + for (loop = 0; loop < loop_num_ret; loop++) + protocols_imp[tot_num_ret + loop] = *(list + loop); + + tot_num_ret += loop_num_ret; + } while (loop_num_ret); + + scmi_one_xfer_put(handle, t); + return ret; +} + +/** + * scmi_base_discover_agent_get() - discover the name of an agent + * + * @handle - SCMI entity handle + * @id - Agent identifier + * @name - Agent identifier ASCII string + * + * An agent id of 0 is reserved to identify the platform itself. + * Generally operating system is represented as "OSPM" + * + * Return: 0 on success, else appropriate SCMI error. + */ +static int scmi_base_discover_agent_get(const struct scmi_handle *handle, + int id, char *name) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, BASE_DISCOVER_AGENT, + SCMI_PROTOCOL_BASE, sizeof(__le32), + SCMI_MAX_STR_SIZE, &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(id); + + ret = scmi_do_xfer(handle, t); + if (!ret) + memcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE); + + scmi_one_xfer_put(handle, t); + return ret; +} + +int scmi_base_protocol_init(struct scmi_handle *h) +{ + int id, ret; + u8 *prot_imp; + u32 version; + char name[SCMI_MAX_STR_SIZE]; + const struct scmi_handle *handle = h; + struct device *dev = handle->dev; + struct scmi_revision_info *rev = handle->version; + + ret = scmi_version_get(handle, SCMI_PROTOCOL_BASE, &version); + if (ret) + return ret; + + prot_imp = devm_kcalloc(dev, MAX_PROTOCOLS_IMP, sizeof(u8), GFP_KERNEL); + if (!prot_imp) + return -ENOMEM; + + rev->major_ver = PROTOCOL_REV_MAJOR(version), + rev->minor_ver = PROTOCOL_REV_MINOR(version); + + scmi_base_attributes_get(handle); + scmi_base_vendor_id_get(handle, false); + scmi_base_vendor_id_get(handle, true); + scmi_base_implementation_version_get(handle); + scmi_base_implementation_list_get(handle, prot_imp); + scmi_setup_protocol_implemented(handle, prot_imp); + + dev_info(dev, "SCMI Protocol v%d.%d '%s:%s' Firmware version 0x%x\n", + rev->major_ver, rev->minor_ver, rev->vendor_id, + rev->sub_vendor_id, rev->impl_ver); + dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols, + rev->num_agents); + + for (id = 0; id < rev->num_agents; id++) { + scmi_base_discover_agent_get(handle, id, name); + dev_dbg(dev, "Agent %d: %s\n", id, name); + } + + return 0; +} diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index cdfc43427c3c..bc767f4997e0 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -19,9 +19,41 @@ */ #include +#include +#include +#include #include #include +#define PROTOCOL_REV_MINOR_BITS 16 +#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1) +#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS) +#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK) +#define MAX_PROTOCOLS_IMP 16 + +enum scmi_common_cmd { + PROTOCOL_VERSION = 0x0, + PROTOCOL_ATTRIBUTES = 0x1, + PROTOCOL_MESSAGE_ATTRIBUTES = 0x2, +}; + +/** + * struct scmi_msg_resp_prot_version - Response for a message + * + * @major_version: Major version of the ABI that firmware supports + * @minor_version: Minor version of the ABI that firmware supports + * + * In general, ABI version changes follow the rule that minor version increments + * are backward compatible. Major revision changes in ABI may not be + * backward compatible. + * + * Response to a generic message with message type SCMI_MSG_VERSION + */ +struct scmi_msg_resp_prot_version { + __le16 minor_version; + __le16 major_version; +}; + /** * struct scmi_msg_hdr - Message(Tx/Rx) header * @@ -75,3 +107,8 @@ 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); +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); + +int scmi_base_protocol_init(struct scmi_handle *h); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 37472a9a1c8b..0ceff82f6f59 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -105,21 +105,27 @@ struct scmi_desc { * @dev: Device pointer * @desc: SoC description for this instance * @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 + * @protocols_imp: list of protocols implemented, currently maximum of + * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: list head * @users: Number of users of this instance */ struct scmi_info { struct device *dev; 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; + u8 *protocols_imp; struct list_head node; int users; }; @@ -433,6 +439,45 @@ int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, } /** + * scmi_version_get() - command to get the revision of the SCMI entity + * + * @handle: Handle to SCMI entity information + * + * Updates the SCMI information in the internal data structure. + * + * Return: 0 if all went fine, else return appropriate error. + */ +int scmi_version_get(const struct scmi_handle *handle, u8 protocol, + u32 *version) +{ + int ret; + __le32 *rev_info; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, PROTOCOL_VERSION, protocol, 0, + sizeof(*version), &t); + if (ret) + return ret; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + rev_info = t->rx.buf; + *version = le32_to_cpu(*rev_info); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +void scmi_setup_protocol_implemented(const struct scmi_handle *handle, + u8 *prot_imp) +{ + struct scmi_info *info = handle_to_scmi_info(handle); + + info->protocols_imp = prot_imp; +} + +/** * scmi_handle_get() - Get the SCMI handle for a device * * @dev: pointer to device for which we want SCMI handle @@ -660,11 +705,19 @@ static int scmi_probe(struct platform_device *pdev) handle = &info->handle; handle->dev = info->dev; + handle->version = &info->version; ret = scmi_mbox_chan_setup(info); if (ret) return ret; + ret = scmi_base_protocol_init(handle); + if (ret) { + dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); + scmi_mbox_free_channel(info); + return ret; + } + mutex_lock(&scmi_list_mutex); list_add_tail(&info->node, &scmi_list); mutex_unlock(&scmi_list_mutex); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 854ed2479993..664da3d763f2 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -17,11 +17,48 @@ */ #include +#define SCMI_MAX_STR_SIZE 16 + +/** + * struct scmi_revision_info - version information structure + * + * @major_ver: Major ABI version. Change here implies risk of backward + * compatibility break. + * @minor_ver: Minor ABI version. Change here implies new feature addition, + * or compatible change in ABI. + * @num_protocols: Number of protocols that are implemented, excluding the + * base protocol. + * @num_agents: Number of agents in the system. + * @impl_ver: A vendor-specific implementation version. + * @vendor_id: A vendor identifier(Null terminated ASCII string) + * @sub_vendor_id: A sub-vendor identifier(Null terminated ASCII string) + */ +struct scmi_revision_info { + u16 major_ver; + u16 minor_ver; + u8 num_protocols; + u8 num_agents; + u32 impl_ver; + char vendor_id[SCMI_MAX_STR_SIZE]; + char sub_vendor_id[SCMI_MAX_STR_SIZE]; +}; + /** * 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 */ struct scmi_handle { struct device *dev; + struct scmi_revision_info *version; +}; + +enum scmi_std_protocol { + SCMI_PROTOCOL_BASE = 0x10, + SCMI_PROTOCOL_POWER = 0x11, + SCMI_PROTOCOL_SYSTEM = 0x12, + SCMI_PROTOCOL_PERF = 0x13, + SCMI_PROTOCOL_CLOCK = 0x14, + SCMI_PROTOCOL_SENSOR = 0x15, }; From patchwork Mon Feb 12 18:45:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128164 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3488827ljc; Mon, 12 Feb 2018 10:51:08 -0800 (PST) X-Google-Smtp-Source: AH8x227L4FBjkeVX+IceFjzP9S4/Uy0eHrlro+5wAHlFHQIull4j32rUMKFFTLMZ0zKC1mNHBYPn X-Received: by 10.98.110.202 with SMTP id j193mr12564065pfc.19.1518461468771; Mon, 12 Feb 2018 10:51:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461468; cv=none; d=google.com; s=arc-20160816; b=pyY189azPAQSvuTdBJFEQqFdMItYx7pKtK3TDqC4DZ9B30neVqlfWbbtUQ+Wy6UOmZ iz4YwJTmyVe2coYvnHq0pfkGXdBo62A5RBi9aY+r82lUN4FOWGM34kW/lMf3/ZOeeRJL 5lekcsnlKQ9jwPtfvRNOUHj9IpbHHOitZTmzKdmn4FpmgvN05f0ZrnF28xrKzw88wO5h gOecWCnq+TWjyPBsZZl78pcwByW+J/StTUQEIB91PaRoINAsZpj1JG9MdzWzuumVsNTJ IRqCG+JMQJdF0v/1QQnPJEMO1lnNRg9Zx21Y2SBQgit+BYz/j2yix/hADL30DbMHb4kU OdDA== 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=Nkd4oJupM8lrnQ1oqGgsvSn0ZHi4YkbUdgWshIxkpFs=; b=n8RpU9BEHjLEU9Odv8Q2Gz1U9rEQJO9cZqW4bwSl/2LpOgroPq71Rms4sG1qDIGLyc qmnvrBQRofzKwIx+/vARRcy9Uq/gU/A3s66i0zcWyc3YLyE8uAbc+07svRxgjg22hSq4 QpBrqG9qK7drYL/lDtzCQxK9dvbmiJ+LcAXMQfcgOgL0od5n3o8ASgWVv+J+ODO5B/SC O/kMqePQw/sUVAwS1hC7k6YKi1yNiyWl77BGRpVBrN6lW/RDW79X/CVwTGPQZLfKIASM P/8WsDog70ixkS6acCn3/JFUeSvhcX6j+2jJVFAn8UTom7ZccvR+Kpm8Vm8jfCUHUuQf BcuQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.08; Mon, 12 Feb 2018 10:51:08 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753933AbeBLSvF (ORCPT + 26 others); Mon, 12 Feb 2018 13:51:05 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47162 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753825AbeBLSpw (ORCPT ); Mon, 12 Feb 2018 13:45:52 -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 15426169F; Mon, 12 Feb 2018 10:45:52 -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 B3C693F24D; Mon, 12 Feb 2018 10:45:50 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 06/20] firmware: arm_scmi: add initial support for performance protocol Date: Mon, 12 Feb 2018 18:45:10 +0000 Message-Id: <1518461124-17371-7-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The performance protocol is intended for the performance management of group(s) of device(s) that run in the same performance domain. It includes even the CPUs. A performance domain is defined by a set of devices that always have to run at the same performance level. For example, a set of CPUs that share a voltage domain, and have a common frequency control, is said to be in the same performance domain. The commands in this protocol provide functionality to describe the protocol version, describe various attribute flags, set and get the performance level of a domain. It also supports discovery of the list of performance levels supported by a performance domain, and the properties of each performance level. This patch adds basic support for the performance protocol. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/common.h | 1 + drivers/firmware/arm_scmi/perf.c | 489 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 35 +++ 4 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/perf.c -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 5f4ec2613db6..687cbbfb3af6 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 +scmi-protocols-y = base.o perf.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index f1eeacaef57b..b045a3f268e7 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -30,6 +30,7 @@ #define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS) #define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK) #define MAX_PROTOCOLS_IMP 16 +#define MAX_OPPS 16 enum scmi_common_cmd { PROTOCOL_VERSION = 0x0, diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c new file mode 100644 index 000000000000..a14093386b57 --- /dev/null +++ b/drivers/firmware/arm_scmi/perf.c @@ -0,0 +1,489 @@ +/* + * System Control and Management Interface (SCMI) Performance 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 +#include +#include +#include + +#include "common.h" + +enum scmi_performance_protocol_cmd { + PERF_DOMAIN_ATTRIBUTES = 0x3, + PERF_DESCRIBE_LEVELS = 0x4, + PERF_LIMITS_SET = 0x5, + PERF_LIMITS_GET = 0x6, + PERF_LEVEL_SET = 0x7, + PERF_LEVEL_GET = 0x8, + PERF_NOTIFY_LIMITS = 0x9, + PERF_NOTIFY_LEVEL = 0xa, +}; + +struct scmi_opp { + u32 perf; + u32 power; + u32 trans_latency_us; +}; + +struct scmi_msg_resp_perf_attributes { + __le16 num_domains; + __le16 flags; +#define POWER_SCALE_IN_MILLIWATT(x) ((x) & BIT(0)) + __le32 stats_addr_low; + __le32 stats_addr_high; + __le32 stats_size; +}; + +struct scmi_msg_resp_perf_domain_attributes { + __le32 flags; +#define SUPPORTS_SET_LIMITS(x) ((x) & BIT(31)) +#define SUPPORTS_SET_PERF_LVL(x) ((x) & BIT(30)) +#define SUPPORTS_PERF_LIMIT_NOTIFY(x) ((x) & BIT(29)) +#define SUPPORTS_PERF_LEVEL_NOTIFY(x) ((x) & BIT(28)) + __le32 rate_limit_us; + __le32 sustained_freq_khz; + __le32 sustained_perf_level; + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_msg_perf_describe_levels { + __le32 domain; + __le32 level_index; +}; + +struct scmi_perf_set_limits { + __le32 domain; + __le32 max_level; + __le32 min_level; +}; + +struct scmi_perf_get_limits { + __le32 max_level; + __le32 min_level; +}; + +struct scmi_perf_set_level { + __le32 domain; + __le32 level; +}; + +struct scmi_perf_notify_level_or_limits { + __le32 domain; + __le32 notify_enable; +}; + +struct scmi_msg_resp_perf_describe_levels { + __le16 num_returned; + __le16 num_remaining; + struct { + __le32 perf_val; + __le32 power; + __le16 transition_latency_us; + __le16 reserved; + } opp[0]; +}; + +struct perf_dom_info { + bool set_limits; + bool set_perf; + bool perf_limit_notify; + bool perf_level_notify; + u32 opp_count; + u32 sustained_freq_khz; + u32 sustained_perf_level; + u32 mult_factor; + char name[SCMI_MAX_STR_SIZE]; + struct scmi_opp opp[MAX_OPPS]; +}; + +struct scmi_perf_info { + int num_domains; + bool power_scale_mw; + u64 stats_addr; + u32 stats_size; + struct perf_dom_info *dom_info; +}; + +static int scmi_perf_attributes_get(const struct scmi_handle *handle, + struct scmi_perf_info *pi) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_perf_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_PERF, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + u16 flags = le16_to_cpu(attr->flags); + + pi->num_domains = le16_to_cpu(attr->num_domains); + pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags); + 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_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, + struct perf_dom_info *dom_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_perf_domain_attributes *attr; + + ret = scmi_one_xfer_init(handle, PERF_DOMAIN_ATTRIBUTES, + SCMI_PROTOCOL_PERF, 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->set_limits = SUPPORTS_SET_LIMITS(flags); + dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags); + dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); + dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); + dom_info->sustained_freq_khz = + le32_to_cpu(attr->sustained_freq_khz); + dom_info->sustained_perf_level = + le32_to_cpu(attr->sustained_perf_level); + dom_info->mult_factor = (dom_info->sustained_freq_khz * 1000) / + dom_info->sustained_perf_level; + memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int opp_cmp_func(const void *opp1, const void *opp2) +{ + const struct scmi_opp *t1 = opp1, *t2 = opp2; + + return t1->perf - t2->perf; +} + +static int +scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, + struct perf_dom_info *perf_dom) +{ + int ret, cnt; + u32 tot_opp_cnt = 0; + u16 num_returned, num_remaining; + struct scmi_xfer *t; + struct scmi_opp *opp; + struct scmi_msg_perf_describe_levels *dom_info; + struct scmi_msg_resp_perf_describe_levels *level_info; + + ret = scmi_one_xfer_init(handle, PERF_DESCRIBE_LEVELS, + SCMI_PROTOCOL_PERF, sizeof(*dom_info), 0, &t); + if (ret) + return ret; + + dom_info = t->tx.buf; + level_info = t->rx.buf; + + do { + dom_info->domain = cpu_to_le32(domain); + /* Set the number of OPPs to be skipped/already read */ + dom_info->level_index = cpu_to_le32(tot_opp_cnt); + + ret = scmi_do_xfer(handle, t); + if (ret) + break; + + num_returned = le16_to_cpu(level_info->num_returned); + num_remaining = le16_to_cpu(level_info->num_remaining); + if (tot_opp_cnt + num_returned > MAX_OPPS) { + dev_err(handle->dev, "No. of OPPs exceeded MAX_OPPS"); + break; + } + + opp = &perf_dom->opp[tot_opp_cnt]; + for (cnt = 0; cnt < num_returned; cnt++, opp++) { + opp->perf = le32_to_cpu(level_info->opp[cnt].perf_val); + opp->power = le32_to_cpu(level_info->opp[cnt].power); + opp->trans_latency_us = le16_to_cpu( + level_info->opp[cnt].transition_latency_us); + + dev_dbg(handle->dev, "Level %d Power %d Latency %dus\n", + opp->perf, opp->power, opp->trans_latency_us); + } + + tot_opp_cnt += num_returned; + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + perf_dom->opp_count = tot_opp_cnt; + scmi_one_xfer_put(handle, t); + + sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL); + return ret; +} + +static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, + u32 max_perf, u32 min_perf) +{ + int ret; + struct scmi_xfer *t; + struct scmi_perf_set_limits *limits; + + ret = scmi_one_xfer_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF, + sizeof(*limits), 0, &t); + if (ret) + return ret; + + limits = t->tx.buf; + limits->domain = cpu_to_le32(domain); + limits->max_level = cpu_to_le32(max_perf); + limits->min_level = cpu_to_le32(min_perf); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, + u32 *max_perf, u32 *min_perf) +{ + int ret; + struct scmi_xfer *t; + struct scmi_perf_get_limits *limits; + + ret = scmi_one_xfer_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF, + sizeof(__le32), 0, &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + + ret = scmi_do_xfer(handle, t); + if (!ret) { + limits = t->rx.buf; + + *max_perf = le32_to_cpu(limits->max_level); + *min_perf = le32_to_cpu(limits->min_level); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, u32 level) +{ + int ret; + struct scmi_xfer *t; + struct scmi_perf_set_level *lvl; + + ret = scmi_one_xfer_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF, + sizeof(*lvl), 0, &t); + if (ret) + return ret; + + lvl = t->tx.buf; + lvl->domain = cpu_to_le32(domain); + lvl->level = cpu_to_le32(level); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, u32 *level) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF, + 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) + *level = le32_to_cpu(*(__le32 *)t->rx.buf); + + scmi_one_xfer_put(handle, t); + return ret; +} + +/* Device specific ops */ +static int scmi_dev_domain_id(struct device *dev) +{ + struct of_phandle_args clkspec; + + if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", + 0, &clkspec)) + return -EINVAL; + + return clkspec.args[0]; +} + +static int scmi_dvfs_add_opps_to_device(const struct scmi_handle *handle, + struct device *dev) +{ + int idx, ret, domain; + unsigned long freq; + struct scmi_opp *opp; + struct perf_dom_info *dom; + struct scmi_perf_info *pi = handle->perf_priv; + + domain = scmi_dev_domain_id(dev); + if (domain < 0) + return domain; + + dom = pi->dom_info + domain; + if (!dom) + return -EIO; + + for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { + freq = opp->perf * dom->mult_factor; + + ret = dev_pm_opp_add(dev, freq, 0); + if (ret) { + dev_warn(dev, "failed to add opp %luHz\n", freq); + + while (idx-- > 0) { + freq = (--opp)->perf * dom->mult_factor; + dev_pm_opp_remove(dev, freq); + } + return ret; + } + } + return 0; +} + +static int scmi_dvfs_get_transition_latency(const struct scmi_handle *handle, + struct device *dev) +{ + struct perf_dom_info *dom; + struct scmi_perf_info *pi = handle->perf_priv; + int domain = scmi_dev_domain_id(dev); + + if (domain < 0) + return domain; + + dom = pi->dom_info + domain; + if (!dom) + return -EIO; + + /* uS to nS */ + return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; +} + +static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain, + unsigned long freq) +{ + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + return scmi_perf_level_set(handle, domain, freq / dom->mult_factor); +} + +static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain, + unsigned long *freq) +{ + int ret; + u32 level; + struct scmi_perf_info *pi = handle->perf_priv; + struct perf_dom_info *dom = pi->dom_info + domain; + + ret = scmi_perf_level_get(handle, domain, &level); + if (!ret) + *freq = level * dom->mult_factor; + + return ret; +} + +static struct scmi_perf_ops perf_ops = { + .limits_set = scmi_perf_limits_set, + .limits_get = scmi_perf_limits_get, + .level_set = scmi_perf_level_set, + .level_get = scmi_perf_level_get, + .device_domain_id = scmi_dev_domain_id, + .get_transition_latency = scmi_dvfs_get_transition_latency, + .add_opps_to_device = scmi_dvfs_add_opps_to_device, + .freq_set = scmi_dvfs_freq_set, + .freq_get = scmi_dvfs_freq_get, +}; + +static int scmi_perf_protocol_init(struct scmi_handle *handle) +{ + int domain; + u32 version; + struct scmi_perf_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_PERF, &version); + + dev_dbg(handle->dev, "Performance 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_perf_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 perf_dom_info *dom = pinfo->dom_info + domain; + + scmi_perf_domain_attributes_get(handle, domain, dom); + scmi_perf_describe_levels_get(handle, domain, dom); + } + + handle->perf_ops = &perf_ops; + handle->perf_priv = pinfo; + + return 0; +} + +static int __init scmi_perf_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_PERF, + &scmi_perf_protocol_init); +} +subsys_initcall(scmi_perf_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 7b72c75cb560..d99645671a47 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -44,15 +44,50 @@ struct scmi_revision_info { char sub_vendor_id[SCMI_MAX_STR_SIZE]; }; +struct scmi_handle; + +/** + * struct scmi_perf_ops - represents the various operations provided + * by SCMI Performance Protocol + * + * @limits_set: sets limits on the performance level of a domain + * @limits_get: gets limits on the performance level of a domain + * @level_set: sets the performance level of a domain + * @level_get: gets the performance level of a domain + * @device_domain_id: gets the scmi domain id for a given device + * @get_transition_latency: gets the DVFS transition latency for a given device + * @add_opps_to_device: adds all the OPPs for a given device + * @freq_set: sets the frequency for a given device using sustained frequency + * to sustained performance level mapping + * @freq_get: gets the frequency for a given device using sustained frequency + * to sustained performance level mapping + */ +struct scmi_perf_ops { + int (*limits_set)(const struct scmi_handle *, u32, u32, u32); + int (*limits_get)(const struct scmi_handle *, u32, u32 *, u32 *); + int (*level_set)(const struct scmi_handle *, u32, u32); + int (*level_get)(const struct scmi_handle *, u32, u32 *); + int (*device_domain_id)(struct device *); + int (*get_transition_latency)(const struct scmi_handle *, + struct device *); + int (*add_opps_to_device)(const struct scmi_handle *, struct device *); + int (*freq_set)(const struct scmi_handle *, u32, unsigned long); + int (*freq_get)(const struct scmi_handle *, u32, unsigned long *); +}; + /** * 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 + * @perf_ops: pointer to set of performance protocol operations */ struct scmi_handle { struct device *dev; struct scmi_revision_info *version; + struct scmi_perf_ops *perf_ops; + /* for protocol internal use */ + void *perf_priv; }; enum scmi_std_protocol { From patchwork Mon Feb 12 18:45:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128162 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3488542ljc; Mon, 12 Feb 2018 10:50:43 -0800 (PST) X-Google-Smtp-Source: AH8x224aZog5iaX3YXf3Ol/VUjA7uG498e3AxdXi6RKMoZmKE6fw6i2woz+dghtuvAxeI02IulYb X-Received: by 10.98.97.198 with SMTP id v189mr12599197pfb.110.1518461442774; Mon, 12 Feb 2018 10:50:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461442; cv=none; d=google.com; s=arc-20160816; b=sU4UhUyd7mtLk9nxF1F6D7RuFzms5Hd3Yk5xshLYVA71NqNHO4g3NnMG9Qs/YToAEi AHkpkup5uI2BS/2pB/azRDWBv7yJ5tkxVapKm4XhEwxJ8OsbLGOsfdy2aLCdNovzM2xV rSEPCtyJjvBX+JRiMk9adDceiSKtsVFkKj0jVllGPb6Ur148dTn0lJP86rBG0qWZIglz Pk2AaIj/4NtaSvVGn3ZCVedjEOyUPqB8FTk7gusr3hFxAL8UKDeQJe0poSoQjk3Pt4gd zpwDWLoQaIi7VYVVfCPFsJirMxvshgCgnI2lKc2h68MIo2rjkpK86yM4oXH56nwmMHyT 2wvg== 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=TZElX2DGiFffT5+646eOZ+QiweBkHyI+nq9yGfgWr9U=; b=DpXlJ+5H864WYV76G4MSNvO6trWS0XmbgzZX+Uqyn+u2l9thLdeCQacOFwH3d2ZNR4 RMOEad2FcyAnKKGb0itFPcYth0sC+hvasDXcHTZuLY4oL16EoteKT5XNLa7myZpEasuU AOlPTO90Zduls7OHanTcprTFJwsJvbBr36DmAfqCQmE3u7KwuQDBPI+k8rOFd2pl1N1L KyP+XUQkz04uyyFZAPBWd6AAvFHHUuDUFF66RwBYUNyDKXYICGVGCqu7A3iQekDZLDje Ive6333qwvDQESHTKsrue2EfbaAWO72bmaD1Q2w5+njvwsIDejnFpN/j9unqFaCcIkPG ie4Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.42; Mon, 12 Feb 2018 10:50:42 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932393AbeBLSuj (ORCPT + 26 others); Mon, 12 Feb 2018 13:50:39 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47174 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753977AbeBLSpy (ORCPT ); Mon, 12 Feb 2018 13:45:54 -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 A9D2116A0; Mon, 12 Feb 2018 10:45:53 -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 5455D3F24D; Mon, 12 Feb 2018 10:45:52 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 07/20] firmware: arm_scmi: add initial support for clock protocol Date: Mon, 12 Feb 2018 18:45:11 +0000 Message-Id: <1518461124-17371-8-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The clock protocol is intended for management of clocks. It is used to enable or disable clocks, and to set and get the clock rates. This protocol provides commands to describe the protocol version, discover various implementation specific attributes, describe a clock, enable and disable a clock and get/set the rate of the clock synchronously or asynchronously. This patch adds initial support for the clock protocol. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/clock.c | 353 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 41 +++++ 3 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/clock.c -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 687cbbfb3af6..2130ee9ac825 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 perf.o +scmi-protocols-y = base.o clock.o perf.o diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c new file mode 100644 index 000000000000..0fac1d4b377b --- /dev/null +++ b/drivers/firmware/arm_scmi/clock.c @@ -0,0 +1,353 @@ +/* + * System Control and Management Interface (SCMI) Clock 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_clock_protocol_cmd { + CLOCK_ATTRIBUTES = 0x3, + CLOCK_DESCRIBE_RATES = 0x4, + CLOCK_RATE_SET = 0x5, + CLOCK_RATE_GET = 0x6, + CLOCK_CONFIG_SET = 0x7, +}; + +struct scmi_msg_resp_clock_protocol_attributes { + __le16 num_clocks; + u8 max_async_req; + u8 reserved; +}; + +struct scmi_msg_resp_clock_attributes { + __le32 attributes; +#define CLOCK_ENABLE BIT(0) + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_clock_set_config { + __le32 id; + __le32 attributes; +}; + +struct scmi_msg_clock_describe_rates { + __le32 id; + __le32 rate_index; +}; + +struct scmi_msg_resp_clock_describe_rates { + __le32 num_rates_flags; +#define NUM_RETURNED(x) ((x) & 0xfff) +#define RATE_DISCRETE(x) !((x) & BIT(12)) +#define NUM_REMAINING(x) ((x) >> 16) + struct { + __le32 value_low; + __le32 value_high; + } rate[0]; +#define RATE_TO_U64(X) \ +({ \ + typeof(X) x = (X); \ + le32_to_cpu((x).value_low) | (u64)le32_to_cpu((x).value_high) << 32; \ +}) +}; + +struct scmi_clock_set_rate { + __le32 flags; +#define CLOCK_SET_ASYNC BIT(0) +#define CLOCK_SET_DELAYED BIT(1) +#define CLOCK_SET_ROUND_UP BIT(2) +#define CLOCK_SET_ROUND_AUTO BIT(3) + __le32 id; + __le32 value_low; + __le32 value_high; +}; + +struct clock_info { + int num_clocks; + int max_async_req; + struct scmi_clock_info *clk; +}; + +static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle, + struct clock_info *ci) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_clock_protocol_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_CLOCK, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + ci->num_clocks = le16_to_cpu(attr->num_clocks); + ci->max_async_req = attr->max_async_req; + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_clock_attributes_get(const struct scmi_handle *handle, + u32 clk_id, struct scmi_clock_info *clk) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_clock_attributes *attr; + + ret = scmi_one_xfer_init(handle, CLOCK_ATTRIBUTES, SCMI_PROTOCOL_CLOCK, + sizeof(clk_id), sizeof(*attr), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(clk_id); + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) + memcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE); + else + clk->name[0] = '\0'; + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, + struct scmi_clock_info *clk) +{ + u64 *rate; + int ret, cnt; + bool rate_discrete; + u32 tot_rate_cnt = 0, rates_flag; + u16 num_returned, num_remaining; + struct scmi_xfer *t; + struct scmi_msg_clock_describe_rates *clk_desc; + struct scmi_msg_resp_clock_describe_rates *rlist; + + ret = scmi_one_xfer_init(handle, CLOCK_DESCRIBE_RATES, + SCMI_PROTOCOL_CLOCK, sizeof(*clk_desc), 0, &t); + if (ret) + return ret; + + clk_desc = t->tx.buf; + rlist = t->rx.buf; + + do { + clk_desc->id = cpu_to_le32(clk_id); + /* Set the number of rates to be skipped/already read */ + clk_desc->rate_index = cpu_to_le32(tot_rate_cnt); + + ret = scmi_do_xfer(handle, t); + if (ret) + break; + + rates_flag = le32_to_cpu(rlist->num_rates_flags); + num_remaining = NUM_REMAINING(rates_flag); + rate_discrete = RATE_DISCRETE(rates_flag); + num_returned = NUM_RETURNED(rates_flag); + + if (tot_rate_cnt + num_returned > SCMI_MAX_NUM_RATES) { + dev_err(handle->dev, "No. of rates > MAX_NUM_RATES"); + break; + } + + if (!rate_discrete) { + clk->range.min_rate = RATE_TO_U64(rlist->rate[0]); + clk->range.max_rate = RATE_TO_U64(rlist->rate[1]); + clk->range.step_size = RATE_TO_U64(rlist->rate[2]); + dev_dbg(handle->dev, "Min %llu Max %llu Step %llu Hz\n", + clk->range.min_rate, clk->range.max_rate, + clk->range.step_size); + break; + } + + rate = &clk->list.rates[tot_rate_cnt]; + for (cnt = 0; cnt < num_returned; cnt++, rate++) { + *rate = RATE_TO_U64(rlist->rate[cnt]); + dev_dbg(handle->dev, "Rate %llu Hz\n", *rate); + } + + tot_rate_cnt += num_returned; + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + if (rate_discrete) + clk->list.num_rates = tot_rate_cnt; + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, CLOCK_RATE_GET, SCMI_PROTOCOL_CLOCK, + sizeof(__le32), sizeof(u64), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(clk_id); + + 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 int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, + u32 config, u64 rate) +{ + int ret; + struct scmi_xfer *t; + struct scmi_clock_set_rate *cfg; + + ret = scmi_one_xfer_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK, + sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->flags = cpu_to_le32(config); + cfg->id = cpu_to_le32(clk_id); + cfg->value_low = cpu_to_le32(rate & 0xffffffff); + cfg->value_high = cpu_to_le32(rate >> 32); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config) +{ + int ret; + struct scmi_xfer *t; + struct scmi_clock_set_config *cfg; + + ret = scmi_one_xfer_init(handle, CLOCK_CONFIG_SET, SCMI_PROTOCOL_CLOCK, + sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(clk_id); + cfg->attributes = cpu_to_le32(config); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_clock_enable(const struct scmi_handle *handle, u32 clk_id) +{ + return scmi_clock_config_set(handle, clk_id, CLOCK_ENABLE); +} + +static int scmi_clock_disable(const struct scmi_handle *handle, u32 clk_id) +{ + return scmi_clock_config_set(handle, clk_id, 0); +} + +static int scmi_clock_count_get(const struct scmi_handle *handle) +{ + struct clock_info *ci = handle->clk_priv; + + return ci->num_clocks; +} + +static const struct scmi_clock_info * +scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id) +{ + struct clock_info *ci = handle->clk_priv; + struct scmi_clock_info *clk = ci->clk + clk_id; + + if (!clk->name || !clk->name[0]) + return NULL; + + return clk; +} + +static struct scmi_clk_ops clk_ops = { + .count_get = scmi_clock_count_get, + .info_get = scmi_clock_info_get, + .rate_get = scmi_clock_rate_get, + .rate_set = scmi_clock_rate_set, + .enable = scmi_clock_enable, + .disable = scmi_clock_disable, +}; + +static int scmi_clock_protocol_init(struct scmi_handle *handle) +{ + u32 version; + int clkid, ret; + struct clock_info *cinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_CLOCK, &version); + + dev_dbg(handle->dev, "Clock Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + cinfo = devm_kzalloc(handle->dev, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + + scmi_clock_protocol_attributes_get(handle, cinfo); + + cinfo->clk = devm_kcalloc(handle->dev, cinfo->num_clocks, + sizeof(*cinfo->clk), GFP_KERNEL); + if (!cinfo->clk) + return -ENOMEM; + + for (clkid = 0; clkid < cinfo->num_clocks; clkid++) { + struct scmi_clock_info *clk = cinfo->clk + clkid; + + ret = scmi_clock_attributes_get(handle, clkid, clk); + if (!ret) + scmi_clock_describe_rates_get(handle, clkid, clk); + } + + handle->clk_ops = &clk_ops; + handle->clk_priv = cinfo; + + return 0; +} + +static int __init scmi_clock_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_CLOCK, + &scmi_clock_protocol_init); +} +subsys_initcall(scmi_clock_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index d99645671a47..cfdc8967e5d9 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -19,6 +19,7 @@ #include #define SCMI_MAX_STR_SIZE 16 +#define SCMI_MAX_NUM_RATES 16 /** * struct scmi_revision_info - version information structure @@ -44,9 +45,46 @@ struct scmi_revision_info { char sub_vendor_id[SCMI_MAX_STR_SIZE]; }; +struct scmi_clock_info { + char name[SCMI_MAX_STR_SIZE]; + bool rate_discrete; + union { + struct { + int num_rates; + u64 rates[SCMI_MAX_NUM_RATES]; + } list; + struct { + u64 min_rate; + u64 max_rate; + u64 step_size; + } range; + }; +}; + struct scmi_handle; /** + * struct scmi_clk_ops - represents the various operations provided + * by SCMI Clock Protocol + * + * @count_get: get the count of clocks provided by SCMI + * @info_get: get the information of the specified clock + * @rate_get: request the current clock rate of a clock + * @rate_set: set the clock rate of a clock + * @enable: enables the specified clock + * @disable: disables the specified clock + */ +struct scmi_clk_ops { + int (*count_get)(const struct scmi_handle *); + const struct scmi_clock_info *(*info_get)(const struct scmi_handle *, + u32); + int (*rate_get)(const struct scmi_handle *, u32, u64*); + int (*rate_set)(const struct scmi_handle *, u32, u32, u64); + int (*enable)(const struct scmi_handle *, u32); + int (*disable)(const struct scmi_handle *, u32); +}; + +/** * struct scmi_perf_ops - represents the various operations provided * by SCMI Performance Protocol * @@ -81,13 +119,16 @@ struct scmi_perf_ops { * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information * @perf_ops: pointer to set of performance protocol operations + * @clk_ops: pointer to set of clock protocol operations */ struct scmi_handle { struct device *dev; struct scmi_revision_info *version; struct scmi_perf_ops *perf_ops; + struct scmi_clk_ops *clk_ops; /* for protocol internal use */ void *perf_priv; + void *clk_priv; }; enum scmi_std_protocol { From patchwork Mon Feb 12 18:45:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128160 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3488082ljc; Mon, 12 Feb 2018 10:50:00 -0800 (PST) X-Google-Smtp-Source: AH8x225fnjza/TB2nJ+tnTl2pIp1bewn4Z+rMb2z3Twau4grfmWQ8ngQRKvtZuZH4IJulc8hzb6P X-Received: by 10.98.152.208 with SMTP id d77mr12512308pfk.108.1518461400835; Mon, 12 Feb 2018 10:50:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461400; cv=none; d=google.com; s=arc-20160816; b=YuiGMwxRi1VVE7Deug4US8NjQMurKTk+aXK8nvjUdZKuRdekIpOkmUMa/M3G0cXl8y GN28De673au4X3BBzq3Fqsm7HXTPehxHJDPSxoQey4COQahhQf22g1xasRtLTF5rnL/f yheApTSmPxewl1PWFMDoRWK3Wlrlz4og9EbSn6cQOtAaOu7v5eHfA2l1xFNHuw+U2Stz uFJYS+/hU6Jw+zaMoHzWJTpJWzPovOFMpyD+kFzlv6wAgom75IWFYi7dXItCweAL2CUm JMSKo+EwAKd59qeYuDsVjYlouW3MScyDrZHoSE9uWpAemmpjKLLTS5642n7irfB1iJcg Xt5w== 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=hv9xDMcIIbFU52VKTKnFCfEGRvHjw+JAEbCu35224NI=; b=DhpEBoE9+bdY344aqfrE52MjFJ2MTftu7Oh9NI1RH8ib5GkvZHnN8/xNxHRNbKVlM/ yMe6MJPB3VclOuqBhnNhHbgKnJ89xtB3vxAFM58tcyPwTrkA5j7pDh6btos92ucknCfH u8BuwGl11QE3rs6ytamDxjxOUDJcFQomiRVU4G9KhrypEsT7bnIACGc3J1/qF7gOG++3 5SS5BJkG+PyomuoQ+ePjLO604AQeUVrjBsmv2PshlCvCpJkx3SDYLpkxNuU8fJ60PLBw zxaCcj2DBPt9kB5Rt6e4kSBH/4UsurLilSHB0So1DFAIMZnGl9fsL8elAR/xVu9suOq0 HgnQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.00; Mon, 12 Feb 2018 10:50:00 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754170AbeBLSt5 (ORCPT + 26 others); Mon, 12 Feb 2018 13:49:57 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47212 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753836AbeBLSp6 (ORCPT ); Mon, 12 Feb 2018 13:45:58 -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 7EEDF165C; Mon, 12 Feb 2018 10:45:58 -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 298383F24D; Mon, 12 Feb 2018 10:45:57 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 10/20] firmware: arm_scmi: probe and initialise all the supported protocols Date: Mon, 12 Feb 2018 18:45:14 +0000 Message-Id: <1518461124-17371-11-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Now that we have basic support for all the protocols in the specification, let's probe them individually and initialise them. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 51 +++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 0ceff82f6f59..939ef626bfdd 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -477,6 +477,21 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle, info->protocols_imp = prot_imp; } +static bool +scmi_is_protocol_implemented(const struct scmi_handle *handle, u8 prot_id) +{ + int i; + struct scmi_info *info = handle_to_scmi_info(handle); + + if (!info->protocols_imp) + return false; + + for (i = 0; i < MAX_PROTOCOLS_IMP; i++) + if (info->protocols_imp[i] == prot_id) + return true; + return false; +} + /** * scmi_handle_get() - Get the SCMI handle for a device * @@ -672,6 +687,23 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) return 0; } +static inline void +scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, + int prot_id) +{ + struct scmi_device *sdev; + + sdev = scmi_device_create(np, info->dev, prot_id); + if (!sdev) { + dev_err(info->dev, "failed to create %d protocol device\n", + prot_id); + return; + } + + /* setup handle now as the transport is ready */ + scmi_set_handle(sdev); +} + static int scmi_probe(struct platform_device *pdev) { int ret; @@ -679,7 +711,7 @@ static int scmi_probe(struct platform_device *pdev) const struct scmi_desc *desc; struct scmi_info *info; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct device_node *child, *np = dev->of_node; /* Only mailbox method supported, check for the presence of one */ if (scmi_mailbox_check(np)) { @@ -722,6 +754,23 @@ static int scmi_probe(struct platform_device *pdev) list_add_tail(&info->node, &scmi_list); mutex_unlock(&scmi_list_mutex); + for_each_available_child_of_node(np, child) { + u32 prot_id; + + if (of_property_read_u32(child, "reg", &prot_id)) + continue; + + prot_id &= MSG_PROTOCOL_ID_MASK; + + if (!scmi_is_protocol_implemented(handle, prot_id)) { + dev_err(dev, "SCMI protocol %d not implemented\n", + prot_id); + continue; + } + + scmi_create_protocol_device(child, info, prot_id); + } + return 0; } From patchwork Mon Feb 12 18:45:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128151 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485419ljc; Mon, 12 Feb 2018 10:46:12 -0800 (PST) X-Google-Smtp-Source: AH8x226+a/zAU0VLNRxjcrar5m5C6dDUr3c9nQ/ap1+rGAfek/sI86G/Qd2wn06sTg7jw320EVQz X-Received: by 10.101.67.71 with SMTP id k7mr9881462pgq.136.1518461172369; Mon, 12 Feb 2018 10:46:12 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461172; cv=none; d=google.com; s=arc-20160816; b=qPLvx+Qw+bai3bEV2tr/8m1QAcVTj4UVqDCuPfqcssM/l8h7C1mu8lrKXtsFo1scew 6J9Ron17ejF5qV81TJwds+Fg69Qwi830ixhSDD1srBbKxR1pmyGaeqrOIuyfZDitiuSk 55mj1NMeuNmb4ud9787sTcDGC0VRwXPI9NLhT+AJaknOR1b73LJ32B4sCXNcbwY2YbMS aRYV3D5Oom0PePW3zDE71L5VgPnEOyVsjDDkmREAQ1xBeqY5jXugviYMnkBVY2KllaTx VvUmuuSWQGKRrYTL93xp57NTuq9BJWlAqskwI/OQICWFc+833EB4MWW1zbWq5VLS+1Mq Gy7Q== 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=CsrEWVgEUhhJgU40rXv8P5u1lcGWdHKSRDHyrDyeuMg=; b=QzuG0CkrqzqAp8zNJ6/71Bs6YqZkeQDVUpSXWcBYV4X8f+2U0Pkxpy8FwzGQzF3u12 S/z2kQk0xiEKNQOuhPFpwAyIuee35JDuju0I9Q/aroya6SAEtgar96OT/1QQ7iASRZUT YncQ3QxgoP/g0m8mIrMWxXoYkzJxDs/1GIwnWVP2nD2O7zauKJ/cu64l+ylrsWXhanis vVfiHSJGchluTYOUk4GfbohnR0fNfTELQpFgJSNPP1iLpLU9x5I9l0+i7WZEqcKzDuG1 xb2xhtrycYPRuzhRzNNUp49p+8+gWfOzBVv/x4tzUy6VXZBVPI8xOka3YWoNJ8FGpG49 El1A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 z100-v6si837258plh.129.2018.02.12.10.46.11; Mon, 12 Feb 2018 10:46:12 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753311AbeBLSqG (ORCPT + 26 others); Mon, 12 Feb 2018 13:46:06 -0500 Received: from foss.arm.com ([217.140.101.70]:47224 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754052AbeBLSqA (ORCPT ); Mon, 12 Feb 2018 13:46:00 -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 1FA0B165D; Mon, 12 Feb 2018 10:46:00 -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 BDF433F24D; Mon, 12 Feb 2018 10:45:58 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 11/20] firmware: arm_scmi: add support for polling based SCMI transfers Date: Mon, 12 Feb 2018 18:45:15 +0000 Message-Id: <1518461124-17371-12-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It would be useful to have options to perform some SCMI transfers atomically by polling for the completion flag instead of interrupt driven. The SCMI specification has option to disable the interrupt and poll for the completion flag in the shared memory. This patch adds support for polling based SCMI transfers using that option. This might be used for uninterrupted/atomic DVFS operations from the scheduler context. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 49 +++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 939ef626bfdd..0108bb39d0f6 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -26,9 +26,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -346,6 +348,21 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) spin_unlock_irqrestore(&minfo->xfer_lock, flags); } +static bool +scmi_xfer_poll_done(const struct scmi_info *info, struct scmi_xfer *xfer) +{ + struct scmi_shared_mem *mem = info->tx_payload; + u16 xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); + + if (xfer->hdr.seq != xfer_id) + return false; + + return le32_to_cpu(mem->channel_status) & + (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); +} + +#define SCMI_MAX_POLLING_TIMEOUT_NS (100 * NSEC_PER_USEC) /** * scmi_do_xfer() - Do one transfer * @@ -372,14 +389,30 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) /* mbox_send_message returns non-negative value on success, so reset */ ret = 0; - /* And we wait for the response. */ - timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); - if (!wait_for_completion_timeout(&xfer->done, timeout)) { - dev_err(dev, "mbox timed out in resp(caller: %pF)\n", - (void *)_RET_IP_); - ret = -ETIMEDOUT; - } else if (xfer->hdr.status) { - ret = scmi_to_linux_errno(xfer->hdr.status); + if (xfer->hdr.poll_completion) { + ktime_t stop, cur; + + stop = ktime_add_ns(ktime_get(), SCMI_MAX_POLLING_TIMEOUT_NS); + do { + udelay(5); + cur = ktime_get(); + } while (!scmi_xfer_poll_done(info, xfer) && + ktime_before(cur, stop)); + + if (ktime_before(cur, stop)) + scmi_fetch_response(xfer, info->tx_payload); + else + ret = -ETIMEDOUT; + } else { + /* And we wait for the response. */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); + if (!wait_for_completion_timeout(&xfer->done, timeout)) { + dev_err(dev, "mbox timed out in resp(caller: %pF)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; + } else if (xfer->hdr.status) { + ret = scmi_to_linux_errno(xfer->hdr.status); + } } /* * NOTE: we might prefer not to need the mailbox ticker to manage the From patchwork Mon Feb 12 18:45:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128159 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3487704ljc; Mon, 12 Feb 2018 10:49:26 -0800 (PST) X-Google-Smtp-Source: AH8x225ur3A3z/bB5AhwT/Wxdf+9+1IYzBkoHsph5avfUBUAvdQRSML0GiKsEnN9wbpnYyxquVpI X-Received: by 2002:a17:902:7d8d:: with SMTP id a13-v6mr4213226plm.304.1518461366298; Mon, 12 Feb 2018 10:49:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461366; cv=none; d=google.com; s=arc-20160816; b=g3MRDjSBNJVCDTcU5GT1atcv6qdKGwkUA/sLBgN/5ZRrcVdG1jSEdPIz6m2XeQZ6Uk 4f6uEQBluLZ3kmWoZvQbEc6DY2quVOqJjhr0cSVLAcVyKpPF9pD2T5Uwy9kh93z5TeTi Mpuj+oGfghRTkIEQ99Y/W8nG3BY0H/NoWndOWDDfVyVVi6RB2IF6KMILLPZRoCoBLdYc CJbT9jUNLsV/gdkqM+qoiWjZUL+8IkOxrHjso7ZeWAI2En2rbOl56tiaqMEEMbTHSrA0 O8qpjC2MBNCKapP3GsUC8XZaQsleCXjg/+S7RxnDsjo4KtaVx+DhEQyEAoT752losWVa xSYg== 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=64ao8uaeps0Foww8D2F7WQA+koPgQMgSMf8VLK7cqdI=; b=tG5h4PvgBqBjJbpUyIs7q6JNFsK98LPLaa62eifcdZ4GJUdQsMOz+w8Gt6J4nI1TEL J4PRjkovbKylDRELBmxBfGfaVomO4M/mKNSsvaYAC4RAIE9NNElUxMivoxIKxEO5YsFe Kcy1S574q0W+pVyCZRUvvPTevdl0iw1DGAyI+90uttGBjEig6l1gTh1KanfkyRy1Fa+K mXH9ByYRu4PW0Nqkw+EL4bOez+h4+xmwD53nkFuZzfs4wP2xFlqDO+TNuFnyyY0OeoAv rq08/RiyXCpIO5GDM6LnH2dwlW4MVhb8mDTiL5XIOTljeN4ZCitytYQdv64fdysfr6Vs zNDw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.26; Mon, 12 Feb 2018 10:49:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932503AbeBLStV (ORCPT + 26 others); Mon, 12 Feb 2018 13:49:21 -0500 Received: from foss.arm.com ([217.140.101.70]:47244 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753346AbeBLSqC (ORCPT ); Mon, 12 Feb 2018 13:46:02 -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 B42AD1682; Mon, 12 Feb 2018 10:46:01 -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 5EAED3F24D; Mon, 12 Feb 2018 10:46:00 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 12/20] firmware: arm_scmi: add option for polling based performance domain operations Date: Mon, 12 Feb 2018 18:45:16 +0000 Message-Id: <1518461124-17371-13-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In order to implement fast CPU DVFS switching, we need to perform all DVFS operations atomically. Since SCMI transfer already provide option to choose between pooling vs interrupt driven(default), we can opt for polling based transfers for set,get performance domain operations. This patch adds option to choose between polling vs interrupt driven SCMI transfers for set,get performance level operations. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/perf.c | 19 +++++++++++-------- include/linux/scmi_protocol.h | 8 ++++---- 2 files changed, 15 insertions(+), 12 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index a14093386b57..6c9126dd6ec7 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -303,8 +303,8 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, return ret; } -static int -scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, u32 level) +static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, + u32 level, bool poll) { int ret; struct scmi_xfer *t; @@ -315,6 +315,7 @@ scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, u32 level) if (ret) return ret; + t->hdr.poll_completion = poll; lvl = t->tx.buf; lvl->domain = cpu_to_le32(domain); lvl->level = cpu_to_le32(level); @@ -325,8 +326,8 @@ scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, u32 level) return ret; } -static int -scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, u32 *level) +static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, + u32 *level, bool poll) { int ret; struct scmi_xfer *t; @@ -336,6 +337,7 @@ scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, u32 *level) if (ret) return ret; + t->hdr.poll_completion = poll; *(__le32 *)t->tx.buf = cpu_to_le32(domain); ret = scmi_do_xfer(handle, t); @@ -411,23 +413,24 @@ static int scmi_dvfs_get_transition_latency(const struct scmi_handle *handle, } static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain, - unsigned long freq) + unsigned long freq, bool poll) { struct scmi_perf_info *pi = handle->perf_priv; struct perf_dom_info *dom = pi->dom_info + domain; - return scmi_perf_level_set(handle, domain, freq / dom->mult_factor); + return scmi_perf_level_set(handle, domain, freq / dom->mult_factor, + poll); } static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain, - unsigned long *freq) + unsigned long *freq, bool poll) { int ret; u32 level; struct scmi_perf_info *pi = handle->perf_priv; struct perf_dom_info *dom = pi->dom_info + domain; - ret = scmi_perf_level_get(handle, domain, &level); + ret = scmi_perf_level_get(handle, domain, &level, poll); if (!ret) *freq = level * dom->mult_factor; diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 6785dd9f61e3..06e8ef1d8aea 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -103,14 +103,14 @@ struct scmi_clk_ops { struct scmi_perf_ops { int (*limits_set)(const struct scmi_handle *, u32, u32, u32); int (*limits_get)(const struct scmi_handle *, u32, u32 *, u32 *); - int (*level_set)(const struct scmi_handle *, u32, u32); - int (*level_get)(const struct scmi_handle *, u32, u32 *); + int (*level_set)(const struct scmi_handle *, u32, u32, bool); + int (*level_get)(const struct scmi_handle *, u32, u32 *, bool); int (*device_domain_id)(struct device *); int (*get_transition_latency)(const struct scmi_handle *, struct device *); int (*add_opps_to_device)(const struct scmi_handle *, struct device *); - int (*freq_set)(const struct scmi_handle *, u32, unsigned long); - int (*freq_get)(const struct scmi_handle *, u32, unsigned long *); + int (*freq_set)(const struct scmi_handle *, u32, unsigned long, bool); + int (*freq_get)(const struct scmi_handle *, u32, unsigned long *, bool); }; /** From patchwork Mon Feb 12 18:45:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128155 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3486125ljc; Mon, 12 Feb 2018 10:47:17 -0800 (PST) X-Google-Smtp-Source: AH8x2267Qv+f11RjmuRywITHVNemAHdAubH1oIgXFszLnwMdwO0fiz0Gvifn83lmQNJL3vLXywxw X-Received: by 2002:a17:902:8c81:: with SMTP id t1-v6mr11355209plo.363.1518461237047; Mon, 12 Feb 2018 10:47:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461237; cv=none; d=google.com; s=arc-20160816; b=K/vajYXjubaSEgVlQa5aRld/W2lKySXiV6KZhsAIfm5rynD7YolvAjlK1AG1uiU8xu qYrZou6LrKlgVyNn5pMAIaugOdT4B7DriLyQvyVack25MK4GMw/SDJvSbDAkaUD2L7WH 4gnrJglYwIUMmFy414Z80t6GZuK6r5YQ7+g4DczXOqSpIwZOcENZ0ow6ON+U5OQqzy7m h0dHcr+ydYq3ZpJKU1s///8G+OcPojKhW+o1to+2vljGu8zBL7WTMrShvbTt9gsE2Cp4 a/+7cf3k5FcMmUw50Tbu8gz2LLyg2GCRD3yW4NVxPZzUBQSOrxUmV4YZ+a8W0hGRL9Qk iTUg== 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=/LgpCOMuvhbXUC2vj8cEsKim6iMp0JjaA9lHM/V5D0Q=; b=dAAuwpUPwQLfPNJTEiZYQkUyekqaHRI/VNhsgUK739hFrlOUrtb/KrjccaiaNRwiMy KiO8fqcaZtH7igtiMWzmRoaF6zPL4nHKwhCnj1G6gV0aZ4eEJzia1c+vEGHrEdd3J5xv Z4rRi5NQnMthdyK8ON4UVGOqe1s26MlgSECflFaBthnjBqpB7AHpcFk6sirpVTaFx5L4 pVTyh/f8WctyF2p/lg3Ng4LEs7Vsp8yFM0QFSu9sfQKoS+mlfKIW3KkuFWkun00a+0P6 AD6FG7RzpTkoO9KFuFOQQyIPGoL+/J2p2O+oi6u//NplXMHqrGKcsuhhEoZo6SkX3HG2 lpdQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 e12si2220413pgf.646.2018.02.12.10.47.16; Mon, 12 Feb 2018 10:47:17 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754162AbeBLSqM (ORCPT + 26 others); Mon, 12 Feb 2018 13:46:12 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:47260 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754104AbeBLSqF (ORCPT ); Mon, 12 Feb 2018 13:46:05 -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 E94E816EA; Mon, 12 Feb 2018 10:46:04 -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 93A1E3F24D; Mon, 12 Feb 2018 10:46:03 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov Subject: [PATCH v5 14/20] firmware: arm_scmi: add per-protocol channels support using idr objects Date: Mon, 12 Feb 2018 18:45:18 +0000 Message-Id: <1518461124-17371-15-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In order to maintain the channel information per protocol, we need some sort of list or hashtable to hold all this information. IDR provides sparse array mapping of small integer ID numbers onto arbitrary pointers. In this case the arbitrary pointers can be pointers to the channel information. This patch adds support for per-protocol channels using those idr objects. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 5dd54f72b587..b91188dc85a1 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -115,6 +115,7 @@ struct scmi_chan_info { struct mbox_chan *chan; void __iomem *payload; struct device *dev; + struct scmi_handle *handle; }; /** @@ -126,7 +127,7 @@ struct scmi_chan_info { * @version: SCMI revision information containing protocol version, * implementation version and (sub-)vendor identification. * @minfo: Message info - * @tx_cinfo: Reference to SCMI channel information + * @tx_idr: IDR object to map protocol id to channel info pointer * @protocols_imp: list of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: list head @@ -138,7 +139,7 @@ struct scmi_info { struct scmi_revision_info version; struct scmi_handle handle; struct scmi_xfers_info minfo; - struct scmi_chan_info *tx_cinfo; + struct idr tx_idr; u8 *protocols_imp; struct list_head node; int users; @@ -229,7 +230,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) struct scmi_xfer *xfer; 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_info *info = handle_to_scmi_info(cinfo->handle); struct scmi_xfers_info *minfo = &info->minfo; struct scmi_shared_mem __iomem *mem = cinfo->payload; @@ -392,7 +393,11 @@ 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; + struct scmi_chan_info *cinfo; + + cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id); + if (unlikely(!cinfo)) + return -EINVAL; ret = mbox_send_message(cinfo->chan, xfer); if (ret < 0) { @@ -662,13 +667,18 @@ 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_chan_info *cinfo) +static int scmi_mbox_free_channel(int id, void *p, void *data) { + struct scmi_chan_info *cinfo = p; + struct idr *idr = data; + if (!IS_ERR_OR_NULL(cinfo->chan)) { mbox_free_channel(cinfo->chan); cinfo->chan = NULL; } + idr_remove(idr, id); + return 0; } @@ -676,6 +686,7 @@ static int scmi_remove(struct platform_device *pdev) { int ret = 0; struct scmi_info *info = platform_get_drvdata(pdev); + struct idr *idr = &info->tx_idr; mutex_lock(&scmi_list_mutex); if (info->users) @@ -684,28 +695,34 @@ static int scmi_remove(struct platform_device *pdev) list_del(&info->node); mutex_unlock(&scmi_list_mutex); - if (!ret) + if (!ret) { /* Safe to free channels since no more users */ - return scmi_mbox_free_channel(info->tx_cinfo); + ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + idr_destroy(&info->tx_idr); + } return ret; } -static inline int scmi_mbox_chan_setup(struct scmi_info *info) +static inline int +scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) { int ret; struct resource res; 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; + if (scmi_mailbox_check(np)) { + cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE); + goto idr_alloc; + } + cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) return -ENOMEM; - info->tx_cinfo = cinfo; cinfo->dev = dev; cl = &cinfo->cl; @@ -739,6 +756,14 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) return ret; } +idr_alloc: + ret = idr_alloc(&info->tx_idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); + if (ret != prot_id) { + dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret); + return ret; + } + + cinfo->handle = &info->handle; return 0; } @@ -755,6 +780,11 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, return; } + if (scmi_mbox_chan_setup(info, &sdev->dev, prot_id)) { + dev_err(&sdev->dev, "failed to setup transport\n"); + scmi_device_destroy(sdev); + } + /* setup handle now as the transport is ready */ scmi_set_handle(sdev); } @@ -789,19 +819,19 @@ static int scmi_probe(struct platform_device *pdev) return ret; platform_set_drvdata(pdev, info); + idr_init(&info->tx_idr); handle = &info->handle; handle->dev = info->dev; handle->version = &info->version; - ret = scmi_mbox_chan_setup(info); + ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE); if (ret) return ret; ret = scmi_base_protocol_init(handle); if (ret) { dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); - scmi_mbox_free_channel(info->tx_cinfo); return ret; } From patchwork Mon Feb 12 18:45:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128157 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3487155ljc; Mon, 12 Feb 2018 10:48:43 -0800 (PST) X-Google-Smtp-Source: AH8x225Tpv2p1++B/dj9Dupsay8PkqAWQFpwoNlQ47VwADDbHq2DpzkaTUy2U7d5nlz4QMSWRLAB X-Received: by 10.99.143.69 with SMTP id r5mr9931786pgn.160.1518461323361; Mon, 12 Feb 2018 10:48:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461323; cv=none; d=google.com; s=arc-20160816; b=zXj57XQSfY2yx87f7oDHSxI7UUMRpNYQm/GYLcuIuE+V5CVRjl+yhUP+/ca2LCWl5P PvO+4+7tMmDDVwXOvw9L6LuBcqHQMHhNxDzLxitBWfVMlcFZPSb1IFJC40Uf8mYnHjow UhjIgjRJYaZmlJbnM7pXRR5CIzO/LRzDINAOj3cNJ877+k4hsFIeG53+KPFJnVCcTPZV lBZv8mTXUwztSf4yru9YuJ5kA/Ew+QugFO/u1YYsugcH8/9jvYOieLmjOY6mj6bduPg9 v52n5c77+I8tkTqrW7m8vypKZAHBMWS1lPe2kwfurmdwWte9HolozprcdtXzX1WroeGX Z0Uw== 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=9k6KTPoq/IXHX4nT2upADuz2ZAmqG7rGHn05db046JY=; b=bMxgvsCngTaYQ8L+4Rjc+DcMWvtmGyjvAOr7WAn3+l0VQvSagtRZDE3xsmZuKp7MxT YeW3XX1bDt0ZeLzToXQlEZPL6H2SE9G4LkfD/v9IGbRtJ70vpJFoASolrR2TijSY0mJa td9TLEdzCE/7pxtBSUG/YEX/4unAa/E3NlSQpyIkH+xjmbTeWt2YB2Z9ZlxcmEWjQDG9 c2N0IinNDCgWxoAOnRigAWLpxtzpkmasDjERscJqhxOtCfhEPm7Pm/r8FnsnM9jPVMKD +aTi/JSnvJl4RlYmMm6QYsHejtNmHr5DtuVR5Pb/QSKUggCv1PoSDla+6jJQilShsvf4 FDOQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 b25si24428pgf.488.2018.02.12.10.48.43; Mon, 12 Feb 2018 10:48:43 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932431AbeBLSsh (ORCPT + 26 others); Mon, 12 Feb 2018 13:48:37 -0500 Received: from foss.arm.com ([217.140.101.70]:47294 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753366AbeBLSqI (ORCPT ); Mon, 12 Feb 2018 13:46:08 -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 9444516A3; Mon, 12 Feb 2018 10:46:08 -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 EBF6A3F24D; Mon, 12 Feb 2018 10:46:06 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , linux-clk@vger.kernel.org, Michael Turquette Subject: [PATCH v5 16/20] clk: add support for clocks provided by SCMI Date: Mon, 12 Feb 2018 18:45:20 +0000 Message-Id: <1518461124-17371-17-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@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. System Control and Management Interface(SCMI) Message Protocol is defined for the communication between the Application Cores(AP) and the SCP. This patch adds support for the clocks provided by SCP using SCMI protocol. Cc: linux-clk@vger.kernel.org Cc: Michael Turquette Acked-by: Stephen Boyd Signed-off-by: Sudeep Holla --- MAINTAINERS | 2 +- drivers/clk/Kconfig | 10 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-scmi.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-scmi.c -- 2.7.4 diff --git a/MAINTAINERS b/MAINTAINERS index 7cede6e7dfed..d6e9e3eae5ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13384,7 +13384,7 @@ M: Sudeep Holla L: linux-arm-kernel@lists.infradead.org S: Maintained F: Documentation/devicetree/bindings/arm/arm,sc[mp]i.txt -F: drivers/clk/clk-scpi.c +F: drivers/clk/clk-sc[mp]i.c F: drivers/cpufreq/scpi-cpufreq.c F: drivers/firmware/arm_scpi.c F: drivers/firmware/arm_scmi/ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98ce9fc6e6c0..7ae23b25b406 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -62,6 +62,16 @@ config COMMON_CLK_HI655X multi-function device has one fixed-rate oscillator, clocked at 32KHz. +config COMMON_CLK_SCMI + tristate "Clock driver controlled via SCMI interface" + depends on ARM_SCMI_PROTOCOL || COMPILE_TEST + ---help--- + This driver provides support for clocks that are controlled + by firmware that implements the SCMI interface. + + This driver uses SCMI Message Protocol to interact with the + firmware providing all the clock controls. + config COMMON_CLK_SCPI tristate "Clock driver controlled via SCPI interface" depends on ARM_SCPI_PROTOCOL || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71ec41e6364f..6605513eaa94 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o +obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c new file mode 100644 index 000000000000..1e4d7a57779b --- /dev/null +++ b/drivers/clk/clk-scmi.c @@ -0,0 +1,213 @@ +/* + * System Control and Power Interface (SCMI) Protocol based clock driver + * + * 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 +#include +#include + +struct scmi_clk { + u32 id; + struct clk_hw hw; + const struct scmi_clock_info *info; + const struct scmi_handle *handle; +}; + +#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw) + +static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int ret; + u64 rate; + struct scmi_clk *clk = to_scmi_clk(hw); + + ret = clk->handle->clk_ops->rate_get(clk->handle, clk->id, &rate); + if (ret) + return 0; + return rate; +} + +static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + int step; + u64 fmin, fmax, ftmp; + struct scmi_clk *clk = to_scmi_clk(hw); + + /* + * We can't figure out what rate it will be, so just return the + * rate back to the caller. scmi_clk_recalc_rate() will be called + * after the rate is set and we'll know what rate the clock is + * running at then. + */ + if (clk->info->rate_discrete) + return rate; + + fmin = clk->info->range.min_rate; + fmax = clk->info->range.max_rate; + if (rate <= fmin) + return fmin; + else if (rate >= fmax) + return fmax; + + ftmp = rate - fmin; + ftmp += clk->info->range.step_size - 1; /* to round up */ + step = do_div(ftmp, clk->info->range.step_size); + + return step * clk->info->range.step_size + fmin; +} + +static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct scmi_clk *clk = to_scmi_clk(hw); + + return clk->handle->clk_ops->rate_set(clk->handle, clk->id, 0, rate); +} + +static int scmi_clk_enable(struct clk_hw *hw) +{ + struct scmi_clk *clk = to_scmi_clk(hw); + + return clk->handle->clk_ops->enable(clk->handle, clk->id); +} + +static void scmi_clk_disable(struct clk_hw *hw) +{ + struct scmi_clk *clk = to_scmi_clk(hw); + + clk->handle->clk_ops->disable(clk->handle, clk->id); +} + +static const struct clk_ops scmi_clk_ops = { + .recalc_rate = scmi_clk_recalc_rate, + .round_rate = scmi_clk_round_rate, + .set_rate = scmi_clk_set_rate, + /* + * We can't provide enable/disable callback as we can't perform the same + * in atomic context. Since the clock framework provides standard API + * clk_prepare_enable that helps cases using clk_enable in non-atomic + * context, it should be fine providing prepare/unprepare. + */ + .prepare = scmi_clk_enable, + .unprepare = scmi_clk_disable, +}; + +static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk) +{ + int ret; + struct clk_init_data init = { + .flags = CLK_GET_RATE_NOCACHE, + .num_parents = 0, + .ops = &scmi_clk_ops, + .name = sclk->info->name, + }; + + sclk->hw.init = &init; + ret = devm_clk_hw_register(dev, &sclk->hw); + if (!ret) + clk_hw_set_rate_range(&sclk->hw, sclk->info->range.min_rate, + sclk->info->range.max_rate); + return ret; +} + +static int scmi_clocks_probe(struct scmi_device *sdev) +{ + int idx, count, err; + struct clk_hw **hws; + struct clk_hw_onecell_data *clk_data; + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + const struct scmi_handle *handle = sdev->handle; + + if (!handle || !handle->clk_ops) + return -ENODEV; + + count = handle->clk_ops->count_get(handle); + if (count < 0) { + dev_err(dev, "%s: invalid clock output count\n", np->name); + return -EINVAL; + } + + clk_data = devm_kzalloc(dev, sizeof(*clk_data) + + sizeof(*clk_data->hws) * count, GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = count; + hws = clk_data->hws; + + for (idx = 0; idx < count; idx++) { + struct scmi_clk *sclk; + + sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL); + if (!sclk) + return -ENOMEM; + + sclk->info = handle->clk_ops->info_get(handle, idx); + if (!sclk->info) { + dev_dbg(dev, "invalid clock info for idx %d\n", idx); + continue; + } + + sclk->id = idx; + sclk->handle = handle; + + err = scmi_clk_ops_init(dev, sclk); + if (err) { + dev_err(dev, "failed to register clock %d\n", idx); + devm_kfree(dev, sclk); + hws[idx] = NULL; + } else { + dev_dbg(dev, "Registered clock:%s\n", sclk->info->name); + hws[idx] = &sclk->hw; + } + } + + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); +} + +static void scmi_clocks_remove(struct scmi_device *sdev) +{ + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + + of_clk_del_provider(np); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_CLOCK }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_clocks_driver = { + .name = "scmi-clocks", + .probe = scmi_clocks_probe, + .remove = scmi_clocks_remove, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_clocks_driver); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI clock driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Feb 12 18:45:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128156 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3486374ljc; Mon, 12 Feb 2018 10:47:40 -0800 (PST) X-Google-Smtp-Source: AH8x227mdUMZQYMVQO0Bto0eQbhj8iozoPey9mPVN4hZlknMoScboLKFCA0jvSqcEHcPFOuib/Rg X-Received: by 2002:a17:902:930a:: with SMTP id bc10-v6mr11673009plb.19.1518461260656; Mon, 12 Feb 2018 10:47:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461260; cv=none; d=google.com; s=arc-20160816; b=mdYuPjKlV3s3pQqeR8NjVqLvnoKTXBVANyRxg/xRLXP2M5lm8sWiAmgkuRulOR05rf 4/NyZqLPbljtTQsnV1/yDj2d57emu91mHr7P3hLR2V58dRzJf+GLlhoGc2MkzvLSC1s+ EhFCq0UPkeXu0t9tHQ8nmMygAQM6VXPfZbX5NiuRErntVRfz2qyqn1041vFkVXei/hms bVFXKJmU2uC/GTozR7oGSCb3pw3925K1J6xnmrnYQFR7/467iiuRbFDJhlwxHljQBJH1 /VKOv3ZmhUTLumQwF4cbemN3qiUKfuzj50pUOnPliYdsEGLV7LSLi9Z7HcyRCDyWjSw2 RqDQ== 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=/i6TuDJNgj4250w3zm8wGHYhfNkmg8vX0SxWN/pRArc=; b=X8GpA58UZt5jyYNb9Tt5lC92AoeGmCSRoS8ePBt0XAYn3dO9jBnPshcr2u4or4pw0r GNAAnuAvtxpxG57XZikxao1fi+Nfp2b1VbKPdhPZE+sHaskyp2fZ4tdvZDmq4eQlGYYx LaDxa5Ar1bcgBvPUzCpuZHmPM3d3JbXBnW5FzT+byaH4C1ATu14IG7ebiLk/kkiRTKFd 6Nki0ux9sbUS6CIiRObZo9oq9LdX7/HHjp4Rmzu/lK7JwQCPq4vvzZ7J8g5Z6UCkY6wn 7OwfQHW+2AhLHVAdZCxWj13Ux4awl9EXt31YMnhcc1u7Rz5Da5At97QM9nIjayuRdhC6 DiNA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 81si4354064pfh.38.2018.02.12.10.47.40; Mon, 12 Feb 2018 10:47:40 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932412AbeBLSrh (ORCPT + 26 others); Mon, 12 Feb 2018 13:47:37 -0500 Received: from foss.arm.com ([217.140.101.70]:47298 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754052AbeBLSqK (ORCPT ); Mon, 12 Feb 2018 13:46:10 -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 616A7165C; Mon, 12 Feb 2018 10:46:10 -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 D329D3F24D; Mon, 12 Feb 2018 10:46:08 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , linux-hwmon@vger.kernel.org Subject: [PATCH v5 17/20] hwmon: (core) Add hwmon_max to hwmon_sensor_types enumeration Date: Mon, 12 Feb 2018 18:45:21 +0000 Message-Id: <1518461124-17371-18-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It's useful to know the maximum types of sensor supported by hwmon framework. It can be used to allocate some data structures when sorting the monitors based on their type. This will be used by scmi hwmon support. Cc: linux-hwmon@vger.kernel.org Acked-by: Guenter Roeck Signed-off-by: Sudeep Holla --- include/linux/hwmon.h | 1 + 1 file changed, 1 insertion(+) -- 2.7.4 diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index ceb751987c40..e5fd2707b6df 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -29,6 +29,7 @@ enum hwmon_sensor_types { hwmon_humidity, hwmon_fan, hwmon_pwm, + hwmon_max, }; enum hwmon_chip_attributes { From patchwork Mon Feb 12 18:45:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128152 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485501ljc; Mon, 12 Feb 2018 10:46:19 -0800 (PST) X-Google-Smtp-Source: AH8x226DNlub7qmq6ZvY1kphq6xB67fPvTTt31d+NS9rKPjdtRdUK3X1jPJxhZqGMg+trApht5sf X-Received: by 10.101.69.67 with SMTP id x3mr10079435pgr.69.1518461179218; Mon, 12 Feb 2018 10:46:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461179; cv=none; d=google.com; s=arc-20160816; b=CayxE2bOFuurdr2Ke5BoynkadEhoN/U1APHvePEHdeaW5U5L4JtgO3W7apZ3r7QapF JbB88EwM+/a+Uo/UNIshzcwHaeOv1lTQaUDgG+sZH3T5/PxKZY9ubGxFHLf9vmOhfe99 ShGNklIS/JrKCg9ZLCeQn6oNHNOE9DxaCFgaF7trMy2a8v5/P2iu1Bb5+cGdyxTbsCiG 10SvxXNuh17EIsRO37zgILSzrJF3F73P4389p7vd6jCtkcg78sQeNm0pq5zkHuHTXkzl OS9YsyE1tq/iKNI5SHA1Id9V7UFAukXzX5lJQVNYuPINsS3dPj1SPWzQlx0J0hVUhXR6 DeBw== 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=ilGoSJT72DstUnBFF82hCPLdyeIBpj1EQ+wsVvfvAm4=; b=gbO+GXNoaars+f2wnWttzJarEVCpmo/YaJBY+bKVPWHkk0cVfTiyONE8xhuf2LMCPd oP54iwT8Rh1M6X53uGldj5gjAAatCRxiiGoNuzp2m9h3ITapCilwSUJ1XbTfU4NkOPlx Ew7XCLDzPKmrq51jrY2xDj/0/Z5sEtBnBwmP/RzNC/YM4aAJFftWCxsg3+CdMN4z+zHy xzEdjdFQs3co56knSbYFMCJkploV/u5IyFVtfVOdpSyL/dENcm68rQuwjiUVP+GmcyiV AVaJuyFVZiPWLjDKXcWMUAo2mvqxl6qNjHxgEYXYZy3mzXOef5W3ppXUGf8++Qkzgj5t Lo2Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.18; Mon, 12 Feb 2018 10:46:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754181AbeBLSqP (ORCPT + 26 others); Mon, 12 Feb 2018 13:46:15 -0500 Received: from foss.arm.com ([217.140.101.70]:47308 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754160AbeBLSqM (ORCPT ); Mon, 12 Feb 2018 13:46:12 -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 25549165D; Mon, 12 Feb 2018 10:46:12 -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 A03873F24D; Mon, 12 Feb 2018 10:46:10 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Greg Kroah-Hartman , Arnd Bergmann , Alexey Klimov , linux-hwmon@vger.kernel.org Subject: [PATCH v5 18/20] hwmon: add support for sensors exported via ARM SCMI Date: Mon, 12 Feb 2018 18:45:22 +0000 Message-Id: <1518461124-17371-19-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Create a driver to add support for SoC sensors exported by the System Control Processor (SCP) via the System Control and Management Interface (SCMI). The supported sensor types is one of voltage, temperature, current, and power. The sensor labels and values provided by the SCP are exported via the hwmon sysfs interface. Cc: linux-hwmon@vger.kernel.org Acked-by: Guenter Roeck Signed-off-by: Sudeep Holla --- drivers/hwmon/Kconfig | 12 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/scmi-hwmon.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/hwmon/scmi-hwmon.c -- 2.7.4 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ef23553ff5cb..033e57366d56 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -317,6 +317,18 @@ config SENSORS_APPLESMC Say Y here if you have an applicable laptop and want to experience the awesome power of applesmc. +config SENSORS_ARM_SCMI + tristate "ARM SCMI Sensors" + depends on ARM_SCMI_PROTOCOL + depends on THERMAL || !THERMAL_OF + help + This driver provides support for temperature, voltage, current + and power sensors available on SCMI based platforms. The actual + number and type of sensors exported depend on the platform. + + This driver can also be built as a module. If so, the module + will be called scmi-hwmon. + config SENSORS_ARM_SCPI tristate "ARM SCPI Sensors" depends on ARM_SCPI_PROTOCOL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index f814b4ace138..e7d52a36e6c4 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o +obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c new file mode 100644 index 000000000000..7a0ab768d4b5 --- /dev/null +++ b/drivers/hwmon/scmi-hwmon.c @@ -0,0 +1,233 @@ +/* + * System Control and Management Interface(SCMI) based hwmon sensor 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. + */ + +#include +#include +#include +#include +#include +#include + +struct scmi_sensors { + const struct scmi_handle *handle; + const struct scmi_sensor_info **info[hwmon_max]; +}; + +static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + int ret; + u64 value; + const struct scmi_sensor_info *sensor; + struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); + const struct scmi_handle *h = scmi_sensors->handle; + + sensor = *(scmi_sensors->info[type] + channel); + ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); + if (!ret) + *val = value; + + return ret; +} + +static int +scmi_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + const struct scmi_sensor_info *sensor; + struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); + + sensor = *(scmi_sensors->info[type] + channel); + *str = sensor->name; + + return 0; +} + +static umode_t +scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct scmi_sensor_info *sensor; + const struct scmi_sensors *scmi_sensors = drvdata; + + sensor = *(scmi_sensors->info[type] + channel); + if (sensor && sensor->name) + return S_IRUGO; + + return 0; +} + +static const struct hwmon_ops scmi_hwmon_ops = { + .is_visible = scmi_hwmon_is_visible, + .read = scmi_hwmon_read, + .read_string = scmi_hwmon_read_string, +}; + +static struct hwmon_chip_info scmi_chip_info = { + .ops = &scmi_hwmon_ops, + .info = NULL, +}; + +static int scmi_hwmon_add_chan_info(struct hwmon_channel_info *scmi_hwmon_chan, + struct device *dev, int num, + enum hwmon_sensor_types type, u32 config) +{ + int i; + u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); + + if (!cfg) + return -ENOMEM; + + scmi_hwmon_chan->type = type; + scmi_hwmon_chan->config = cfg; + for (i = 0; i < num; i++, cfg++) + *cfg = config; + + return 0; +} + +static enum hwmon_sensor_types scmi_types[] = { + [TEMPERATURE_C] = hwmon_temp, + [VOLTAGE] = hwmon_in, + [CURRENT] = hwmon_curr, + [POWER] = hwmon_power, + [ENERGY] = hwmon_energy, +}; + +static u32 hwmon_attributes[] = { + [hwmon_chip] = HWMON_C_REGISTER_TZ, + [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL, + [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, + [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, + [hwmon_power] = HWMON_P_INPUT | HWMON_P_LABEL, + [hwmon_energy] = HWMON_E_INPUT | HWMON_E_LABEL, +}; + +static int scmi_hwmon_probe(struct scmi_device *sdev) +{ + int i, idx; + u16 nr_sensors; + enum hwmon_sensor_types type; + struct scmi_sensors *scmi_sensors; + const struct scmi_sensor_info *sensor; + int nr_count[hwmon_max] = {0}, nr_types = 0; + const struct hwmon_chip_info *chip_info; + struct device *hwdev, *dev = &sdev->dev; + struct hwmon_channel_info *scmi_hwmon_chan; + const struct hwmon_channel_info **ptr_scmi_ci; + const struct scmi_handle *handle = sdev->handle; + + if (!handle || !handle->sensor_ops) + return -ENODEV; + + nr_sensors = handle->sensor_ops->count_get(handle); + if (!nr_sensors) + return -EIO; + + scmi_sensors = devm_kzalloc(dev, sizeof(*scmi_sensors), GFP_KERNEL); + if (!scmi_sensors) + return -ENOMEM; + + scmi_sensors->handle = handle; + + for (i = 0; i < nr_sensors; i++) { + sensor = handle->sensor_ops->info_get(handle, i); + if (!sensor) + return PTR_ERR(sensor); + + switch (sensor->type) { + case TEMPERATURE_C: + case VOLTAGE: + case CURRENT: + case POWER: + case ENERGY: + type = scmi_types[sensor->type]; + if (!nr_count[type]) + nr_types++; + nr_count[type]++; + break; + } + } + + if (nr_count[hwmon_temp]) + nr_count[hwmon_chip]++, nr_types++; + + scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), + GFP_KERNEL); + if (!scmi_hwmon_chan) + return -ENOMEM; + + ptr_scmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*ptr_scmi_ci), + GFP_KERNEL); + if (!ptr_scmi_ci) + return -ENOMEM; + + scmi_chip_info.info = ptr_scmi_ci; + chip_info = &scmi_chip_info; + + for (type = 0; type < hwmon_max && nr_count[type]; type++) { + scmi_hwmon_add_chan_info(scmi_hwmon_chan, dev, nr_count[type], + type, hwmon_attributes[type]); + *ptr_scmi_ci++ = scmi_hwmon_chan++; + + scmi_sensors->info[type] = + devm_kcalloc(dev, nr_count[type], + sizeof(*scmi_sensors->info), GFP_KERNEL); + if (!scmi_sensors->info[type]) + return -ENOMEM; + } + + for (i = nr_sensors - 1; i >= 0 ; i--) { + sensor = handle->sensor_ops->info_get(handle, i); + if (!sensor) + continue; + + switch (sensor->type) { + case TEMPERATURE_C: + case VOLTAGE: + case CURRENT: + case POWER: + case ENERGY: + type = scmi_types[sensor->type]; + idx = --nr_count[type]; + *(scmi_sensors->info[type] + idx) = sensor; + break; + } + } + + hwdev = devm_hwmon_device_register_with_info(dev, "scmi_sensors", + scmi_sensors, chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwdev); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_SENSOR }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_hwmon_drv = { + .name = "scmi-hwmon", + .probe = scmi_hwmon_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_hwmon_drv); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI HWMON interface driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Feb 12 18:45:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 128153 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3485690ljc; Mon, 12 Feb 2018 10:46:36 -0800 (PST) X-Google-Smtp-Source: AH8x224QwNDLkujDSDjc/G9ig9HstRreZdxykjOSOIl9SjMhTUzWihsvEKrdAeJR6O4zhRQK8G4H X-Received: by 10.101.64.74 with SMTP id h10mr9728726pgp.200.1518461195905; Mon, 12 Feb 2018 10:46:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518461195; cv=none; d=google.com; s=arc-20160816; b=OZCIfUXvSiwy7SnK+AM00/0jufRBdPDNSt5NwtxeK4EIbZrftKfY5CYKIqaCcrAdIb SrE2tm7KFLcnLtIg2gqgngr0SnGkP8owTdC52q4FTgWDywo58ekSE51v+nXykUB8CREY cTWtJFcx77R+FnqTfD7TDy9t2ezKR6UCbYq3bok89C0gafMSDwRnjFxD12woKTR6Lhn+ biI+fAvZ4BYKzGMneaCJ+mwZw/ablub2c8NnrCgd6sH7ucWSymhGkGTj5vy/bnrRVXYQ Yyc5bOu0i1HxQrODpdDzomNGdI0b0USuCSNZTrS/rXLnkToaV2YNs/bEV/UcT3wmggd1 WVGA== 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=PjOe8S8Onvct3BSagmr9w+aYI5UY8YfLSSSDIIsw9bc=; b=pU1Q/VxezFZ5hBCEvhQFh/MU85StMDv0Wy9sfrzjNVIqnhBudQpJj3uk2VEaAjA8Kn KlhKD4o36O9KaL/r1It0SjRtY85dcnIWpbleIyWu5UoJngr6tcJ/rZMKQmOvVjLQUEjS +C9AxN0HLrDgZt7FESmmv2mv1y4StbwAqQCegcSJeujGElwuyVw1sweIxcCbXy80UZcg 2EnwpkbpYNTh9PqukDgFFH07GpSZ0whCO0El9BHt/Mid2k5mxne3e93RI1u8SObNWHG5 0pDnqQoYGTl5m28nQ/ZLDcrJ8R70gUaO9K62Rr7jYglMNdjcOCizQIo5KV7Pd9uXlCqs MWAg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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.35; Mon, 12 Feb 2018 10:46:35 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932190AbeBLSqS (ORCPT + 26 others); Mon, 12 Feb 2018 13:46:18 -0500 Received: from foss.arm.com ([217.140.101.70]:47326 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754160AbeBLSqP (ORCPT ); Mon, 12 Feb 2018 13:46:15 -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 A05C91435; Mon, 12 Feb 2018 10:46:15 -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 2788E3F24D; Mon, 12 Feb 2018 10:46:14 -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 20/20] cpufreq: scmi: add support for fast frequency switching Date: Mon, 12 Feb 2018 18:45:24 +0000 Message-Id: <1518461124-17371-21-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: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The cpufreq core provides option for drivers to implement fast_switch callback which is invoked for frequency switching from interrupt context. This patch adds support for fast_switch callback in SCMI cpufreq driver by making use of polling based SCMI transfer. It also sets the flag fast_switch_possible. Cc: linux-pm@vger.kernel.org Acked-by: Rafael J. Wysocki Acked-by: Viresh Kumar Signed-off-by: Sudeep Holla --- drivers/cpufreq/scmi-cpufreq.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) -- 2.7.4 diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index d6d35f7692b3..c869c99b2142 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -64,6 +64,19 @@ scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) return perf_ops->freq_set(handle, priv->domain_id, freq, false); } +static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct scmi_data *priv = policy->driver_data; + struct scmi_perf_ops *perf_ops = handle->perf_ops; + + if (!perf_ops->freq_set(handle, priv->domain_id, + target_freq * 1000, true)) + return target_freq; + + return 0; +} + static int scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) { @@ -163,6 +176,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = latency; + policy->fast_switch_possible = true; return 0; out_free_cpufreq_table: @@ -201,6 +215,7 @@ static struct cpufreq_driver scmi_cpufreq_driver = { .verify = cpufreq_generic_frequency_table_verify, .attr = cpufreq_generic_attr, .target_index = scmi_cpufreq_set_target, + .fast_switch = scmi_cpufreq_fast_switch, .get = scmi_cpufreq_get_rate, .init = scmi_cpufreq_init, .exit = scmi_cpufreq_exit,