On Tue, May 19, 2026 at 11:45:53AM +0530, Ekansh Gupta via B4 Relay wrote:
From: Ekansh Gupta ekansh.gupta@oss.qualcomm.com
Add the foundational driver files for the Qualcomm DSP Accelerator (QDA), a DRM accel driver for Qualcomm DSPs. The driver integrates with the DRM accel subsystem (drivers/accel/) and provides:
- A standard /dev/accel/accel* character device node via DRM.
- GEM-based buffer management with DMA-BUF import/export (PRIME).
- IOMMU context bank management for per-session memory isolation.
- Standard DRM IOCTLs for device management and job submission.
qda_drv.c / qda_drv.h: Core DRM driver registration. Defines the drm_driver ops table, per-file private state (qda_file_priv), and the main device structure (qda_dev) which embeds drm_device.
qda_rpmsg.c / qda_rpmsg.h: RPMsg transport layer. Registers an rpmsg_driver matching the "qcom,fastrpc" compatible string. On probe it allocates a qda_dev, reads the DSP domain name from the "label" DT property, and registers the DRM device.
Assisted-by: Claude:claude-4-6-sonnet Signed-off-by: Ekansh Gupta ekansh.gupta@oss.qualcomm.com
drivers/accel/Kconfig | 1 + drivers/accel/Makefile | 1 + drivers/accel/qda/Kconfig | 30 +++++++++++++ drivers/accel/qda/Makefile | 10 +++++ drivers/accel/qda/qda_drv.c | 97 ++++++++++++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_drv.h | 62 +++++++++++++++++++++++++++ drivers/accel/qda/qda_rpmsg.c | 99 +++++++++++++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_rpmsg.h | 13 ++++++ 8 files changed, 313 insertions(+)
diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig index bdf48ccafcf2..74ac0f71bc9d 100644 --- a/drivers/accel/Kconfig +++ b/drivers/accel/Kconfig @@ -29,6 +29,7 @@ source "drivers/accel/ethosu/Kconfig" source "drivers/accel/habanalabs/Kconfig" source "drivers/accel/ivpu/Kconfig" source "drivers/accel/qaic/Kconfig" +source "drivers/accel/qda/Kconfig" source "drivers/accel/rocket/Kconfig" endif diff --git a/drivers/accel/Makefile b/drivers/accel/Makefile index 1d3a7251b950..58c08dd5f389 100644 --- a/drivers/accel/Makefile +++ b/drivers/accel/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_ACCEL_ARM_ETHOSU) += ethosu/ obj-$(CONFIG_DRM_ACCEL_HABANALABS) += habanalabs/ obj-$(CONFIG_DRM_ACCEL_IVPU) += ivpu/ obj-$(CONFIG_DRM_ACCEL_QAIC) += qaic/ +obj-$(CONFIG_DRM_ACCEL_QDA) += qda/ obj-$(CONFIG_DRM_ACCEL_ROCKET) += rocket/ \ No newline at end of file diff --git a/drivers/accel/qda/Kconfig b/drivers/accel/qda/Kconfig new file mode 100644 index 000000000000..484d21ff1b55 --- /dev/null +++ b/drivers/accel/qda/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Qualcomm DSP accelerator driver +#
+config DRM_ACCEL_QDA
- tristate "Qualcomm DSP accelerator"
- depends on DRM_ACCEL
- depends on ARCH_QCOM || COMPILE_TEST
- depends on RPMSG
- help
Enables the DRM-based accelerator driver for Qualcomm's Hexagon DSPs.This driver provides a standardized interface for offloading computationaltasks to the DSP, including audio processing, sensor offload, computervision, and AI inference workloads.The driver supports all DSP domains (ADSP, CDSP, SDSP, GDSP) andimplements the FastRPC protocol for communication between the applicationprocessor and DSP. It integrates with the Linux kernel's ComputeAccelerators subsystem (drivers/accel/) and provides a modern alternativeto the legacy FastRPC driver found in drivers/misc/.Key features include DMA-BUF interoperability for seamless buffer sharing
Key features of what? Consider distro maintainers reading your help text in order to identify whether to enable it or not.
with other multimedia subsystems, IOMMU-based memory isolation, andstandard DRM IOCTLs for device management and job submission.If unsure, say N.To compile this driver as a module, choose M here: themodule will be called qda.diff --git a/drivers/accel/qda/Makefile b/drivers/accel/qda/Makefile new file mode 100644 index 000000000000..dbe809067a8b --- /dev/null +++ b/drivers/accel/qda/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for Qualcomm DSP accelerator driver +#
+obj-$(CONFIG_DRM_ACCEL_QDA) := qda.o
+qda-y := \
- qda_drv.o \
- qda_rpmsg.o
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c new file mode 100644 index 000000000000..1c1bab68d445 --- /dev/null +++ b/drivers/accel/qda/qda_drv.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +#include <linux/module.h> +#include <linux/slab.h> +#include <drm/drm_accel.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_gem.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_print.h>
+#include "qda_drv.h" +#include "qda_rpmsg.h"
+static int qda_open(struct drm_device *dev, struct drm_file *file) +{
- struct qda_file_priv *qda_file_priv;
- qda_file_priv = kzalloc_obj(*qda_file_priv);
- if (!qda_file_priv)
return -ENOMEM;- qda_file_priv->qda_dev = qda_dev_from_drm(dev);
- file->driver_priv = qda_file_priv;
- return 0;
+}
+static void qda_postclose(struct drm_device *dev, struct drm_file *file) +{
- struct qda_file_priv *qda_file_priv = file->driver_priv;
- kfree(qda_file_priv);
- file->driver_priv = NULL;
+}
+DEFINE_DRM_ACCEL_FOPS(qda_accel_fops);
+static const struct drm_driver qda_drm_driver = {
- .driver_features = DRIVER_COMPUTE_ACCEL,
- .fops = &qda_accel_fops,
- .open = qda_open,
- .postclose = qda_postclose,
- .name = QDA_DRIVER_NAME,
- .desc = "Qualcomm DSP Accelerator Driver",
+};
+struct qda_dev *qda_alloc_device(struct device *dev) +{
- struct qda_dev *qdev;
- qdev = devm_drm_dev_alloc(dev, &qda_drm_driver, struct qda_dev, drm_dev);
- if (IS_ERR(qdev))
return ERR_CAST(qdev);- return qdev;
+}
+void qda_unregister_device(struct qda_dev *qdev) +{
- drm_dev_unregister(&qdev->drm_dev);
+}
+int qda_register_device(struct qda_dev *qdev) +{
- int ret;
- ret = drm_dev_register(&qdev->drm_dev, 0);
- if (ret)
drm_err(&qdev->drm_dev, "Failed to register DRM device: %d\n", ret);- return ret;
+}
+static int __init qda_core_init(void) +{
- int ret;
- ret = qda_rpmsg_register();
- if (ret)
return ret;- pr_info("qda: QDA driver initialization complete\n");
- return 0;
+}
+static void __exit qda_core_exit(void) +{
- qda_rpmsg_unregister();
+}
+module_init(qda_core_init); +module_exit(qda_core_exit);
+MODULE_AUTHOR("Qualcomm AI Infra Team"); +MODULE_DESCRIPTION("Qualcomm DSP Accelerator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/accel/qda/qda_drv.h b/drivers/accel/qda/qda_drv.h new file mode 100644 index 000000000000..7ba2ef19a411 --- /dev/null +++ b/drivers/accel/qda/qda_drv.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef __QDA_DRV_H__ +#define __QDA_DRV_H__
+#include <linux/device.h> +#include <linux/rpmsg.h> +#include <linux/types.h> +#include <drm/drm_device.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h>
+/* Driver identification */ +#define QDA_DRIVER_NAME "qda"
+/**
- struct qda_file_priv - Per-process private data for DRM file
- */
+struct qda_file_priv {
- /** @qda_dev: Back-pointer to device structure */
- struct qda_dev *qda_dev;
+};
+/**
- struct qda_dev - Main device structure for QDA driver
- The DRM device is embedded as the first member so that container_of()
- can recover the qda_dev from any drm_device pointer.
- */
+struct qda_dev {
- /** @drm_dev: Embedded DRM device; recover via qda_dev_from_drm() */
- struct drm_device drm_dev;
- /** @rpdev: RPMsg device for communication with the remote processor */
- struct rpmsg_device *rpdev;
- /** @dev: Underlying Linux device */
- struct device *dev;
- /** @dsp_name: Name of the DSP domain (e.g. "cdsp", "adsp") */
- const char *dsp_name;
+};
+/**
- qda_dev_from_drm - Recover qda_dev from an embedded drm_device pointer
- @dev: Pointer to the embedded drm_device
- Return: Pointer to the enclosing qda_dev.
- */
+static inline struct qda_dev *qda_dev_from_drm(struct drm_device *dev) +{
- return container_of(dev, struct qda_dev, drm_dev);
+}
+/* Device allocation (uses devm_drm_dev_alloc internally) */ +struct qda_dev *qda_alloc_device(struct device *dev);
+/* Core device lifecycle */ +int qda_register_device(struct qda_dev *qdev); +void qda_unregister_device(struct qda_dev *qdev);
+#endif /* __QDA_DRV_H__ */ diff --git a/drivers/accel/qda/qda_rpmsg.c b/drivers/accel/qda/qda_rpmsg.c new file mode 100644 index 000000000000..6eaf1b145f8a --- /dev/null +++ b/drivers/accel/qda/qda_rpmsg.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +#include <linux/module.h> +#include <linux/of.h> +#include <linux/rpmsg.h> +#include <drm/drm_print.h>
+#include "qda_drv.h" +#include "qda_rpmsg.h"
+static struct qda_dev *alloc_and_init_qdev(struct rpmsg_device *rpdev)
Use the prefix uniformly.
+{
- struct qda_dev *qdev;
- qdev = qda_alloc_device(&rpdev->dev);
- if (IS_ERR(qdev))
return qdev;- qdev->dev = &rpdev->dev;
- qdev->rpdev = rpdev;
- dev_set_drvdata(&rpdev->dev, qdev);
- return qdev;
+}
+static int qda_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)+{
- /* Placeholder: responses will be dispatched here */
- return 0;
+}
+static void qda_rpmsg_remove(struct rpmsg_device *rpdev) +{
- struct qda_dev *qdev = dev_get_drvdata(&rpdev->dev);
- drm_dev_unplug(&qdev->drm_dev);
- qdev->rpdev = NULL;
- qda_unregister_device(qdev);
- dev_info(qdev->dev, "RPMsg device removed\n");
Drop the spamming. And useless (where it is useless) drm_dbg() / dev_dbg() spamming too.
+}
+static int qda_rpmsg_probe(struct rpmsg_device *rpdev) +{
- struct qda_dev *qdev;
- const char *label;
- int ret;
- dev_dbg(&rpdev->dev, "QDA RPMsg probe starting\n");
- qdev = alloc_and_init_qdev(rpdev);
- if (IS_ERR(qdev))
return PTR_ERR(qdev);- ret = of_property_read_string(rpdev->dev.of_node, "label", &label);
- if (ret) {
dev_err(qdev->dev, "Missing 'label' property in DT node: %d\n", ret);return ret;- }
- qdev->dsp_name = label;
Why not just of_property_read_string(...., &qdev->dsp_name)?
- ret = qda_register_device(qdev);
return qda_register_device();
- if (ret)
return ret;- drm_info(&qdev->drm_dev, "QDA RPMsg probe complete for %s\n", qdev->dsp_name);
- return 0;
+}
+static const struct of_device_id qda_rpmsg_id_table[] = {
- { .compatible = "qcom,fastrpc" },
- {},
+}; +MODULE_DEVICE_TABLE(of, qda_rpmsg_id_table);
+static struct rpmsg_driver qda_rpmsg_driver = {
- .probe = qda_rpmsg_probe,
- .remove = qda_rpmsg_remove,
- .callback = qda_rpmsg_cb,
- .drv = {
.name = "qcom,fastrpc",.of_match_table = qda_rpmsg_id_table,- },
+};
+int qda_rpmsg_register(void) +{
- int ret = register_rpmsg_driver(&qda_rpmsg_driver);
- if (ret)
pr_err("qda: Failed to register RPMsg driver: %d\n", ret);- return ret;
+}
+void qda_rpmsg_unregister(void) +{
- unregister_rpmsg_driver(&qda_rpmsg_driver);
+}
Just use module_rpmsg_driver(), drop all the wrappers and module_init() / exit().
diff --git a/drivers/accel/qda/qda_rpmsg.h b/drivers/accel/qda/qda_rpmsg.h new file mode 100644 index 000000000000..5229d834b34b --- /dev/null +++ b/drivers/accel/qda/qda_rpmsg.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
- */
+#ifndef __QDA_RPMSG_H__ +#define __QDA_RPMSG_H__
+/* RPMsg transport layer registration */ +int qda_rpmsg_register(void); +void qda_rpmsg_unregister(void);
+#endif /* __QDA_RPMSG_H__ */
-- 2.34.1