From patchwork Wed Sep 9 16:44:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Etienne Carriere X-Patchwork-Id: 249509 Delivered-To: patch@linaro.org Received: by 2002:a05:6e02:dcd:0:0:0:0 with SMTP id l13csp541732ilj; Wed, 9 Sep 2020 09:44:23 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxu7ov/MHlkokJfYcRB8EZEuhpC5dlYCdvZzya7+csSLZxk3fRCzc75Yq1T6Ncl4oQiUwIX X-Received: by 2002:a05:6402:1710:: with SMTP id y16mr5193836edu.197.1599669862845; Wed, 09 Sep 2020 09:44:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1599669862; cv=none; d=google.com; s=arc-20160816; b=T8AOKCQgT49bp+JWYbWYWqEAmHuv4lgFzYebSFouKim17Q3OQ0D7jiAAlOerj/bT4m lYI5iX2k2dKzU88bNu5UWnjByY3KnXpgesh7Jv1+KNZLrAHmXXJbIEeArRhqVz9d7JR3 xIBdH0T0rYHJh6t3zOCx75sswe1B+AZ/HpkZWKMSsf/q9LDRMtV3tqRJoF/Qy7r73yfJ yUdSVkP3diXvrQbO6ejZ30NI/uC2VlOu+griW3alrXVwzxo2aEkZaDNeXL8jINdOdQCj mhq4w9vYHVUWepa1uiAqK2g3nmHIM+ezdy2H+apC5rDnLSOj/onrOKqout7pxNzQJjzi Nhkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=AiZlhWfo9XRQnmXmmoQHefW/5t8xfc/EO3BhMZXXo9M=; b=cmsqn+Z0+ZSi+eni8ZvvpjbjoDed4gr85dvCitu5lRtxNeS+FYUzL0e3qrhrWs0KjW ig0v998p/N1VKNOJSS09qolnyip3f7SQjQcpsj3/+mqH/k/Sxjqy9jy9+FpDyMNJcAEN DuP9hRV2Lyw/cX53Lu6CVWSkOUb3bX27p3uDhJRDjnA4YiBdWz4LdTpU2AfXdWb0Vqfr 0MGD1dvYdAjbxvuvtClGzTFo28hNQsMwIaX6/grc2XZ8ESTmDC2sKdY1FcYPPnLAHXgV iQzfXvljY845jBPBHjgsoBjOmTqRAM6g4WPWUpyri2/vNZo3YjrfyPTS10l7E/CO9zsY a8oA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=UcXOSjCQ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id u17si1866320edr.266.2020.09.09.09.44.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Sep 2020 09:44:22 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=UcXOSjCQ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2EBF782249; Wed, 9 Sep 2020 18:44:21 +0200 (CEST) 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="UcXOSjCQ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 6957C82281; Wed, 9 Sep 2020 18:44:19 +0200 (CEST) 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,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) (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 79F328158B for ; Wed, 9 Sep 2020 18:44:15 +0200 (CEST) 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-wm1-x342.google.com with SMTP id q9so2956624wmj.2 for ; Wed, 09 Sep 2020 09:44:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=AiZlhWfo9XRQnmXmmoQHefW/5t8xfc/EO3BhMZXXo9M=; b=UcXOSjCQ9Z/jNnW/WlQQSllXPEAEmmgzmoLm62cJ6FNW+PPssz332C1DGg7lwOEKzj levQTZ6ditIRLYpZfxlB1TbYC36LuUaSr7HUSYLiVUWL5h+vv1dgnOS10XnKKEav9FUj 9ybZyskvDMsPYYiJK8mkFDllV56ikTnCRbr4IM+Yd+k529aF9W1ewQb2n4i8CvWAA9QS 7l54OKwcrUX2D3C4boBCPWrMsbvCGkU8I7poIxgCWLqSLdtVy4JTM+Gx64Ih9vb3WHCf LMA7kseqIk5A8RjHAdvOyeGILugnibGDz8d3PM3lbopfyBxeDvE7LpvNvhMD9fso/quz fyRA== 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=AiZlhWfo9XRQnmXmmoQHefW/5t8xfc/EO3BhMZXXo9M=; b=CxArXJVDCFVTTeXQY3v6bFMX0Gt79JsSRyM1RX/dAoBP4Ar/6jzS/GE4mOkIWKvO0d x/cb6R71QccsfpDk5zHfEqpm4+eLYnSxbygOhx6og7tCgU+nb7VEAvv3GKr6t07ZTwtQ S64pm/AslXgblR2Z80mQPv3whE9QkO5Nmv3n7fsLkR8vvywq4XBQ6HYfsLgSOAuVvcRH u8U2Ag3cQrdA2gel/3cllQa1QOI3FYFky3oRQvKqPLJ9vWJNLuDFxS7mL/ycABrIZFYg mgookr3+KZ6VLqT3myuW3l1wifR//ChNeWSBzJcizbrCrFY95UDh6Mt1SQDxGdbVoUxK JqjQ== X-Gm-Message-State: AOAM530kD7vZR4yG9zOzpnXym7Y2/txxDjY+Ho1QrSORqWdqOs/N/9wy SFXuy+Tc7vQ+eDksVY8qL5JTnmwuRhUVsTRJL1I= X-Received: by 2002:a1c:2003:: with SMTP id g3mr4112594wmg.99.1599669854678; Wed, 09 Sep 2020 09:44:14 -0700 (PDT) Received: from lmecxl0524.lme.st.com ([2a04:cec0:100d:d03f:c9d0:c7b0:9925:5cde]) by smtp.gmail.com with ESMTPSA id t15sm4468301wmj.15.2020.09.09.09.44.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Sep 2020 09:44:13 -0700 (PDT) From: Etienne Carriere To: u-boot@lists.denx.de Cc: Simon Glass , Lukasz Majewski , Peng Fan , Sudeep Holla , Etienne Carriere Subject: [PATCH v4 1/8] firmware: add SCMI agent uclass Date: Wed, 9 Sep 2020 18:44:00 +0200 Message-Id: <20200909164407.14327-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 This change introduces SCMI agent uclass to interact with a firmware using the SCMI protocols [1]. SCMI agent uclass currently supports a single method to request processing of the SCMI message by an identified server. A SCMI message is made of a byte payload associated to a protocol ID and a message ID, all defined by the SCMI specification [1]. On return from process_msg() method, the caller gets the service response. SCMI agent uclass defines a post bind generic sequence for all devices. The sequence binds all the SCMI protocols listed in the FDT for that SCMI agent device. Currently none, but later change will introduce protocols. This change implements a simple sandbox device for the SCMI agent uclass. The sandbox nicely answers SCMI_NOT_SUPPORTED to SCMI messages. To prepare for further test support, the sandbox exposes a architecture function for test application to read the sandbox emulated devices state. Currently supports 2 SCMI agents, identified by an ID in the FDT device name. The simplistic DM test does nothing yet. SCMI agent uclass is designed for platforms that embed a SCMI server in a firmware hosted somewhere, for example in a companion co-processor or in the secure world of the executing processor. SCMI protocols allow an SCMI agent to discover and access external resources as clock, reset controllers and more. SCMI agent and server communicate following the SCMI specification [1]. This SCMI agent implementation complies with the DT bindings defined in the Linux kernel source tree regarding SCMI agent description since v5.8. Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi Signed-off-by: Etienne Carriere Cc: Simon Glass Cc: Peng Fan Cc: Sudeep Holla Reviewed-by: Simon Glass --- Changes in v4: - Remove local helper function dev2agent() used to hide a useless cast. Changes in v3: - Address comments about adding a new uclass and some sandbox test from v2 in https://patchwork.ozlabs.org/project/uboot/list/?series=196253 - New directory drivers/firmware/scmi/. The path mimics Linux kernel source tree for the equivalent driver. - Split scmi.h (patch v2) into scmi_protocols.h, scmi_agent.h and scmi_agent-uclass.h. - Create new uclass UCLASS_SCMI_AGENT. - Introduce a simple sandbox on that agent. Mailbox and smccc agents are moved to specific commits in the series. Changes in v2: - Fix CONFIG_SCMI_FIRMWARE description with explicit SCMI reference. - Move struct, enum and macro definitions at source file top and add inline comment description for the structures and local functions. - Replace rc with ret as return value local variable label. - Use explicit return 0 on successful return paths. - Replace EINVAL with more accurate error numbers. - Use dev_read_u32() instead of ofnode_read_u32(dev_ofnode(), ...). - Use memcpy_toio()/memcpy_fromio() when copying message payload to/from IO memory. - Embed mailbox transport resources upon CONFIG_DM_MAILBOX and SMCCC transport resources upon CONFIG_ARM_SMCCC. Note: review comments on defining a uclass and sandbox for SCMI transport drivers are NOT addressed in this v2. Main issue is that there is no driver/device defined for SCMI transport layer as well as and no defined compatible ID in the SCMI DT bindings documentation. --- arch/sandbox/dts/test.dts | 16 +++ arch/sandbox/include/asm/scmi_test.h | 43 +++++++ configs/sandbox_defconfig | 2 + drivers/firmware/Kconfig | 2 + drivers/firmware/Makefile | 1 + drivers/firmware/scmi/Kconfig | 17 +++ drivers/firmware/scmi/Makefile | 2 + drivers/firmware/scmi/sandbox-scmi_agent.c | 142 +++++++++++++++++++++ drivers/firmware/scmi/scmi_agent-uclass.c | 107 ++++++++++++++++ include/dm/uclass-id.h | 1 + include/scmi_agent-uclass.h | 24 ++++ include/scmi_agent.h | 68 ++++++++++ include/scmi_protocols.h | 41 ++++++ test/dm/Makefile | 1 + test/dm/scmi.c | 38 ++++++ 15 files changed, 505 insertions(+) create mode 100644 arch/sandbox/include/asm/scmi_test.h create mode 100644 drivers/firmware/scmi/Kconfig create mode 100644 drivers/firmware/scmi/Makefile create mode 100644 drivers/firmware/scmi/sandbox-scmi_agent.c create mode 100644 drivers/firmware/scmi/scmi_agent-uclass.c create mode 100644 include/scmi_agent-uclass.h create mode 100644 include/scmi_agent.h create mode 100644 include/scmi_protocols.h create mode 100644 test/dm/scmi.c -- 2.17.1 diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9f45c48e4e..dd3b43885e 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -356,6 +356,22 @@ sandbox_firmware: sandbox-firmware { compatible = "sandbox,firmware"; }; + + sandbox-scmi-agent@0 { + compatible = "sandbox,scmi-agent"; + #address-cells = <1>; + #size-cells = <0>; + }; + + sandbox-scmi-agent@1 { + compatible = "sandbox,scmi-agent"; + #address-cells = <1>; + #size-cells = <0>; + + protocol@10 { + reg = <0x10>; + }; + }; }; pinctrl-gpio { diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h new file mode 100644 index 0000000000..a811fe19c3 --- /dev/null +++ b/arch/sandbox/include/asm/scmi_test.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020, Linaro Limited + */ + +#ifndef __SANDBOX_SCMI_TEST_H +#define __SANDBOX_SCMI_TEST_H + +struct udevice; +struct sandbox_scmi_agent; +struct sandbox_scmi_service; + +/** + * struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent + * @idx: Identifier for the SCMI agent, its index + */ +struct sandbox_scmi_agent { + uint idx; +}; + +/** + * struct sandbox_scmi_service - Reference to simutaed SCMI agents/services + * @agent: Pointer to SCMI sandbox agent pointers array + * @agent_count: Number of emulated agents exposed in array @agent. + */ +struct sandbox_scmi_service { + struct sandbox_scmi_agent **agent; + size_t agent_count; +}; + +#ifdef CONFIG_SCMI_FIRMWARE +/** + * sandbox_scmi_service_context - Get the simulated SCMI services context + * @return: Reference to backend simulated resources state + */ +struct sandbox_scmi_service *sandbox_scmi_service_ctx(void); +#else +static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +{ + return NULL; +} +#endif /* CONFIG_SCMI_FIRMWARE */ +#endif /* __SANDBOX_SCMI_TEST_H */ diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6e9f029cc9..2c130c01f0 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -132,6 +132,8 @@ CONFIG_BOARD_SANDBOX=y CONFIG_DMA=y CONFIG_DMA_CHANNELS=y CONFIG_SANDBOX_DMA=y +CONFIG_FIRMWARE=y +CONFIG_SCMI_FIRMWARE=y CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_PM8916_GPIO=y diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b70a206355..ef958b3a7a 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -36,3 +36,5 @@ config ZYNQMP_FIRMWARE various platform management services. Say yes to enable ZynqMP firmware interface driver. If in doubt, say N. + +source "drivers/firmware/scmi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index a0c250a473..7ce83d72bd 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_$(SPL_)ARM_PSCI_FW) += psci.o obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_SANDBOX) += firmware-sandbox.o obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o +obj-$(CONFIG_SCMI_FIRMWARE) += scmi/ diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig new file mode 100644 index 0000000000..57e2ebbe42 --- /dev/null +++ b/drivers/firmware/scmi/Kconfig @@ -0,0 +1,17 @@ +config SCMI_FIRMWARE + bool "Enable SCMI support" + select FIRMWARE + select OF_TRANSLATE + depends on SANDBOX + help + System Control and Management Interface (SCMI) is a communication + protocol that defines standard interfaces for power, performance + and system management. The SCMI specification is available at + https://developer.arm.com/architectures/system-architectures/software-standards/scmi + + An SCMI agent communicates with a related SCMI server firmware + located in another sub-system, as a companion micro controller + or a companion host in the CPU system. + + Communications between agent (client) and the SCMI server are + based on message exchange. diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile new file mode 100644 index 0000000000..336ea1f2a3 --- /dev/null +++ b/drivers/firmware/scmi/Makefile @@ -0,0 +1,2 @@ +obj-y += scmi_agent-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c new file mode 100644 index 0000000000..3179438aab --- /dev/null +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The sandbox SCMI agent driver simulates to some extend a SCMI message + * processing. It simulates few of the SCMI services for some of the + * SCMI protocols embedded in U-Boot. Currently none. + * + * This driver simulates 2 SCMI agents for test purpose. + * + * This Driver exports sandbox_scmi_service_ct() for the test sequence to + * get the state of the simulated services (clock state, rate, ...) and + * check back-end device state reflects the request send through the + * various uclass devices, currently nothing. + */ + +#define SANDBOX_SCMI_AGENT_COUNT 2 + +/* The list saves to simulted end devices references for test purpose */ +struct sandbox_scmi_agent *sandbox_scmi_agent_list[SANDBOX_SCMI_AGENT_COUNT]; + +static struct sandbox_scmi_service sandbox_scmi_service_state = { + .agent = sandbox_scmi_agent_list, + .agent_count = SANDBOX_SCMI_AGENT_COUNT, +}; + +struct sandbox_scmi_service *sandbox_scmi_service_ctx(void) +{ + return &sandbox_scmi_service_state; +} + +static void debug_print_agent_state(struct udevice *dev, char *str) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + + dev_dbg(dev, "Dump sandbox_scmi_agent %u: %s\n", agent->idx, str); +}; + +static int sandbox_scmi_test_process_msg(struct udevice *dev, + struct scmi_msg *msg) +{ + switch (msg->protocol_id) { + case SCMI_PROTOCOL_ID_BASE: + case SCMI_PROTOCOL_ID_POWER_DOMAIN: + case SCMI_PROTOCOL_ID_SYSTEM: + case SCMI_PROTOCOL_ID_PERF: + case SCMI_PROTOCOL_ID_CLOCK: + case SCMI_PROTOCOL_ID_SENSOR: + case SCMI_PROTOCOL_ID_RESET_DOMAIN: + *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED; + return 0; + default: + break; + } + + dev_err(dev, "%s(%s): Unhandled protocol_id %#x/message_id %#x\n", + __func__, dev->name, msg->protocol_id, msg->message_id); + + if (msg->out_msg_sz < sizeof(u32)) + return -EINVAL; + + /* Intentionnaly report unhandled IDs through the SCMI return code */ + *(u32 *)msg->out_msg = SCMI_PROTOCOL_ERROR; + return 0; +} + +static int sandbox_scmi_test_remove(struct udevice *dev) +{ + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + + debug_print_agent_state(dev, "removed"); + + /* We only need to dereference the agent in the context */ + sandbox_scmi_service_ctx()->agent[agent->idx] = NULL; + + return 0; +} + +static int sandbox_scmi_test_probe(struct udevice *dev) +{ + static const char basename[] = "sandbox-scmi-agent@"; + struct sandbox_scmi_agent *agent = dev_get_priv(dev); + const size_t basename_size = sizeof(basename) - 1; + + if (strncmp(basename, dev->name, basename_size)) + return -ENOENT; + + switch (dev->name[basename_size]) { + case '0': + *agent = (struct sandbox_scmi_agent){ + .idx = 0, + }; + break; + case '1': + *agent = (struct sandbox_scmi_agent){ + .idx = 1, + }; + break; + default: + dev_err(dev, "%s(): Unexpected agent ID %s\n", + __func__, dev->name + basename_size); + return -ENOENT; + } + + debug_print_agent_state(dev, "probed"); + + /* Save reference for tests purpose */ + sandbox_scmi_service_ctx()->agent[agent->idx] = agent; + + return 0; +}; + +static const struct udevice_id sandbox_scmi_test_ids[] = { + { .compatible = "sandbox,scmi-agent" }, + { } +}; + +struct scmi_agent_ops sandbox_scmi_test_ops = { + .process_msg = sandbox_scmi_test_process_msg, +}; + +U_BOOT_DRIVER(sandbox_scmi_agent) = { + .name = "sandbox-scmi_agent", + .id = UCLASS_SCMI_AGENT, + .of_match = sandbox_scmi_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_scmi_agent), + .probe = sandbox_scmi_test_probe, + .remove = sandbox_scmi_test_remove, + .ops = &sandbox_scmi_test_ops, +}; diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c new file mode 100644 index 0000000000..67a6f907c9 --- /dev/null +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Linaro Limited. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/** + * struct error_code - Helper structure for SCMI error code conversion + * @scmi: SCMI error code + * @errno: Related standard error number + */ +struct error_code { + int scmi; + int errno; +}; + +static const struct error_code scmi_linux_errmap[] = { + { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, }, + { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, }, + { .scmi = SCMI_DENIED, .errno = -EACCES, }, + { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, }, + { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, }, + { .scmi = SCMI_BUSY, .errno = -EBUSY, }, + { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, }, + { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, }, + { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, }, + { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, }, +}; + +int scmi_to_linux_errno(s32 scmi_code) +{ + int n; + + if (!scmi_code) + return 0; + + for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++) + if (scmi_code == scmi_linux_errmap[n].scmi) + return scmi_linux_errmap[1].errno; + + return -EPROTO; +} + +/* + * SCMI agent devices binds devices of various uclasses depeding on + * the FDT description. scmi_bind_protocol() is a generic bind sequence + * called by the uclass at bind stage, that is uclass post_bind. + */ +static int scmi_bind_protocols(struct udevice *dev) +{ + int ret = 0; + ofnode node; + struct driver *drv; + + dev_for_each_subnode(node, dev) { + u32 protocol_id; + + if (!ofnode_is_available(node)) + continue; + + if (ofnode_read_u32(node, "reg", &protocol_id)) + continue; + + switch (protocol_id) { + default: + dev_info(dev, "Ignore unsupported SCMI protocol %#x\n", + protocol_id); + continue; + } + + ret = device_bind_ofnode(dev, drv, ofnode_get_name(node), + NULL, node, NULL); + if (ret) + break; + } + + return ret; +} + +static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev) +{ + return (const struct scmi_agent_ops *)dev->driver->ops; +} + +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg) +{ + const struct scmi_agent_ops *ops = transport_dev_ops(dev); + + if (ops->process_msg) + return ops->process_msg(dev, msg); + + return -EPROTONOSUPPORT; +} + +UCLASS_DRIVER(scmi_agent) = { + .id = UCLASS_SCMI_AGENT, + .name = "scmi_agent", + .post_bind = scmi_bind_protocols, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 4ec5fa6670..88f10c4622 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -94,6 +94,7 @@ enum uclass_id { UCLASS_RESET, /* Reset controller device */ UCLASS_RNG, /* Random Number Generator */ UCLASS_RTC, /* Real time clock device */ + UCLASS_SCMI_AGENT, /* Interface with an SCMI server */ UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ diff --git a/include/scmi_agent-uclass.h b/include/scmi_agent-uclass.h new file mode 100644 index 0000000000..a501d1b482 --- /dev/null +++ b/include/scmi_agent-uclass.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019-2020 Linaro Limited. + */ +#ifndef _SCMI_AGENT_UCLASS_H +#define _SCMI_AGENT_UCLASS_H + +struct udevice; +struct scmi_msg; + +/** + * struct scmi_transport_ops - The functions that a SCMI transport layer must implement. + */ +struct scmi_agent_ops { + /* + * process_msg - Request transport to get the SCMI message processed + * + * @agent: Agent using the transport + * @msg: SCMI message to be transmitted + */ + int (*process_msg)(struct udevice *dev, struct scmi_msg *msg); +}; + +#endif /* _SCMI_TRANSPORT_UCLASS_H */ diff --git a/include/scmi_agent.h b/include/scmi_agent.h new file mode 100644 index 0000000000..f1be9ff209 --- /dev/null +++ b/include/scmi_agent.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020, Linaro Limited + * + * An SCMI agent device represent on communication path from a + * device driver to the remote SCMI server which driver sends + * messages to and receives response messages from. + */ +#ifndef SCMI_AGENT_H +#define SCMI_AGENT_H + +#include + +struct udevice; + +/* + * struct scmi_msg - Context of a SCMI message sent and the response received + * + * @protocol_id: SCMI protocol ID + * @message_id: SCMI message ID for a defined protocol ID + * @in_msg: Pointer to the message payload sent by the driver + * @in_msg_sz: Byte size of the message payload sent + * @out_msg: Pointer to buffer to store response message payload + * @out_msg_sz: Byte size of the response buffer and response payload + */ +struct scmi_msg { + unsigned int protocol_id; + unsigned int message_id; + u8 *in_msg; + size_t in_msg_sz; + u8 *out_msg; + size_t out_msg_sz; +}; + +/* Helper macro to match a message on input/output array references */ +#define SCMI_MSG_IN(_protocol, _message, _in_array, _out_array) \ + (struct scmi_msg){ \ + .protocol_id = (_protocol), \ + .message_id = (_message), \ + .in_msg = (uint8_t *)&(_in_array), \ + .in_msg_sz = sizeof(_in_array), \ + .out_msg = (uint8_t *)&(_out_array), \ + .out_msg_sz = sizeof(_out_array), \ + } + +/** + * scmi_send_and_process_msg() - send and process a SCMI message + * + * Send a message to a SCMI server through a target SCMI agent device. + * Caller sets scmi_msg::out_msg_sz to the output message buffer size. + * On return, scmi_msg::out_msg_sz stores the response payload size. + * + * @dev: SCMI agent device + * @msg: Message structure reference + * @return 0 on success and a negative errno on failure + */ +int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg); + +/** + * scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code + * + * @scmi_errno: SCMI error code value + * @return 0 for successful status and a negative errno otherwise + */ +int scmi_to_linux_errno(s32 scmi_errno); + +#endif /* SCMI_H */ diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h new file mode 100644 index 0000000000..86a2d109c8 --- /dev/null +++ b/include/scmi_protocols.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. + * Copyright (C) 2019-2020, Linaro Limited + */ +#ifndef _SCMI_PROTOCOLS_H +#define _SCMI_PROTOCOLS_H + +#include + +/* + * Subset the SCMI protocols definition + * based on SCMI specification v2.0 (DEN0056B) + * https://developer.arm.com/docs/den0056/b + */ + +enum scmi_std_protocol { + SCMI_PROTOCOL_ID_BASE = 0x10, + SCMI_PROTOCOL_ID_POWER_DOMAIN = 0x11, + SCMI_PROTOCOL_ID_SYSTEM = 0x12, + SCMI_PROTOCOL_ID_PERF = 0x13, + SCMI_PROTOCOL_ID_CLOCK = 0x14, + SCMI_PROTOCOL_ID_SENSOR = 0x15, + SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16, +}; + +enum scmi_status_code { + SCMI_SUCCESS = 0, + SCMI_NOT_SUPPORTED = -1, + SCMI_INVALID_PARAMETERS = -2, + SCMI_DENIED = -3, + SCMI_NOT_FOUND = -4, + SCMI_OUT_OF_RANGE = -5, + SCMI_BUSY = -6, + SCMI_COMMS_ERROR = -7, + SCMI_GENERIC_ERROR = -8, + SCMI_HARDWARE_ERROR = -9, + SCMI_PROTOCOL_ERROR = -10, +}; + +#endif /* _SCMI_PROTOCOLS_H */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 864c8d0b4c..70ba1b6695 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -80,4 +80,5 @@ obj-$(CONFIG_DM_RNG) += rng.o obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o +obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o endif diff --git a/test/dm/scmi.c b/test/dm/scmi.c new file mode 100644 index 0000000000..d8c1e71f12 --- /dev/null +++ b/test/dm/scmi.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020, Linaro Limited + * + * Tests scmi_agent uclass and the SCMI drivers implemented in other + * uclass devices probe when a SCMI server exposes resources. + * + * Note in test.dts the protocol@10 node in agent 1. Protocol 0x10 is not + * implemented in U-Boot SCMI components but the implementation is exepected + * to not complain on unknown protocol IDs, as long as it is not used. Note + * in test.dts tests that SCMI drivers probing does not fail for such an + * unknown SCMI protocol ID. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Test SCMI states when loading and releasing resources + * related to SCMI drivers. + */ +static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) +{ + struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); + + ut_assertnonnull(scmi_ctx); + ut_asserteq(2, scmi_ctx->agent_count); + ut_assertnull(scmi_ctx->agent[0]); + ut_assertnull(scmi_ctx->agent[1]); + + return 0; +} + +DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);