From patchwork Mon Feb 22 07:27:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Etienne Carriere X-Patchwork-Id: 1442949 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=Pwy695no; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DkYhk6FLnz9sBJ for ; Mon, 22 Feb 2021 18:29:10 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id CBCEF82770; Mon, 22 Feb 2021 08:29:04 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="Pwy695no"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id AFFD882899; Mon, 22 Feb 2021 08:29:01 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 6172F82764 for ; Mon, 22 Feb 2021 08:28:56 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=etienne.carriere@linaro.org Received: by mail-wr1-x430.google.com with SMTP id u14so17951007wri.3 for ; Sun, 21 Feb 2021 23:28:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=oeKsyBHCgifpSehAywSjEelS2tgrFnqncZinDQ1xhtI=; b=Pwy695noWauXXjBKS4UHdr24/hYf6wr4EO9V2LxhVmh7tdoWXg+AI0R5RQ/bM0In3G PnD4q4P4gbkK9iWR0KxFDD93zVEscQl3OATij6PMR2AkGFAMI88QOK0hT/LoRcyQeGE0 q1EKsVAdG2LFii3n+ePIc4cuDxHGZI+yKEeDb7fuIJY85e37UpgZytdTHgbFqArAhIvk eDESzRmiO2Fb401Q5xD+/XFJrYswDK0uRrRym6uSfJN8sls3GRWocPF+RaheZaoyBlqq T5qPIic5vRta5tiHS4fj9wnH0nEOQsBu7Nb2AeFm5diLApF3P59WPoCcTq9EekEWDa11 xzlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=oeKsyBHCgifpSehAywSjEelS2tgrFnqncZinDQ1xhtI=; b=HAkq9iFE6myW1gfojt5tSzQwohvRx5xq0hBV6+Vp8teohWyRZCFcjHC7aLX56sPKPX 8iW/2hkQwf167+7vnWbX/MnIi2ppSyJmMx1FMx8r2H/SpUORMQf+qPDm5dxh3pzrtmvU xNkxm/svVlUs00QoDQhMnb0QfP7s2Vr7+so6fB4D9RdZDPy2RARTdXkm18so5U7c/gFD mMnV6dwX80xUWbocn5Pj8n9KZYH0kjzBV6PxrbT04ot0HAbnchskRve9Rbc6sbwDPrRs aqk7eazP8BgSDnq4UmuZHVmXEx7kANJs3FWPl4FyMVimbk95m94WSxjXNwHsWxRD30PJ AV6g== X-Gm-Message-State: AOAM531Tyfa7z4e+eXMQD3rylzH2FTYIGOwGjCXy11/z7XrNjN1RNyzH eaHonLnA9eiLKGVeh6AzDqLd8Zn9fZteMA== X-Google-Smtp-Source: ABdhPJyk+1QqDYW5enJ+9TvPK8eqmysNfL48uX9zuuLqi8oug6rqW2ochuK4MR3mdUZ+pgR7eUtbDg== X-Received: by 2002:adf:f5ce:: with SMTP id k14mr17127978wrp.194.1613978935728; Sun, 21 Feb 2021 23:28:55 -0800 (PST) Received: from lmecxl0524.lme.st.com (2a01cb058b850800b51a732fdac74386.ipv6.abo.wanadoo.fr. [2a01:cb05:8b85:800:b51a:732f:dac7:4386]) by smtp.gmail.com with ESMTPSA id u137sm25426244wmu.20.2021.02.21.23.28.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 21 Feb 2021 23:28:55 -0800 (PST) From: Etienne Carriere To: u-boot@lists.denx.de Cc: Simon Glass , Jaehoon Chung , Patrick Delaunay , Patrice Chotard , etienne.carriere@linaro.org Subject: [PATCH v3 1/4] firmware: scmi: voltage regulator Date: Mon, 22 Feb 2021 08:27:44 +0100 Message-Id: <20210222072747.7514-1-etienne.carriere@linaro.org> X-Mailer: git-send-email 2.17.1 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Implement voltage regulators interfaced by the SCMI voltage domain protocol. The DT bindings are defined in the Linux kernel since SCMI voltage domain and regulators patches [1] and [2] integration in v5.11-rc7. Link: [1] https://github.com/torvalds/linux/commit/0f80fcec08e9c50b8d2992cf26495673765ebaba Link: [2] https://github.com/torvalds/linux/commit/2add5cacff3531e54c50b0832128299faa9f0563 Signed-off-by: Etienne Carriere Reviewed-by: Simon Glass Reviewed-by: Jaehoon Chung --- Changes in v3: - applied review tags Changes in v2: - no change --- doc/device-tree-bindings/arm/arm,scmi.txt | 34 +++++ drivers/firmware/scmi/scmi_agent-uclass.c | 35 ++++- drivers/power/regulator/Kconfig | 8 + drivers/power/regulator/Makefile | 1 + drivers/power/regulator/scmi_regulator.c | 170 ++++++++++++++++++++++ include/scmi_protocols.h | 113 ++++++++++++++ 6 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 drivers/power/regulator/scmi_regulator.c diff --git a/doc/device-tree-bindings/arm/arm,scmi.txt b/doc/device-tree-bindings/arm/arm,scmi.txt index 1f293ea24..a76124f4a 100644 --- a/doc/device-tree-bindings/arm/arm,scmi.txt +++ b/doc/device-tree-bindings/arm/arm,scmi.txt @@ -62,6 +62,20 @@ Required properties: - #power-domain-cells : Should be 1. Contains the device or the power domain ID value used by SCMI commands. +Regulator bindings for the SCMI Regulator based on SCMI Message Protocol +------------------------------------------------------------ +An SCMI Regulator is permanently bound to a well defined SCMI Voltage Domain, +and should be always positioned as a root regulator. +It does not support any current operation. + +SCMI Regulators are grouped under a 'regulators' node which in turn is a child +of the SCMI Voltage protocol node inside the desired SCMI instance node. + +This binding uses the common regulator binding[6]. + +Required properties: + - reg : shall identify an existent SCMI Voltage Domain. + Sensor bindings for the sensors based on SCMI Message Protocol -------------------------------------------------------------- SCMI provides an API to access the various sensors on the SoC. @@ -105,6 +119,7 @@ Required sub-node properties: [3] Documentation/devicetree/bindings/thermal/thermal.txt [4] Documentation/devicetree/bindings/sram/sram.yaml [5] Documentation/devicetree/bindings/reset/reset.txt +[6] Documentation/devicetree/bindings/regulator/regulator.yaml Example: @@ -169,6 +184,25 @@ firmware { reg = <0x16>; #reset-cells = <1>; }; + + scmi_voltage: protocol@17 { + reg = <0x17>; + + regulators { + regulator_devX: regulator@0 { + reg = <0x0>; + regulator-max-microvolt = <3300000>; + }; + + regulator_devY: regulator@9 { + reg = <0x9>; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <4200000>; + }; + + ... + }; + }; }; }; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 516e690ac..03d236426 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -50,6 +50,29 @@ int scmi_to_linux_errno(s32 scmi_code) return -EPROTO; } +static int regulator_devices_bind(struct udevice *dev, struct driver *drv, + ofnode protocol_node) +{ + ofnode regulators_node; + ofnode node; + int ret; + + regulators_node = ofnode_find_subnode(protocol_node, "regulators"); + if (!ofnode_valid(regulators_node)) { + dev_err(dev, "regulators subnode not found\n"); + return -ENXIO; + } + + ofnode_for_each_subnode(node, regulators_node) { + ret = device_bind(dev, drv, ofnode_get_name(node), NULL, node, + NULL); + if (ret) + return ret; + } + + return 0; +} + /* * SCMI agent devices binds devices of various uclasses depeding on * the FDT description. scmi_bind_protocol() is a generic bind sequence @@ -79,6 +102,10 @@ static int scmi_bind_protocols(struct udevice *dev) if (IS_ENABLED(CONFIG_RESET_SCMI)) drv = DM_DRIVER_GET(scmi_reset_domain); break; + case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: + if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) + drv = DM_DRIVER_GET(scmi_voltage_domain); + break; default: break; } @@ -89,8 +116,12 @@ static int scmi_bind_protocols(struct udevice *dev) continue; } - ret = device_bind(dev, drv, ofnode_get_name(node), NULL, node, - NULL); + if (protocol_id == SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN) + ret = regulator_devices_bind(dev, drv, node); + else + ret = device_bind(dev, drv, ofnode_get_name(node), + NULL, node, NULL); + if (ret) break; } diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index fbbea18c7..5d6180229 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -353,3 +353,11 @@ config DM_REGULATOR_TPS65941 TPS65941 series of PMICs have 5 single phase BUCKs that can also be configured in multi phase modes & 4 LDOs. The driver implements get/set api for value and enable. + +config DM_REGULATOR_SCMI + bool "Enable driver for SCMI voltage domain regulators" + depends on DM_REGULATOR + select SCMI_AGENT + help + Enable this option if you want to support regulators exposed through + the SCMI voltage domain protocol by a SCMI server. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 9d58112dc..b2f5972ea 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o +obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c new file mode 100644 index 000000000..072a978a8 --- /dev/null +++ b/drivers/power/regulator/scmi_regulator.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020-2021 Linaro Limited + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator + * @domain_id: ID representing the regulator for the related SCMI agent + */ +struct scmi_regulator_platdata { + u32 domain_id; +}; + +static int scmi_voltd_set_enable(struct udevice *dev, bool enable) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + struct scmi_voltd_config_set_in in = { + .domain_id = pdata->domain_id, + .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF, + }; + struct scmi_voltd_config_set_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, + SCMI_VOLTAGE_DOMAIN_CONFIG_SET, + in, out); + int ret; + + ret = devm_scmi_process_msg(dev->parent, &msg); + if (ret) + return ret; + + ret = scmi_to_linux_errno(out.status); + if (ret) + return ret; + + return ret; +} + +static int scmi_voltd_get_enable(struct udevice *dev) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + struct scmi_voltd_config_get_in in = { + .domain_id = pdata->domain_id, + }; + struct scmi_voltd_config_get_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, + SCMI_VOLTAGE_DOMAIN_CONFIG_GET, + in, out); + int ret; + + ret = devm_scmi_process_msg(dev->parent, &msg); + if (ret < 0) + return ret; + + ret = scmi_to_linux_errno(out.status); + if (ret < 0) + return ret; + + return out.config == SCMI_VOLTD_CONFIG_ON; +} + +static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + struct scmi_voltd_level_set_in in = { + .domain_id = pdata->domain_id, + .voltage_level = uV, + }; + struct scmi_voltd_level_set_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, + SCMI_VOLTAGE_DOMAIN_LEVEL_SET, + in, out); + int ret; + + ret = devm_scmi_process_msg(dev->parent, &msg); + if (ret < 0) + return ret; + + return scmi_to_linux_errno(out.status); +} + +static int scmi_voltd_get_voltage_level(struct udevice *dev) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + struct scmi_voltd_level_get_in in = { + .domain_id = pdata->domain_id, + }; + struct scmi_voltd_level_get_out out; + struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, + SCMI_VOLTAGE_DOMAIN_LEVEL_GET, + in, out); + int ret; + + ret = devm_scmi_process_msg(dev->parent, &msg); + if (ret < 0) + return ret; + + ret = scmi_to_linux_errno(out.status); + if (ret < 0) + return ret; + + return out.voltage_level; +} + +static int scmi_regulator_of_to_plat(struct udevice *dev) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + fdt_addr_t reg; + + reg = dev_read_addr(dev); + if (reg == FDT_ADDR_T_NONE) + return -EINVAL; + + pdata->domain_id = (u32)reg; + + return 0; +} + +static int scmi_regulator_probe(struct udevice *dev) +{ + struct scmi_regulator_platdata *pdata = dev_get_plat(dev); + struct scmi_voltd_attr_in in = { 0 }; + struct scmi_voltd_attr_out out = { 0 }; + struct scmi_msg scmi_msg = { + .protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, + .message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + /* Check voltage domain is known from SCMI server */ + in.domain_id = pdata->domain_id; + + ret = devm_scmi_process_msg(dev->parent, &scmi_msg); + if (ret) { + dev_err(dev, "Failed to query voltage domain %u: %d\n", + pdata->domain_id, ret); + return -ENXIO; + } + + return 0; +} + +static const struct dm_regulator_ops scmi_voltd_ops = { + .get_value = scmi_voltd_get_voltage_level, + .set_value = scmi_voltd_set_voltage_level, + .get_enable = scmi_voltd_get_enable, + .set_enable = scmi_voltd_set_enable, +}; + +U_BOOT_DRIVER(scmi_voltage_domain) = { + .name = "scmi_voltage_domain", + .id = UCLASS_REGULATOR, + .ops = &scmi_voltd_ops, + .probe = scmi_regulator_probe, + .of_to_plat = scmi_regulator_of_to_plat, + .plat_auto = sizeof(struct scmi_regulator_platdata), +}; diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index ccab97c96..2db71697e 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -23,6 +23,7 @@ enum scmi_std_protocol { SCMI_PROTOCOL_ID_CLOCK = 0x14, SCMI_PROTOCOL_ID_SENSOR = 0x15, SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16, + SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN = 0x17, }; enum scmi_status_code { @@ -176,4 +177,116 @@ struct scmi_rd_reset_out { s32 status; }; +/* + * SCMI Voltage Domain Protocol + */ + +enum scmi_voltage_domain_message_id { + SCMI_VOLTAGE_DOMAIN_ATTRIBUTES = 0x3, + SCMI_VOLTAGE_DOMAIN_CONFIG_SET = 0x5, + SCMI_VOLTAGE_DOMAIN_CONFIG_GET = 0x6, + SCMI_VOLTAGE_DOMAIN_LEVEL_SET = 0x7, + SCMI_VOLTAGE_DOMAIN_LEVEL_GET = 0x8, +}; + +#define SCMI_VOLTD_NAME_LEN 16 + +#define SCMI_VOLTD_CONFIG_MASK GENMASK(3, 0) +#define SCMI_VOLTD_CONFIG_OFF 0 +#define SCMI_VOLTD_CONFIG_ON 0x7 + +/** + * struct scmi_voltd_attr_in - Payload for VOLTAGE_DOMAIN_ATTRIBUTES message + * @domain_id: SCMI voltage domain ID + */ +struct scmi_voltd_attr_in { + u32 domain_id; +}; + +/** + * struct scmi_voltd_attr_out - Payload for VOLTAGE_DOMAIN_ATTRIBUTES response + * @status: SCMI command status + * @attributes: Retrieved attributes of the voltage domain + * @name: Voltage domain name + */ +struct scmi_voltd_attr_out { + s32 status; + u32 attributes; + char name[SCMI_VOLTD_NAME_LEN]; +}; + +/** + * struct scmi_voltd_config_set_in - Message payload for VOLTAGE_CONFIG_SET cmd + * @domain_id: SCMI voltage domain ID + * @config: Configuration data of the voltage domain + */ +struct scmi_voltd_config_set_in { + u32 domain_id; + u32 config; +}; + +/** + * struct scmi_voltd_config_set_out - Response for VOLTAGE_CONFIG_SET command + * @status: SCMI command status + */ +struct scmi_voltd_config_set_out { + s32 status; +}; + +/** + * struct scmi_voltd_config_get_in - Message payload for VOLTAGE_CONFIG_GET cmd + * @domain_id: SCMI voltage domain ID + */ +struct scmi_voltd_config_get_in { + u32 domain_id; +}; + +/** + * struct scmi_voltd_config_get_out - Response for VOLTAGE_CONFIG_GET command + * @status: SCMI command status + * @config: Configuration data of the voltage domain + */ +struct scmi_voltd_config_get_out { + s32 status; + u32 config; +}; + +/** + * struct scmi_voltd_level_set_in - Message payload for VOLTAGE_LEVEL_SET cmd + * @domain_id: SCMI voltage domain ID + * @flags: Parameter flags for configuring target level + * @voltage_level: Target voltage level in microvolts (uV) + */ +struct scmi_voltd_level_set_in { + u32 domain_id; + u32 flags; + s32 voltage_level; +}; + +/** + * struct scmi_voltd_level_set_out - Response for VOLTAGE_LEVEL_SET command + * @status: SCMI command status + */ +struct scmi_voltd_level_set_out { + s32 status; +}; + +/** + * struct scmi_voltd_level_get_in - Message payload for VOLTAGE_LEVEL_GET cmd + * @domain_id: SCMI voltage domain ID + */ +struct scmi_voltd_level_get_in { + u32 domain_id; +}; + +/** + * struct scmi_voltd_level_get_out - Response for VOLTAGE_LEVEL_GET command + * @status: SCMI command status + * @voltage_level: Voltage level in microvolts (uV) + */ +struct scmi_voltd_level_get_out { + s32 status; + s32 voltage_level; +}; + #endif /* _SCMI_PROTOCOLS_H */