From patchwork Thu Sep 28 13:11:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114422 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727237qgf; Thu, 28 Sep 2017 06:14:11 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDysT3eD1K6XNSjMellizgJ8wGV9RIFZSCmZMlhgFfkmRexUW5uJuzsE/YzcOrnN221qvLf X-Received: by 10.84.194.3 with SMTP id g3mr4141689pld.246.1506604451469; Thu, 28 Sep 2017 06:14:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604451; cv=none; d=google.com; s=arc-20160816; b=G/mFno+DXRq7mYhe9PDTIDT09jMvAI8NB8v3nYFo4eV1NKSOdg/rYYMnsLJLq4/hjp RX5HHtNxbDt05D3+C8adRYGJ/3d3vAO2APX/weHZPvPVbOsBJgvyk9BTrHJhtUEZ7rtO 87P1QPOliGNtTMmGpnAwHC7wBoYIcqM2T9YFpcsWog2vzP3k5xozqgPT4kYO0MUTX51v nueCzFPj6MwoGuVL3VLQ7Q3sffrNqr20XNTEmWs9pUZPr9jhj9ZJxArYYXt1s5Uc51DE Dlt9Uc2s/6dkTBkpXUaM13pS6BXeQ7hHaGOofAYOimg87R9gcDKZxvInvBOYFWuc0Lms /QQA== 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=gxGR7bZ00RcPMxdzG1zm0ZpuijseVr2VvuB23nvc6So=; b=fSV7M5w3OKTgMnTbYC/n6oSuBgUYfbB4/fnBGGeWCoFT6QT6V2VVb+k3wCDjIt8K9a 1oNBMxPUnqbYeLldsaJ0hOlfaqdm3/pVustqTb3FenFo8Nkavwmzlbj6OpQPgs0hpApb TLcpXYEJbQk4RXKj7uNd29nQqWQqTe+rjLjDfHFV816EHSuARHlKmYUf1VgH1BQsHl8o 2beCGb+7IVuaBbq+hSSydoxoK6ytteZ0pqWTBk4qBAHha5bkgff5AFvyKJuHqBgh2wIc XEkewIGjJ2dId5wWSJAXWsSNr7OG6i2gj6VYu3j/RXE53RXMZWRAg9caOewrOWPKSE2t X7aw== 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 v11si1386448pgo.292.2017.09.28.06.14.10; Thu, 28 Sep 2017 06:14:11 -0700 (PDT) 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 S1753227AbdI1NOI (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:08 -0400 Received: from foss.arm.com ([217.140.101.70]:56922 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751943AbdI1NOG (ORCPT ); Thu, 28 Sep 2017 09:14:06 -0400 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 747E61596; Thu, 28 Sep 2017 06:14:06 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 1B09D3F483; Thu, 28 Sep 2017 06:14:03 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Rob Herring , Mark Rutland Subject: [PATCH v3 01/22] dt-bindings: mailbox: add support for mailbox client shared memory Date: Thu, 28 Sep 2017 14:11:25 +0100 Message-Id: <1506604306-20739-2-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: Rob Herring 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 Thu Sep 28 13:11:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114423 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727316qgf; Thu, 28 Sep 2017 06:14:15 -0700 (PDT) X-Google-Smtp-Source: AOwi7QBfgQWWo5G25njOPntK06mQZxweUs/GylT4T8HrjxeFu6KeqJ7SSq8atX2LWdrvqOD4O3Lh X-Received: by 10.99.173.67 with SMTP id y3mr4247795pgo.69.1506604455204; Thu, 28 Sep 2017 06:14:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604455; cv=none; d=google.com; s=arc-20160816; b=dNrwGFhunGJmO1LALTtlhK2rLvqBsy3WZDSAGKZFKBsjAyH7xUMR3Qix8S9n1Af/1F VxHWS3W+LNcYikj1I+RqJj92KBtV8fkoLACwcVPURUGoP0Y+b5l7uVUafBxPNI4uoqoo wYCzPgqNhM/4ZiJXWFzLaeaBU+x/a5N4LMmPKB8nWFYL+dtBkfjwJRGWsr4IC+KC6mpg p/XDuRcDISImJINYfBHcqGo3uVKbNTcJ7AHKPeZrm84bVuy24VqSbrRwOOxazQbF4dus 7KTOB5hx3EvpKTpu9DsMJiw3vN98pRAIS/rl3TdAas75UM8zttwbIaQmvsJe1zrHySly aQvQ== 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=H7yvKRejmBAHzcR6gKsQYexGPNDFHh0m3FOZDNQ1BmU=; b=0F2xyzuAWEXGVrgoPUafAaf2h5siZ4c2CTj5C43t0imFqAlKUQ1olFFSqyWcpTmuIk PPnOlk9nfXbXMv/rSpW1xXFTJEBDpeXsR6j/IbpECBNYvKpLpZmNx/QjLrNAPJPpQavi w43GycDw3lNzPf2hJlv3xIiU07GTLVivkY5eKxj0CGdGMBHdfuPBE6QwwkIWZNywk48y 8GuCzPAmOpR3ic6HQnkgbHIQJI2AVmC8h1AOKyLdPBASUo5LpnVv5QxxOAghmD1Qt0Ji psHNfqXFBU8VGnSDEQ87pEZ9SquyivJuHB5DPFXMkOo2m6Jt0zuo11Lc642mTKjwguuE qWGg== 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 v11si1386448pgo.292.2017.09.28.06.14.14; Thu, 28 Sep 2017 06:14:15 -0700 (PDT) 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 S1753248AbdI1NOM (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:12 -0400 Received: from foss.arm.com ([217.140.101.70]:56936 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751943AbdI1NOJ (ORCPT ); Thu, 28 Sep 2017 09:14:09 -0400 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 19C4F15BF; Thu, 28 Sep 2017 06:14:09 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id B478A3F483; Thu, 28 Sep 2017 06:14:06 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Rob Herring , Mark Rutland Subject: [PATCH v3 02/22] dt-bindings: arm: add support for ARM System Control and Management Interface(SCMI) protocol Date: Thu, 28 Sep 2017 14:11:26 +0100 Message-Id: <1506604306-20739-3-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: Rob Herring Cc: Mark Rutland Signed-off-by: Sudeep Holla --- Documentation/devicetree/bindings/arm/arm,scmi.txt | 171 +++++++++++++++++++++ MAINTAINERS | 4 +- 2 files changed, 173 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..226ed2e9ac6a --- /dev/null +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -0,0 +1,171 @@ +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. +- mbox-names: shall be "tx" or "rx" +- shmem : List of phandle pointing to the shared memory(SHM) area as per + generic mailbox client binding. + +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>; + 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 6671f375f7fc..f4b5f3967725 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12936,11 +12936,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 Thu Sep 28 13:11:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114443 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp732762qgf; Thu, 28 Sep 2017 06:19:03 -0700 (PDT) X-Google-Smtp-Source: AOwi7QAHNOmK625A9H5qLPTmtcapsz5uN2f1yCXdSTf3SMOEtRnHlB+p5UY/SEthivNromMsCfXU X-Received: by 10.101.83.72 with SMTP id w8mr4276477pgr.226.1506604743187; Thu, 28 Sep 2017 06:19:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604743; cv=none; d=google.com; s=arc-20160816; b=As0mB0DTJYox2VUveDpx/1StWT3F05oToKwALdx7L+s5vCSvFf5s/urC/vM1hqavDU +/tXmyACBcqQYGp0xOyvu+QoQF2t2HLWrsfsUg7Qr2VrhFDMV0riQTvMcd8xalFftZD+ /4tuelX1EZgiymFwhJVCARXXmkLQWrlq2sV3XQM60JvixDsbiPSqh589bgn1GUCR5yuj owEiaNgjCO9m/sHN0nNDyDUws1xzen9ebHZYKgTfMOEllr+Oftdj89T7jiSVScgQge6G 6C6gSGdc84r1FG52VRySxOET4Q5K8dQBaBmJR4atqokhKJzf/MmNj0G1WKPskKOnXRpw apjA== 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=Uo4elpFxza2FFi9lacrd23H15f1dLjA49BTjLUGLruY=; b=djE3oafGNvPaBZWz/VOTtNcP0LP0o7iteULSy/jz17DZqOzsX145/g9l7MdWHU1G7F w6op5f+1AGk0fggcI/b3zr/taGDj5Mjpgp8q0phWRYeA9DqKfxKoLwnlESgMUMrP9kV5 2W3tSM8MPfZq0e/TyPbcWtVqNaTWcScrzNbNQdjw5cwCQSB9Z/ECeVRuQ2620Mmn2pdK 5aC8laVdRMcgLW5jTbK/9oVbmRnYs+RCI+0ESyH6ayICW4ZLhXEgqByfVeL91vfLhbSO KGTMy7aEwY4qlpiF/9HEZuD1UKARoWSnLVuc28qtudtpMGEVzmpJ6xyoWqWqKOCmPER/ a1BA== 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 h5si1403765pfe.224.2017.09.28.06.19.02; Thu, 28 Sep 2017 06:19:03 -0700 (PDT) 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 S1753437AbdI1NTB (ORCPT + 26 others); Thu, 28 Sep 2017 09:19:01 -0400 Received: from foss.arm.com ([217.140.101.70]:56964 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753228AbdI1NOM (ORCPT ); Thu, 28 Sep 2017 09:14:12 -0400 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 B3079164F; Thu, 28 Sep 2017 06:14:11 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 59A833F483; Thu, 28 Sep 2017 06:14:09 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Rob Herring , Mark Rutland Subject: [PATCH v3 03/22] dt-bindings: arm: scmi: add ARM MHU specific mailbox client bindings Date: Thu, 28 Sep 2017 14:11:27 +0100 Message-Id: <1506604306-20739-4-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 ARM MHU specific mailbox client bindings to support SCMI. Since SCMI specification just requires doorbell mechanism from mailbox controllers, we add mailbox data to specify the doorbell bit(s). Cc: Rob Herring Cc: Mark Rutland Signed-off-by: Sudeep Holla --- .../devicetree/bindings/arm/arm,mhu-scmi.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/arm,mhu-scmi.txt -- 2.7.4 diff --git a/Documentation/devicetree/bindings/arm/arm,mhu-scmi.txt b/Documentation/devicetree/bindings/arm/arm,mhu-scmi.txt new file mode 100644 index 000000000000..8c106f1cdeb8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/arm,mhu-scmi.txt @@ -0,0 +1,19 @@ +ARM MHU mailbox client bindings for SCMI Message Protocol +---------------------------------------------------------- + +This binding is intended to define the ARM MHU specific extensions to +the generic SCMI bindings[2]. + +Required properties: + +The scmi node with the following properties shall be under the /firmware/ node. + +- compatible : shall be "arm,scmi" and "arm,mhu-scmi" +- mbox-data : For each phandle listed in mboxes property, an unsigned 32-bit + data as expected by the mailbox controller + +See [1] for details on all other required/optional properties of the generic +mailbox controller and [2] for generic SCMI bindings. + +[1] Documentation/devicetree/bindings/mailbox/mailbox.txt +[2] Documentation/devicetree/bindings/arm/arm,scmi.txt From patchwork Thu Sep 28 13:11:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114424 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727479qgf; Thu, 28 Sep 2017 06:14:22 -0700 (PDT) X-Google-Smtp-Source: AOwi7QD8KHtDyawvAJtIuPYikIqKKltIB0tvCivTqNGAa330JVH17eo7iKrdyR+V4D9MlxHKjpzo X-Received: by 10.98.207.194 with SMTP id b185mr4346598pfg.243.1506604462186; Thu, 28 Sep 2017 06:14:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604462; cv=none; d=google.com; s=arc-20160816; b=xn1ieUHnRRBSboAsYOfp++4oxyd14QWHWWFE29pUT+cijGynXhWsikaf3YCmbx2fQu Qe5bgbCEpacSs1q9xLS95gpRSKM15ryP4CLtoiuMX9zX1MXUfAI4yIjgFzVc0DnYWXYu M0qkAVxCcNIIgxz/PGY0oBSxHr/PzqJKzd16Sf+a9DdGQBZFfYsQAHMunjYFWgRZAZ+s jA5WX+itA9qJ3X+nR/IlSC/oziY3yET9iXO0gJQcU3Xkr9w/NCMm6TCe9bD1ekmAjj0P 2G/Itg5763h8GBQMMAyg4B736BCZLbEXELG+PaMIuycrhmL8aEDt47IltQf226mi1MJd o8Bw== 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=ltk/u88gevWhPF20C5o428of0epUofK/3OZ0SBlFga8=; b=s12wlfwFKj+fNe4AJ8CCcCf3MjW04ZV761RggQMVwpKGQ5romf4O1qTNOLsYgtwsQ0 kYVTk0sRjX14R18pCCwto/xsnFEoA5k1p6URnXvCJIU9ySWVodykxKbBvuhlnjM4IMUv RAaREH6qrNqCZt9Arfx2c2amw5a2TeJE6gd7lsxs+QUQiFM1F4s92IhwzqZHgnhxqiAg DX0Obrr6Y7M2CTzHpRtrx8eKMRryrgZ1ciFQkM201TrVERe/KGxuEsp1qXyZj3bBU0wY xc30F6mMVNGSv8MGjKg8+A68+Bz0O83cT9D92DCdSgprPBViPKJ4ECv8MVBpSB8wqTei /o4A== 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 f5si1405493pgn.194.2017.09.28.06.14.21; Thu, 28 Sep 2017 06:14:22 -0700 (PDT) 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 S1753287AbdI1NOU (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:20 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:56968 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751943AbdI1NOO (ORCPT ); Thu, 28 Sep 2017 09:14:14 -0400 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 34CB8165C; Thu, 28 Sep 2017 06:14:14 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id F2D853F483; Thu, 28 Sep 2017 06:14:11 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 04/22] firmware: arm_scmi: add basic driver infrastructure for SCMI Date: Thu, 28 Sep 2017 14:11:28 +0100 Message-Id: <1506604306-20739-5-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 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 | 75 ++++ drivers/firmware/arm_scmi/driver.c | 769 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 48 +++ 7 files changed, 918 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 f4b5f3967725..23ec3471f542 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12944,7 +12944,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 6e4ed5a9c6fd..c3d1a12763ce 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 + tristate "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 a37f12e8d137..91d3ff62c653 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -23,6 +23,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..58e94c95e523 --- /dev/null +++ b/drivers/firmware/arm_scmi/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o +arm_scmi-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..344b234d4e64 --- /dev/null +++ b/drivers/firmware/arm_scmi/common.h @@ -0,0 +1,75 @@ +/* + * 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); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c new file mode 100644 index 000000000000..1d556a928de9 --- /dev/null +++ b/drivers/firmware/arm_scmi/driver.c @@ -0,0 +1,769 @@ +/* + * 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 + * + * @sem_xfer_count: Counting Semaphore for managing max simultaneous + * Messages. + * @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 semaphore sem_xfer_count; + 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) + +/* + * The SCP firmware providing SCM interface to OSPM and other agents must + * execute only in little-endian mode as per SCMI specification, so any buffers + * shared through SCMI should have their contents converted to little-endian + */ +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 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 *mem) +{ + xfer->hdr.status = le32_to_cpu(*(__le32 *)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, + le32_to_cpu(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 *mem = info->tx_payload; + + xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(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 *mem = info->tx_payload; + + mem->channel_status = 0x0; /* Mark channel busy + clear error */ + mem->flags = t->hdr.poll_completion ? 0 : + cpu_to_le32(SCMI_SHMEM_FLAG_INTR_ENABLED); + mem->length = cpu_to_le32(sizeof(mem->msg_header) + t->tx.len); + mem->msg_header = cpu_to_le32(pack_scmi_header(&t->hdr)); + 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; + int ret, timeout; + 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; + + /* + * Ensure we have only controlled number of pending messages. + * Ideally, we might just have to wait a single message, be + * conservative and wait 5 times that.. + */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms) * 5; + ret = down_timeout(&minfo->sem_xfer_count, timeout); + if (ret < 0) + return ERR_PTR(ret); + + /* 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); + + /* Increment the count for the next user to get through */ + up(&minfo->sem_xfer_count); +} + +/** + * 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, else: + * -EPROBE_DEFER if the instance is not ready + * -ENODEV if the required node handler is missing + * -EINVAL if invalid conditions are encountered. + */ +const struct scmi_handle *scmi_handle_get(struct device *dev) +{ + struct list_head *p; + struct scmi_info *info; + struct scmi_handle *handle = NULL; + + if (!dev || !dev->parent) { + pr_err("missing device or parent pointer\n"); + return ERR_PTR(-EINVAL); + } + + 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); + + if (!handle) + return ERR_PTR(-EPROBE_DEFER); + + return handle; +} +EXPORT_SYMBOL_GPL(scmi_handle_get); + +/** + * 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 an error pointer was passed, it returns the error value back, + * if null was passed, it returns -EINVAL; + */ +int scmi_handle_put(const struct scmi_handle *handle) +{ + struct scmi_info *info; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + 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; +} +EXPORT_SYMBOL_GPL(scmi_handle_put); + +static void devm_scmi_release(struct device *dev, void *res) +{ + const struct scmi_handle **ptr = res; + const struct scmi_handle *handle = *ptr; + int ret; + + ret = scmi_handle_put(handle); + if (ret) + dev_err(dev, "failed to put handle %d\n", ret); +} + +/** + * devm_scmi_handle_get() - Managed get handle + * @dev: device for which we want SCMI handle for. + * + * NOTE: This releases the handle once the device resources are + * no longer needed. MUST NOT BE released with scmi_handle_put. + * The function does not track individual clients of the framework + * and is expected to be maintained by caller of SCMI protocol library. + * + * Return: 0 if all went fine, else corresponding error. + */ +const struct scmi_handle *devm_scmi_handle_get(struct device *dev) +{ + const struct scmi_handle **ptr; + const struct scmi_handle *handle; + + ptr = devres_alloc(devm_scmi_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + handle = scmi_handle_get(dev); + + if (!IS_ERR(handle)) { + *ptr = handle; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return handle; +} +EXPORT_SYMBOL_GPL(devm_scmi_handle_get); + +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); + + sema_init(&info->sem_xfer_count, desc->max_msg); + + 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); + + of_platform_depopulate(&pdev->dev); + + 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 = of_match_ptr(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..fbe80fa1ec9f --- /dev/null +++ b/include/linux/scmi_protocol.h @@ -0,0 +1,48 @@ +/* + * 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; +}; + +#if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL) +int scmi_handle_put(const struct scmi_handle *handle); +const struct scmi_handle *scmi_handle_get(struct device *dev); +const struct scmi_handle *devm_scmi_handle_get(struct device *dev); +#else +static inline int scmi_handle_put(const struct scmi_handle *handle) +{ + return 0; +} + +static inline const struct scmi_handle *scmi_handle_get(struct device *dev) +{ + return NULL; +} + +static inline const struct scmi_handle *devm_scmi_handle_get(struct device *dev) +{ + return NULL; +} +#endif /* CONFIG_ARM_SCMI_PROTOCOL */ From patchwork Thu Sep 28 13:11:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114441 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp732059qgf; Thu, 28 Sep 2017 06:18:22 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDeRzpU2tcRLmpaO7uqEb3x3K5N/7uDqWDWsb9tz7uCaE2k5yDsCeGlvis262MY61RZM6pl X-Received: by 10.99.174.78 with SMTP id e14mr4205614pgp.155.1506604702372; Thu, 28 Sep 2017 06:18:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604702; cv=none; d=google.com; s=arc-20160816; b=IYHFzJEWbBeWnSs0BIGn+NerRXTxym/+OizzgUkGhJW9SpOxoyxFJ/cuqRKXXQR3MW QNIjQafU4zqG+U7DVYU+xwNH9Eca42iyFdHRx/g0DtTxqFf+HBj4EMHOwfc+9PWMqdkx QktPZoTuJhhyI0BiGybh9yYHJr15H01Yj/65jtHE8IQ0gbICKV4dsRK2yUy8+gsUkuzS x6beNxdRubhcqHva3/yBBLWETPnTCbk5qL0D5Khxfwrao6icb2qgQvrAUb8pFhwVtSWJ fvJ98cJ1ESjFitgHMYpk7Hm0ur531vspNXesLouOwhcPiiRu0nSFWlxPKpADfljB4Z/j 30hA== 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=yA5NAhtJx+RZ2S03fMMCub9GRyLUEP1xkk2zRAnKm+4=; b=lxQQZtS4HoKjOhK4raxN9yqxN3+43eiYQc6BLq3qc1/stRstbUlWHixzCEihdr8TkE VsbUMxyUvYgSW1uXF0EyCNDBZDlY8+oAPt/lGNGA+YtDd7gGgfgD5hrFkqWBHHHl6z4j TQi7iNNbQHQ572qsiHMkHZWPwqJ5UwsYJCr9+jKTHk9InIsXg27eNSn/u33CUrmYEmy8 AZwRpqjnxFhD0NTP9OsYWwN44/zBWLfcNSvn/lNbbL45euyVpsf7RE7Llhy+1/yJioB2 uULEwPRddrJLbF3Ju90MCrjOgsmYBwfUK/Oyl2e1hIOCmSwjHxtEzC62GX8Wau+I+j+u 1JBg== 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 o10si1406179pgn.50.2017.09.28.06.18.22; Thu, 28 Sep 2017 06:18:22 -0700 (PDT) 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 S1753476AbdI1NSV (ORCPT + 26 others); Thu, 28 Sep 2017 09:18:21 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57014 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753253AbdI1NOT (ORCPT ); Thu, 28 Sep 2017 09:14:19 -0400 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 DB0431688; Thu, 28 Sep 2017 06:14:18 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C6FA13F483; Thu, 28 Sep 2017 06:14:16 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 06/22] firmware: arm_scmi: add initial support for performance protocol Date: Thu, 28 Sep 2017 14:11:30 +0100 Message-Id: <1506604306-20739-7-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/common.h | 1 + drivers/firmware/arm_scmi/perf.c | 511 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 31 +++ 4 files changed, 544 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 21d01d1d6b9c..159de726ee45 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o -arm_scmi-y = base.o driver.o +arm_scmi-y = base.o driver.o perf.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 7a30a517a10b..0df52905ba48 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_std_protocol { SCMI_PROTOCOL_BASE = 0x10, diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c new file mode 100644 index 000000000000..13d84d829201 --- /dev/null +++ b/drivers/firmware/arm_scmi/perf.c @@ -0,0 +1,511 @@ +/* + * 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 struct scmi_perf_info perf_info; + +static int scmi_perf_attributes_get(const struct scmi_handle *handle, + struct scmi_perf_info *perf_info) +{ + 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); + + perf_info->num_domains = le16_to_cpu(attr->num_domains); + perf_info->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags); + perf_info->stats_addr = le32_to_cpu(attr->stats_addr_low) | + (u64)le32_to_cpu(attr->stats_addr_high) << 32; + perf_info->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; +} + +static int __scmi_perf_notify_enable(const struct scmi_handle *handle, u32 cmd, + u32 domain, bool enable) +{ + int ret; + struct scmi_xfer *t; + struct scmi_perf_notify_level_or_limits *notify; + + ret = scmi_one_xfer_init(handle, cmd, SCMI_PROTOCOL_PERF, + sizeof(*notify), 0, &t); + if (ret) + return ret; + + notify = t->tx.buf; + notify->domain = cpu_to_le32(domain); + notify->notify_enable = cpu_to_le32(enable & BIT(0)); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_perf_limits_notify_enable(const struct scmi_handle *handle, + u32 domain, bool enable) +{ + return __scmi_perf_notify_enable(handle, PERF_NOTIFY_LIMITS, + domain, enable); +} + +static int scmi_perf_level_notify_enable(const struct scmi_handle *handle, + u32 domain, bool enable) +{ + return __scmi_perf_notify_enable(handle, PERF_NOTIFY_LEVEL, + domain, enable); +} + +/* 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(struct device *dev) +{ + int idx, ret, domain; + unsigned long freq; + struct scmi_opp *opp; + struct perf_dom_info *dom; + + domain = scmi_dev_domain_id(dev); + if (domain < 0) + return domain; + + dom = perf_info.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, opp->power); + if (ret) { + dev_warn(dev, "failed to add opp %luHz %umV\n", + freq, opp->power); + + 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(struct device *dev) +{ + struct perf_dom_info *dom; + int domain = scmi_dev_domain_id(dev); + + if (domain < 0) + return domain; + + dom = perf_info.dom_info + domain; + if (!dom) + return -EIO; + + return dom->opp[dom->opp_count - 1].trans_latency_us; +} + +static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain, + unsigned long freq) +{ + struct perf_dom_info *dom = perf_info.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 perf_dom_info *dom = perf_info.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, + .limits_notify_enable = scmi_perf_limits_notify_enable, + .level_notify_enable = scmi_perf_level_notify_enable, + .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, +}; + +int scmi_perf_protocol_init(struct scmi_handle *handle) +{ + int domain; + u32 version; + + 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)); + + scmi_perf_attributes_get(handle, &perf_info); + + perf_info.dom_info = devm_kcalloc(handle->dev, perf_info.num_domains, + sizeof(struct perf_dom_info), + GFP_KERNEL); + if (!perf_info.dom_info) + return -ENOMEM; + + for (domain = 0; domain < perf_info.num_domains; domain++) { + struct perf_dom_info *dom = perf_info.dom_info + domain; + + scmi_perf_domain_attributes_get(handle, domain, dom); + scmi_perf_describe_levels_get(handle, domain, dom); + } + + handle->perf_ops = &perf_ops; + + return 0; +} diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 3ef2d48f03c2..c9f97e69444a 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -43,15 +43,46 @@ 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 + * @limits_notify_enable: requests notifications from the platform for changes + * in the allowed maximum and minimum performance levels + * @level_notify_enable: requests notifications from the platform when the + * performance level for a domain changes in value + */ +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 (*limits_notify_enable)(const struct scmi_handle *, u32, bool); + int (*level_notify_enable)(const struct scmi_handle *, u32, bool); + int (*device_domain_id)(struct device *); + int (*get_transition_latency)(struct device *); + int (*add_opps_to_device)(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; }; #if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL) From patchwork Thu Sep 28 13:11:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114425 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727620qgf; Thu, 28 Sep 2017 06:14:29 -0700 (PDT) X-Google-Smtp-Source: AOwi7QB++avFtQnqLFohHDU7uBdBLIhHHAIDNEoRP4wYWCj25B7zzQj9qh64gNoWNlSXEka2id5o X-Received: by 10.98.155.220 with SMTP id e89mr4501952pfk.120.1506604469524; Thu, 28 Sep 2017 06:14:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604469; cv=none; d=google.com; s=arc-20160816; b=j43hmaBmD6eZc8gIPQuS4Hwpt+7dRtYVGczJfTgDawgUPNaUeHMTeiqmOrhssKzyEV eIIwK2d8+fikMuLHP7CbkqeVZK5CosG770o9l1kFhHFSSiVGo24Zsy/1Pm5a0IWrnnQL hux19Tx9LztVPUB/bjGLSEZwctdX+5UsR1wUM+W7VokRx3O30utuf8aQWKQ+PdRYUwoN PNM7nSlkOthI76Sq6nCLQhnfiF80zmaJADSwucPidK+9mnu9ggV/zMT7gaOFenRE4rZq +vYH/Za+Oxq+UDqFCSNumeZFjlL1G5JjaY+YvpQvucLxAk/y14chrmW4Ss9fB/f1gaHH TAiA== 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=wcq5jN0nLLDDBO/RLW6Jp6r2y3Qey4qzfGG/sFh2NNg=; b=xnkOaigy+XxYvXhAT8WZRX32jbKYMnghuoOQ28q6K7FThUR7m6r9jpIvGspFQwlpQp ChnZqRAjYg4zNYK2hpmT6ctDxFRd3KGrmZCHiFa/8Al4l22uLzz12puwl2tuU09JSKW6 RUBPp39GSjdI5yReQ0F0prozSytS6a5/B6H0fxyQ4gSuxj+KWurWR3i/GjDvrY2voTnS MfU1dLCVrgBW7ZhPzK86StmYI5JC4QiG/L8ge1gABBRGulrl/ZF8GM7MN5OHe7QYrJ7C arL6eQcihQNXyahduVTCDY2ptUEFFpyH7wJUEl3MuNp09ZezUaY48B9Vz3OaarruM+ol BvCA== 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 d7si1412277pln.428.2017.09.28.06.14.29; Thu, 28 Sep 2017 06:14:29 -0700 (PDT) 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 S1753310AbdI1NO1 (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:27 -0400 Received: from foss.arm.com ([217.140.101.70]:57022 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751943AbdI1NOV (ORCPT ); Thu, 28 Sep 2017 09:14:21 -0400 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 39521169E; Thu, 28 Sep 2017 06:14:21 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 269F73F483; Thu, 28 Sep 2017 06:14:19 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 07/22] firmware: arm_scmi: add initial support for clock protocol Date: Thu, 28 Sep 2017 14:11:31 +0100 Message-Id: <1506604306-20739-8-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/clock.c | 339 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 40 +++++ 3 files changed, 380 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 159de726ee45..6836b1f38f7f 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o -arm_scmi-y = base.o driver.o perf.o +arm_scmi-y = base.o clock.o driver.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..87d0befab07d --- /dev/null +++ b/drivers/firmware/arm_scmi/clock.c @@ -0,0 +1,339 @@ +/* + * 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 struct clock_info clocks; + +static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle, + struct clock_info *clocks) +{ + 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) { + clocks->num_clocks = le16_to_cpu(attr->num_clocks); + clocks->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) +{ + return clocks.num_clocks; +} + +static const struct scmi_clock_info * +scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id) +{ + struct scmi_clock_info *clk = clocks.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, +}; + +int scmi_clock_protocol_init(struct scmi_handle *handle) +{ + int clkid, ret; + u32 version; + + 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)); + + scmi_clock_protocol_attributes_get(handle, &clocks); + + clocks.clk = devm_kcalloc(handle->dev, clocks.num_clocks, + sizeof(struct scmi_clock_info), GFP_KERNEL); + if (!clocks.clk) + return -ENOMEM; + + for (clkid = 0; clkid < clocks.num_clocks; clkid++) { + struct scmi_clock_info *clk = clocks.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; + + return 0; +} diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index c9f97e69444a..c15f37c86025 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -18,6 +18,7 @@ #include #define SCMI_MAX_STR_SIZE 16 +#define SCMI_MAX_NUM_RATES 16 /** * struct scmi_revision_info - version information structure @@ -43,9 +44,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 * @@ -78,11 +116,13 @@ 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; }; #if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL) From patchwork Thu Sep 28 13:11:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114426 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727646qgf; Thu, 28 Sep 2017 06:14:30 -0700 (PDT) X-Google-Smtp-Source: AOwi7QATOIdR+SzuY0knYauw9dQKt67SCH16M9MnDulAQQP414lEIuC7DTTsrIIIgwLOsxU4h4sk X-Received: by 10.99.53.4 with SMTP id c4mr1107479pga.170.1506604470730; Thu, 28 Sep 2017 06:14:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604470; cv=none; d=google.com; s=arc-20160816; b=YSEBhHAid17TAHNoxmrrrh510mqj4+V62SdroEF6dBmoYBi4i9WrnpJeSIYV8iD8De BKdbW8lXTuIuxkYU8SwApiEowqMtbng2wZP6yAXN+IdCdyi/XdzM2PUuQEusDzLPp2tl Mqo1x4L2zK0NwcPZv3AZxJCJkgG9dsBPHrscaBfodv8hsk8hjCsJSPkd2qCKPEpwgaZv ruxmIcyfp8Y0kZFVlwoe8L6sBOpGplRp7ac2EkLbBVkuO+ehgE9BXQAvscO0OzCWhADn gwIsH/0rqzzfL9iSUFQClf6jb/BXTe4PLT3knAhOo9YjKCZB6VQu1IrFXoAjWlXvJ/Tq vPlw== 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=dW1qLevhR7b/1OdO2fwIeK/CCmtR1/Xd3xDphODFLis=; b=VB2yHpibytKU1tQdHD10ARvHEoyQ2xrppGmH08cX9vRXmcde9MUCeNcQcgLAcUU/hV 0xuOiL97kMQt2XQarSNhVyCgPwt9WM83yvRLQ4dtqQ3GDKEpzwtuhBdtvorB5MAsVaV4 9oyCz9G/76leGqVQbRzg22DAk8bzIiVM63oSeBKvAO3un5e0vvyImpOsDgEmZzSjuHgY mHcBUJ6yYgWVqcK4TMn2G2LStD0RLv60U5Uf07RmYGP6+MCCDFLpoIotc2ZdyzXnmJKG it6eeelcbe72Ky8ZWTOXlGeqSeZ8MpzyI+wc86AwAF9Wb92204KOgJOGDtv7ELCoYJjx WVQA== 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 p11si1436340plk.297.2017.09.28.06.14.30; Thu, 28 Sep 2017 06:14:30 -0700 (PDT) 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 S1753325AbdI1NO2 (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:28 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57038 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752438AbdI1NOX (ORCPT ); Thu, 28 Sep 2017 09:14:23 -0400 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 8BB4816A3; Thu, 28 Sep 2017 06:14:23 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 790703F483; Thu, 28 Sep 2017 06:14:21 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 08/22] firmware: arm_scmi: add initial support for power protocol Date: Thu, 28 Sep 2017 14:11:32 +0100 Message-Id: <1506604306-20739-9-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 power protocol is intended for management of power states of various power domains. The power domain management protocol provides commands to describe the protocol version, discover the implementation specific attributes, set and get the power state of a domain. This patch adds support for the above mention features of the protocol. Cc: Arnd Bergmann Signed-off-by: Sudeep Holla -- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 242 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 28 +++++ 3 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 242 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 28 +++++ 3 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 6836b1f38f7f..52ecc08556a2 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o -arm_scmi-y = base.o clock.o driver.o perf.o +arm_scmi-y = base.o clock.o driver.o perf.o power.o diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c new file mode 100644 index 000000000000..34c45f101abb --- /dev/null +++ b/drivers/firmware/arm_scmi/power.c @@ -0,0 +1,242 @@ +/* + * System Control and Management Interface (SCMI) Power Protocol + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "common.h" + +enum scmi_power_protocol_cmd { + POWER_DOMAIN_ATTRIBUTES = 0x3, + POWER_STATE_SET = 0x4, + POWER_STATE_GET = 0x5, + POWER_STATE_NOTIFY = 0x6, +}; + +struct scmi_msg_resp_power_attributes { + __le16 num_domains; + __le16 reserved; + __le32 stats_addr_low; + __le32 stats_addr_high; + __le32 stats_size; +}; + +struct scmi_msg_resp_power_domain_attributes { + __le32 flags; +#define SUPPORTS_STATE_SET_NOTIFY(x) ((x) & BIT(31)) +#define SUPPORTS_STATE_SET_ASYNC(x) ((x) & BIT(30)) +#define SUPPORTS_STATE_SET_SYNC(x) ((x) & BIT(29)) + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_set_state { + __le32 flags; +#define STATE_SET_ASYNC BIT(0) + __le32 domain; + __le32 state; +}; + +struct scmi_power_state_notify { + __le32 domain; + __le32 notify_enable; +}; + +struct power_dom_info { + bool state_set_sync; + bool state_set_async; + bool state_set_notify; + char name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_info { + int num_domains; + u64 stats_addr; + u32 stats_size; + struct power_dom_info *dom_info; +}; + +static struct scmi_power_info power_info; + +static int scmi_power_attributes_get(const struct scmi_handle *handle, + struct scmi_power_info *power_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + power_info->num_domains = le16_to_cpu(attr->num_domains); + power_info->stats_addr = le32_to_cpu(attr->stats_addr_low) | + (u64)le32_to_cpu(attr->stats_addr_high) << 32; + power_info->stats_size = le32_to_cpu(attr->stats_size); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, + struct power_dom_info *dom_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_domain_attributes *attr; + + ret = scmi_one_xfer_init(handle, POWER_DOMAIN_ATTRIBUTES, + SCMI_PROTOCOL_POWER, sizeof(domain), + sizeof(*attr), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + u32 flags = le32_to_cpu(attr->flags); + + dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags); + dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags); + dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags); + memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) +{ + int ret; + struct scmi_xfer *t; + struct scmi_power_set_state *st; + + ret = scmi_one_xfer_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, + sizeof(*st), 0, &t); + if (ret) + return ret; + + st = t->tx.buf; + st->flags = cpu_to_le32(0); + st->domain = cpu_to_le32(domain); + st->state = cpu_to_le32(state); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, + sizeof(u32), sizeof(u32), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + + ret = scmi_do_xfer(handle, t); + if (!ret) + *state = le32_to_cpu(*(__le32 *)t->rx.buf); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_power_state_notify_enable(const struct scmi_handle *handle, + u32 domain, bool enable) +{ + int ret; + struct scmi_xfer *t; + struct scmi_power_state_notify *notify; + + ret = scmi_one_xfer_init(handle, POWER_STATE_NOTIFY, + SCMI_PROTOCOL_POWER, sizeof(*notify), 0, &t); + if (ret) + return ret; + + notify = t->tx.buf; + notify->domain = cpu_to_le32(domain); + notify->notify_enable = cpu_to_le32(enable & BIT(0)); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_power_num_domains_get(const struct scmi_handle *handle) +{ + return power_info.num_domains; +} + +static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain) +{ + struct power_dom_info *dom = power_info.dom_info + domain; + + return dom->name; +} + +static struct scmi_power_ops power_ops = { + .num_domains_get = scmi_power_num_domains_get, + .name_get = scmi_power_name_get, + .state_set = scmi_power_state_set, + .state_get = scmi_power_state_get, + .state_notify_enable = scmi_power_state_notify_enable, +}; + +int scmi_power_protocol_init(struct scmi_handle *handle) +{ + u32 version; + int domain; + + scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version); + + dev_dbg(handle->dev, "Power Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + scmi_power_attributes_get(handle, &power_info); + + power_info.dom_info = devm_kcalloc(handle->dev, power_info.num_domains, + sizeof(struct power_dom_info), + GFP_KERNEL); + if (!power_info.dom_info) + return -ENOMEM; + + for (domain = 0; domain < power_info.num_domains; domain++) { + struct power_dom_info *dom = power_info.dom_info + domain; + + scmi_power_domain_attributes_get(handle, domain, dom); + } + + handle->power_ops = &power_ops; + + return 0; +} diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index c15f37c86025..e5a80511f88c 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -111,16 +111,44 @@ struct scmi_perf_ops { }; /** + * struct scmi_power_ops - represents the various operations provided + * by SCMI Power Protocol + * + * @num_domains_get: get the count of power domains provided by SCMI + * @name_get: gets the name of a power domain + * @state_set: sets the power state of a power domain + * @state_get: gets the power state of a power domain + * @state_notify_enable: request notifications from the platform for + * state changes in a specific power domain + */ +struct scmi_power_ops { + int (*num_domains_get)(const struct scmi_handle *); + char *(*name_get)(const struct scmi_handle *, u32); +#define SCMI_POWER_STATE_TYPE_SHIFT 30 +#define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1) +#define SCMI_POWER_STATE_PARAM(type, id) \ + ((((type) & BIT(0)) << SCMI_POWER_STATE_TYPE_SHIFT) | \ + ((id) & SCMI_POWER_STATE_ID_MASK)) +#define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0) +#define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0) + int (*state_set)(const struct scmi_handle *, u32, u32); + int (*state_get)(const struct scmi_handle *, u32, u32 *); + int (*state_notify_enable)(const struct scmi_handle *, u32, bool); +}; + +/** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information + * @power_ops: pointer to set of power protocol operations * @perf_ops: pointer to set of performance protocol operations * @clk_ops: pointer to set of clock protocol operations */ struct scmi_handle { struct device *dev; struct scmi_revision_info *version; + struct scmi_power_ops *power_ops; struct scmi_perf_ops *perf_ops; struct scmi_clk_ops *clk_ops; }; From patchwork Thu Sep 28 13:11:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114440 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp731356qgf; Thu, 28 Sep 2017 06:17:44 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDZgBA69sogqG91BbunLvise9uffG0KNlmToer1Mm39t9E/ZoZbbg+GGWsottXu32WVNTxq X-Received: by 10.84.253.131 with SMTP id a3mr4152462plm.244.1506604664732; Thu, 28 Sep 2017 06:17:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604664; cv=none; d=google.com; s=arc-20160816; b=H86cs5yh4t7KFkVfaQA7aXkZiNUUTSbpV1p5M3ffE8FfYk3UAwmxSdXQBGUIrJnwOM 7ess4VPHFUfS7IpTxyWrqiMn5yxwdTqykm2nT7HMBzCmCPYWGAz0MP4m0aEjp0idham4 3fDPti7ArNHGQeVXzAg8itjJ8RyOIdRrmnjQH0fhWki0sh22PpMzRjttFZ7koF59cTwy csK++dT2Q1yob8Rp2lIibXQWFJkMlvW82ykb4hbAH3p7GQqICBpoK6V/aDaz0GzDgPb1 TCPNfQYv2PDcu1XdQuTgdPUUgvkgfP8oL8ymhzwzV96NW4CygtvDgTru530QwRzCCDqf rBSA== 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=/ziqQJbWZ2+2CPjveFxHMH2k0BzjH0WncFGx2c6zUek=; b=swV1d4fYpVhJVg7m1d/zRSMCpwqS8aR0Hsi8WME0bKLwsKV7T+jr7UlOLUi8Q9E0Q3 ti6FGXnuH9EZf+nJp/3bRQB2PnGmHUdtCARtmhoVShPleiwbq6Ub1AgwVPkTp9Ho6fcj YlYhG+g6qOTOxiyycwfLDeuko9XuHq7Hw7xC2Yji9BIUtuBz8OOeOHuRX3IOtgtVq8M2 K+GNkBcC0O1x+8npdR8YyGCkhwhsbFxDh4U+qL1OQAQ02IdxapxdM7DsUuathldgse41 pg6cZDHj7oJOK9xs/FsO2P1hv7dVMlHxIj+YySW7GBU6GtovzO0kcVGip2zvEcFtJtE2 BvgA== 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 c2si1263916pgp.685.2017.09.28.06.17.44; Thu, 28 Sep 2017 06:17:44 -0700 (PDT) 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 S1753467AbdI1NRm (ORCPT + 26 others); Thu, 28 Sep 2017 09:17:42 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57052 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753292AbdI1NO0 (ORCPT ); Thu, 28 Sep 2017 09:14:26 -0400 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 DE5551713; Thu, 28 Sep 2017 06:14:25 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CB9683F483; Thu, 28 Sep 2017 06:14:23 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 09/22] firmware: arm_scmi: add initial support for sensor protocol Date: Thu, 28 Sep 2017 14:11:33 +0100 Message-Id: <1506604306-20739-10-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 sensor protocol provides functions to manage platform sensors, and provides the commands to describe the protocol version and the various attribute flags. It also provides commands to discover various sensors implemented and managed by the platform, read any sensor synchronously or asynchronously as allowed by the platform, program sensor attributes and/or configurations, if applicable. This patch adds support for most of the above features. Cc: Arnd Bergmann Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/sensors.c | 287 ++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 41 ++++++ 3 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/sensors.c -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 52ecc08556a2..f9dee5ad0aa0 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o -arm_scmi-y = base.o clock.o driver.o perf.o power.o +arm_scmi-y = base.o clock.o driver.o perf.o power.o sensors.o diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c new file mode 100644 index 000000000000..c868ccb7d6a3 --- /dev/null +++ b/drivers/firmware/arm_scmi/sensors.c @@ -0,0 +1,287 @@ +/* + * System Control and Management Interface (SCMI) Sensor Protocol + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "common.h" + +enum scmi_sensor_protocol_cmd { + SENSOR_DESCRIPTION_GET = 0x3, + SENSOR_CONFIG_SET = 0x4, + SENSOR_TRIP_POINT_SET = 0x5, + SENSOR_READING_GET = 0x6, +}; + +struct scmi_msg_resp_sensor_attributes { + __le16 num_sensors; + u8 max_requests; + u8 reserved; + __le32 reg_addr_low; + __le32 reg_addr_high; + __le32 reg_size; +}; + +struct scmi_msg_resp_sensor_description { + __le16 num_returned; + __le16 num_remaining; + struct { + __le32 id; + __le32 attributes_low; +#define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31)) +#define NUM_TRIP_POINTS(x) (((x) >> 4) & 0xff) + __le32 attributes_high; +#define SENSOR_TYPE(x) ((x) & 0xff) +#define SENSOR_SCALE(x) (((x) >> 11) & 0x3f) +#define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f) +#define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f) + u8 name[SCMI_MAX_STR_SIZE]; + } desc[0]; +}; + +struct scmi_msg_set_sensor_config { + __le32 id; + __le32 event_control; +}; + +struct scmi_msg_set_sensor_trip_point { + __le32 id; + __le32 event_control; +#define SENSOR_TP_EVENT_MASK (0x3) +#define SENSOR_TP_DISABLED 0x0 +#define SENSOR_TP_POSITIVE 0x1 +#define SENSOR_TP_NEGATIVE 0x2 +#define SENSOR_TP_BOTH 0x3 +#define SENSOR_TP_ID(x) (((x) & 0xff) << 4) + __le32 value_low; + __le32 value_high; +}; + +struct scmi_msg_sensor_reading_get { + __le32 id; + __le32 flags; +#define SENSOR_READ_ASYNC BIT(0) +}; + +struct sensors_info { + int num_sensors; + int max_requests; + u64 reg_addr; + u32 reg_size; + struct scmi_sensor_info *sensors; +}; + +static struct sensors_info sensor_info; + +static int scmi_sensor_attributes_get(const struct scmi_handle *handle, + struct sensors_info *sensor_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_sensor_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + sensor_info->num_sensors = le16_to_cpu(attr->num_sensors); + sensor_info->max_requests = attr->max_requests; + sensor_info->reg_addr = le32_to_cpu(attr->reg_addr_low) | + (u64)le32_to_cpu(attr->reg_addr_high) << 32; + sensor_info->reg_size = le32_to_cpu(attr->reg_size); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_description_get(const struct scmi_handle *handle) +{ + int ret, cnt; + u32 desc_index = 0; + u16 num_returned, num_remaining; + struct scmi_xfer *t; + struct scmi_msg_resp_sensor_description *buf; + + ret = scmi_one_xfer_init(handle, SENSOR_DESCRIPTION_GET, + SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t); + if (ret) + return ret; + + buf = t->rx.buf; + + do { + /* Set the number of sensors to be skipped/already read */ + *(__le32 *)t->tx.buf = cpu_to_le32(desc_index); + + ret = scmi_do_xfer(handle, t); + if (ret) + break; + + num_returned = le16_to_cpu(buf->num_returned); + num_remaining = le16_to_cpu(buf->num_remaining); + + if (desc_index + num_returned > sensor_info.num_sensors) { + dev_err(handle->dev, "No. of sensors can't exceed %d", + sensor_info.num_sensors); + break; + } + + for (cnt = 0; cnt < num_returned; cnt++) { + u32 attrh; + struct scmi_sensor_info *s; + + attrh = le32_to_cpu(buf->desc[cnt].attributes_high); + s = &sensor_info.sensors[desc_index + cnt]; + s->id = le32_to_cpu(buf->desc[cnt].id); + s->type = SENSOR_TYPE(attrh); + memcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); + } + + desc_index += num_returned; + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) +{ + int ret; + u32 evt_cntl = BIT(0); + struct scmi_xfer *t; + struct scmi_msg_set_sensor_config *cfg; + + ret = scmi_one_xfer_init(handle, SENSOR_CONFIG_SET, + SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(sensor_id); + cfg->event_control = cpu_to_le32(evt_cntl); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, + u32 sensor_id, u8 trip_id, u64 trip_value) +{ + int ret; + u32 evt_cntl = SENSOR_TP_BOTH; + struct scmi_xfer *t; + struct scmi_msg_set_sensor_trip_point *trip; + + ret = scmi_one_xfer_init(handle, SENSOR_TRIP_POINT_SET, + SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t); + if (ret) + return ret; + + trip = t->tx.buf; + trip->id = cpu_to_le32(sensor_id); + trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id)); + trip->value_low = cpu_to_le32(trip_value & 0xffffffff); + trip->value_high = cpu_to_le32(trip_value >> 32); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_reading_get(const struct scmi_handle *handle, + u32 sensor_id, bool async, u64 *value) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_sensor_reading_get *sensor; + + ret = scmi_one_xfer_init(handle, SENSOR_READING_GET, + SCMI_PROTOCOL_SENSOR, sizeof(*sensor), + sizeof(u64), &t); + if (ret) + return ret; + + sensor = t->tx.buf; + sensor->id = cpu_to_le32(sensor_id); + sensor->flags = cpu_to_le32(async ? SENSOR_READ_ASYNC : 0); + + ret = scmi_do_xfer(handle, t); + if (!ret) { + __le32 *pval = t->rx.buf; + + *value = le32_to_cpu(*pval); + *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static const struct scmi_sensor_info * +scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id) +{ + return sensor_info.sensors + sensor_id; +} + +static int scmi_sensor_count_get(const struct scmi_handle *handle) +{ + return sensor_info.num_sensors; +} + +static struct scmi_sensor_ops sensor_ops = { + .count_get = scmi_sensor_count_get, + .info_get = scmi_sensor_info_get, + .configuration_set = scmi_sensor_configuration_set, + .trip_point_set = scmi_sensor_trip_point_set, + .reading_get = scmi_sensor_reading_get, +}; + +int scmi_sensors_protocol_init(struct scmi_handle *handle) +{ + u32 version; + + scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version); + + dev_dbg(handle->dev, "Sensor Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + scmi_sensor_attributes_get(handle, &sensor_info); + + sensor_info.sensors = devm_kcalloc(handle->dev, sensor_info.num_sensors, + sizeof(struct scmi_sensor_info), + GFP_KERNEL); + if (!sensor_info.sensors) + return -ENOMEM; + + scmi_sensor_description_get(handle); + + handle->sensor_ops = &sensor_ops; + + return 0; +} diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index e5a80511f88c..5e29394b5cc9 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -136,6 +136,45 @@ struct scmi_power_ops { int (*state_notify_enable)(const struct scmi_handle *, u32, bool); }; +struct scmi_sensor_info { + u32 id; + u8 type; + char name[SCMI_MAX_STR_SIZE]; +}; + +/* + * Partial list from Distributed Management Task Force (DMTF) specification: + * DSP0249 (Platform Level Data Model specification) + */ +enum scmi_sensor_class { + NONE = 0x0, + TEMPERATURE_C = 0x2, + VOLTAGE = 0x5, + CURRENT = 0x6, + POWER = 0x7, + ENERGY = 0x8, +}; + +/** + * struct scmi_sensor_ops - represents the various operations provided + * by SCMI Sensor Protocol + * + * @count_get: get the count of sensors provided by SCMI + * @info_get: get the information of the specified sensor + * @configuration_set: control notifications on cross-over events for + * the trip-points + * @trip_point_set: selects and configures a trip-point of interest + * @reading_get: gets the current value of the sensor + */ +struct scmi_sensor_ops { + int (*count_get)(const struct scmi_handle *); + const struct scmi_sensor_info *(*info_get)(const struct scmi_handle *, + u32); + int (*configuration_set)(const struct scmi_handle *, u32); + int (*trip_point_set)(const struct scmi_handle *, u32, u8, u64); + int (*reading_get)(const struct scmi_handle *, u32, bool, u64 *); +}; + /** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * @@ -144,6 +183,7 @@ struct scmi_power_ops { * @power_ops: pointer to set of power protocol operations * @perf_ops: pointer to set of performance protocol operations * @clk_ops: pointer to set of clock protocol operations + * @sensor_ops: pointer to set of sensor protocol operations */ struct scmi_handle { struct device *dev; @@ -151,6 +191,7 @@ struct scmi_handle { struct scmi_power_ops *power_ops; struct scmi_perf_ops *perf_ops; struct scmi_clk_ops *clk_ops; + struct scmi_sensor_ops *sensor_ops; }; #if IS_REACHABLE(CONFIG_ARM_SCMI_PROTOCOL) From patchwork Thu Sep 28 13:11:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114427 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727716qgf; Thu, 28 Sep 2017 06:14:34 -0700 (PDT) X-Google-Smtp-Source: AOwi7QAbBcN5ifas7Mx2fYOCtZfTHVUvb3bTHPW/wViLQS98UywoPGopHAmSzFvFqewzhm1WpeYK X-Received: by 10.98.166.136 with SMTP id r8mr4370372pfl.228.1506604474195; Thu, 28 Sep 2017 06:14:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604474; cv=none; d=google.com; s=arc-20160816; b=0ZmXkheG7IItP4EWvcN6vwePycwJ8YcXQ+fCfpkycQmpgFEdOjp5GJNj+qNbmHdKr6 03UdeCNpizpboEJroARVxkPWA/BhvMCm16nZzRLkz2AM314NcHc52FgGRldWLtve/Q1p 2/0xVamYNKLaYFpGdDbG8cqtkfXvksgzxcY55wrQ86mvrDVrHQ/xdZgyxFhVnfng+AoN hT5hmTeeh6n+jNjv9+KMXlYtGK7+a5+O8PaLYeEnXNKp55G8HqTtfymFFORCjqjbdkfM rEdNWbvxj52my3SGubfGwvCEwOatFMWt1N9I8GgAUhJyLDZ2VJLbvu+gBQQlOp1MxBWf v/kw== 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=8HD3uBlhpb0UoM1VxKVwjePtg3/iRNjQDgTenjBhArE=; b=d12qtVCfs2jkONjiLHkKJ0W0Nqf1rciBnFjlknerx9M0S5xaPGynRm+me8nsfSLOoQ q1ihDksH5QgySHj0Px3qp77okK0i01K4tSY9k4PpTaJh88Q3GQtr4bqzOvDkb5p/v02i 5X6WvJ8jLO7yXAye1IZJqhduUQU6XxbYep199YrzhpAHKLgzQmKPX5iCeQmMLEgg3HvQ eca/2dstfbpgLkSmp4y1yLbFb13REjYTrGEp6n2CIf6vOJ/YMcmgvwmcoejsMdxkHh5U BCkvTp6JKYudNzHQdQRvnBTbEEwabsWZRswW/OFdAwTErxjg1LTXeXOWUOGoU/yoyBkK Gt0g== 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 p11si1436340plk.297.2017.09.28.06.14.33; Thu, 28 Sep 2017 06:14:34 -0700 (PDT) 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 S1753342AbdI1NOc (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:32 -0400 Received: from foss.arm.com ([217.140.101.70]:57070 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753317AbdI1NO2 (ORCPT ); Thu, 28 Sep 2017 09:14:28 -0400 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 3CF0D1991; Thu, 28 Sep 2017 06:14:28 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 29FDD3F483; Thu, 28 Sep 2017 06:14:26 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 10/22] firmware: arm_scmi: probe and initialise all the supported protocols Date: Thu, 28 Sep 2017 14:11:34 +0100 Message-Id: <1506604306-20739-11-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 5 +++ drivers/firmware/arm_scmi/driver.c | 82 +++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 0df52905ba48..07acddf5c060 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -119,4 +119,9 @@ 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); +typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *); int scmi_base_protocol_init(struct scmi_handle *h); +int scmi_perf_protocol_init(struct scmi_handle *h); +int scmi_sensors_protocol_init(struct scmi_handle *h); +int scmi_power_protocol_init(struct scmi_handle *h); +int scmi_clock_protocol_init(struct scmi_handle *h); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 5df76512a291..a1abcf2049ca 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -154,6 +154,12 @@ struct scmi_shared_mem { u8 msg_payload[0]; }; +struct scmi_protocol_match { + u8 protocol_id; + scmi_prot_init_fn_t fn; + char name[32]; +}; + static int scmi_linux_errmap[] = { /* better than switch case as long as return value is continuous */ 0, /* SCMI_SUCCESS */ @@ -686,6 +692,39 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) return 0; } +static const struct scmi_protocol_match scmi_protocols[] = { + { + .protocol_id = SCMI_PROTOCOL_PERF, + .fn = scmi_perf_protocol_init, + .name = "scmi-cpufreq", + }, { + .protocol_id = SCMI_PROTOCOL_CLOCK, + .fn = scmi_clock_protocol_init, + .name = "scmi-clocks", + }, { + .protocol_id = SCMI_PROTOCOL_POWER, + .fn = scmi_power_protocol_init, + .name = "scmi-power-domain", + }, { + .protocol_id = SCMI_PROTOCOL_SENSOR, + .fn = scmi_sensors_protocol_init, + .name = "scmi-hwmon", + }, + {} +}; + +static const struct scmi_protocol_match *scmi_protocol_match_get(u8 protocol_id) +{ + int i; + const struct scmi_protocol_match *loop = scmi_protocols; + + for (i = 0; i < ARRAY_SIZE(scmi_protocols); i++, loop++) + if (loop->protocol_id == protocol_id) + return loop; + + return NULL; +} + static int scmi_mailbox_check(struct device_node *np) { struct of_phandle_args arg; @@ -767,6 +806,27 @@ 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, + const struct scmi_protocol_match *match) +{ + int init_ret; + struct platform_device *cdev; + + cdev = of_platform_device_create(np, match->name, info->dev); + if (!cdev) { + dev_err(info->dev, "failed to create %s device\n", match->name); + return; + } + + init_ret = match->fn(&info->handle); + if (init_ret) { + dev_err(info->dev, "SCMI protocol %d init error %d\n", + match->protocol_id, init_ret); + of_platform_device_destroy(&cdev->dev, NULL); + } +} + static int scmi_probe(struct platform_device *pdev) { int ret; @@ -774,7 +834,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)) { @@ -813,6 +873,26 @@ static int scmi_probe(struct platform_device *pdev) return ret; } + for_each_available_child_of_node(np, child) { + u32 prot_id; + const struct scmi_protocol_match *match; + + 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; + } + + match = scmi_protocol_match_get(prot_id); + if (match) + scmi_create_protocol_device(child, info, match); + } + mutex_lock(&scmi_list_mutex); list_add_tail(&info->node, &scmi_list); mutex_unlock(&scmi_list_mutex); From patchwork Thu Sep 28 13:11:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114439 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp730786qgf; Thu, 28 Sep 2017 06:17:14 -0700 (PDT) X-Google-Smtp-Source: AOwi7QCanx2/efJk9oFz25hfl2Vi2czHuknamk4WyX9Awh/7lqZh8Cndi/merS2GNtu4qtXDmXlx X-Received: by 10.84.129.7 with SMTP id 7mr4067608plb.40.1506604634453; Thu, 28 Sep 2017 06:17:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604634; cv=none; d=google.com; s=arc-20160816; b=kLglezW1nN7IzKeG7V8A6lsx1oSjsoUZll1xCCUG5psSoDCM2NHn3kZWDUIWaV5eGH QR3cBlV1Nii33csPV7VV6IhU/JmkppL7OF2xkqr+g4M13AlnVwf/vnwYvqOk32x9xXwZ F68I/oMd+eQdiM708kxOHsSDSEOWwFRBzzVWZPDSpviHEW2O5Re3OboOH8frOZHR7Cb/ 349wA8OyQFezuWf7biHsz1o2Ii6fT3RDpk+m99iNhnUd9k2QA38KKsWW16W7pIalDsFZ WcYo9/EAEFCHexAWlXtrwffSjCGu/cT/7PgfeQH6Gc1IP58ccoBVnUbD04I4lTtaP/RO 7Sjg== 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=8k8iF9KxfWijeqBVif7EuyRbINu0wtsPqQsBo9DeXS0=; b=Ptx5xuCL9/CT0cw8uU2TqpW9kI1ENHJ5etinAUVuLM+brPntqs6NfqLBKUqlSk1xpF pcOymPlLkMbdySizyRxzj56eRdULNCy4teQoIZ6eB1pA4Ftgz+G1gSeEZ0uxeT771mgl utIE746UjhuQeUjrJFYvCWMOcjYvu/0wJOni9aqZSyKIMB5tl4CGaRgc7BN3gnTlS0kY pqug26QrYj/3OJtCjzAUBO34MU4XNW1FHGz6cRkFmh3JP6NBUBbQRD92gApqvmIR1fEG E9IfZ/5lX1LUrJ/I2prMpqjfY6cud+Nosslt6hw3xqUgaYX46Rr6iZUABW8nKmKMMD2g aZsA== 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 x124si1373170pfx.227.2017.09.28.06.17.14; Thu, 28 Sep 2017 06:17:14 -0700 (PDT) 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 S1753461AbdI1NRL (ORCPT + 26 others); Thu, 28 Sep 2017 09:17:11 -0400 Received: from foss.arm.com ([217.140.101.70]:57092 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752438AbdI1NOb (ORCPT ); Thu, 28 Sep 2017 09:14:31 -0400 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 8F74A15BF; Thu, 28 Sep 2017 06:14:30 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7CAD03F483; Thu, 28 Sep 2017 06:14:28 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 11/22] firmware: arm_scmi: add support for polling based SCMI transfers Date: Thu, 28 Sep 2017 14:11:35 +0100 Message-Id: <1506604306-20739-12-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 41 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index a1abcf2049ca..e1abedf15cb0 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -369,6 +370,20 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) up(&minfo->sem_xfer_count); } +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); +} + /** * scmi_do_xfer() - Do one transfer * @@ -395,14 +410,24 @@ 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) { + timeout = info->desc->max_rx_timeout_ms * 100; + while (!scmi_xfer_poll_done(info, xfer) && timeout--) + udelay(10); + if (timeout) + 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 Thu Sep 28 13:11:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114428 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727787qgf; Thu, 28 Sep 2017 06:14:38 -0700 (PDT) X-Google-Smtp-Source: AOwi7QBdgPfGVSXYT61GaUpKIm3NuEF1psbmjPR+YFklHarrW1vRzpR78cGwyXgDboXmvk/nXK3w X-Received: by 10.99.96.10 with SMTP id u10mr4300672pgb.70.1506604478839; Thu, 28 Sep 2017 06:14:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604478; cv=none; d=google.com; s=arc-20160816; b=yLsQNiZY/eM90sCkDJJZBQ8F+f4O+2zwFaDLKr0wFmwXJ3DjGbto5bh2U49H1YvUqX emrDWzRI7nplx9g0WKOObUaqf8/RehvbkK6v/F+PbxJ2vx01i7UhLzbs0nisRLGnyNde LVrbmjMvNM2qYtSo6U35C96cDt+0MNIg4fLIhaaoNSL24QD2oB7ElDLdyK1AR218M517 A29g8tTAgP9up7pScZGxQLd3zI0GopLSgWeoaC0yy1wjM8/VP57VRf+7Wkjvk8GnnKwl x0KpHBbYEW5agvSmwRaAn6KS48FQJwQ8adJkIZcxznZRE0TDMa9qSLw83Sx56dl1d2r/ muZw== 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=uIhS5bTGXpNjCOkMQ2swFpdoL4CysHk1mc0bTadSkfQ=; b=E1vxIK8G6FuieYu38nsWPtNwu7ib4/2AOLtoWtFiElRaWzhFjEhMazb5dJ3jvESvPI XwbJ+N2M0JDZTHHHiC2w0k6PFNxtWY4ZjFqXjYQS9R1fxiXc4vGXzZmk4STDEts/p2mQ SWXWXERzXQT5MowsJPy9GWuaZhru33z9i0pMqiR7jAVCMjBhBfICcqsxXMeDkEHxzp/e NPcywFyO7Xkrxf7uKYS7BFCcSsSsgcqhgyZMMJ3ABL4e9zSyd+/OOQkgK7gcDRDEqh7W KdSC8gTCzjcBzEfYSw1UPqMAxC3gUDd3bV4yJzjgmkPjKgC7M6VOJNo1Gv9kr+7NZbr7 KCKg== 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 q11si1378625pli.749.2017.09.28.06.14.38; Thu, 28 Sep 2017 06:14:38 -0700 (PDT) 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 S1753359AbdI1NOg (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:36 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57128 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753317AbdI1NOd (ORCPT ); Thu, 28 Sep 2017 09:14:33 -0400 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 E49861435; Thu, 28 Sep 2017 06:14:32 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CF2EB3F483; Thu, 28 Sep 2017 06:14:30 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 12/22] firmware: arm_scmi: add option for polling based performance domain operations Date: Thu, 28 Sep 2017 14:11:36 +0100 Message-Id: <1506604306-20739-13-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 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 13d84d829201..334e8ec321ed 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -305,8 +305,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; @@ -317,6 +317,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); @@ -327,8 +328,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; @@ -338,6 +339,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); @@ -445,21 +447,22 @@ static int scmi_dvfs_get_transition_latency(struct device *dev) } static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain, - unsigned long freq) + unsigned long freq, bool poll) { struct perf_dom_info *dom = perf_info.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 perf_dom_info *dom = perf_info.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 5e29394b5cc9..ac1a4a096314 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -99,15 +99,15 @@ 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 (*limits_notify_enable)(const struct scmi_handle *, u32, bool); int (*level_notify_enable)(const struct scmi_handle *, u32, bool); int (*device_domain_id)(struct device *); int (*get_transition_latency)(struct device *); int (*add_opps_to_device)(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 Thu Sep 28 13:11:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114438 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp730297qgf; Thu, 28 Sep 2017 06:16:46 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDUAzxSwJ1E1r9RmOHM71NM2OWLvAflB4kqk5mK7fL+rzwLerX0OSsBznVWtA/VGSh3q1ev X-Received: by 10.99.167.68 with SMTP id w4mr4199182pgo.390.1506604606720; Thu, 28 Sep 2017 06:16:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604606; cv=none; d=google.com; s=arc-20160816; b=stRhdmIBTXxNz+hMyEs/iMWWP+bJiZi2gnPoryluMSOtOPjWdUZ5epqF+IDoej49LF vIEqN9M6nY2LbYI767afGJDhcZZWCBtHIlEb4v5FOEl9nzYJ/iYvLB2E1jJWCxtHM4Kp uJv+PpMYFmh6iKHbSnNdTzWKFNxlImVHh+1SS+rYJwhd6t0+xrieJLeGTPpDxa64/d+t iEd/qKwIA0UB4m575lHR6SW8xY/nh72NCuWVd8fT/z1/VjOsOaZ9ZdDjouwHwFtvJv91 UAy0TwqHs7FLT0NodMTVC8AWDKkj1XkdzADZUlxn+vl0A3Zul/CURvb1Yj3LCZqO3mJi hsUw== 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=mGAM/buZZFrp0yS8KPZigEW8OUp0iG0Iq14zUljsn8I=; b=EQwskjy3u898eIa3K8xikadV+rQvn6BZPXX1MZeztmNFt00P391EU/24D8eWfSre2M 4Kp/FXXY01ZkfQ8N/l3nJyY+xhthql9sOkbjS0kmO6ATyCj1Cb2GDpkWgdV6KYeMicQz PqAKYtmdwcGXwhTuzrlEJ5+fBct8lWG23p3NnPtSRzIQy3FFPPIyJAgPaP+fAGySvlkQ J7nSejJkBrOSucogS/xQ3wxcNnyr+Gf7taa7v0VSUH6sLYNTVKShREccujsaewaWP0XP rqbUy1mv2FHxIyU+Xvv7dlZJP6mQNiQ+IYi+kHC7gzhhF4Z49BX9s2OIDml1wGi7YrpN rqJw== 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 h6si1423965pgs.436.2017.09.28.06.16.46; Thu, 28 Sep 2017 06:16:46 -0700 (PDT) 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 S1753448AbdI1NQn (ORCPT + 26 others); Thu, 28 Sep 2017 09:16:43 -0400 Received: from foss.arm.com ([217.140.101.70]:57138 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753346AbdI1NOf (ORCPT ); Thu, 28 Sep 2017 09:14:35 -0400 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 431941596; Thu, 28 Sep 2017 06:14:35 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 306623F483; Thu, 28 Sep 2017 06:14:33 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 13/22] firmware: arm_scmi: refactor in preparation to support per-protocol channels Date: Thu, 28 Sep 2017 14:11:37 +0100 Message-Id: <1506604306-20739-14-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 support per-protocol channels if available, we need to factor out all the mailbox channel information(Tx/Rx payload and channel handle) out of the main SCMI instance information structure. This patch refactors the existing channel information into a separate chan_info structure. Cc: Arnd Bergmann Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 84 ++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 30 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index e1abedf15cb0..93b3bd8d437f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -104,6 +104,22 @@ struct scmi_desc { }; /** + * struct scmi_chan_info - Structure representing a SCMI channel informfation + * + * @cl: Mailbox Client + * @chan: Transmit/Receive mailbox channel + * @payload: Transmit/Receive mailbox channel payload area + * @dev: Reference to device in the SCMI hierarchy corresponding to this + * channel + */ +struct scmi_chan_info { + struct mbox_client cl; + struct mbox_chan *chan; + void __iomem *payload; + struct device *dev; +}; + +/** * struct scmi_info - Structure representing a SCMI instance * * @dev: Device pointer @@ -111,10 +127,8 @@ struct scmi_desc { * @handle: Instance of SCMI handle to send to clients * @version: SCMI revision information containing protocol version, * implementation version and (sub-)vendor identification. - * @cl: Mailbox Client - * @tx_chan: Transmit mailbox channel - * @tx_payload: Transmit mailbox channel payload area * @minfo: Message info + * @tx_cinfo: Reference to SCMI channel information * @protocols_imp: list of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: list head @@ -125,16 +139,14 @@ struct scmi_info { const struct scmi_desc *desc; struct scmi_revision_info version; struct scmi_handle handle; - struct mbox_client cl; - struct mbox_chan *tx_chan; - void __iomem *tx_payload; struct scmi_xfers_info minfo; + struct scmi_chan_info *tx_cinfo; u8 *protocols_imp; struct list_head node; int users; }; -#define client_to_scmi_info(c) container_of(c, struct scmi_info, cl) +#define client_to_scmi_chan_info(c) container_of(c, struct scmi_chan_info, cl) #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) /* @@ -224,10 +236,11 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) { u16 xfer_id; struct scmi_xfer *xfer; - struct scmi_info *info = client_to_scmi_info(cl); + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + struct device *dev = cinfo->dev; + struct scmi_info *info = dev_get_drvdata(dev); struct scmi_xfers_info *minfo = &info->minfo; - struct device *dev = info->dev; - struct scmi_shared_mem *mem = info->tx_payload; + struct scmi_shared_mem *mem = cinfo->payload; xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); @@ -278,8 +291,8 @@ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) static void scmi_tx_prepare(struct mbox_client *cl, void *m) { struct scmi_xfer *t = m; - struct scmi_info *info = client_to_scmi_info(cl); - struct scmi_shared_mem *mem = info->tx_payload; + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + struct scmi_shared_mem *mem = cinfo->payload; mem->channel_status = 0x0; /* Mark channel busy + clear error */ mem->flags = t->hdr.poll_completion ? 0 : @@ -371,9 +384,9 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) } static bool -scmi_xfer_poll_done(const struct scmi_info *info, struct scmi_xfer *xfer) +scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { - struct scmi_shared_mem *mem = info->tx_payload; + struct scmi_shared_mem *mem = cinfo->payload; u16 xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); if (xfer->hdr.seq != xfer_id) @@ -400,8 +413,9 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) int timeout; struct scmi_info *info = handle_to_scmi_info(handle); struct device *dev = info->dev; + struct scmi_chan_info *cinfo = info->tx_cinfo; - ret = mbox_send_message(info->tx_chan, xfer); + ret = mbox_send_message(cinfo->chan, xfer); if (ret < 0) { dev_dbg(dev, "mbox send fail %d\n", ret); return ret; @@ -412,10 +426,10 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) if (xfer->hdr.poll_completion) { timeout = info->desc->max_rx_timeout_ms * 100; - while (!scmi_xfer_poll_done(info, xfer) && timeout--) + while (!scmi_xfer_poll_done(cinfo, xfer) && timeout--) udelay(10); if (timeout) - scmi_fetch_response(xfer, info->tx_payload); + scmi_fetch_response(xfer, cinfo->payload); else ret = -ETIMEDOUT; } else { @@ -435,7 +449,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) * Unfortunately, we have to kick the mailbox framework after we have * received our message. */ - mbox_client_txdone(info->tx_chan, ret); + mbox_client_txdone(cinfo->chan, ret); return ret; } @@ -757,11 +771,11 @@ static int scmi_mailbox_check(struct device_node *np) return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); } -static int scmi_mbox_free_channel(struct scmi_info *info) +static int scmi_mbox_free_channel(struct scmi_chan_info *cinfo) { - if (!IS_ERR_OR_NULL(info->tx_chan)) { - mbox_free_channel(info->tx_chan); - info->tx_chan = NULL; + if (!IS_ERR_OR_NULL(cinfo->chan)) { + mbox_free_channel(cinfo->chan); + cinfo->chan = NULL; } return 0; @@ -783,7 +797,7 @@ static int scmi_remove(struct platform_device *pdev) if (!ret) /* Safe to free channels since no more users */ - return scmi_mbox_free_channel(info); + return scmi_mbox_free_channel(info->tx_cinfo); return ret; } @@ -795,9 +809,17 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) resource_size_t size; struct device *dev = info->dev; struct device_node *shmem, *np = dev->of_node; + struct scmi_chan_info *cinfo; struct mbox_client *cl; - cl = &info->cl; + cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + + info->tx_cinfo = cinfo; + cinfo->dev = dev; + + cl = &cinfo->cl; cl->dev = dev; cl->rx_callback = scmi_rx_callback; cl->tx_prepare = scmi_tx_prepare; @@ -813,16 +835,16 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) } size = resource_size(&res); - info->tx_payload = devm_ioremap(dev, res.start, size); - if (!info->tx_payload) { + cinfo->payload = devm_ioremap(info->dev, res.start, size); + if (!cinfo->payload) { dev_err(dev, "failed to ioremap SCMI Tx payload\n"); return -EADDRNOTAVAIL; } /* Transmit channel is first entry i.e. index 0 */ - info->tx_chan = mbox_request_channel(cl, 0); - if (IS_ERR(info->tx_chan)) { - ret = PTR_ERR(info->tx_chan); + cinfo->chan = mbox_request_channel(cl, 0); + if (IS_ERR(cinfo->chan)) { + ret = PTR_ERR(cinfo->chan); if (ret != -EPROBE_DEFER) dev_err(dev, "failed to request SCMI Tx mailbox\n"); return ret; @@ -844,6 +866,8 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, return; } + platform_set_drvdata(cdev, info); + init_ret = match->fn(&info->handle); if (init_ret) { dev_err(info->dev, "SCMI protocol %d init error %d\n", @@ -894,7 +918,7 @@ static int scmi_probe(struct platform_device *pdev) ret = scmi_base_protocol_init(handle); if (ret) { dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); - scmi_mbox_free_channel(info); + scmi_mbox_free_channel(info->tx_cinfo); return ret; } From patchwork Thu Sep 28 13:11:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114429 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp727913qgf; Thu, 28 Sep 2017 06:14:44 -0700 (PDT) X-Google-Smtp-Source: AOwi7QApTCbnIRic0JbyqNZj4vBWzj+RKFZgBCFuRFoVgPywAYlSNH3MdBBdzpKztYatUufb1hPn X-Received: by 10.98.86.28 with SMTP id k28mr4336351pfb.89.1506604484568; Thu, 28 Sep 2017 06:14:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604484; cv=none; d=google.com; s=arc-20160816; b=D1wIhJ2ePkor80hGcM8vOtPpF5h8clWSq7P/6x3IljbhVdcWVKgBGtBUaVL4Va+K2P QQW0bg6Nli/2QcqVQyjuvHL05jDvK+1y7sH9zB59+IzEQcTGXLYAs8SrLHkG2L0nBbUA valfExdhCHdcQrf1LB7bD20ZJ7KvBstvElvlUpgOVRfYatXIn0GUI9glhnLWVu5Y90uZ uAym7W3NC0/b8ZknLJZ7ZYcwgpXgRwSRdK8YCXkhvQd3J7n/rUaia679xHU1b4xtRlRi ImxSnmGIV0UNMNSV4Lzx12hlk8yNRo2zhrmOB+gQxqT5g63b/h7Yy14gr2FDMpTuktdK t0gA== 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=L645vZwFlZfDHUyry2YYzrDBjrm/tf94M8nj2Yy20co=; b=Cpai2wn75eiEqmMgDKWiez80Uu2K2YMIx56d0Erzpl8lRGQokLbiOQyc+y6AKj97QD 7lD9uGUQ2TRSGrqNuQQTElhu/y3IePG9OGm0llGB139s/k2z2mB4KDh69r7yHYLRb42z K9oIR6KK2k2Q+bAIplxfIlmrV3jdv5Dwwjk4s5IPqSjtBRwchIYDpBHjAn3O/NNrw7sa wwFjCUVAXjSajfkzFXNOhOQhWcaNBc1M3cFM399TJGTeGxif3lodDRUhQSG3ymkMouEv U9bjWTjBZQeF3NK6EHJD1AbYHvDENKwFHKMBrkvCFz7saFed4TxIdjliXjSlllMTsBc6 GvRA== 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 q11si1378625pli.749.2017.09.28.06.14.43; Thu, 28 Sep 2017 06:14:44 -0700 (PDT) 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 S1753376AbdI1NOl (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:41 -0400 Received: from foss.arm.com ([217.140.101.70]:57158 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753317AbdI1NOh (ORCPT ); Thu, 28 Sep 2017 09:14:37 -0400 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 954F5164F; Thu, 28 Sep 2017 06:14:37 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 82E153F483; Thu, 28 Sep 2017 06:14:35 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 14/22] firmware: arm_scmi: add per-protocol channels support using idr objects Date: Thu, 28 Sep 2017 14:11:38 +0100 Message-Id: <1506604306-20739-15-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 47 +++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 93b3bd8d437f..92ef21d6aa5a 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -128,7 +128,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 @@ -140,7 +140,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; @@ -413,7 +413,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) { @@ -771,13 +775,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; } @@ -785,6 +794,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; of_platform_depopulate(&pdev->dev); @@ -795,28 +805,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; @@ -850,6 +866,13 @@ 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; + } + return 0; } @@ -868,6 +891,8 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, platform_set_drvdata(cdev, info); + scmi_mbox_chan_setup(info, &cdev->dev, match->protocol_id); + init_ret = match->fn(&info->handle); if (init_ret) { dev_err(info->dev, "SCMI protocol %d init error %d\n", @@ -906,19 +931,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 Thu Sep 28 13:11:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114437 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp729833qgf; Thu, 28 Sep 2017 06:16:21 -0700 (PDT) X-Google-Smtp-Source: AOwi7QCe3U+KJhSQ6TgsRZ8yKg4/r3oA/iVIruc69lCIojZFYSk5W6vKpwgWvU2ifd324I7Dy3C+ X-Received: by 10.99.127.68 with SMTP id p4mr4234110pgn.253.1506604581691; Thu, 28 Sep 2017 06:16:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604581; cv=none; d=google.com; s=arc-20160816; b=UFl5IDc6Vqd2UMg4KYQAxcPBoZCPJxj4MBZVmBaFwTTITxxBy21mMXdxKgjBWF21Ui PS5acw63JN3mPvKePmS1JH5thNDbzUVfBmzMBvcVpf48b9d7VrjgnSbGpuFbw/bASY/o JLV5pMe6d2NvBU78LysXkXZwbeoum+Z0uYsjNeFdrICH6S0nkeVfNJW9whn1WiFw6mvB ZmMihplPwHIb+2+BudkIAaBlWM+dXd/Uai4wgXz8lEtlNjg3Qaipw2T6oZb8odpEp02f SWiQKysSUV1mgP1QtU4kZtbWMsSbtCLA9d6dRYq/urBeUMPQ3LvEgoatwp/8LuaSi7aC snxQ== 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=r1yM0LuFaN6w8faRBYI6JON6IsZmKfixeNXlpO+cUsE=; b=f2KqexT3f2ZhRg63mck7n2gT6OXDQ0C/BQVJ0cr5y1I36NQMTWNaWHkK9D4DFFGw8h Y4kKEXQyYmh5pMvZNy/ZGJAp27jG0blbkOPEqIF7cmq19qVtlHUMtfKvSZ4/MJnVwDHe 3PorjakImupy0aG5FbVaIMmVD8GAHOGZ1ZWNEJ8OnhRLzkW133zXH9n3j70RQd5GaynB O9Lls00uUITdQXLy7Rw/l25N3cePfS737p/GYlAZ8QVd2TXAqp/W+yny7CeqhaHgYjpH g7ts1Rw3A/ojW+AVwZqatPHYpm8FgxiSsrrzLWwzsaqTkJSSDuRGKKrMo96wda40yxrP p3hg== 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 b89si1393972pfd.354.2017.09.28.06.16.21; Thu, 28 Sep 2017 06:16:21 -0700 (PDT) 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 S1753433AbdI1NQU (ORCPT + 26 others); Thu, 28 Sep 2017 09:16:20 -0400 Received: from foss.arm.com ([217.140.101.70]:57186 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753365AbdI1NOk (ORCPT ); Thu, 28 Sep 2017 09:14:40 -0400 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 E79DA1993; Thu, 28 Sep 2017 06:14:39 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D52E33F483; Thu, 28 Sep 2017 06:14:37 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar Subject: [PATCH v3 15/22] firmware: arm_scmi: abstract mailbox interface Date: Thu, 28 Sep 2017 14:11:39 +0100 Message-Id: <1506604306-20739-16-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 Some of the mailbox controller expects controller specific data in order to implement simple doorbell mechanism as expected by SCMI specification. This patch creates a shim layer to abstract the mailbox interface so that it can support any mailbox controller. It also provides default implementation which maps to standard mailbox client APIs, so that controllers implementing doorbell mechanism need not require any additional layer. Cc: Arnd Bergmann Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/driver.c | 84 ++++++++++--------------------------- drivers/firmware/arm_scmi/mbox_if.c | 80 +++++++++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/mbox_if.h | 68 ++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 62 deletions(-) create mode 100644 drivers/firmware/arm_scmi/mbox_if.c create mode 100644 drivers/firmware/arm_scmi/mbox_if.h -- 2.7.4 diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index f9dee5ad0aa0..733157c5b4e2 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o -arm_scmi-y = base.o clock.o driver.o perf.o power.o sensors.o +arm_scmi-y = base.o clock.o driver.o mbox_if.o perf.o power.o sensors.o diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 92ef21d6aa5a..97285a22dfaa 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include "common.h" +#include "mbox_if.h" #define MSG_ID_SHIFT 0 #define MSG_ID_MASK 0xff @@ -90,36 +90,6 @@ struct scmi_xfers_info { }; /** - * 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_chan_info - Structure representing a SCMI channel informfation - * - * @cl: Mailbox Client - * @chan: Transmit/Receive mailbox channel - * @payload: Transmit/Receive mailbox channel payload area - * @dev: Reference to device in the SCMI hierarchy corresponding to this - * channel - */ -struct scmi_chan_info { - struct mbox_client cl; - struct mbox_chan *chan; - void __iomem *payload; - struct device *dev; -}; - -/** * struct scmi_info - Structure representing a SCMI instance * * @dev: Device pointer @@ -137,6 +107,7 @@ struct scmi_chan_info { struct scmi_info { struct device *dev; const struct scmi_desc *desc; + struct scmi_mbox_ops *mbox_ops; struct scmi_revision_info version; struct scmi_handle handle; struct scmi_xfers_info minfo; @@ -146,7 +117,6 @@ struct scmi_info { int users; }; -#define client_to_scmi_chan_info(c) container_of(c, struct scmi_chan_info, cl) #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) /* @@ -221,10 +191,10 @@ static void scmi_fetch_response(struct scmi_xfer *xfer, } /** - * scmi_rx_callback() - mailbox client callback for receive messages + * scmi_generic_rx_callback() -generic mailbox client callback for receive + * messages * - * @cl: client pointer - * @m: mailbox message + * @cinfo: pointer to structure with SCMI mailbox channels information * * Processes one received message to appropriate transfer information and * signals completion of the transfer. @@ -232,11 +202,10 @@ static void scmi_fetch_response(struct scmi_xfer *xfer, * 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) +void scmi_generic_rx_callback(struct scmi_chan_info *cinfo) { u16 xfer_id; 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_xfers_info *minfo = &info->minfo; @@ -280,18 +249,18 @@ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) } /** - * scmi_tx_prepare() - mailbox client callback to prepare for the transfer + * scmi_generic_tx_prepare() - generic mailbox client callback to prepare for + * the transfer * - * @cl: client pointer + * @cinfo: pointer to structure with SCMI mailbox channels information * @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) +void scmi_generic_tx_prepare(struct scmi_chan_info *cinfo, void *m) { struct scmi_xfer *t = m; - struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); struct scmi_shared_mem *mem = cinfo->payload; mem->channel_status = 0x0; /* Mark channel busy + clear error */ @@ -384,9 +353,8 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) } static bool -scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) +scmi_xfer_poll_done(struct scmi_shared_mem *mem, struct scmi_xfer *xfer) { - struct scmi_shared_mem *mem = cinfo->payload; u16 xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); if (xfer->hdr.seq != xfer_id) @@ -419,7 +387,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) if (unlikely(!cinfo)) return -EINVAL; - ret = mbox_send_message(cinfo->chan, xfer); + ret = info->mbox_ops->send_message(cinfo, xfer); if (ret < 0) { dev_dbg(dev, "mbox send fail %d\n", ret); return ret; @@ -430,7 +398,8 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) if (xfer->hdr.poll_completion) { timeout = info->desc->max_rx_timeout_ms * 100; - while (!scmi_xfer_poll_done(cinfo, xfer) && timeout--) + while (!scmi_xfer_poll_done(cinfo->payload, xfer) && + timeout--) udelay(10); if (timeout) scmi_fetch_response(xfer, cinfo->payload); @@ -676,12 +645,6 @@ const struct scmi_handle *devm_scmi_handle_get(struct device *dev) } EXPORT_SYMBOL_GPL(devm_scmi_handle_get); -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 }, @@ -775,13 +738,14 @@ 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(int id, void *p, void *data) +static int scmi_free_channel(int id, void *p, void *data) { - struct scmi_chan_info *cinfo = p; struct idr *idr = data; + struct scmi_chan_info *cinfo = p; + struct scmi_info *info = dev_get_drvdata(cinfo->dev); if (!IS_ERR_OR_NULL(cinfo->chan)) { - mbox_free_channel(cinfo->chan); + info->mbox_ops->free_channel(cinfo); cinfo->chan = NULL; } @@ -807,7 +771,7 @@ static int scmi_remove(struct platform_device *pdev) if (!ret) { /* Safe to free channels since no more users */ - ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + ret = idr_for_each(idr, scmi_free_channel, idr); idr_destroy(&info->tx_idr); } @@ -834,11 +798,8 @@ scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) return -ENOMEM; cinfo->dev = dev; - cl = &cinfo->cl; cl->dev = dev; - cl->rx_callback = scmi_rx_callback; - cl->tx_prepare = scmi_tx_prepare; cl->tx_block = false; cl->knows_txdone = true; @@ -858,9 +819,8 @@ scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) } /* Transmit channel is first entry i.e. index 0 */ - cinfo->chan = mbox_request_channel(cl, 0); - if (IS_ERR(cinfo->chan)) { - ret = PTR_ERR(cinfo->chan); + ret = info->mbox_ops->request_channel(cinfo, 0); + if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to request SCMI Tx mailbox\n"); return ret; @@ -924,6 +884,8 @@ static int scmi_probe(struct platform_device *pdev) info->dev = dev; info->desc = desc; + /* set up mailbox operations */ + info->mbox_ops = desc->mbox_ops; INIT_LIST_HEAD(&info->node); ret = scmi_xfer_info_init(info); diff --git a/drivers/firmware/arm_scmi/mbox_if.c b/drivers/firmware/arm_scmi/mbox_if.c new file mode 100644 index 000000000000..dc2bcc060f30 --- /dev/null +++ b/drivers/firmware/arm_scmi/mbox_if.c @@ -0,0 +1,80 @@ +/* + * System Control and Management Interface (SCMI) default mailbox interface + * + * 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 "mbox_if.h" + +static void scmi_tx_prepare(struct mbox_client *cl, void *m) +{ + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + + scmi_generic_tx_prepare(cinfo, m); +} + +static void scmi_rx_callback(struct mbox_client *cl, void *m) +{ + struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); + + scmi_generic_rx_callback(cinfo); +} + +static int scmi_mbox_request_channel(struct scmi_chan_info *cinfo, int index) +{ + int ret = 0; + struct mbox_client *cl = &cinfo->cl; + + cl->rx_callback = scmi_rx_callback; + cl->tx_prepare = scmi_tx_prepare; + + cinfo->chan = mbox_request_channel(cl, index); + if (IS_ERR(cinfo->chan)) + ret = PTR_ERR(cinfo->chan); + + return ret; +} + +static int scmi_mbox_send_message(struct scmi_chan_info *cinfo, void *msg) +{ + return mbox_send_message(cinfo->chan, msg); +} + +static void scmi_mbox_client_txdone(struct scmi_chan_info *cinfo, int r) +{ + mbox_client_txdone(cinfo->chan, r); +} + +static void scmi_mbox_free_channel(struct scmi_chan_info *cinfo) +{ + mbox_free_channel(cinfo->chan); +} + +static struct scmi_mbox_ops scmi_default_mbox_ops = { + .request_channel = scmi_mbox_request_channel, + .send_message = scmi_mbox_send_message, + .client_txdone = scmi_mbox_client_txdone, + .free_channel = scmi_mbox_free_channel, +}; + +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, + .mbox_ops = &scmi_default_mbox_ops, +}; diff --git a/drivers/firmware/arm_scmi/mbox_if.h b/drivers/firmware/arm_scmi/mbox_if.h new file mode 100644 index 000000000000..02baa73e8613 --- /dev/null +++ b/drivers/firmware/arm_scmi/mbox_if.h @@ -0,0 +1,68 @@ +/* + * System Control and Management Interface (SCMI) mailbox interface 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_chan_info - Structure representing a SCMI channel informfation + * + * @cl: Mailbox Client + * @tx_chan: Transmit mailbox channel + * @rx_chan: Receive mailbox channel + * @tx_payload: Transmit mailbox channel payload area + * @rx_payload: Receive mailbox channel payload area + * @dev: Reference to device in the SCMI hierarchy corresponding to this + * channel + */ +struct scmi_chan_info { + struct mbox_client cl; + struct mbox_chan *chan; + void __iomem *payload; + struct device *dev; + void *priv; +}; + +#define client_to_scmi_chan_info(c) container_of(c, struct scmi_chan_info, cl) + +struct scmi_mbox_ops { + int (*request_channel)(struct scmi_chan_info *cinfo, int index); + int (*send_message)(struct scmi_chan_info *cinfo, void *msg); + void (*client_txdone)(struct scmi_chan_info *cinfo, int r); + void (*free_channel)(struct scmi_chan_info *cinfo); +}; + +/** + * 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. + * @mbox_ops: Function to initialise the mailbox operations + */ +struct scmi_desc { + int max_rx_timeout_ms; + int max_msg; + int max_msg_size; + struct scmi_mbox_ops *mbox_ops; +}; + +void scmi_generic_rx_callback(struct scmi_chan_info *cinfo); +void scmi_generic_tx_prepare(struct scmi_chan_info *cinfo, void *m); + +extern const struct scmi_desc scmi_generic_desc; From patchwork Thu Sep 28 13:11:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114431 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp728052qgf; Thu, 28 Sep 2017 06:14:51 -0700 (PDT) X-Google-Smtp-Source: AOwi7QCjvL/mgnyDtnZeG0qGll2n9wSjt/X5TK7FgCNzGRjKZTr8j/e/C1EjZbgg53SwhBdwd76h X-Received: by 10.98.10.12 with SMTP id s12mr4380136pfi.127.1506604491034; Thu, 28 Sep 2017 06:14:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604491; cv=none; d=google.com; s=arc-20160816; b=oBygjCfsb4nufwI0GFo6LXjOY3duZXozK7YsCdsY5ot60+HyP/Ox8g5ESHpDKW+q9O /Ntj8u/fOMAvc3whRuRLRAebKyM3m7oyf0weKE+xoVTU7DhRniH+GhSavPW1Ysnz8GaY yMuljFukbq0UVHhTM/Cjg4a2NAt+qsBLVzzTXvHSdx/arPrOl+9Ztbkw6mRW10j4OWAO WvWJj44mwWNGfAHXUi1jAY+wDDlEpP0uoFe0EDd+0YsXbuSw4ZQS8hTQRU8xl1NrNW+c 5vUw0yJzPKblJR88uRY6LteODolfxkGf5/3Bfxcng1H8GbkE743wl4TqP8JMwQO6U5xY b35Q== 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=iaVnY0tokBLadkbOPYMnddK/vyqepNugIOxQckMadzE=; b=aVwbv6hPm81LjjvW0EA6kGBDRVxcFmpssoNfQCDyxpE+kjR7ffC2t8rvbQokt+Mw8M LfqiQ1Czkwy9ddgWWmzRM01K2bXkg3aMI5eD2T9y40fJOuoXqdgcqSc4iiT34z4Ciwj+ rt4yj0NfsQNaZKDYQziGbEaWalEjZAm4vR5WkETEGYngrAy6grzUuYYhJnNUA35KRzEW LohnndLnd6tGu+hr3/KHh0rfRGJDFVRD032n84z8gOdDy4B2ubMsjLa4Utng566UVhiz AFFwrBT33BfXMGc3flRhulBoWrkwS2Q4m6SBSVOdcPTB6ocVqQgoKG9f0vbSUl+K7oe+ F8fg== 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 x85si1374651pfk.613.2017.09.28.06.14.49; Thu, 28 Sep 2017 06:14:51 -0700 (PDT) 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 S1753408AbdI1NOs (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:48 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57226 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752079AbdI1NOp (ORCPT ); Thu, 28 Sep 2017 09:14:45 -0400 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 DF6B9165C; Thu, 28 Sep 2017 06:14:44 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 85E8C3F483; Thu, 28 Sep 2017 06:14:42 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Kevin Hilman , Ulf Hansson Subject: [PATCH v3 17/22] firmware: arm_scmi: add device power domain support using genpd Date: Thu, 28 Sep 2017 14:11:41 +0100 Message-Id: <1506604306-20739-18-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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 hooks up the support for device power domain provided by SCMI using the Linux generic power domain infrastructure. Cc: Kevin Hilman Cc: Ulf Hansson Signed-off-by: Sudeep Holla --- drivers/firmware/Kconfig | 13 +++ drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/scmi_pm_domain.c | 134 +++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 drivers/firmware/arm_scmi/scmi_pm_domain.c -- 2.7.4 Reviewed-by: Ulf Hansson diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index c3d1a12763ce..a4462bc661c8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -40,6 +40,19 @@ config ARM_SCMI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCMI. +config ARM_SCMI_POWER_DOMAIN + tristate "SCMI power domain driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCMI power domains which can be + enabled or disabled via the SCP firmware + + This driver can also be built as a module. If so, the module + will be called scmi_pm_domain. Note this may needed early in boot + before rootfs may be available. + config ARM_SCPI_PROTOCOL tristate "ARM System Control and Power Interface (SCPI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 7fb026c71833..289e9e5a4764 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) = arm_scmi.o arm_scmi-y = base.o clock.o driver.o mbox_if.o perf.o power.o sensors.o arm_scmi-$(CONFIG_ARM_MHU) += arm_mhu_if.o +obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c new file mode 100644 index 000000000000..e53aa9d0af6e --- /dev/null +++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c @@ -0,0 +1,134 @@ +/* + * SCMI Generic power domain support. + * + * Copyright (C) 2017 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct scmi_pm_domain { + struct generic_pm_domain genpd; + const struct scmi_handle *handle; + const char *name; + u32 domain; +}; + +#define to_scmi_pd(gpd) container_of(gpd, struct scmi_pm_domain, genpd) + +static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + int ret; + u32 state, ret_state; + struct scmi_pm_domain *pd = to_scmi_pd(domain); + const struct scmi_power_ops *ops = pd->handle->power_ops; + + if (power_on) + state = SCMI_POWER_STATE_GENERIC_ON; + else + state = SCMI_POWER_STATE_GENERIC_OFF; + + ret = ops->state_set(pd->handle, pd->domain, state); + if (!ret) + ret = ops->state_get(pd->handle, pd->domain, &ret_state); + if (!ret && state != ret_state) + return -EIO; + + return ret; +} + +static int scmi_pd_power_on(struct generic_pm_domain *domain) +{ + return scmi_pd_power(domain, true); +} + +static int scmi_pd_power_off(struct generic_pm_domain *domain) +{ + return scmi_pd_power(domain, false); +} + +static int scmi_pm_domain_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct scmi_pm_domain *scmi_pd; + struct genpd_onecell_data *scmi_pd_data; + struct generic_pm_domain **domains; + int num_domains, i; + const struct scmi_handle *handle = devm_scmi_handle_get(dev); + + if (IS_ERR_OR_NULL(handle) || !handle->power_ops) + return -EPROBE_DEFER; + + num_domains = handle->power_ops->num_domains_get(handle); + if (num_domains < 0) { + dev_err(dev, "number of domains not found\n"); + return num_domains; + } + + scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL); + if (!scmi_pd) + return -ENOMEM; + + scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL); + if (!scmi_pd_data) + return -ENOMEM; + + domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + for (i = 0; i < num_domains; i++, scmi_pd++) { + domains[i] = &scmi_pd->genpd; + + scmi_pd->domain = i; + scmi_pd->handle = handle; + scmi_pd->name = handle->power_ops->name_get(handle, i); + scmi_pd->genpd.name = scmi_pd->name; + scmi_pd->genpd.power_off = scmi_pd_power_off; + scmi_pd->genpd.power_on = scmi_pd_power_on; + + /* + * Treat all power domains as off at boot. + * + * The SCP firmware itself may have switched on some domains, + * but for reference counting purpose, keep it this way. + */ + pm_genpd_init(&scmi_pd->genpd, NULL, true); + } + + scmi_pd_data->domains = domains; + scmi_pd_data->num_domains = num_domains; + + of_genpd_add_provider_onecell(np, scmi_pd_data); + + return 0; +} + +static struct platform_driver scmi_power_domain_driver = { + .driver = { + .name = "scmi-power-domain", + }, + .probe = scmi_pm_domain_probe, +}; +module_platform_driver(scmi_power_domain_driver); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI power domain driver"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Sep 28 13:11:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114432 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp728148qgf; Thu, 28 Sep 2017 06:14:56 -0700 (PDT) X-Google-Smtp-Source: AOwi7QAodoheS9toiWEvS6zpgM96ENErb3ctyeBEdoUSFdvUJJ83YKoNkHYenLh2RQuNIKyQlYAt X-Received: by 10.159.211.9 with SMTP id bc9mr4159185plb.192.1506604496012; Thu, 28 Sep 2017 06:14:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604496; cv=none; d=google.com; s=arc-20160816; b=KF1H3YvRB68SmnHvA0nGqAU6s1OmfvvtbPKymv/0WfrDIJJelpKclxVj8RsbRFHuDO m6gmvIXYrE2BM+QU5iNAFDG37XdORk/4Cg0kvamtLnIVwWXLn8J8CqIbb7Y95AYJkSrM lxsuP6WotqbSO2QPA52SqqjsPUZbYcHU40UJcHEs/NnLha4wI06Tvau8H8xqJENTFJVt tdAXrl8YzC+S8VEmRxE/dpGou5g8Zen9GXRAQyWYd9rFI5AXiEKUrRXtlbBMef/QkTkb mJcCqEFZACWD+97zq5OcGjUPx4JLmX4TT8rb7Ib+Yrq9ziRWV1Xm/ebOkIfQNZmtMLlq behg== 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=WoGsQ2jv9RQ7jFr5Zd6CZCGawnLzXLu/frsViNDVnrQ=; b=hiCDwFaCHy1NoXDHiHr9usrn8tvX0iq7JDpqBx6FdrgAmFeRTvAX9kZD8JxGPC7KU0 iwTuTGHDDoAO2rc9HUKDCcw59H2kFwZJ5cCs4RBdH4tqnkYT9mnu8dLXDJ3pg+YHwX9f 02ekz7GYLAUiAt/6J6psQq8zGrAe3tkNjAB+6Q28hRzl7OeB07riYKyID9/UKwwC2ovG r8YWitr4VeaIA8V4jK8IFTw1Rw6qh5JK87YieMe2yx+8HSp5Nc/WHHRl5Ysr1+okRUTP 67usmxUNGm5i/d+feh0I8far5VhuAah8LTGLu7ErW4DMo99RIuMc+/Kx8UM1Gdq5S9rg MuzQ== 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 m14si1353540pfh.564.2017.09.28.06.14.55; Thu, 28 Sep 2017 06:14:55 -0700 (PDT) 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 S1753424AbdI1NOx (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:53 -0400 Received: from foss.arm.com ([217.140.101.70]:57240 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753403AbdI1NOs (ORCPT ); Thu, 28 Sep 2017 09:14:48 -0400 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 A83D119BF; Thu, 28 Sep 2017 06:14:47 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 2B6A13F483; Thu, 28 Sep 2017 06:14:45 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Michael Turquette , Stephen Boyd , linux-clk@vger.kernel.org Subject: [PATCH v3 18/22] clk: add support for clocks provided by SCMI Date: Thu, 28 Sep 2017 14:11:42 +0100 Message-Id: <1506604306-20739-19-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Sudeep Holla --- MAINTAINERS | 2 +- drivers/clk/Kconfig | 10 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-scmi.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-scmi.c -- 2.7.4 diff --git a/MAINTAINERS b/MAINTAINERS index 23ec3471f542..32c184391aee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12941,7 +12941,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 1c4e1aa6767e..57c66b22eab8 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 c99f363826f0..46ad2f2b686a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -39,6 +39,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..bd546a9cdf37 --- /dev/null +++ b/drivers/clk/clk-scmi.c @@ -0,0 +1,210 @@ +/* + * 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 +#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 platform_device *pdev) +{ + int idx, count, err; + struct clk_hw **hws; + struct clk_hw_onecell_data *clk_data; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct scmi_handle *handle = devm_scmi_handle_get(dev); + + if (IS_ERR_OR_NULL(handle) || !handle->clk_ops) + return -EPROBE_DEFER; + + 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 int scmi_clocks_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + of_clk_del_provider(np); + return 0; +} + +static struct platform_driver scmi_clocks_driver = { + .driver = { + .name = "scmi-clocks", + }, + .probe = scmi_clocks_probe, + .remove = scmi_clocks_remove, +}; +module_platform_driver(scmi_clocks_driver); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI clock driver"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Sep 28 13:11:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114436 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp729202qgf; Thu, 28 Sep 2017 06:15:48 -0700 (PDT) X-Google-Smtp-Source: AOwi7QC9hm8Tm6pg/Y0/f65g6IXRNAmay5MyLtdKnEzotf3fyWGLY6C1RSfMxEaTxjuCoEKY2/jp X-Received: by 10.84.216.75 with SMTP id f11mr4159063plj.236.1506604548301; Thu, 28 Sep 2017 06:15:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604548; cv=none; d=google.com; s=arc-20160816; b=VIebvaO1qotg2Ez9ZOAUwfB5SS12KrIRPEE90Q2htF+lbp5u04qaIAk/vY6sDcHVBz bV5fdc6/SduJJbV/dSn5bpnJhvqSQFVM4NZZeFIIrZ15n+GHMPaRGkEg9LJiEH9KQJKC b4/rv8b/XvpQfIOYBVhgtrLAA2Z9G9vHWEt8qTIdLD2xmDBrZFsnq+L9pzfgeTT3L4pf xsKsWO9P8Qa231SRZopSYH4AdghLwClZH9oigbr1epSw+LNPyLEaNoBz0l5qGMkTSssQ zlkDThkc6o1ciVbEZjJlca8I3vn1paSJ5Ub0xLNYeVnh94Ybaoet8ifT4HIuNutaoSCT 3z2w== 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=XE2JM44Xtb0rEp6sPK51yp57aXtsYqkdj2uH0m6ZGt0=; b=E13uINJAfek/1nsu/+aoxrxN2VTWCLntuLLLfzmCH5qsacag9uKDW7xJA8s2canAWv DHGvP5kMLjAkptZ22dccdyiWCaxMMdFUJOcOXWqskOxteiy/k/V0AQUDqXEMM4qYPz0/ aDBc8clSqAfVuiJK6N/Xv05f6pv2R1hUqycVmBoACZ50forsaONxLiwJbx9xHxE9hxPv TrHkpcxuz9rCOoTE83qch5SjbyQAHmTd1D6KJixzHW3LmFxDmqo+TUPsQz4ZIJwuFUhc Lfh/nBiZQPahjFj9CfcHo3y5hpBWJ1HTfhGdRw1Ea0R7KyQt/OfBG6i6pXBGSeBGnCIM SM6A== 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 62si1416636plc.742.2017.09.28.06.15.48; Thu, 28 Sep 2017 06:15:48 -0700 (PDT) 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 S932135AbdI1NPq (ORCPT + 26 others); Thu, 28 Sep 2017 09:15:46 -0400 Received: from foss.arm.com ([217.140.101.70]:57262 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752079AbdI1NOu (ORCPT ); Thu, 28 Sep 2017 09:14:50 -0400 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 5706619E8; Thu, 28 Sep 2017 06:14:50 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id E84BB3F483; Thu, 28 Sep 2017 06:14:47 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Guenter Roeck , linux-hwmon@vger.kernel.org Subject: [PATCH v3 19/22] hwmon: (core) Add hwmon_max to hwmon_sensor_types enumeration Date: Thu, 28 Sep 2017 14:11:43 +0100 Message-Id: <1506604306-20739-20-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: Guenter Roeck Cc: linux-hwmon@vger.kernel.org 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 Thu Sep 28 13:11:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114433 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp728197qgf; Thu, 28 Sep 2017 06:14:59 -0700 (PDT) X-Google-Smtp-Source: AOwi7QC+PiFga0tvsH47yFt8zjc3eu9CPxUlbHnysdBPXYtavuxEZe5BTfuEiOAceMpqaNwyUOm1 X-Received: by 10.84.129.226 with SMTP id b89mr4069606plb.0.1506604499089; Thu, 28 Sep 2017 06:14:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604499; cv=none; d=google.com; s=arc-20160816; b=XnZ5qZiLmjGUotcSjLhcwWLwEviImIccboi5G4ZQEBmiA39A4dTQhO7xoPmxUozwDx iwCxsoF1OFAMgwaf6PQMVTZOG8ArlBJv/f9xwuHC8VmkdwfM+zPQQlutu+EEW1FxTTvX VsZoiy1pJ1YGJ24wlQi0las/v46E3t3za6wRhT4sIiSsNwCuzmf4h0ehNl8RkAag1UqC US+BSAVZ4gSpcu6wA5lcBzuOZWr7re4wjd0RRKyZEZCMt9OONST86aOGpC40MQcZyVhq jORDD3QRDMStE4GhtdgsDnk9bNKKhPIYPevUvYvWe/+EXFUC4uRIx8yfB2d/2Z5LqbE9 OxAw== 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=rI2krCoE4wAGvD0SuTStYKtk/ntWo/E6urHF8iIDqmI=; b=kkXOej+muQDVhxW3wgwzOAflfYB0Hxh5tQWk8mORIO27eOBFAwbtDWX+7SHf1ZZsLT qWXb4029STNsHvxeKiQ+aP7p4/cAn4qWQMXIVTO+B8nFJfLtKwVxoDMwb/799XuI4v5n bX7v/rjk8rHZWC5coPQbWl6BXTzQSBVLpDDA7roj0rQJIKPFwEDrbx8Op8lBJVw+S88V ToDfcqXBTEVHBoi5PLGZF7gJs1MlY+OT4t3S5GgNH2qoSlIWDzIJHD9ymPJx5w1VcLdE +KTFSnDpbZW4aCt95+Cq19A4o/ANL230duNNLl+07xYgi+csBtjXdL/XFoOorMxNm6Go FENg== 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 m14si1353540pfh.564.2017.09.28.06.14.58; Thu, 28 Sep 2017 06:14:59 -0700 (PDT) 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 S932080AbdI1NOz (ORCPT + 26 others); Thu, 28 Sep 2017 09:14:55 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57280 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753426AbdI1NOx (ORCPT ); Thu, 28 Sep 2017 09:14:53 -0400 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 F0EAE19F6; Thu, 28 Sep 2017 06:14:52 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 9722C3F483; Thu, 28 Sep 2017 06:14:50 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , Guenter Roeck , linux-hwmon@vger.kernel.org Subject: [PATCH v3 20/22] hwmon: add support for sensors exported via ARM SCMI Date: Thu, 28 Sep 2017 14:11:44 +0100 Message-Id: <1506604306-20739-21-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: Guenter Roeck Cc: linux-hwmon@vger.kernel.org Signed-off-by: Sudeep Holla --- drivers/hwmon/Kconfig | 12 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/scmi-hwmon.c | 235 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 drivers/hwmon/scmi-hwmon.c -- 2.7.4 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d65431417b17..0b75e9a89463 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -321,6 +321,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 c84d9784be98..a51c2dcef11c 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -44,6 +44,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..0a8c0e8dc5d1 --- /dev/null +++ b/drivers/hwmon/scmi-hwmon.c @@ -0,0 +1,235 @@ +/* + * 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 +#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 platform_device *pdev) +{ + 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 = &pdev->dev; + struct hwmon_channel_info *scmi_hwmon_chan; + const struct hwmon_channel_info **ptr_scmi_ci; + const struct scmi_handle *handle = devm_scmi_handle_get(dev); + + if (IS_ERR_OR_NULL(handle) || !handle->sensor_ops) + return -EPROBE_DEFER; + + 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; + } + + *ptr_scmi_ci = NULL; + platform_set_drvdata(pdev, scmi_sensors); + + 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); + + if (IS_ERR(hwdev)) + return PTR_ERR(hwdev); + + return 0; +} + +static struct platform_driver scmi_hwmon_platdrv = { + .driver = { + .name = "scmi-hwmon", + }, + .probe = scmi_hwmon_probe, +}; +module_platform_driver(scmi_hwmon_platdrv); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI HWMON interface driver"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Sep 28 13:11:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 114435 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp728334qgf; Thu, 28 Sep 2017 06:15:05 -0700 (PDT) X-Google-Smtp-Source: AOwi7QB1TS+u5w+sE6eO/DcVWF7FWZhReL5wb5sbZOYD8PjdaEOxkVZpT6q9wP0wo+JXwMI5tLOY X-Received: by 10.98.32.139 with SMTP id m11mr4381658pfj.172.1506604504941; Thu, 28 Sep 2017 06:15:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506604504; cv=none; d=google.com; s=arc-20160816; b=hqZhO9plbZmiraQwusQIYXJFzFXtqgpxV8MHbF1zDF6gAtw//wu1TRpTQydDRKB0ef KUWOdaVbkqPhFhmkAYR5q/+QXMmoB/ZfL2RTaYsOqd+1iDmG0MNusUY1htLGs3S9OfmC FVIG4qGnA/bAUMV4XnjezVgiEEZul1U47kYXS2N0BkHXWMSf7GO3aecJDd987JC2OTrq P9GEXzrsGNrysvMbs78xh8+0c3LdN98t6cCXwZ2VY9WsZxh1kaNph/KXzYd+toQ3wKR0 oYhDaXM8Irtls1nwuu9PWVUyqLxr2sUa1q2qfB1WhYaP3b3x2gDlXzdlPUNP0TLjfCsk M5sA== 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=0yGtQ9nqnIb64PKSfjTUNRFugGAMlGGxgYyuOs/8LtY=; b=oQNDoONZBX+lSZ7GK2ozvQRD+XG1h3mdg30NjYxabRL08cWpZuXHMpPiSigszgI+A6 Kh9Z5FW6NpMSQV/qtQrHe+FkVxDswqOItdXqXLIAorxjKqYHKMKgXFxIVIYUNDpqiPC3 qznqn34MmgtMVmqZF4csxb8GREXljCRL3OoWboKOfemZs3hjzeLKzi+7B+EmoiSvbbaJ 3G3RmwUMQoX5+JC1m88Nzay4nM4GI3O+6sMJRUv8krHQPIQpMa34Iy8gleLXmV4RLxFD o14vYr678lT8mEtaFZrQoe0liSAMinKUWmL1Af7Lbhm9UnsBkG/xC879cekdn8GjXciN T17Q== 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 k185si1386695pgk.665.2017.09.28.06.15.04; Thu, 28 Sep 2017 06:15:04 -0700 (PDT) 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 S932121AbdI1NPC (ORCPT + 26 others); Thu, 28 Sep 2017 09:15:02 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57332 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932100AbdI1NO6 (ORCPT ); Thu, 28 Sep 2017 09:14:58 -0400 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 836D21682; Thu, 28 Sep 2017 06:14:58 -0700 (PDT) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 067923F483; Thu, 28 Sep 2017 06:14:55 -0700 (PDT) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Roy Franz , Harb Abdulhamid , Nishanth Menon , Arnd Bergmann , Loc Ho , Alexey Klimov , Ryan Harkin , Jassi Brar , "Rafael J. Wysocki" , Viresh Kumar , linux-pm@vger.kernel.org Subject: [PATCH v3 22/22] cpufreq: scmi: add support for fast frequency switching Date: Thu, 28 Sep 2017 14:11:46 +0100 Message-Id: <1506604306-20739-23-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506604306-20739-1-git-send-email-sudeep.holla@arm.com> References: <1506604306-20739-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: "Rafael J. Wysocki" Cc: Viresh Kumar Cc: linux-pm@vger.kernel.org Signed-off-by: Sudeep Holla --- drivers/cpufreq/scmi-cpufreq.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) -- 2.7.4 diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index bc5385638eb4..067a39bd5167 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -65,6 +65,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) { @@ -168,6 +181,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: @@ -184,6 +198,7 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy) { struct scmi_data *priv = policy->driver_data; + policy->fast_switch_possible = false; cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); kfree(priv); @@ -227,6 +242,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,