From: Alexandre Bailon <abailon@baylibre.com>
To: airlied@gmail.com, daniel@ffwll.ch,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de
Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, matthias.bgg@gmail.com,
angelogioacchino.delregno@collabora.com, sumit.semwal@linaro.org,
christian.koenig@amd.com, jstephan@baylibre.com,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org, linux-media@vger.kernel.org,
linaro-mm-sig@lists.linaro.org, khilman@baylibre.com,
nbelin@baylibre.com, bero@baylibre.com,
Alexandre Bailon <abailon@baylibre.com>
Subject: [PATCH 1/7] drm: Add support of AI Processor Unit (APU)
Date: Wed, 17 May 2023 16:52:31 +0200 [thread overview]
Message-ID: <20230517145237.295461-2-abailon@baylibre.com> (raw)
In-Reply-To: <20230517145237.295461-1-abailon@baylibre.com>
Many AI Processur Unit (APU) have a similar architecture.
This driver intends helping supporting them.
This relies on DRM and provides some abstractions useful
for AI accelerators.
Currently, this provides the infrastructure to alloc an APU
device and register one or many cores.
The driver will takes care to register itself to DRM.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Reviewed-by: Julien Stephan <jstephan@baylibre.com>
---
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/apu/Kconfig | 12 ++
drivers/gpu/drm/apu/Makefile | 5 +
drivers/gpu/drm/apu/apu_drv.c | 272 +++++++++++++++++++++++++++++
drivers/gpu/drm/apu/apu_internal.h | 68 ++++++++
include/uapi/drm/apu_drm.h | 28 +++
7 files changed, 388 insertions(+)
create mode 100644 drivers/gpu/drm/apu/Kconfig
create mode 100644 drivers/gpu/drm/apu/Makefile
create mode 100644 drivers/gpu/drm/apu/apu_drv.c
create mode 100644 drivers/gpu/drm/apu/apu_internal.h
create mode 100644 include/uapi/drm/apu_drm.h
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index ba3fb04bb691..32ffa66a8b54 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -371,6 +371,8 @@ source "drivers/gpu/drm/solomon/Kconfig"
source "drivers/gpu/drm/sprd/Kconfig"
+source "drivers/gpu/drm/apu/Kconfig"
+
config DRM_HYPERV
tristate "DRM Support for Hyper-V synthetic video device"
depends on DRM && PCI && MMU && HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index a33257d2bc7f..7cd8c0f3936a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -191,6 +191,7 @@ obj-$(CONFIG_DRM_MCDE) += mcde/
obj-$(CONFIG_DRM_TIDSS) += tidss/
obj-y += xlnx/
obj-y += gud/
+obj-$(CONFIG_DRM_APU) += apu/
obj-$(CONFIG_DRM_HYPERV) += hyperv/
obj-y += solomon/
obj-$(CONFIG_DRM_SPRD) += sprd/
diff --git a/drivers/gpu/drm/apu/Kconfig b/drivers/gpu/drm/apu/Kconfig
new file mode 100644
index 000000000000..226dcf072115
--- /dev/null
+++ b/drivers/gpu/drm/apu/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+config DRM_APU
+ tristate "APU (AI Processor Unit)"
+ select DRM_GEM_DMA_HELPER
+ select DRM_KMS_HELPER
+ help
+ This provides a DRM driver that provides some facilities to
+ communicate with an AI Processor Unit (APU).
+ The driver intends to provide a common infrastructure that may be
+ used to support many different APU.
diff --git a/drivers/gpu/drm/apu/Makefile b/drivers/gpu/drm/apu/Makefile
new file mode 100644
index 000000000000..ad85b88a8b52
--- /dev/null
+++ b/drivers/gpu/drm/apu/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+drm_apu-y += apu_drv.o
+
+obj-$(CONFIG_DRM_APU) += drm_apu.o
diff --git a/drivers/gpu/drm/apu/apu_drv.c b/drivers/gpu/drm/apu/apu_drv.c
new file mode 100644
index 000000000000..b420b13a9ffd
--- /dev/null
+++ b/drivers/gpu/drm/apu/apu_drv.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright 2020 BayLibre SAS
+
+#include <linux/list.h>
+#include <linux/module.h>
+
+#include <drm/apu_drm.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_probe_helper.h>
+
+#include "apu_internal.h"
+
+static LIST_HEAD(apu_devices);
+
+static int ioctl_apu_state(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+static const struct drm_ioctl_desc ioctls[] = {
+ DRM_IOCTL_DEF_DRV(APU_STATE, ioctl_apu_state,
+ DRM_RENDER_ALLOW),
+};
+
+DEFINE_DRM_GEM_DMA_FOPS(apu_drm_ops);
+
+static struct drm_driver apu_drm_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_SYNCOBJ,
+ .name = "drm_apu",
+ .desc = "APU DRM driver",
+ .date = "20210319",
+ .major = 1,
+ .minor = 0,
+ .patchlevel = 0,
+ .ioctls = ioctls,
+ .num_ioctls = ARRAY_SIZE(ioctls),
+ .fops = &apu_drm_ops,
+ DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(drm_gem_dma_dumb_create),
+};
+
+/**
+ * apu_dev_alloc() - Allocate a new APU device
+ *
+ * @dev: Pointer to the device instance.
+
+ * This allocate an APU device.
+ * The APU describe a hardware accelerator that may have one or more
+ * core (or unit).
+ *
+ * Returns: A pointer or NULL in case of failure.
+ */
+struct apu_drm *apu_dev_alloc(struct device *dev)
+{
+ struct drm_device *drm;
+ struct apu_drm *apu;
+
+ apu = devm_drm_dev_alloc(dev, &apu_drm_driver, typeof(*apu), base);
+ if (IS_ERR(apu))
+ return NULL;
+ INIT_LIST_HEAD(&apu->cores);
+
+ apu->dev = dev;
+ ida_init(&apu->ida);
+ drm = &apu->base;
+ drm->dev_private = apu;
+
+ dev_set_drvdata(dev, drm);
+
+ return apu;
+}
+EXPORT_SYMBOL_GPL(apu_dev_alloc);
+
+/**
+ * apu_dev_register() - Register the APU to DRM
+ *
+ * @apu: Pointer to APU device
+ *
+ * Register an APU device to DRM.
+ * On success, this creates everything required to use the APU.
+ * Note that at this step, the cores (or units) have not been
+ * registered so we can't yet perform any operations.
+ *
+ * Returns: Zero on success, non-zero value on failure.
+ */
+int apu_dev_register(struct apu_drm *apu)
+{
+ struct drm_device *drm = &apu->base;
+ int ret;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ return ret;
+
+ list_add(&apu->node, &apu_devices);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apu_dev_register);
+
+/**
+ * apu_dev_unregister() - Unregister the APU
+ *
+ * @apu: Pointer to APU device
+ *
+ * This undo what has been done by apu_dev_register();
+ */
+void apu_dev_unregister(struct apu_drm *apu)
+{
+ struct drm_device *drm = &apu->base;
+
+ list_del(&apu->node);
+ drm_dev_unregister(drm);
+}
+EXPORT_SYMBOL_GPL(apu_dev_unregister);
+
+/**
+ * apu_core_alloc() - Allocate an APU core
+ *
+ * @apu: Pointer to APU device
+ * @ops: The operation callbacks to use for this core
+ * @priv:
+ *
+ * Allocate an APU core. This represents a computing unit that could
+ * execute a job. The APU may be composed of different units that doesn't
+ * accept same kind of jobs so we may to use differents callbacks for each
+ * core.
+ *
+ * Returns: A pointer or NULL in case of failure.
+ */
+struct apu_core *apu_core_alloc(struct apu_drm *apu, struct apu_core_ops *ops,
+ void *priv)
+{
+ struct apu_core *core;
+
+ if (!ops || !ops->is_ready)
+ return NULL;
+
+ core = devm_kzalloc(apu->dev, sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return NULL;
+
+ core->device_id = ida_alloc(&apu->ida, GFP_KERNEL);
+ if (core->device_id < 0)
+ return NULL;
+
+ core->apu = apu;
+ core->priv = priv;
+ core->ops = ops;
+
+ list_add(&core->node, &apu->cores);
+
+ return core;
+}
+EXPORT_SYMBOL_GPL(apu_core_alloc);
+
+/**
+ * apu_core_free() - Free an APU core allocated using apu_core_alloc()
+ *
+ * @core: The APU core to release
+ */
+void apu_core_free(struct apu_core *core)
+{
+ ida_free(&core->apu->ida, core->device_id);
+ list_del(&core->node);
+}
+EXPORT_SYMBOL_GPL(apu_core_free);
+
+/**
+ * apu_core_register() - Register a core to APU device
+ *
+ * @dev: Pointer to APU device
+ * @core: Pointer to APU core to register
+ * @priv: Private data attached to this core
+ *
+ * Register an APU core and make it available for computing.
+ * On success, userspace can start using this core.
+ *
+ * Returns: Zero on success, non-zero value on failure.
+ */
+int apu_core_register(struct device *dev, struct apu_core *core, void *priv)
+{
+ int ret;
+
+ core->dev_priv = priv;
+ core->dev = dev;
+
+ if (core->ops->register_core) {
+ ret = core->ops->register_core(core);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apu_core_register);
+
+/**
+ * apu_core_remove() - Remove a core from the APU device
+ *
+ * @core: Pointer to APU core to remove
+ */
+void apu_core_remove(struct apu_core *core)
+{
+ core->dev_priv = NULL;
+}
+EXPORT_SYMBOL_GPL(apu_core_remove);
+
+/**
+ * apu_find_core_by_priv() - Find a core allocated by apu_core_alloc()
+ *
+ * @priv: The pointer used to allocate the core
+ *
+ * All core allocated using apu_core_alloc() is registered to a list.
+ * This goes through the list to find the core using the @priv field.
+ *
+ * Returns: A pointer or NULL if no core has been found.
+ */
+struct apu_core *apu_find_core_by_priv(void *priv)
+{
+ struct apu_drm *apu;
+ struct apu_core *core;
+
+ list_for_each_entry(apu, &apu_devices, node) {
+ list_for_each_entry(core, &apu->cores, node) {
+ if (core->priv == priv)
+ return core;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(apu_find_core_by_priv);
+
+static struct apu_core *get_apu_core(struct apu_drm *apu, int device_id)
+{
+ struct apu_core *core;
+
+ list_for_each_entry(core, &apu->cores, node) {
+ if (core->device_id == device_id)
+ return core;
+ }
+
+ return NULL;
+}
+
+static void apu_core_update_state(struct apu_core *core)
+{
+ if (!core->ops->is_ready(core))
+ core->flags &= ~APU_ONLINE;
+}
+
+static int ioctl_apu_state(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct apu_drm *apu = dev->dev_private;
+ struct drm_apu_state *args = data;
+ struct apu_core *core;
+
+ args->flags = 0;
+
+ core = get_apu_core(apu, args->device);
+ if (!core)
+ return -ENODEV;
+
+ apu_core_update_state(core);
+ args->flags |= core->flags;
+
+ return 0;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexandre Bailon");
diff --git a/drivers/gpu/drm/apu/apu_internal.h b/drivers/gpu/drm/apu/apu_internal.h
new file mode 100644
index 000000000000..58d93a16c68f
--- /dev/null
+++ b/drivers/gpu/drm/apu/apu_internal.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __APU_INTERNAL_H__
+#define __APU_INTERNAL_H__
+
+#include <drm/drm_drv.h>
+
+struct apu_core {
+ int device_id;
+ struct device *dev;
+ struct apu_core_ops *ops;
+ struct apu_drm *apu;
+
+ struct list_head node;
+ void *priv;
+ void *dev_priv;
+
+ u32 flags;
+};
+
+struct apu_drm {
+ struct drm_device base;
+ struct device *dev;
+
+ struct list_head cores;
+ struct list_head node;
+
+ struct ida ida;
+};
+
+/**
+ * @apu_core_ops: Provides platform specific callbacks
+ */
+struct apu_core_ops {
+ /**
+ * @register_core:
+ *
+ * Optional. Platform specific APU core registration.
+ */
+ int (*register_core)(struct apu_core *core);
+
+ /**
+ * @is_ready:
+ *
+ * Implements platform specific code to test if APU is ready to receive
+ * commands.
+ * Basically, an APU core may be running but not be ready to handle
+ * commands. This allows checking if APU is ready and start executing
+ * requests.
+ *
+ * Returns:
+ *
+ * One if the APU is ready or zero.
+ */
+ int (*is_ready)(struct apu_core *core);
+};
+
+struct apu_drm *apu_dev_alloc(struct device *dev);
+int apu_dev_register(struct apu_drm *apu);
+void apu_dev_unregister(struct apu_drm *apu);
+
+struct apu_core *apu_core_alloc(struct apu_drm *apu, struct apu_core_ops *ops,
+ void *priv);
+void apu_core_free(struct apu_core *core);
+int apu_core_register(struct device *dev, struct apu_core *core, void *priv);
+void apu_core_remove(struct apu_core *core);
+struct apu_core *apu_find_core_by_priv(void *priv);
+
+#endif /* __APU_INTERNAL_H__ */
diff --git a/include/uapi/drm/apu_drm.h b/include/uapi/drm/apu_drm.h
new file mode 100644
index 000000000000..d50c63d1b813
--- /dev/null
+++ b/include/uapi/drm/apu_drm.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note*/
+
+#ifndef __UAPI_APU_DRM_H__
+#define __UAPI_APU_DRM_H__
+
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define APU_ONLINE BIT(0)
+
+struct drm_apu_state {
+ __u32 device;
+ __u32 flags;
+};
+
+#define DRM_APU_STATE 0x00
+#define DRM_APU_NUM_IOCTLS 0x01
+
+#define DRM_IOCTL_APU_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_APU_STATE, struct drm_apu_state)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __UAPI_APU_DRM_H__ */
--
2.39.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2023-05-17 16:00 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-17 14:52 [PATCH 0/7] Add a DRM driver to support AI Processing Unit (APU) Alexandre Bailon
2023-05-17 14:52 ` Alexandre Bailon [this message]
2023-05-17 14:52 ` [PATCH 2/7] drm/apu: Add memory allocator Alexandre Bailon
2023-05-17 14:52 ` [PATCH 3/7] drm/apu: Add support of requests Alexandre Bailon
2023-05-17 14:52 ` [PATCH 4/7] drm/apu: Add support of IOMMU Alexandre Bailon
2023-05-18 13:24 ` Robin Murphy
2023-05-17 14:52 ` [PATCH 5/7] drm/apu: allow platform driver to implement their own mmap function Alexandre Bailon
2023-05-17 19:45 ` Krzysztof Kozlowski
2023-05-26 15:08 ` Alexandre Bailon
2023-05-17 14:52 ` [PATCH 6/7] drm/apu: Add support for a simulated APU Alexandre Bailon
2023-05-17 14:52 ` [PATCH 7/7] dt-bindings: Add bidings for mtk,apu-drm Alexandre Bailon
2023-05-17 15:04 ` AngeloGioacchino Del Regno
2023-05-17 17:28 ` Conor Dooley
2023-05-22 8:53 ` Alexandre Bailon
2023-05-17 15:28 ` Rob Herring
2023-05-17 16:53 ` Krzysztof Kozlowski
2023-05-17 19:38 ` Krzysztof Kozlowski
2023-05-17 19:41 ` Krzysztof Kozlowski
2023-05-17 15:05 ` [PATCH 0/7] Add a DRM driver to support AI Processing Unit (APU) Thomas Zimmermann
2023-05-17 15:12 ` Jeffrey Hugo
2023-05-23 23:34 ` Kevin Hilman
2023-05-24 10:27 ` Oded Gabbay
2023-05-24 10:40 ` Daniel Vetter
2023-05-26 15:45 ` Alexandre Bailon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230517145237.295461-2-abailon@baylibre.com \
--to=abailon@baylibre.com \
--cc=airlied@gmail.com \
--cc=angelogioacchino.delregno@collabora.com \
--cc=bero@baylibre.com \
--cc=christian.koenig@amd.com \
--cc=conor+dt@kernel.org \
--cc=daniel@ffwll.ch \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=jstephan@baylibre.com \
--cc=khilman@baylibre.com \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=matthias.bgg@gmail.com \
--cc=mripard@kernel.org \
--cc=nbelin@baylibre.com \
--cc=robh+dt@kernel.org \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).