From patchwork Tue Jul 25 14:06:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tanmay Shah X-Patchwork-Id: 1812719 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.a=rsa-sha256 header.s=selector1 header.b=5OQfk95B; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4R9LsQ1kkMz1yYc for ; Wed, 26 Jul 2023 01:43:22 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 3F498867E6; Tue, 25 Jul 2023 17:42:18 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.b="5OQfk95B"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 7873F8636F; Tue, 25 Jul 2023 16:08:23 +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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (mail-mw2nam12on20620.outbound.protection.outlook.com [IPv6:2a01:111:f400:fe5a::620]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E1F4686380 for ; Tue, 25 Jul 2023 16:08:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=tanmay.shah@amd.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=hD//SEIgAnAZHOKFqRTtGYY1E+u9dcfaPdFdRrFW1GnbNdNq9I8JzXgLJF42dPQtL27a9NlfU3SUXkWb3hLIaCzQYvBalDXhP812mPTfOvOR00tYAapjoLgYTtCtZutlz6sFsSYgOiy1DBaeXuCGky3CEAYJdSiWA/Tyy3Ei1iOlLWKTHlR9kaYY0INvFql4thlhPrnCfNeMfRPLgqrrNFfpqgCxWnbHvBXRAjyKjMZLRy46EYJqz7qokHD/X38tDRuVVXhIZ4ShYH6F+nPoWlLgptRUfpo7yX4HoK1mgwuppEhyItyibqR3UwAM3R437WSvEiLUORD5jriScdGR5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=alCme80Qdm1Xl6oDYYVLIGM0F8GqXTF8dmdaPQAqsYc=; b=U7+YGTmn5qjppsjcp2H7EQWypIf9JjV0QW/J22u/XjLzWi6nqAk/UxSGX//LXHZKjhFOipdPCOjdyzjx5xcguz6N12rfkPG/Q3uzBkwWVARKMGZLPlZbHET33atrgN8kY+oRC5pVKrQubJBcz3G/LX1uC/OmQ26LOD562/XQbCWvcmtcoYCvSb4MDLVp59ZLqNF9gRxZJnPeH3QP4y6uSDxGY39T3eWYmICvISkTwhW27babU8e7+Mteyf9gQMs+xQ0Jmfw0ATTCedWql6FSBkWQKOjtw19zKfHLPPMIs1cUwDuDJ1rcx7WGxHknu3OphaJiQCIILGJTghDNTyK5tQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=chromium.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=alCme80Qdm1Xl6oDYYVLIGM0F8GqXTF8dmdaPQAqsYc=; b=5OQfk95BhhjyfmVqgBFeuVZe+sj/IE0mas4GjO3EV10ozbUNK/1TYjdqN4kUm6UVEQ2gM8FGe9dAIje7GJ0EGSbfGhvZ1DKr5/UCaFzo2KooW/MQpwmqgno1isk/nUCTsNfyE4nStLwWpPnWHPIymFRLcAV6D17pYEDueTxFSCU= Received: from DS7PR05CA0075.namprd05.prod.outlook.com (2603:10b6:8:57::16) by SA3PR12MB8437.namprd12.prod.outlook.com (2603:10b6:806:2f5::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6609.32; Tue, 25 Jul 2023 14:08:07 +0000 Received: from DM6NAM11FT082.eop-nam11.prod.protection.outlook.com (2603:10b6:8:57:cafe::f7) by DS7PR05CA0075.outlook.office365.com (2603:10b6:8:57::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6631.25 via Frontend Transport; Tue, 25 Jul 2023 14:08:06 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C Received: from SATLEXMB04.amd.com (165.204.84.17) by DM6NAM11FT082.mail.protection.outlook.com (10.13.173.107) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.6631.29 via Frontend Transport; Tue, 25 Jul 2023 14:08:06 +0000 Received: from SATLEXMB04.amd.com (10.181.40.145) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.27; Tue, 25 Jul 2023 09:08:03 -0500 Received: from xsjtanmays50.xilinx.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server id 15.1.2507.27 via Frontend Transport; Tue, 25 Jul 2023 09:08:02 -0500 From: Tanmay Shah To: Simon Glass , Tom Rini CC: , , , Michal Simek , Venkatesh Abbarapu , Mathieu Poirier , Nishanth Menon , Tanmay Shah Subject: [RFC PATCH 04/10] drivers: add RPMsg framework Date: Tue, 25 Jul 2023 07:06:44 -0700 Message-ID: <20230725140650.951581-5-tanmay.shah@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230725140650.951581-1-tanmay.shah@amd.com> References: <20230725140650.951581-1-tanmay.shah@amd.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT082:EE_|SA3PR12MB8437:EE_ X-MS-Office365-Filtering-Correlation-Id: 47a95609-2bb8-4192-a33d-08db8d1891d9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: IZhhlYa+U/tvtDQZscuspEzX578BqT7R8kwa2zA7mVhGllkOpGhbO/Yp6NJp3VoHutfjFW6P5c8z0ycY8+FzEb5Wx3pUGXoqnkIJ59+O/4ExUQq1EjLFB+Go+wndHke4glKDmafgdqekOnjIDK3RNZY02YclVfm54a0TxmbA36UsdmkshsDIR/llTqGJbAK/QQsNvIupqBGnHSc3qPYq4fByjPyWea7NpomO+N61ViZsCEl/EyPTS9My75O+kGZDGKYCopZpwZH0figYvMeY8ulzh8tOZ7H1875xZ+E/gAKZBUIYgv15R8Rj4gQE7OU1ZD1lC1o49u2JQcCU8xB8YLxon2s27jHL7ntTeNnMETb7/wK90Ob2CfiC55lN19rWgsi/KzH2kVvhWGXXbAy0NPRq9w1tC8LvqWoScHs9ndMPBGI0qqzEgWHBbhLFUNwCi4804eAtoQ+NAyTkiEM9uLTvmJyMcYAco9ij0W4gze8lkG2JqVHbwaVVJbEe7NW09Eb3svJ02ogvBB+GYFexrD2blogaODTob6jACkFdrew1Wd1KoBsbpaLKfJxtI0uRZYU7Q0HvVJTeQLDKinIUmE3Bh8As0cUTSnNC/lY5aOM7UzYV83/KWPvP1NbIqSO1pclyF67ZdPoCRAL6SUXdF8J4tbo1dKaRjNg7KXY4im2pYv0p26mWHe22l7V9yCFz+BToEoJsd+2VB0si7F7+tuJ+PJt8f4V8SOIo7QNqeekQLf0TC7tBplNXitTVAfhK+wTU9wgJtK5GIZSVmbCJhQ== X-Forefront-Antispam-Report: CIP:165.204.84.17; CTRY:US; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:SATLEXMB04.amd.com; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230028)(4636009)(346002)(39860400002)(396003)(376002)(136003)(451199021)(82310400008)(40470700004)(36840700001)(46966006)(40480700001)(81166007)(40460700003)(356005)(36860700001)(47076005)(426003)(2616005)(83380400001)(36756003)(44832011)(5660300002)(8676002)(8936002)(54906003)(110136005)(478600001)(316002)(4326008)(70586007)(70206006)(41300700001)(26005)(186003)(1076003)(336012)(2906002)(6666004)(30864003)(86362001)(82740400003)(36900700001); DIR:OUT; SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Jul 2023 14:08:06.7966 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 47a95609-2bb8-4192-a33d-08db8d1891d9 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT082.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA3PR12MB8437 X-Mailman-Approved-At: Tue, 25 Jul 2023 17:40:30 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 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.103.8 at phobos.denx.de X-Virus-Status: Clean RPMsg framework is used to communicate to remote processor using rpmsg protocol. This framework is ported from the Linux kernel directory: drivers/rpmsg/ kernel version: 6.4-rc2 (d848a4819d85) Signed-off-by: Tanmay Shah Reviewed-by: Simon Glass --- MAINTAINERS | 7 + arch/sandbox/dts/test.dts | 8 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/rpmsg/Kconfig | 31 +++ drivers/rpmsg/Makefile | 10 + drivers/rpmsg/rpmsg-uclass.c | 156 ++++++++++++ drivers/rpmsg/rpmsg_internal.h | 52 ++++ drivers/rpmsg/sandbox_test_rpmsg.c | 88 +++++++ drivers/rpmsg/virtio_rpmsg_bus.c | 384 +++++++++++++++++++++++++++++ drivers/virtio/virtio-uclass.c | 1 + include/dm/uclass-id.h | 1 + include/rpmsg.h | 140 +++++++++++ include/rproc_virtio.h | 8 +- include/virtio.h | 4 +- include/virtio_ring.h | 15 ++ test/dm/Makefile | 1 + test/dm/rpmsg.c | 41 +++ 18 files changed, 947 insertions(+), 3 deletions(-) create mode 100644 drivers/rpmsg/Kconfig create mode 100644 drivers/rpmsg/Makefile create mode 100644 drivers/rpmsg/rpmsg-uclass.c create mode 100644 drivers/rpmsg/rpmsg_internal.h create mode 100644 drivers/rpmsg/sandbox_test_rpmsg.c create mode 100644 drivers/rpmsg/virtio_rpmsg_bus.c create mode 100644 include/rpmsg.h create mode 100644 test/dm/rpmsg.c diff --git a/MAINTAINERS b/MAINTAINERS index c4a32a0956..876a7fdbdf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1365,6 +1365,13 @@ F: drivers/usb/gadget/f_rockusb.c F: cmd/rockusb.c F: doc/README.rockusb +RPMSG +M: Tanmay Shah +S: Maintained +F: drivers/rpmsg/* +F: include/rpmsg.h +F: test/dm/rpmsg.c + SANDBOX M: Simon Glass S: Maintained diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b5509eee8c..fca1a591fb 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1247,6 +1247,14 @@ compatible = "sandbox,sandbox-rng"; }; + rpmsg_1: rpmsg@1 { + compatible = "sandbox,test-rpmsg"; + }; + + rpmsg_2: rpmsg@2 { + compatible = "sandbox,test-rpmsg"; + }; + rproc_1: rproc@1 { compatible = "sandbox,test-processor"; remoteproc-name = "remoteproc-test-dev1"; diff --git a/drivers/Kconfig b/drivers/Kconfig index a25f6ae02f..69700f1f83 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -112,6 +112,8 @@ source "drivers/reset/Kconfig" source "drivers/rng/Kconfig" +source "drivers/rpmsg/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/scsi/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 3bc6d279d7..68e8d8b065 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -109,6 +109,7 @@ obj-y += mfd/ obj-y += mtd/ obj-y += pwm/ obj-y += reset/ +obj-y += rpmsg/ obj-y += input/ obj-y += iommu/ # SOC specific infrastructure drivers. diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig new file mode 100644 index 0000000000..4efb8dfcd7 --- /dev/null +++ b/drivers/rpmsg/Kconfig @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2023, Advanced Micro devices, Inc. + +menu "RPMsg drivers" + +# RPMsg gets selected by drivers as needed +# All users should depend on DM +config RPMSG + bool + depends on DM + +config VIRTIO_RPMSG_BUS + bool "virtio rpmsg bus" + depends on DM + select RPMSG + select REMOTEPROC_VIRTIO + help + Say 'y' here to enable virtio based RPMsg. RPMsg allows + U-Boot drivers to communicate with remote processors. + +config RPMSG_SANDBOX + bool "RPMsg driver for sandbox platform" + depends on DM + select RPMSG + depends on SANDBOX + help + Say 'y' here to add sandbox driver for RPMsg framework used + for dummy communication with remote processor on sandbox platform + +endmenu diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile new file mode 100644 index 0000000000..21611725ea --- /dev/null +++ b/drivers/rpmsg/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2023, Advanced Micro Devices, Inc. + +obj-$(CONFIG_RPMSG) += rpmsg-uclass.o + +obj-$(CONFIG_RPMSG_SANDBOX) += sandbox_test_rpmsg.o + +# virtio driver for rpmsg +obj-$(CONFIG_VIRTIO_RPMSG_BUS) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/rpmsg-uclass.c b/drivers/rpmsg/rpmsg-uclass.c new file mode 100644 index 0000000000..3e749a5827 --- /dev/null +++ b/drivers/rpmsg/rpmsg-uclass.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * remote processor messaging bus + * + * Copyright (C) 2023, Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +int rpmsg_init(int core_id) +{ + struct udevice *udev = NULL; + int ret; + + ret = uclass_find_device_by_seq(UCLASS_RPMSG, core_id, &udev); + if (ret) { + debug("can't find rpmsg dev for core_id %d\n", core_id); + return ret; + } + + ret = device_probe(udev); + if (ret) + debug("failed to probe rpmsg dev, ret = %d\n", ret); + + return ret; +} + +static int rpmsg_find_device(int core_id, struct udevice **rpdev) +{ + int core_count; + + core_count = uclass_id_count(UCLASS_RPMSG); + if (core_id >= core_count) { + debug("invalid core id = %d\n", core_id); + return -EINVAL; + } + + return uclass_find_device(UCLASS_RPMSG, core_id, rpdev); +} + +/** + * rpmsg_send() - send a message across to the remote processor + * @core_id: remote processor core id + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @core_id endpoint. + * The message will be sent to the remote processor which the @core_id + * belongs to, using @ept's address and its associated rpmsg + * device destination addresses. + * In case there are no TX buffers available, the function will fail + * immediately + * + * Return: 0 on success and an appropriate error value on failure. + */ +int rpmsg_send(int core_id, void *data, int len) +{ + struct udevice *rpdev = NULL; + const struct rpmsg_device_ops *ops; + int ret; + + ret = rpmsg_find_device(core_id, &rpdev); + if (ret) { + debug("no rpmsg device for core = %d, ret = %d\n", core_id, ret); + return ret; + } + if (!rpdev) + return -ENODEV; + + ops = (const struct rpmsg_device_ops *)device_get_ops(rpdev); + if (!ops) { + debug("send op not registered for device %s\n", rpdev->name); + return -EINVAL; + } + + return ops->send(rpdev, data, len); +} + +int rpmsg_recv(int core_id, rpmsg_rx_cb_t cb) +{ + struct udevice *rpdev = NULL; + const struct rpmsg_device_ops *ops; + int ret; + + ret = rpmsg_find_device(core_id, &rpdev); + if (ret) { + debug("no rpmsg device for core = %d, ret = %d\n", core_id, ret); + return ret; + } + if (!rpdev) + return -ENODEV; + + ops = (const struct rpmsg_device_ops *)device_get_ops(rpdev); + if (!ops) { + debug("recv op not registered for device %s\n", rpdev->name); + return -EINVAL; + } + + return ops->recv(rpdev, cb); +} + +void rpmsg_debug_data(int core_id, int vq_id) +{ + struct udevice *rpdev = NULL; + const struct rpmsg_device_ops *ops; + int ret; + + if (vq_id > 1) + debug("vq_id %d not supported\n", vq_id); + + ret = rpmsg_find_device(core_id, &rpdev); + if (ret || !rpdev) { + debug("no rpmsg device for core = %d, ret = %d\n", core_id, ret); + return; + } + + ops = (const struct rpmsg_device_ops *)device_get_ops(rpdev); + if (!ops || !ops->debug_data) { + debug("recv op not registered for device %s\n", rpdev->name); + return; + } + + ops->debug_data(rpdev, vq_id); +} + +int rpmsg_uclass_init(struct uclass *class) +{ + int ret; + + /* make sure virtio framework is initialized */ + ret = virtio_init(); + if (ret) + debug("virtio init failed, %d\n", ret); + + return ret; +} + +UCLASS_DRIVER(rpmsg_bus) = { + .name = "rpmsg_bus", + .id = UCLASS_RPMSG, + .init = rpmsg_uclass_init, + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h new file mode 100644 index 0000000000..4f7bf9fb90 --- /dev/null +++ b/drivers/rpmsg/rpmsg_internal.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * remote processor messaging bus internals + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2023, Advanced Micro Devices, Inc. + * + * Ohad Ben-Cohen + * Brian Swetland + */ + +#ifndef __RPMSG_INTERNAL_H__ +#define __RPMSG_INTERNAL_H__ + +#include +#include + +/** + * struct rpmsg_hdr - common header for all rpmsg messages + * @src: source address + * @dst: destination address + * @reserved: reserved for future use + * @len: length of payload (in bytes) + * @flags: message flags + * @data: @len bytes of message payload data + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +struct rpmsg_hdr { + __rpmsg32 src; + __rpmsg32 dst; + __rpmsg32 reserved; + __rpmsg16 len; + __rpmsg16 flags; + u8 data[]; +} __packed; + +/** + * struct rpmsg_device_ops - indirection table for the rpmsg_device operations + * @send: send data to core + * @recv: recv data to buf. data limited to buf_len bytes and buf is expected + * to have that much memory allocated + * @debug_data: calls virtqueue_dump debug utility to print vq data + */ +struct rpmsg_device_ops { + int (*send)(struct udevice *rpdev, void *data, int len); + int (*recv)(struct udevice *rpdev, rpmsg_rx_cb_t cb); + void (*debug_data)(struct udevice *rpdev, int vq_id); +}; + +#endif diff --git a/drivers/rpmsg/sandbox_test_rpmsg.c b/drivers/rpmsg/sandbox_test_rpmsg.c new file mode 100644 index 0000000000..c94254aa4e --- /dev/null +++ b/drivers/rpmsg/sandbox_test_rpmsg.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023, Advanced Micro Devices, Inc. + */ +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +#define TEST_RPMSG_BUF_SIZE 512 + +struct sandbox_test_devdata { + char rpmsg_data_buf[TEST_RPMSG_BUF_SIZE]; + int msg_len; +}; + +static int sandbox_test_rpmsg_send(struct udevice *rpdev, void *msg, int len) +{ + /* ToDo: (maintainer) Implement send functionality for sandbox drv */ + struct sandbox_test_devdata *data = dev_get_priv(rpdev); + + if (len > TEST_RPMSG_BUF_SIZE) + len = TEST_RPMSG_BUF_SIZE; + + data->msg_len = len; + memcpy(data->rpmsg_data_buf, msg, len); + + return 0; +} + +static int sandbox_test_rpmsg_recv(struct udevice *rpdev, rpmsg_rx_cb_t cb) +{ + /* ToDo: (maintainer) Implement recv functionality for sandbox drv */ + struct sandbox_test_devdata *data = dev_get_priv(rpdev); + int len; + + len = data->msg_len; + + /* as of now only 1 buffer is used for testing. so third arg is 1 */ + if (cb) + cb(&data->rpmsg_data_buf, len, 1); + + return 0; +} + +static void sandbox_test_rpmsg_debug_data(struct udevice *rpdev, int vq_id) +{ + /* + * ToDo: (maintainer) Implement debug_data functionality + * for sandbox drv + */ +} + +int sandbox_test_rpmsg_probe(struct udevice *dev) +{ + /* ToDo: (maintainer) any init work */ + debug("sandbox driver probbed\n"); + + return 0; +} + +static const struct rpmsg_device_ops sandbox_test_rpmsg_ops = { + .send = sandbox_test_rpmsg_send, + .recv = sandbox_test_rpmsg_recv, + .debug_data = sandbox_test_rpmsg_debug_data, +}; + +static const struct udevice_id sandbox_ids[] = { + {.compatible = "sandbox,test-rpmsg"}, + {} +}; + +U_BOOT_DRIVER(sandbox_test_rpmsg) = { + .name = "sandbox_test_rpmsg", + .of_match = sandbox_ids, + .id = UCLASS_RPMSG, + .ops = &sandbox_test_rpmsg_ops, + .probe = sandbox_test_rpmsg_probe, + .priv_auto = sizeof(struct sandbox_test_devdata), +}; + +U_BOOT_DRVINFO(sandbox_test_rpmsg) = { + .name = "sandbox_test_rpmsg", +}; diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c new file mode 100644 index 0000000000..a41fab177d --- /dev/null +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2023, Advanced Micro Devices, Inc. + * + * RPMsg virtio driver + * File proted from the Linux kernel: + * drivers/rpmsg/virtio_rpmsg_bus + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +/* + * Allocate buffers of 512 bytes each for communications. The + * number of buffers will be computed from the number of buffers supported + * by the vring, upto a maximum of 512 buffers (256 in each direction). + * + * Each buffer will have 16 bytes for the msg header and 496 bytes for + * the payload. + * + * This will utilize a maximum total space of 256KB for the buffers. + * + * In future add support for user-provided buffers. + * This will allow bigger buffer size flexibility, and can also be used + * to achieve zero-copy messaging. + * + * Note that these numbers are purely a decision of this driver - user + * can change this without changing anything in the firmware of the remote + * processor. + */ +#define MAX_RPMSG_NUM_BUFS (512) +#define MAX_RPMSG_BUF_SIZE (512) + +#define RPMSG_UBOOT_ADDR (1035) + +/* + * Local addresses are dynamically allocated on-demand. + * We do not dynamically assign addresses from the low 1024 range, + * in order to reserve that address range for predefined services. + */ +#define RPMSG_RESERVED_ADDRESSES (1024) + +/** + * struct virtproc_info - virtual remote processor state + * @vdev: the virtio device + * @vqs: rx and tx virtqueues + * @rvq: rx virtqueue + * @svq: tx virtqueue + * @rbufs: kernel address of rx buffers + * @sbufs: kernel address of tx buffers + * @num_bufs: total number of buffers for rx and tx + * @buf_size: size of one rx or tx buffer + * @last_sbuf: index of last tx buffer used + * @bufs_dma: dma base addr of the buffers + * + * This structure stores the rpmsg state of a given virtio remote processor + * device (there might be several virtio proc devices for each physical + * remote processor). + */ +struct virtproc_info { + struct udevice *vdev; + + union { + struct virtqueue *vqs[2]; + struct { + struct virtqueue *rvq; + struct virtqueue *svq; + }; + }; + void *rbufs, *sbufs; + unsigned int num_bufs; + unsigned int buf_size; + int last_sbuf; + unsigned long bufs_dma; +}; + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP doesn't support name service */ + +/** + * rpmsg_sg_init - initialize scatterlist according to cpu address location + * @sg: scatterlist to fill + * @cpu_addr: virtual address of the buffer + * @len: buffer length + * + * An internal function filling scatterlist according to virtual address + * location (in vmalloc or in kernel). + */ +static void +rpmsg_sg_init(struct virtio_sg *sg, void *cpu_addr, unsigned int len) +{ + sg->addr = cpu_addr; + sg->length = len; +} + +void *get_tx_buf(struct virtproc_info *vrp) +{ + unsigned int len; + void *ret; + + if (!vrp->svq) { + dev_err(vrp->vdev, "send vq not available for dev\n"); + return NULL; + } + + /* + * either pick the next unused tx buffer + * (half of our buffers are used for sending messages) + */ + if (vrp->last_sbuf < vrp->num_bufs / 2) + ret = vrp->sbufs + (vrp->buf_size * vrp->last_sbuf++); + /* or recycle a used one */ + else + ret = virtqueue_get_buf(vrp->svq, &len); + + return ret; +} + +int virtio_rpmsg_bus_send(struct udevice *vdev, void *data, int len) +{ + struct virtproc_info *vrp; + struct rpmsg_hdr *msg; + struct virtio_sg sg = {0}; + struct virtio_sg *sgs[] = { &sg }; + int msg_len, err = 0; + + vrp = dev_get_priv(vdev); + + if (len > (vrp->buf_size - sizeof(struct rpmsg_hdr))) { + dev_err(vdev, "msg len %d is out of bound\n", len); + return -EMSGSIZE; + } + + msg = get_tx_buf(vrp); + if (!msg) { + dev_err(vdev, "rpmsg can't get tx buffer\n"); + return -ENOMEM; + } + + msg->len = cpu_to_rpmsg16(len); + msg->src = cpu_to_rpmsg32(RPMSG_UBOOT_ADDR); + msg->dst = cpu_to_rpmsg32(RPMSG_UBOOT_ADDR); + msg->flags = 0; + msg->reserved = 0; + memcpy(msg->data, (char *)data, len); + msg_len = len + sizeof(*msg); + rpmsg_sg_init(&sg, msg, msg_len); + + /* add messages to the remote processor's virtqueue */ + err = virtqueue_add(vrp->svq, sgs, 1, 0); + if (err) { + /* + * need to reclaim the buffer or it's lost. + * memory won't lost but rpmsg won't use it for tx. + * this will wait for buffer management overhaul. + */ + dev_err(vdev, "failed to add out buf\n"); + return err; + } + + /* tell remote processor that it has pending message to read */ + virtqueue_kick(vrp->svq); + + return 0; +} + +static int rpmsg_recv_single(struct virtproc_info *vrp, struct rpmsg_hdr *msg, + unsigned int len, int msgs_received, + rpmsg_rx_cb_t cb) +{ + struct virtio_sg sg; + struct virtio_sg *sgs[] = { &sg }; + bool little_endian = virtio_is_little_endian(vrp->vdev); + unsigned int msg_len = __rpmsg16_to_cpu(little_endian, msg->len); + int err; + + debug("From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n", + __rpmsg32_to_cpu(little_endian, msg->src), + __rpmsg32_to_cpu(little_endian, msg->dst), msg_len, + __rpmsg16_to_cpu(little_endian, msg->flags), + __rpmsg32_to_cpu(little_endian, msg->reserved)); + + /* + * We currently use fixed-sized buffers, so trivially sanitize + * the reported payload length. + */ + if (len > vrp->buf_size || + msg_len > (len - sizeof(struct rpmsg_hdr))) { + debug("inbound msg too big: (%d, %d)\n", len, msg_len); + return -EINVAL; + } + + /* call rpmsg callback */ + if (cb && msg->dst == RPMSG_UBOOT_ADDR) + cb(msg->data, msg_len, msgs_received); + + /* publish the real size of the buffer */ + rpmsg_sg_init(&sg, msg, vrp->buf_size); + + /* add the buffer back to the remote processor's virtqueue */ + err = virtqueue_add(vrp->rvq, sgs, 0, 1); + if (err < 0) { + dev_err(vrp->vdev, "failed to add a virtqueue buffer %d\n", err); + return err; + } + + return 0; +} + +int virtio_rpmsg_bus_recv(struct udevice *vdev, rpmsg_rx_cb_t cb) +{ + struct virtproc_info *vrp = dev_get_priv(vdev); + struct rpmsg_hdr *msg; + unsigned int len, msgs_received = 0; + int err; + + rproc_flush_dcache(vdev->parent); + + msg = virtqueue_get_buf(vrp->rvq, &len); + if (!msg) { + debug("uhm, incoming signal, but no used buffer ?\n"); + return -ENODATA; + } + + while (msg) { + err = rpmsg_recv_single(vrp, msg, len, msgs_received, cb); + if (err) { + debug("rpmsg failed to recv msg\n"); + return err; + } + + msgs_received++; + + msg = virtqueue_get_buf(vrp->rvq, &len); + } + + debug("rpmsg messages received = %d\n", msgs_received); + + return 0; +} + +static int virtio_rpmsg_bus_remove(struct udevice *vdev) +{ + virtio_reset(vdev); + + return 0; +} + +static int virtio_rpmsg_bus_probe(struct udevice *uvdev) +{ + struct rproc_rvdev_data *rvdev_data; + struct rproc_mem_entry *vdev_buf; + struct virtproc_info *vrp; + size_t total_buf_space; + int err = 0, i; + void *bufs_va; + + vrp = dev_get_priv(uvdev); + if (!vrp) { + dev_err(uvdev, "vrp not available\n"); + return -EINVAL; + } + + vrp->vdev = uvdev; + rvdev_data = (struct rproc_rvdev_data *)dev_get_plat(uvdev->parent); + vdev_buf = rvdev_data->vdev_buf; + if (!vdev_buf) { + dev_err(uvdev, "vdev buffer isn't availablne\n"); + return -ENOMEM; + } + + err = virtio_find_vqs(uvdev, 2, vrp->vqs); + if (err) { + dev_err(uvdev, "failed to find vqs with err = %d\n", err); + return -EINVAL; + } + + if (!vrp->vqs[0] || !vrp->vqs[1]) { + dev_err(uvdev, "failed to find vq\n"); + return -EINVAL; + } + + /* symmetric tx/rx vrings are expected */ + if (virtqueue_get_vring_size(vrp->rvq) != virtqueue_get_vring_size(vrp->svq)) + dev_warn(uvdev, "rx vq and tx vq are not same size\n"); + + /* less buffers are needed if vrings are small */ + if (virtqueue_get_vring_size(vrp->rvq) < MAX_RPMSG_NUM_BUFS / 2) + vrp->num_bufs = virtqueue_get_vring_size(vrp->rvq) * 2; + else + vrp->num_bufs = MAX_RPMSG_NUM_BUFS; + + vrp->buf_size = MAX_RPMSG_BUF_SIZE; + vrp->last_sbuf = 0; + + total_buf_space = vrp->num_bufs * vrp->buf_size; + + if (vdev_buf->len < total_buf_space) { + dev_err(uvdev, "not enough vdev buffer memory\n"); + return -EINVAL; + } + + /* allocate coherent memory for the buffers */ + bufs_va = vdev_buf->va; + if (!bufs_va) { + err = -ENOMEM; + goto vqs_del; + } + + /* half of the buffers is dedicated for RX */ + vrp->rbufs = bufs_va; + + /* and half is dedicated for TX */ + vrp->sbufs = bufs_va + (total_buf_space / 2); + + /* set up the receive buffers */ + for (i = 0; i < vrp->num_bufs / 2; i++) { + struct virtio_sg sg; + struct virtio_sg *sgs[] = { &sg }; + + void *cpu_addr = vrp->rbufs + i * vrp->buf_size; + + rpmsg_sg_init(&sg, cpu_addr, vrp->buf_size); + + err = virtqueue_add(vrp->rvq, sgs, 0, 1); + if (err) /* sanity check; this can't really happen */ + dev_warn(uvdev, "adding inbuf for dev %s, vq %d failed\n", + vrp->vdev->name, vrp->rvq->index); + } + + /* ToDo: Support Named service announcement */ + + /* let remote know that host can receive data */ + virtqueue_kick(vrp->rvq); + + return 0; + +vqs_del: + virtio_del_vqs(uvdev); + + return err; +} + +static void virtio_rpmsg_bus_debug_data(struct udevice *uvdev, int vq_id) +{ + struct virtproc_info *vrp; + + vrp = dev_get_priv(uvdev); + + if (vrp->vqs[vq_id]) + virtqueue_dump(vrp->vqs[vq_id]); + else + dev_info(uvdev, "virtqueue %d not found\n", vq_id); +} + +static const struct rpmsg_device_ops virtio_rpmsg_dev_ops = { + .send = virtio_rpmsg_bus_send, + .recv = virtio_rpmsg_bus_recv, + .debug_data = virtio_rpmsg_bus_debug_data, +}; + +U_BOOT_DRIVER(virtio_rpmsg_bus) = { + .name = VIRTIO_RPROC_DRV_NAME, + .id = UCLASS_RPMSG, + .probe = virtio_rpmsg_bus_probe, + .remove = virtio_rpmsg_bus_remove, + .ops = &virtio_rpmsg_dev_ops, + .priv_auto = sizeof(struct virtproc_info), + .flags = DM_FLAG_ACTIVE_DMA, +}; diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index 31bb21c534..0c76479c45 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -31,6 +31,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = { [VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME, [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME, [VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME, + [VIRTIO_ID_RPROC] = VIRTIO_RPROC_DRV_NAME, }; int virtio_get_config(struct udevice *vdev, unsigned int offset, diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 307ad6931c..a1a4746a63 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -114,6 +114,7 @@ enum uclass_id { UCLASS_REMOTEPROC, /* Remote Processor device */ UCLASS_RESET, /* Reset controller device */ UCLASS_RNG, /* Random Number Generator */ + UCLASS_RPMSG, /* RPMsg device */ UCLASS_RTC, /* Real time clock device */ UCLASS_SCMI_AGENT, /* Interface with an SCMI server */ UCLASS_SCSI, /* SCSI device */ diff --git a/include/rpmsg.h b/include/rpmsg.h new file mode 100644 index 0000000000..bed61240ca --- /dev/null +++ b/include/rpmsg.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _RPMSG_H_ +#define _RPMSG_H_ + +/** + * struct dm_rpmsg_uclass_pdata - platform data for a CPU + * @name: Platform-specific way of naming the RPMsg platform device + * @driver_plat_data: driver specific platform data that may be needed. + * + * This can be accessed with dev_get_uclass_plat() for any UCLASS_RPMSG + * device. + * + */ +struct dm_rpmsg_uclass_pdata { + const char *name; + void *driver_plat_data; +}; + +typedef __u16 __bitwise __rpmsg16; +typedef __u32 __bitwise __rpmsg32; +typedef __u64 __bitwise __rpmsg64; + +#define RPMSG_ADDR_ANY 0xFFFFFFFF + +#define RPMSG_NAME_SIZE 32 + +static inline bool rpmsg_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} + +static inline u16 __rpmsg16_to_cpu(bool little_endian, __rpmsg16 val) +{ + if (little_endian) + return le16_to_cpu((__force __le16)val); + else + return be16_to_cpu((__force __be16)val); +} + +static inline __rpmsg16 __cpu_to_rpmsg16(bool little_endian, u16 val) +{ + if (little_endian) + return (__force __rpmsg16)cpu_to_le16(val); + else + return (__force __rpmsg16)cpu_to_be16(val); +} + +static inline u32 __rpmsg32_to_cpu(bool little_endian, __rpmsg32 val) +{ + if (little_endian) + return le32_to_cpu((__force __le32)val); + else + return be32_to_cpu((__force __be32)val); +} + +static inline __rpmsg32 __cpu_to_rpmsg32(bool little_endian, u32 val) +{ + if (little_endian) + return (__force __rpmsg32)cpu_to_le32(val); + else + return (__force __rpmsg32)cpu_to_be32(val); +} + +static inline u64 __rpmsg64_to_cpu(bool little_endian, __rpmsg64 val) +{ + if (little_endian) + return le64_to_cpu((__force __le64)val); + else + return be64_to_cpu((__force __be64)val); +} + +static inline __rpmsg64 __cpu_to_rpmsg64(bool little_endian, u64 val) +{ + if (little_endian) + return (__force __rpmsg64)cpu_to_le64(val); + else + return (__force __rpmsg64)cpu_to_be64(val); +} + +static inline u16 rpmsg16_to_cpu(__rpmsg16 val) +{ + return __rpmsg16_to_cpu(rpmsg_is_little_endian(), val); +} + +static inline __rpmsg16 cpu_to_rpmsg16(u16 val) +{ + return __cpu_to_rpmsg16(rpmsg_is_little_endian(), val); +} + +static inline u32 rpmsg32_to_cpu(__rpmsg32 val) +{ + return __rpmsg32_to_cpu(rpmsg_is_little_endian(), val); +} + +static inline __rpmsg32 cpu_to_rpmsg32(u32 val) +{ + return __cpu_to_rpmsg32(rpmsg_is_little_endian(), val); +} + +static inline u64 rpmsg64_to_cpu(__rpmsg64 val) +{ + return __rpmsg64_to_cpu(rpmsg_is_little_endian(), val); +} + +static inline __rpmsg64 cpu_to_rpmsg64(u64 val) +{ + return __cpu_to_rpmsg64(rpmsg_is_little_endian(), val); +} + +typedef int (*rpmsg_rx_cb_t)(void *buf, int msg_len, u32 msgs_received); + +#if IS_ENABLED(CONFIG_RPMSG) + +int rpmsg_init(int core_id); +int rpmsg_send(int core_id, void *data, int len); +int rpmsg_recv(int core_id, rpmsg_rx_cb_t cb); + +#else +int rpmsg_init(int core_id) +{ + return -ENODEV; +} + +int rpmsg_send(int core_id, void *data, int len) +{ + return -ENODEV; +} + +int rpmsg_recv(int core_id, rpmsg_rx_cb_t cb) +{ + return -ENODEV; +} + +#endif /* IS_ENABLED(CONFIG_RPMSG) */ + +#endif /* _RPMSG_H */ diff --git a/include/rproc_virtio.h b/include/rproc_virtio.h index cbe8ff420f..96d0e3d15c 100644 --- a/include/rproc_virtio.h +++ b/include/rproc_virtio.h @@ -9,15 +9,19 @@ #include #include -void rproc_flush_dcache(struct udevice *dev); - #ifndef CONFIG_SANDBOX +void rproc_flush_dcache(struct udevice *dev); + int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc, int offset); #else +void rproc_flush_dcache(struct udevice *dev) +{ +} + int rproc_virtio_create_dev(struct udevice *parent, struct fw_rsc_vdev *rsc, int offset) { diff --git a/include/virtio.h b/include/virtio.h index 16d0f8aa7f..35274a3593 100644 --- a/include/virtio.h +++ b/include/virtio.h @@ -26,11 +26,13 @@ #define VIRTIO_ID_NET 1 /* virtio net */ #define VIRTIO_ID_BLOCK 2 /* virtio block */ #define VIRTIO_ID_RNG 4 /* virtio rng */ -#define VIRTIO_ID_MAX_NUM 5 +#define VIRTIO_ID_RPROC 7 /* virtio rproc */ +#define VIRTIO_ID_MAX_NUM 8 #define VIRTIO_NET_DRV_NAME "virtio-net" #define VIRTIO_BLK_DRV_NAME "virtio-blk" #define VIRTIO_RNG_DRV_NAME "virtio-rng" +#define VIRTIO_RPROC_DRV_NAME "virtio-rpmsg-bus" /* Status byte for guest to report progress, and synchronize features */ diff --git a/include/virtio_ring.h b/include/virtio_ring.h index 4a9b4078ee..e0cd773913 100644 --- a/include/virtio_ring.h +++ b/include/virtio_ring.h @@ -264,6 +264,21 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, unsigned int vring_align, struct udevice *udev); +/** + * vring_new_virtqueue - create a virtqueue at user defined address + * + * @index: the index of the queue + * @vring: vring created at user defined address + * @udev: the virtio transport udevice + * @return: the virtqueue pointer or NULL if failed + * + * This creates a virtqueue using vring address decided by the user of API + * + * This API is supposed to be called by the virtio transport driver in the + * virtio find_vqs() uclass method. + */ +struct virtqueue *vring_new_virtqueue(unsigned int index, struct vring vring, + struct udevice *udev); /** * vring_del_virtqueue - destroy a virtqueue * diff --git a/test/dm/Makefile b/test/dm/Makefile index 3799b1ae8f..732c35a496 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o obj-$(CONFIG_REMOTEPROC) += remoteproc.o obj-$(CONFIG_DM_RESET) += reset.o +obj-$(CONFIG_RPMSG) += rpmsg.o obj-$(CONFIG_SYSRESET) += sysreset.o obj-$(CONFIG_DM_REGULATOR) += regulator.o obj-$(CONFIG_DM_RNG) += rng.o diff --git a/test/dm/rpmsg.c b/test/dm/rpmsg.c new file mode 100644 index 0000000000..ecd2ba3680 --- /dev/null +++ b/test/dm/rpmsg.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023, Advanced Micro Devices, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char test_buf[512]; + +static int rpmsg_rx_cb(void *buf, int msg_len, u32 msgs_received) +{ + memcpy(test_buf, buf, msg_len); + + return 0; +} + +/** + * dm_test_rpmsg() - test the operations after initializations + * @uts: unit test state + * + * @return: 0 if all test pass + */ +static int dm_test_rpmsg(struct unit_test_state *uts) +{ + ut_assertok(rpmsg_init(0)); + ut_assertok(rpmsg_send(0, "test rpmsg", strlen("test rpmsg"))); + ut_assertok(rpmsg_recv(0, rpmsg_rx_cb)); + + ut_asserteq_str(test_buf, "test rpmsg"); + + return 0; +} + +DM_TEST(dm_test_rpmsg, UT_TESTF_SCAN_PDATA | UT_TESTF_FLAT_TREE);