From nobody Tue Oct 7 08:38:16 2025 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27A8E1F473A; Sun, 13 Jul 2025 08:39:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752395947; cv=none; b=fVmALn0obQq/5w+R1bYR611Ulc6LQMQUQ6zvksvHwjCVX8Jg4zppz4DskkzhyZDNDFSH8faWvopSAFpD+HthHmR3Aco6bwJJfT8nYcIIqAjNnQo/+6k1eVnNRiBNODxpmR0rTU1oQSFNb2eP0tKRmuMk0wNAk5fOFJ6Lr4UWIok= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752395947; c=relaxed/simple; bh=83R2LA8CSH1fzq7CZIOPs7u9eZl4INNjSvuHQFL7NUM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VUu4q0PiYVs+WIwgGdzMpK7tbtXO1MR/Om0uB9VKppt3KI6tt2wER6S3DFJnFsDwIy4KtlEY4U86TSo+MEcpDPDkU4bMvViF7QZ+8QbV7fFTJa2jIaxgh4IZaSc8A1gkUCFtyvMR1qL/YeXR83P59IJjuii5kkXYD64LfZqjuR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tomeuvizoso.net; spf=pass smtp.mailfrom=gmail.com; arc=none smtp.client-ip=209.85.208.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tomeuvizoso.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-6099d89a19cso6525501a12.2; Sun, 13 Jul 2025 01:39:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752395943; x=1753000743; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DMiXIrmKsUVlfBcC+Mvov3+rHZjXokr3HXS7jyEvnoY=; b=l85+6+Ye5qwjS6G5LsAgCZwPKhcfX2+C3BrqESBAOknqaNzfjLLfyf8rueo1NBZdoZ 98+YnC8Y8mh2pbA7lTfi7+RPw17EBGvA3iM53M0Izc/wK+0ii7csmEu4oaf0SRGSdJ/b daE8LwY202KjO1vU00WnrOM3wUil/cVR0KQHDvKSTsZJOlkRmqYWm7gShVXmhUJag2G3 XHEL1WW+xd4CxejSF89qkLdwOs3j8UhmwSVUT7AY4oukXTEJ6mCdZFL28xgjWCwnQSo7 ZLJSmK/WfQr7fChy87gpTdVbp2vW+caC+zjF8gRo4Jem96L52TuS8b7OxQWLd6TfMXE1 8Yog== X-Forwarded-Encrypted: i=1; AJvYcCV1ta/2U7rPN08uRhmrNboCyF5EjzBLjXx49JBoU6tmUJNgj/86Nh1MxXobGxx1Fl3z2I/QhZlLvg7QQGZD@vger.kernel.org, AJvYcCV3NnTmzrFkVMpyttL60BpoDLDzsiCjdmfHFdjE06/tVoWyHTBOnS1jWXsjdWUKZ/v9u53aAD9nmhA=@vger.kernel.org, AJvYcCXeooGgM5Egcc/thqHRufDPokVi1ljqYLVebsAySdDxZ3sh1ghwZvAQCsrcVEonrVc1NFDITrQS4jSHo/g=@vger.kernel.org X-Gm-Message-State: AOJu0YxyFElKNAtDs1CEznnEFJst4OSd1jts//rtkIX0ISzHJKs7b57o MleCiyFOWqPUVPOgVS31DiacimkO0PldS3NCr/uLf4Mvfba8+lQxcQ2k X-Gm-Gg: ASbGncuQ2h2+Fl5465JOeUwpCP93r2pD7ijLW8LnwY1aL9NaO5ePyc0wqK1OEPlMNI3 d8Q+0+MxSYe0eWui/giNQwj/I2cIO2wc9YAfudlYqHOB6Hp0CLvWukolWHa7jPzFGBfpXqmSsL9 8YqAbGEM4iAJRKD9vzfesdF7vR2QSqiOfhyZLIj6aTdS0JP+Q3Gx6fwOP2ATF2SHhu3oMOEqIUC zAyd4TcztYB1m1B3Ob1+RFxJikCBGmYQZUudjMdCAKb0/2dA5MjJBuundmJpzUIFu3t4EoPd0AI EJ1aTrUKmXHkDrdAjwYHmIa1S7KAr87CHRau0swujl3ib+JZaP7ohbadry0CPNe4PT30L5/nlAn 9SlwAYzWebYH6NlgD5jDWolK/ntM+Y9PMYjw1JjSX+RWqQ+M9Wdi+rNV9 X-Google-Smtp-Source: AGHT+IEEapecy6If7fMnnNG7jf95Ga8/Go2zDEV8xGXASa+XFZ8RHznsn0vImZSZkEQwMwklzQauIQ== X-Received: by 2002:a17:907:c301:b0:ae6:de90:9e26 with SMTP id a640c23a62f3a-ae6fcc78a61mr914298066b.56.1752395942986; Sun, 13 Jul 2025 01:39:02 -0700 (PDT) Received: from [10.42.0.1] (cst-prg-46-162.cust.vodafone.cz. [46.135.46.162]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae6e7e90a42sm610876266b.27.2025.07.13.01.39.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Jul 2025 01:39:02 -0700 (PDT) From: Tomeu Vizoso Date: Sun, 13 Jul 2025 10:38:52 +0200 Subject: [PATCH v8 02/10] accel/rocket: Add a new driver for Rockchip's NPU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250713-6-10-rocket-v8-2-64fa3115e910@tomeuvizoso.net> References: <20250713-6-10-rocket-v8-0-64fa3115e910@tomeuvizoso.net> In-Reply-To: <20250713-6-10-rocket-v8-0-64fa3115e910@tomeuvizoso.net> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heiko Stuebner , Oded Gabbay , Jonathan Corbet , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= , Sebastian Reichel , Nicolas Frattaroli , Kever Yang , Robin Murphy , Daniel Stone , Da Xue , Philipp Zabel , Jeff Hugo Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, Tomeu Vizoso , Robert Foss X-Mailer: b4 0.14.2 This initial version supports the NPU as shipped in the RK3588 SoC and described in the first part of its TRM, in Chapter 36. This NPU contains 3 independent cores that the driver can submit jobs to. This commit adds just hardware initialization and power management. v2: - Split cores and IOMMUs as independent devices (Sebastian Reichel) - Add some documentation (Jeffrey Hugo) - Be more explicit in the Kconfig documentation (Jeffrey Hugo) - Remove resets, as these haven't been found useful so far (Zenghui Yu) - Repack structs (Jeffrey Hugo) - Use DEFINE_DRM_ACCEL_FOPS (Jeffrey Hugo) - Use devm_drm_dev_alloc (Jeffrey Hugo) - Use probe log helper (Jeffrey Hugo) - Introduce UABI header in a later patch (Jeffrey Hugo) v3: - Adapt to a split of the register block in the DT bindings (Nicolas Frattaroli) - Move registers header to its own commit (Thomas Zimmermann) - Misc. cleanups (Thomas Zimmermann and Jeff Hugo) - Make use of GPL-2.0-only for the copyright notice (Jeff Hugo) - PM improvements (Nicolas Frattaroli) v4: - Use bulk clk API (Krzysztof Kozlowski) v6: - Remove mention to NVDLA, as the hardware is only incidentally related (Kever Yang) - Use calloc instead of GFP_ZERO (Jeff Hugo) - Explicitly include linux/container_of.h (Jeff Hugo) - pclk and npu clocks are now needed by all cores (Rob Herring) v7: - Assign its own IOMMU domain to each client, for isolation (Daniel Stone and Robin Murphy) v8: - Kconfig: fix depends to be more explicit about Rockchip, and remove superfluous selects (Robin Murphy) - Use reset lines to reset the cores (Robin Murphy) - Reference count the module - Set dma_set_max_seg_size - Correctly acquire a reference to the IOMMU (Robin Murphy) - Remove notion of top core (Robin Murphy) Reviewed-by: Robert Foss Tested-by: Heiko Stuebner Signed-off-by: Tomeu Vizoso Reviewed-by: Jeff Hugo --- Documentation/accel/index.rst | 1 + Documentation/accel/rocket/index.rst | 19 +++ MAINTAINERS | 10 ++ drivers/accel/Kconfig | 1 + drivers/accel/Makefile | 1 + drivers/accel/rocket/Kconfig | 24 ++++ drivers/accel/rocket/Makefile | 8 ++ drivers/accel/rocket/rocket_core.c | 100 ++++++++++++++ drivers/accel/rocket/rocket_core.h | 49 +++++++ drivers/accel/rocket/rocket_device.c | 56 ++++++++ drivers/accel/rocket/rocket_device.h | 28 ++++ drivers/accel/rocket/rocket_drv.c | 261 +++++++++++++++++++++++++++++++= ++++ drivers/accel/rocket/rocket_drv.h | 23 +++ 13 files changed, 581 insertions(+) diff --git a/Documentation/accel/index.rst b/Documentation/accel/index.rst index bc85f26533d88891dde482f91e26c99991b22869..d8fa332d60a890dbb617454d2a2= 6d9b6f9b196aa 100644 --- a/Documentation/accel/index.rst +++ b/Documentation/accel/index.rst @@ -10,6 +10,7 @@ Compute Accelerators introduction amdxdna/index qaic/index + rocket/index =20 .. only:: subproject and html =20 diff --git a/Documentation/accel/rocket/index.rst b/Documentation/accel/roc= ket/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..70f97bccf100022550ac7a0718d= c77094f1a8c28 --- /dev/null +++ b/Documentation/accel/rocket/index.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + accel/rocket Rockchip NPU driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The accel/rocket driver supports the Neural Processing Units (NPUs) inside= some +Rockchip SoCs such as the RK3588. Rockchip calls it RKNN and sometimes RKN= PU. + +The hardware is described in chapter 36 in the RK3588 TRM. + +This driver just powers the hardware on and off, allocates and maps buffer= s to +the device and submits jobs to the frontend unit. Everything else is done = in +userspace, as a Gallium driver (also called rocket) that is part of the Me= sa3D +project. + +Hardware currently supported: + +* RK3588 diff --git a/MAINTAINERS b/MAINTAINERS index a92290fffa163f9fe8fe3f04bf66426f9a894409..3ae890e178d1455d99323a59419= 72a50e82b70b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7390,6 +7390,16 @@ T: git https://gitlab.freedesktop.org/drm/misc/kerne= l.git F: drivers/accel/ivpu/ F: include/uapi/drm/ivpu_accel.h =20 +DRM ACCEL DRIVER FOR ROCKCHIP NPU +M: Tomeu Vizoso +L: dri-devel@lists.freedesktop.org +S: Supported +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/accel/rocket/ +F: Documentation/devicetree/bindings/npu/rockchip,rknn-core.yaml +F: drivers/accel/rocket/ +F: include/uapi/drm/rocket_accel.h + DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK M: Oded Gabbay L: dri-devel@lists.freedesktop.org diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig index 5b9490367a39fd12d35a8d9021768aa186c09308..bb01cebc42bf16ebf02e938040f= 339ff94869e33 100644 --- a/drivers/accel/Kconfig +++ b/drivers/accel/Kconfig @@ -28,5 +28,6 @@ source "drivers/accel/amdxdna/Kconfig" source "drivers/accel/habanalabs/Kconfig" source "drivers/accel/ivpu/Kconfig" source "drivers/accel/qaic/Kconfig" +source "drivers/accel/rocket/Kconfig" =20 endif diff --git a/drivers/accel/Makefile b/drivers/accel/Makefile index a301fb6089d4c515430175c5e2ba9190f6dc9158..ffc3fa58866616d933184a76595= 73cd4d4780a8d 100644 --- a/drivers/accel/Makefile +++ b/drivers/accel/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_DRM_ACCEL_AMDXDNA) +=3D amdxdna/ obj-$(CONFIG_DRM_ACCEL_HABANALABS) +=3D habanalabs/ obj-$(CONFIG_DRM_ACCEL_IVPU) +=3D ivpu/ obj-$(CONFIG_DRM_ACCEL_QAIC) +=3D qaic/ +obj-$(CONFIG_DRM_ACCEL_ROCKET) +=3D rocket/ \ No newline at end of file diff --git a/drivers/accel/rocket/Kconfig b/drivers/accel/rocket/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..43d6cd98ec8e4e3448df4d032da= 720932e2db9c3 --- /dev/null +++ b/drivers/accel/rocket/Kconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config DRM_ACCEL_ROCKET + tristate "Rocket (support for Rockchip NPUs)" + depends on DRM + depends on (ARCH_ROCKCHIP && ARM64) || COMPILE_TEST + depends on ROCKCHIP_IOMMU || COMPILE_TEST + depends on MMU + select DRM_SCHED + select DRM_GEM_SHMEM_HELPER + help + Choose this option if you have a Rockchip SoC that contains a + compatible Neural Processing Unit (NPU), such as the RK3588. Called by + Rockchip either RKNN or RKNPU, it accelerates inference of neural + networks. + + The interface exposed to userspace is described in + include/uapi/drm/rocket_accel.h and is used by the Rocket userspace + driver in Mesa3D. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called rocket. diff --git a/drivers/accel/rocket/Makefile b/drivers/accel/rocket/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..abdd75f2492eaecf8bf5e78a2ac= 150ea19ac3e96 --- /dev/null +++ b/drivers/accel/rocket/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_DRM_ACCEL_ROCKET) :=3D rocket.o + +rocket-y :=3D \ + rocket_core.o \ + rocket_device.o \ + rocket_drv.o diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rock= et_core.c new file mode 100644 index 0000000000000000000000000000000000000000..9be964b5fbaef31f9b283b8da6f= e15e6c540e916 --- /dev/null +++ b/drivers/accel/rocket/rocket_core.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2024-2025 Tomeu Vizoso */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rocket_core.h" + +int rocket_core_init(struct rocket_core *core) +{ + struct device *dev =3D core->dev; + struct platform_device *pdev =3D to_platform_device(dev); + u32 version; + int err =3D 0; + + core->resets[0].id =3D "srst_a"; + core->resets[1].id =3D "srst_h"; + err =3D devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(core= ->resets), + core->resets); + if (err) + return dev_err_probe(dev, err, "failed to get resets for core %d\n", cor= e->index); + + err =3D devm_clk_bulk_get(dev, ARRAY_SIZE(core->clks), core->clks); + if (err) + return dev_err_probe(dev, err, "failed to get clocks for core %d\n", cor= e->index); + + core->pc_iomem =3D devm_platform_ioremap_resource_byname(pdev, "pc"); + if (IS_ERR(core->pc_iomem)) { + dev_err(dev, "couldn't find PC registers %ld\n", PTR_ERR(core->pc_iomem)= ); + return PTR_ERR(core->pc_iomem); + } + + core->cna_iomem =3D devm_platform_ioremap_resource_byname(pdev, "cna"); + if (IS_ERR(core->cna_iomem)) { + dev_err(dev, "couldn't find CNA registers %ld\n", PTR_ERR(core->cna_iome= m)); + return PTR_ERR(core->cna_iomem); + } + + core->core_iomem =3D devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(core->core_iomem)) { + dev_err(dev, "couldn't find CORE registers %ld\n", PTR_ERR(core->core_io= mem)); + return PTR_ERR(core->core_iomem); + } + + dma_set_max_seg_size(dev, UINT_MAX); + + err =3D dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (err) + return err; + + core->iommu_group =3D iommu_group_get(dev); + + pm_runtime_use_autosuspend(dev); + + /* + * As this NPU will be most often used as part of a media pipeline that + * ends presenting in a display, choose 50 ms (~3 frames at 60Hz) as an + * autosuspend delay as that will keep the device powered up while the + * pipeline is running. + */ + pm_runtime_set_autosuspend_delay(dev, 50); + + pm_runtime_enable(dev); + + err =3D pm_runtime_get_sync(dev); + + version =3D rocket_pc_readl(core, VERSION); + version +=3D rocket_pc_readl(core, VERSION_NUM) & 0xffff; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + dev_info(dev, "Rockchip NPU core %d version: %d\n", core->index, version); + + return 0; +} + +void rocket_core_fini(struct rocket_core *core) +{ + pm_runtime_dont_use_autosuspend(core->dev); + pm_runtime_disable(core->dev); + iommu_group_put(core->iommu_group); + core->iommu_group =3D NULL; +} + +void rocket_core_reset(struct rocket_core *core) +{ + reset_control_bulk_assert(ARRAY_SIZE(core->resets), core->resets); + + udelay(10); + + reset_control_bulk_deassert(ARRAY_SIZE(core->resets), core->resets); +} diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rock= et_core.h new file mode 100644 index 0000000000000000000000000000000000000000..660de2d70f7d9294bc4db8b235b= 3796941136307 --- /dev/null +++ b/drivers/accel/rocket/rocket_core.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2024-2025 Tomeu Vizoso */ + +#ifndef __ROCKET_CORE_H__ +#define __ROCKET_CORE_H__ + +#include +#include +#include +#include +#include + +#include "rocket_registers.h" + +#define rocket_pc_readl(core, reg) \ + readl((core)->pc_iomem + (REG_PC_##reg)) +#define rocket_pc_writel(core, reg, value) \ + writel(value, (core)->pc_iomem + (REG_PC_##reg)) + +#define rocket_cna_readl(core, reg) \ + readl((core)->cna_iomem + (REG_CNA_##reg) - REG_CNA_S_STATUS) +#define rocket_cna_writel(core, reg, value) \ + writel(value, (core)->cna_iomem + (REG_CNA_##reg) - REG_CNA_S_STATUS) + +#define rocket_core_readl(core, reg) \ + readl((core)->core_iomem + (REG_CORE_##reg) - REG_CORE_S_STATUS) +#define rocket_core_writel(core, reg, value) \ + writel(value, (core)->core_iomem + (REG_CORE_##reg) - REG_CORE_S_STATUS) + +struct rocket_core { + struct device *dev; + struct rocket_device *rdev; + unsigned int index; + + int irq; + void __iomem *pc_iomem; + void __iomem *cna_iomem; + void __iomem *core_iomem; + struct clk_bulk_data clks[4]; + struct reset_control_bulk_data resets[2]; + + struct iommu_group *iommu_group; +}; + +int rocket_core_init(struct rocket_core *core); +void rocket_core_fini(struct rocket_core *core); +void rocket_core_reset(struct rocket_core *core); + +#endif diff --git a/drivers/accel/rocket/rocket_device.c b/drivers/accel/rocket/ro= cket_device.c new file mode 100644 index 0000000000000000000000000000000000000000..b05a0df91d48385ce4ada221378= 42b3e819f8266 --- /dev/null +++ b/drivers/accel/rocket/rocket_device.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2024-2025 Tomeu Vizoso */ + +#include +#include +#include +#include +#include +#include + +#include "rocket_device.h" + +struct rocket_device *rocket_device_init(struct platform_device *pdev, + const struct drm_driver *rocket_drm_driver) +{ + struct device *dev =3D &pdev->dev; + struct device_node *core_node; + struct rocket_device *rdev; + struct drm_device *ddev; + unsigned int num_cores =3D 0; + int err; + + rdev =3D devm_drm_dev_alloc(dev, rocket_drm_driver, struct rocket_device,= ddev); + if (IS_ERR(rdev)) + return rdev; + + ddev =3D &rdev->ddev; + dev_set_drvdata(dev, rdev); + + for_each_compatible_node(core_node, NULL, "rockchip,rk3588-rknn-core") + if (of_device_is_available(core_node)) + num_cores++; + + rdev->cores =3D devm_kcalloc(dev, num_cores, sizeof(*rdev->cores), GFP_KE= RNEL); + if (!rdev->cores) + return ERR_PTR(-ENOMEM); + + dma_set_max_seg_size(dev, UINT_MAX); + + err =3D dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (err) + return ERR_PTR(err); + + err =3D drm_dev_register(ddev, 0); + if (err) + return ERR_PTR(err); + + return rdev; +} + +void rocket_device_fini(struct rocket_device *rdev) +{ + WARN_ON(rdev->num_cores > 0); + + drm_dev_unregister(&rdev->ddev); +} diff --git a/drivers/accel/rocket/rocket_device.h b/drivers/accel/rocket/ro= cket_device.h new file mode 100644 index 0000000000000000000000000000000000000000..a5a5857bb1991161ebfbdcbffac= d75bbb579c572 --- /dev/null +++ b/drivers/accel/rocket/rocket_device.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2024-2025 Tomeu Vizoso */ + +#ifndef __ROCKET_DEVICE_H__ +#define __ROCKET_DEVICE_H__ + +#include +#include +#include +#include +#include + +#include "rocket_core.h" + +struct rocket_device { + struct drm_device ddev; + + struct rocket_core *cores; + unsigned int num_cores; +}; + +struct rocket_device *rocket_device_init(struct platform_device *pdev, + const struct drm_driver *rocket_drm_driver); +void rocket_device_fini(struct rocket_device *rdev); +#define to_rocket_device(drm_dev) \ + ((struct rocket_device *)(container_of((drm_dev), struct rocket_device, d= dev))) + +#endif /* __ROCKET_DEVICE_H__ */ diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocke= t_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..a5df94f6b1259ae335fbccd0105= ba44f3432999c --- /dev/null +++ b/drivers/accel/rocket/rocket_drv.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2024-2025 Tomeu Vizoso */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rocket_drv.h" + +/* + * Facade device, used to expose a single DRM device to userspace, that + * schedules jobs to any RKNN cores in the system. + */ +static struct platform_device *drm_dev; +static struct rocket_device *rdev; + +static void +rocket_iommu_domain_destroy(struct kref *kref) +{ + struct rocket_iommu_domain *domain =3D container_of(kref, struct rocket_i= ommu_domain, kref); + + iommu_domain_free(domain->domain); + domain->domain =3D NULL; + kfree(domain); +} + +static struct rocket_iommu_domain* +rocket_iommu_domain_create(struct device *dev) +{ + struct rocket_iommu_domain *domain =3D kmalloc(sizeof(*domain), GFP_KERNE= L); + void *err; + + if (!domain) + return ERR_PTR(-ENOMEM); + + domain->domain =3D iommu_paging_domain_alloc(dev); + if (IS_ERR(domain->domain)) { + err =3D ERR_CAST(domain->domain); + kfree(domain); + return err; + } + kref_init(&domain->kref); + + return domain; +} + +struct rocket_iommu_domain * +rocket_iommu_domain_get(struct rocket_file_priv *rocket_priv) +{ + kref_get(&rocket_priv->domain->kref); + return rocket_priv->domain; +} + +void +rocket_iommu_domain_put(struct rocket_iommu_domain *domain) +{ + kref_put(&domain->kref, rocket_iommu_domain_destroy); +} + +static int +rocket_open(struct drm_device *dev, struct drm_file *file) +{ + struct rocket_device *rdev =3D to_rocket_device(dev); + struct rocket_file_priv *rocket_priv; + int ret; + + if (!try_module_get(THIS_MODULE)) + return -EINVAL; + + rocket_priv =3D kzalloc(sizeof(*rocket_priv), GFP_KERNEL); + if (!rocket_priv) { + ret =3D -ENOMEM; + goto err_put_mod; + } + + rocket_priv->rdev =3D rdev; + rocket_priv->domain =3D rocket_iommu_domain_create(rdev->cores[0].dev); + if (IS_ERR(rocket_priv->domain)) { + ret =3D PTR_ERR(rocket_priv->domain); + goto err_free; + } + + file->driver_priv =3D rocket_priv; + + return 0; + +err_free: + kfree(rocket_priv); +err_put_mod: + module_put(THIS_MODULE); + return ret; +} + +static void +rocket_postclose(struct drm_device *dev, struct drm_file *file) +{ + struct rocket_file_priv *rocket_priv =3D file->driver_priv; + + rocket_iommu_domain_put(rocket_priv->domain); + kfree(rocket_priv); + module_put(THIS_MODULE); +} + +static const struct drm_ioctl_desc rocket_drm_driver_ioctls[] =3D { +#define ROCKET_IOCTL(n, func) \ + DRM_IOCTL_DEF_DRV(ROCKET_##n, rocket_ioctl_##func, 0) +}; + +DEFINE_DRM_ACCEL_FOPS(rocket_accel_driver_fops); + +/* + * Rocket driver version: + * - 1.0 - initial interface + */ +static const struct drm_driver rocket_drm_driver =3D { + .driver_features =3D DRIVER_COMPUTE_ACCEL, + .open =3D rocket_open, + .postclose =3D rocket_postclose, + .ioctls =3D rocket_drm_driver_ioctls, + .num_ioctls =3D ARRAY_SIZE(rocket_drm_driver_ioctls), + .fops =3D &rocket_accel_driver_fops, + .name =3D "rocket", + .desc =3D "rocket DRM", +}; + +static int rocket_probe(struct platform_device *pdev) +{ + if (rdev =3D=3D NULL) { + /* First core probing, initialize DRM device. */ + rdev =3D rocket_device_init(drm_dev, &rocket_drm_driver); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to initialize rocket device\n"); + return PTR_ERR(rdev); + } + } + + unsigned int core =3D rdev->num_cores; + + dev_set_drvdata(&pdev->dev, rdev); + + rdev->cores[core].rdev =3D rdev; + rdev->cores[core].dev =3D &pdev->dev; + rdev->cores[core].index =3D core; + + rdev->num_cores++; + + return rocket_core_init(&rdev->cores[core]); +} + +static void rocket_remove(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + + for (unsigned int core =3D 0; core < rdev->num_cores; core++) { + if (rdev->cores[core].dev =3D=3D dev) { + rocket_core_fini(&rdev->cores[core]); + rdev->num_cores--; + break; + } + } + + if (rdev->num_cores =3D=3D 0) { + /* Last core removed, deinitialize DRM device. */ + rocket_device_fini(rdev); + rdev =3D NULL; + } +} + +static const struct of_device_id dt_match[] =3D { + { .compatible =3D "rockchip,rk3588-rknn-core" }, + {} +}; +MODULE_DEVICE_TABLE(of, dt_match); + +static int find_core_for_dev(struct device *dev) +{ + struct rocket_device *rdev =3D dev_get_drvdata(dev); + + for (unsigned int core =3D 0; core < rdev->num_cores; core++) { + if (dev =3D=3D rdev->cores[core].dev) + return core; + } + + return -1; +} + +static int rocket_device_runtime_resume(struct device *dev) +{ + struct rocket_device *rdev =3D dev_get_drvdata(dev); + int core =3D find_core_for_dev(dev); + int err =3D 0; + + if (core < 0) + return -ENODEV; + + err =3D clk_bulk_prepare_enable(ARRAY_SIZE(rdev->cores[core].clks), rdev-= >cores[core].clks); + if (err) { + dev_err(dev, "failed to enable (%d) clocks for core %d\n", err, core); + return err; + } + + return 0; +} + +static int rocket_device_runtime_suspend(struct device *dev) +{ + struct rocket_device *rdev =3D dev_get_drvdata(dev); + int core =3D find_core_for_dev(dev); + + if (core < 0) + return -ENODEV; + + clk_bulk_disable_unprepare(ARRAY_SIZE(rdev->cores[core].clks), rdev->core= s[core].clks); + + return 0; +} + +EXPORT_GPL_DEV_PM_OPS(rocket_pm_ops) =3D { + RUNTIME_PM_OPS(rocket_device_runtime_suspend, rocket_device_runtime_resum= e, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + +static struct platform_driver rocket_driver =3D { + .probe =3D rocket_probe, + .remove =3D rocket_remove, + .driver =3D { + .name =3D "rocket", + .pm =3D pm_ptr(&rocket_pm_ops), + .of_match_table =3D dt_match, + }, +}; + +static int __init rocket_register(void) +{ + drm_dev =3D platform_device_register_simple("rknn", -1, NULL, 0); + if (IS_ERR(drm_dev)) + return PTR_ERR(drm_dev); + + return platform_driver_register(&rocket_driver); +} + +static void __exit rocket_unregister(void) +{ + platform_driver_unregister(&rocket_driver); + + platform_device_unregister(drm_dev); +} + +module_init(rocket_register); +module_exit(rocket_unregister); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DRM driver for the Rockchip NPU IP"); +MODULE_AUTHOR("Tomeu Vizoso"); diff --git a/drivers/accel/rocket/rocket_drv.h b/drivers/accel/rocket/rocke= t_drv.h new file mode 100644 index 0000000000000000000000000000000000000000..36b1291b0ead388b8843965758c= 57a0405315519 --- /dev/null +++ b/drivers/accel/rocket/rocket_drv.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2024-2025 Tomeu Vizoso */ + +#ifndef __ROCKET_DRV_H__ +#define __ROCKET_DRV_H__ + +#include "rocket_device.h" + +struct rocket_iommu_domain { + struct iommu_domain *domain; + struct kref kref; +}; + +struct rocket_file_priv { + struct rocket_device *rdev; + + struct rocket_iommu_domain *domain; +}; + +struct rocket_iommu_domain *rocket_iommu_domain_get(struct rocket_file_pri= v *rocket_priv); +void rocket_iommu_domain_put(struct rocket_iommu_domain *domain); + +#endif --=20 2.50.0