Add the skeleton of the Qualcomm DSP Accelerator (QDA) driver, a DRM accel driver for the Hexagon DSPs found on Qualcomm SoCs.
This patch registers a DRM accel device, exposing a /dev/accel/accelN character device node, and binds it to the RPMsg channel used to reach the DSP. Buffer management, IOMMU context banks and the FastRPC protocol are added by later patches in this series. qda_drv.c / qda_drv.h define the drm_driver ops table, the per-file private state (qda_file_priv) and the main device structure (qda_dev), which embeds drm_device so that it can be recovered with container_of(). qda_rpmsg.c binds to the "qcom,fastrpc" compatible via module_rpmsg_driver(), reads the DSP domain name from the "label" device-tree property, and registers the DRM device. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Ekansh Gupta <[email protected]> --- Changes in v2: - Use module_rpmsg_driver() and drop the qda_rpmsg_register()/ _unregister() wrappers, module_init()/module_exit() and qda_rpmsg.h entirely (Dmitry Baryshkov) - Read the "label" property directly into qdev->dsp_name (Dmitry Baryshkov) - Drop the probe/remove/init log messages (Dmitry Baryshkov) - Return the result of qda_register_device() directly (Dmitry Baryshkov) - Clarify the Kconfig help text (Dmitry Baryshkov) --- drivers/accel/Kconfig | 1 + drivers/accel/Makefile | 1 + drivers/accel/qda/Kconfig | 30 ++++++++++++++++ drivers/accel/qda/Makefile | 10 ++++++ drivers/accel/qda/qda_drv.c | 71 ++++++++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_drv.h | 61 +++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_rpmsg.c | 79 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 253 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..e679cd00f092 --- /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 computational + tasks to the DSP, including audio processing, sensor offload, computer + vision, and AI inference workloads. + + The driver supports all DSP domains (ADSP, CDSP, SDSP, GDSP) and + implements the FastRPC protocol for communication between the application + processor and DSP. It integrates with the Linux kernel's Compute + Accelerators subsystem (drivers/accel/) and provides a modern alternative + to the legacy FastRPC driver found in drivers/misc/. + + The interface exposed to userspace is described in + include/uapi/drm/qda_accel.h and is used by the FastRPC userspace + library at https://github.com/qualcomm/fastrpc. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module 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..9a64f7dfcb6e --- /dev/null +++ b/drivers/accel/qda/qda_drv.c @@ -0,0 +1,71 @@ +// 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" + +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; +} + +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; +} + +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..4a27fb40c280 --- /dev/null +++ b/drivers/accel/qda/qda_drv.h @@ -0,0 +1,61 @@ +/* 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); + +#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..6a6e58333a68 --- /dev/null +++ b/drivers/accel/qda/qda_rpmsg.c @@ -0,0 +1,79 @@ +// 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" + +static struct qda_dev *qda_rpmsg_alloc_and_init_qdev(struct rpmsg_device *rpdev) +{ + 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); + + /* + * Unplug first so no ioctl or response callback can be in flight, then + * fail any invocation still waiting for the now-departed DSP so it + * releases the GEM objects it holds. + */ + drm_dev_unplug(&qdev->drm_dev); + qdev->rpdev = NULL; +} + +static int qda_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct qda_dev *qdev; + int ret; + + qdev = qda_rpmsg_alloc_and_init_qdev(rpdev); + if (IS_ERR(qdev)) + return PTR_ERR(qdev); + + ret = of_property_read_string(rpdev->dev.of_node, "label", &qdev->dsp_name); + if (ret) { + dev_err(&rpdev->dev, "Missing 'label' property in DT node: %d\n", ret); + return ret; + } + + return qda_register_device(qdev); +} + +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, + }, +}; + +module_rpmsg_driver(qda_rpmsg_driver); -- 2.34.1
