2023-11-29 22:03:05

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 0/8] drm/etnaviv: Add PCI(e) device driver wrapper and instances

This series is add PCI device driver wrapper, to support the Vivante GC1000
GPU in LS2K1000 and LS7A1000.

The whole serie have been tested on X86-64 and LoongArch platform, only the
kernel space driver are tested, basically normal and run stable!

v6:
* Fix build issue on system without CONFIG_PCI enabled
v7:
* Add a separate patch for the platform driver rearrangement (Bjorn)
* Switch to runtime check if the GPU is dma coherent or not (Lucas)
* Add ETNAVIV_PARAM_GPU_COHERENT to allow userspace to query (Lucas)
* Remove etnaviv_gpu.no_clk member (Lucas)
* Various Typos and coding style fixed (Bjorn)
v8:
* Fix typos and remove unnecessary header included (Bjorn).
* Add a dedicated function to create the virtual master platform
device.
v9:
* Use PCI_VDEVICE() macro (Bjorn)
* Add trivial stubs for the PCI driver (Bjorn)
* Remove a redundant dev_err() usage (Bjorn)
* Clean up etnaviv_pdev_probe() with etnaviv_of_first_available_node()
v10:
* Add one more cleanup patch
* Resolve the conflict with a patch from Rob
* Make the dummy PCI stub inlined
* Print only if the platform is dma-coherrent
V11:
* Drop unnecessary changes (Lucas)
* Tweak according to other reviews of v10.

V12:
* Create a virtual platform device for the subcomponent GPU cores
* Bind all subordinate GPU cores to the real PCI master via component.

Sui Jingfeng (8):
drm/etnaviv: Add a helper function to get clocks
drm/etnaviv: Add constructor and destructor for struct
etnaviv_drm_private
drm/etnaviv: Allow bypass component framework
drm/etnaviv: Support for the vivante GPU core attached on PCI(e)
device
drm/etnaviv: Add support for cached coherent caching mode
drm/etnaviv: Embed struct drm_device in struct etnaviv_drm_private
drm/etnaviv: Add support for the JingJia Macro and LingJiu PCI(e) GPUs
drm/etnaviv: Support binding multiple GPU cores with component

drivers/gpu/drm/etnaviv/Kconfig | 8 +
drivers/gpu/drm/etnaviv/Makefile | 2 +
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 189 ++++++++-----
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 27 ++
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 22 +-
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +-
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 187 +++++++++----
drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 10 +
drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 4 +-
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 279 +++++++++++++++++++
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h | 37 +++
include/uapi/drm/etnaviv_drm.h | 1 +
12 files changed, 639 insertions(+), 129 deletions(-)
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h


base-commit: 5ce7ae0a6faece18d91ce807026197cface429db
--
2.34.1


2023-11-29 22:03:13

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 1/8] drm/etnaviv: Add a helper function to get clocks

From: Sui Jingfeng <[email protected]>

Because the current implement is DT-based, this is only works when the host
platform has the DT support. Typically, the PLL hardwares are provided by
the host platform, not the GPU core itself. So add a dedicated helper
function to get clocks, only call this function when DT is available.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 53 ++++++++++++++++-----------
1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 3e35e7db5177..4d5819632597 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1597,6 +1597,35 @@ static irqreturn_t irq_handler(int irq, void *data)
return ret;
}

+static int etnaviv_gpu_clk_get(struct etnaviv_gpu *gpu)
+{
+ struct device *dev = gpu->dev;
+
+ gpu->clk_reg = devm_clk_get_optional(dev, "reg");
+ DBG("clk_reg: %p", gpu->clk_reg);
+ if (IS_ERR(gpu->clk_reg))
+ return PTR_ERR(gpu->clk_reg);
+
+ gpu->clk_bus = devm_clk_get_optional(dev, "bus");
+ DBG("clk_bus: %p", gpu->clk_bus);
+ if (IS_ERR(gpu->clk_bus))
+ return PTR_ERR(gpu->clk_bus);
+
+ gpu->clk_core = devm_clk_get(dev, "core");
+ DBG("clk_core: %p", gpu->clk_core);
+ if (IS_ERR(gpu->clk_core))
+ return PTR_ERR(gpu->clk_core);
+ gpu->base_rate_core = clk_get_rate(gpu->clk_core);
+
+ gpu->clk_shader = devm_clk_get_optional(dev, "shader");
+ DBG("clk_shader: %p", gpu->clk_shader);
+ if (IS_ERR(gpu->clk_shader))
+ return PTR_ERR(gpu->clk_shader);
+ gpu->base_rate_shader = clk_get_rate(gpu->clk_shader);
+
+ return 0;
+}
+
static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu)
{
int ret;
@@ -1872,27 +1901,9 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
}

/* Get Clocks: */
- gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg");
- DBG("clk_reg: %p", gpu->clk_reg);
- if (IS_ERR(gpu->clk_reg))
- return PTR_ERR(gpu->clk_reg);
-
- gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus");
- DBG("clk_bus: %p", gpu->clk_bus);
- if (IS_ERR(gpu->clk_bus))
- return PTR_ERR(gpu->clk_bus);
-
- gpu->clk_core = devm_clk_get(&pdev->dev, "core");
- DBG("clk_core: %p", gpu->clk_core);
- if (IS_ERR(gpu->clk_core))
- return PTR_ERR(gpu->clk_core);
- gpu->base_rate_core = clk_get_rate(gpu->clk_core);
-
- gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader");
- DBG("clk_shader: %p", gpu->clk_shader);
- if (IS_ERR(gpu->clk_shader))
- return PTR_ERR(gpu->clk_shader);
- gpu->base_rate_shader = clk_get_rate(gpu->clk_shader);
+ err = etnaviv_gpu_clk_get(gpu);
+ if (err)
+ return err;

/* TODO: figure out max mapped size */
dev_set_drvdata(dev, gpu);
--
2.34.1

2023-11-29 22:03:44

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 2/8] drm/etnaviv: Add constructor and destructor for struct etnaviv_drm_private

From: Sui Jingfeng <[email protected]>

Noticed that there are a lot of members in the struct etnaviv_drm_private,
which are intended to be shared by all GPU cores. Introduces two helpers
for construction and destruction purpose for it. The benefit is that error
handling get simplified a lot.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 70 +++++++++++++++++----------
1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index a9a1659840ec..41ef7a8b7839 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,6 +41,43 @@ static struct device_node *etnaviv_of_first_available_node(void)
return NULL;
}

+static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)
+{
+ struct etnaviv_drm_private *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+
+ xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
+
+ mutex_init(&priv->gem_lock);
+ INIT_LIST_HEAD(&priv->gem_list);
+ priv->num_gpus = 0;
+ priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
+
+ priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(dev);
+ if (IS_ERR(priv->cmdbuf_suballoc)) {
+ kfree(priv);
+ dev_err(dev, "Failed to create cmdbuf suballocator\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return priv;
+}
+
+static void etnaviv_free_private(struct etnaviv_drm_private *priv)
+{
+ if (!priv)
+ return;
+
+ etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
+
+ xa_destroy(&priv->active_contexts);
+
+ kfree(priv);
+}
+
static void load_gpu(struct drm_device *dev)
{
struct etnaviv_drm_private *priv = dev->dev_private;
@@ -521,35 +558,21 @@ static int etnaviv_bind(struct device *dev)
if (IS_ERR(drm))
return PTR_ERR(drm);

- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "failed to allocate private data\n");
- ret = -ENOMEM;
+ priv = etnaviv_alloc_private(dev);
+ if (IS_ERR(priv)) {
+ ret = PTR_ERR(priv);
goto out_put;
}
+
drm->dev_private = priv;

dma_set_max_seg_size(dev, SZ_2G);

- xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
-
- mutex_init(&priv->gem_lock);
- INIT_LIST_HEAD(&priv->gem_list);
- priv->num_gpus = 0;
- priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
-
- priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);
- if (IS_ERR(priv->cmdbuf_suballoc)) {
- dev_err(drm->dev, "Failed to create cmdbuf suballocator\n");
- ret = PTR_ERR(priv->cmdbuf_suballoc);
- goto out_free_priv;
- }
-
dev_set_drvdata(dev, drm);

ret = component_bind_all(dev, drm);
if (ret < 0)
- goto out_destroy_suballoc;
+ goto out_free_priv;

load_gpu(drm);

@@ -561,10 +584,8 @@ static int etnaviv_bind(struct device *dev)

out_unbind:
component_unbind_all(dev, drm);
-out_destroy_suballoc:
- etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
out_free_priv:
- kfree(priv);
+ etnaviv_free_private(priv);
out_put:
drm_dev_put(drm);

@@ -580,12 +601,9 @@ static void etnaviv_unbind(struct device *dev)

component_unbind_all(dev, drm);

- etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
-
- xa_destroy(&priv->active_contexts);
+ etnaviv_free_private(priv);

drm->dev_private = NULL;
- kfree(priv);

drm_dev_put(drm);
}
--
2.34.1

2023-11-29 22:03:58

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 4/8] drm/etnaviv: Support for the vivante GPU core attached on PCI(e) device

From: Sui Jingfeng <[email protected]>

There is a Vivante GC1000 GPU (v5037) in Loongson LS2K1000 (0x0014:0x7a05)
and LS7A1000 (0x0014:0x7a15), the GPU in these chips is a PCI(e) device,
has only one core with both the 3D pipe and 2D pipe. This patch adds PCI
driver wrapper on the top of what drm/etnaviv already have, since this GPU
has only one GPU core, there no need to bind to anything for now. Hence,
the component framework get bypassed.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/Kconfig | 8 +++
drivers/gpu/drm/etnaviv/Makefile | 2 +
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 ++-
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 3 +
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 74 +++++++++++++++++++++++
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h | 18 ++++++
6 files changed, 113 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h

diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig
index faa7fc68b009..38c251585ec1 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -15,6 +15,14 @@ config DRM_ETNAVIV
help
DRM driver for Vivante GPUs.

+config DRM_ETNAVIV_PCI_DRIVER
+ bool "enable ETNAVIV PCI driver support"
+ depends on DRM_ETNAVIV
+ depends on PCI
+ help
+ Compile in support for Vivante GPUs attached via PCI(e).
+ Say Y if you have such hardwares.
+
config DRM_ETNAVIV_THERMAL
bool "enable ETNAVIV thermal throttling"
depends on DRM_ETNAVIV
diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 46e5ffad69a6..6829e1ebf2db 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -16,4 +16,6 @@ etnaviv-y := \
etnaviv_perfmon.o \
etnaviv_sched.o

+etnaviv-$(CONFIG_DRM_ETNAVIV_PCI_DRIVER) += etnaviv_pci_drv.o
+
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 0b68c76d117e..8db86120b11d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -23,6 +23,7 @@
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
+#include "etnaviv_pci_drv.h"
#include "etnaviv_perfmon.h"

static struct etnaviv_drm_private *etna_drm_priv_ptr;
@@ -547,7 +548,7 @@ static const struct drm_driver etnaviv_drm_driver = {
.minor = 3,
};

-static int etnaviv_drm_bind(struct device *dev, bool component)
+int etnaviv_drm_bind(struct device *dev, bool component)
{
struct etnaviv_drm_private *priv;
struct drm_device *drm;
@@ -598,7 +599,7 @@ static int etnaviv_drm_bind(struct device *dev, bool component)
return ret;
}

-static void etnaviv_drm_unbind(struct device *dev, bool component)
+void etnaviv_drm_unbind(struct device *dev, bool component)
{
struct etnaviv_drm_private *priv = etna_drm_priv_ptr;
struct drm_device *drm = priv->drm;
@@ -758,6 +759,10 @@ static int __init etnaviv_init(void)
if (ret != 0)
goto unregister_gpu_driver;

+ ret = etnaviv_register_pci_driver();
+ if (ret != 0)
+ goto unregister_platform_driver;
+
/*
* If the DT contains at least one available GPU device, instantiate
* the DRM platform device.
@@ -786,6 +791,7 @@ static void __exit etnaviv_exit(void)
etnaviv_destroy_platform_device(&etnaviv_drm);
platform_driver_unregister(&etnaviv_platform_driver);
platform_driver_unregister(&etnaviv_gpu_driver);
+ etnaviv_unregister_pci_driver();
}
module_exit(etnaviv_exit);

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index e58f82e698de..9cd72948cfad 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -83,6 +83,9 @@ bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
u32 *stream, unsigned int size,
struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);

+int etnaviv_drm_bind(struct device *dev, bool component);
+void etnaviv_drm_unbind(struct device *dev, bool component);
+
#ifdef CONFIG_DEBUG_FS
void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
struct seq_file *m);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
new file mode 100644
index 000000000000..37de661844d8
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/pci.h>
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gpu.h"
+#include "etnaviv_pci_drv.h"
+
+static int etnaviv_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ void __iomem *mmio;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ dev_err(dev, "failed to enable\n");
+ return ret;
+ }
+
+ pci_set_master(pdev);
+
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ /* PCI bar 0 contain the MMIO registers */
+ mmio = pcim_iomap(pdev, 0, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ ret = etnaviv_gpu_driver_create(dev, mmio, pdev->irq, false, false);
+ if (ret)
+ return ret;
+
+ return etnaviv_drm_bind(dev, false);
+}
+
+static void etnaviv_pci_remove(struct pci_dev *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ etnaviv_drm_unbind(dev, false);
+
+ etnaviv_gpu_driver_destroy(dev, false);
+
+ pci_clear_master(pdev);
+}
+
+static const struct pci_device_id etnaviv_pci_id_lists[] = {
+ {PCI_VDEVICE(LOONGSON, 0x7a15)},
+ {PCI_VDEVICE(LOONGSON, 0x7a05)},
+ { }
+};
+
+static struct pci_driver etnaviv_pci_driver = {
+ .name = "etnaviv",
+ .id_table = etnaviv_pci_id_lists,
+ .probe = etnaviv_pci_probe,
+ .remove = etnaviv_pci_remove,
+};
+
+int etnaviv_register_pci_driver(void)
+{
+ return pci_register_driver(&etnaviv_pci_driver);
+}
+
+void etnaviv_unregister_pci_driver(void)
+{
+ pci_unregister_driver(&etnaviv_pci_driver);
+}
+
+MODULE_DEVICE_TABLE(pci, etnaviv_pci_id_lists);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
new file mode 100644
index 000000000000..1db559ee5e9b
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ETNAVIV_PCI_DRV_H__
+#define __ETNAVIV_PCI_DRV_H__
+
+#ifdef CONFIG_DRM_ETNAVIV_PCI_DRIVER
+
+int etnaviv_register_pci_driver(void);
+void etnaviv_unregister_pci_driver(void);
+
+#else
+
+static inline int etnaviv_register_pci_driver(void) { return 0; }
+static inline void etnaviv_unregister_pci_driver(void) { }
+
+#endif
+
+#endif
--
2.34.1

2023-11-29 22:04:00

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 5/8] drm/etnaviv: Add support for cached coherent caching mode

From: Sui Jingfeng <[email protected]>

Modern Loongson CPUs choose to define the peripheral devices as DMA
coherent by default, to be specific, the peripheral devices are capable
of snooping CPU's cache. This means that device drivers do not need to
manually maintain the coherency issue between a processor and an I/O
for the cached mappings. Because such hardware features are host platform
specific and vivante GPU IP has been integrated into different platform,
probe the features before using is necessary. Therefore, Do the probe with
the dev_is_dma_coherent() function and allow userspace to query.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 3 +++
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 9 +++++++++
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 16 ++++++++++++++--
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 4 ++++
include/uapi/drm/etnaviv_drm.h | 1 +
5 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 8db86120b11d..883352aded32 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -5,6 +5,7 @@

#include <linux/component.h>
#include <linux/dma-mapping.h>
+#include <linux/dma-map-ops.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -66,6 +67,8 @@ static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)
return ERR_PTR(-ENOMEM);
}

+ priv->cached_coherent = dev_is_dma_coherent(dev);
+
return priv;
}

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 9cd72948cfad..acc2e77ad2db 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -46,6 +46,15 @@ struct etnaviv_drm_private {
struct xarray active_contexts;
u32 next_context_id;

+ /*
+ * If true, the cached mapping is consistent for all CPU cores and
+ * bus masters(refer to GPU cores here) in the system. It means that
+ * both of the CPU and GPU will see the same data if the buffer being
+ * access is cached. And this coherency is guaranteed by host platform
+ * specific hardware, not maintained by software.
+ */
+ bool cached_coherent;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 71a6d2b1c80f..a72ca0a6883e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -342,6 +342,7 @@ void *etnaviv_gem_vmap(struct drm_gem_object *obj)
static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj)
{
struct page **pages;
+ pgprot_t prot;

lockdep_assert_held(&obj->lock);

@@ -349,8 +350,19 @@ static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj)
if (IS_ERR(pages))
return NULL;

- return vmap(pages, obj->base.size >> PAGE_SHIFT,
- VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+ switch (obj->flags) {
+ case ETNA_BO_CACHED:
+ prot = PAGE_KERNEL;
+ break;
+ case ETNA_BO_UNCACHED:
+ prot = pgprot_noncached(PAGE_KERNEL);
+ break;
+ case ETNA_BO_WC:
+ default:
+ prot = pgprot_writecombine(PAGE_KERNEL);
+ }
+
+ return vmap(pages, obj->base.size >> PAGE_SHIFT, VM_MAP, prot);
}

static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 9db0fbfaf41a..c5a6d5809e2b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -164,6 +164,10 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
*value = gpu->identity.eco_id;
break;

+ case ETNAVIV_PARAM_CACHED_COHERENT:
+ *value = priv->cached_coherent;
+ break;
+
default:
DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
return -EINVAL;
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index af024d90453d..61eaa8cd0f5e 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -77,6 +77,7 @@ struct drm_etnaviv_timespec {
#define ETNAVIV_PARAM_GPU_PRODUCT_ID 0x1c
#define ETNAVIV_PARAM_GPU_CUSTOMER_ID 0x1d
#define ETNAVIV_PARAM_GPU_ECO_ID 0x1e
+#define ETNAVIV_PARAM_CACHED_COHERENT 0x1f

#define ETNA_MAX_PIPES 4

--
2.34.1

2023-11-29 22:04:01

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 7/8] drm/etnaviv: Add support for the JingJia Macro and LingJiu PCI(e) GPUs

Tested on X86-64 with JM9100 GPU, the JM9100 discrete GPU has only one
vivante GPU found so far.

$ sudo dmesg | grep etnaviv

etnaviv 0000:0d:00.0: enabling device (0000 -> 0003)
etnaviv 0000:0d:00.0: Unbalanced pm_runtime_enable!
etnaviv 0000:0d:00.0: model: GC9200, revision: 6304
[drm] Initialized etnaviv 1.3.0 20151214 for 0000:0d:00.0 on minor 0

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 112 +++++++++++++++++++++-
1 file changed, 109 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
index 37de661844d8..b55ee6dd723e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -6,10 +6,109 @@
#include "etnaviv_gpu.h"
#include "etnaviv_pci_drv.h"

+enum etnaviv_pci_gpu_chip_id {
+ GC_CORE_UNKNOWN = 0,
+ JM9100 = 1,
+ JD9230P = 2,
+ LINGJIU_GP102 = 3,
+ GC1000_IN_LS7A1000 = 4,
+ GC1000_IN_LS2K1000 = 5,
+ GC_CORE_PCI_LAST,
+};
+
+struct etnaviv_pci_gpu_platform_data {
+ enum etnaviv_pci_gpu_chip_id chip_id;
+ u32 num_core;
+ u32 num_vram;
+ u32 vram_bars[2];
+ u32 mmio_bar;
+ struct {
+ u32 id;
+ u32 offset;
+ u32 size;
+ char name[20];
+ } cores[ETNA_MAX_PIPES];
+
+ bool has_dedicated_vram;
+ bool no_clk;
+ bool share_irq;
+ char name[24];
+};
+
+static const struct etnaviv_pci_gpu_platform_data
+gc_core_plaform_data[GC_CORE_PCI_LAST] = {
+ {
+ .chip_id = GC_CORE_UNKNOWN,
+ },
+ {
+ .chip_id = JM9100,
+ .num_core = 1,
+ .num_vram = 2,
+ .vram_bars = {0, 2},
+ .mmio_bar = 1,
+ .cores = {{0, 0x00900000, 0x00010000, "etnaviv-gpu,3d"},},
+ .has_dedicated_vram = true,
+ .no_clk = true,
+ .share_irq = true,
+ .name = "JingJia Micro JM9100",
+ },
+ {
+ .chip_id = JD9230P,
+ .num_core = 2,
+ .num_vram = 2,
+ .vram_bars = {0, 2},
+ .mmio_bar = 1,
+ .cores = {{0, 0x00900000, 0x00010000, "etnaviv-gpu,3d"},
+ {1, 0x00910000, 0x00010000, "etnaviv-gpu,3d"},},
+ .has_dedicated_vram = true,
+ .no_clk = true,
+ .share_irq = true,
+ .name = "JingJia Micro JD9230P",
+ },
+ {
+ .chip_id = LINGJIU_GP102,
+ .num_core = 2,
+ .num_vram = 1,
+ .vram_bars = {0,},
+ .mmio_bar = 2,
+ .cores = {{0, 0x00040000, 0x00010000, "etnaviv-gpu,3d"},
+ {0, 0x000C0000, 0x00010000, "etnaviv-gpu,2d"},},
+ .has_dedicated_vram = true,
+ .no_clk = true,
+ .share_irq = true,
+ .name = "LingJiu GP102",
+ },
+ {
+ .chip_id = GC1000_IN_LS7A1000,
+ .num_core = 1,
+ .num_vram = 1,
+ .vram_bars = {2, 0},
+ .mmio_bar = 0,
+ .cores = {{0, 0, 0, "etnaviv-gpu,3d"}, {}, {}, {}},
+ .has_dedicated_vram = true,
+ .no_clk = true,
+ .share_irq = true,
+ .name = "GC1000 in LS7A1000",
+ },
+ {
+ .chip_id = GC1000_IN_LS2K1000,
+ .num_core = 1,
+ .num_vram = 0,
+ .mmio_bar = 0,
+ .cores = {{0, 0, 0, "etnaviv-gpu,3d"}, {}, {}, {}},
+ .has_dedicated_vram = false,
+ .no_clk = true,
+ .share_irq = true,
+ .name = "GC1000 in LS2K1000",
+ },
+};
+
static int etnaviv_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ enum etnaviv_pci_gpu_chip_id chip_id = ent->driver_data;
struct device *dev = &pdev->dev;
+ const struct etnaviv_pci_gpu_platform_data *pdata;
void __iomem *mmio;
int ret;

@@ -25,11 +124,15 @@ static int etnaviv_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;

+ pdata = &gc_core_plaform_data[chip_id];
+
/* PCI bar 0 contain the MMIO registers */
- mmio = pcim_iomap(pdev, 0, 0);
+ mmio = pcim_iomap(pdev, pdata->mmio_bar, 0);
if (IS_ERR(mmio))
return PTR_ERR(mmio);

+ mmio += pdata->cores[0].offset;
+
ret = etnaviv_gpu_driver_create(dev, mmio, pdev->irq, false, false);
if (ret)
return ret;
@@ -49,8 +152,11 @@ static void etnaviv_pci_remove(struct pci_dev *pdev)
}

static const struct pci_device_id etnaviv_pci_id_lists[] = {
- {PCI_VDEVICE(LOONGSON, 0x7a15)},
- {PCI_VDEVICE(LOONGSON, 0x7a05)},
+ {0x0731, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, JM9100},
+ {0x0731, 0x9230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, JD9230P},
+ {0x0709, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LINGJIU_GP102},
+ {PCI_VDEVICE(LOONGSON, 0x7a15), GC1000_IN_LS7A1000},
+ {PCI_VDEVICE(LOONGSON, 0x7a05), GC1000_IN_LS2K1000},
{ }
};

--
2.34.1

2023-11-29 22:04:05

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 6/8] drm/etnaviv: Embed struct drm_device in struct etnaviv_drm_private

From: Sui Jingfeng <[email protected]>

The instance of struct drm_device and struct etnaviv_drm_private are
intended to be shared by all GPU cores. Embedding struct drm_device into
struct etnaviv_drm_private allow us to allocate storage for them togather.
And use container_of() to retrieve pointer for the containing structure.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 73 +++++++++-----------
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 8 ++-
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +-
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 2 +-
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 6 +-
drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 4 +-
6 files changed, 47 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 883352aded32..4a7a451237d5 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -45,14 +45,9 @@ static struct device_node *etnaviv_of_first_available_node(void)
return NULL;
}

-static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)
+static int etnaviv_private_init(struct device *dev,
+ struct etnaviv_drm_private *priv)
{
- struct etnaviv_drm_private *priv;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return ERR_PTR(-ENOMEM);
-
xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);

mutex_init(&priv->gem_lock);
@@ -62,17 +57,16 @@ static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)

priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(dev);
if (IS_ERR(priv->cmdbuf_suballoc)) {
- kfree(priv);
dev_err(dev, "Failed to create cmdbuf suballocator\n");
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}

priv->cached_coherent = dev_is_dma_coherent(dev);

- return priv;
+ return 0;
}

-static void etnaviv_free_private(struct etnaviv_drm_private *priv)
+static void etnaviv_private_fini(struct etnaviv_drm_private *priv)
{
if (!priv)
return;
@@ -80,13 +74,11 @@ static void etnaviv_free_private(struct etnaviv_drm_private *priv)
etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);

xa_destroy(&priv->active_contexts);
-
- kfree(priv);
}

static void load_gpu(struct drm_device *dev)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
unsigned int i;

for (i = 0; i < ETNA_MAX_PIPES; i++) {
@@ -104,7 +96,7 @@ static void load_gpu(struct drm_device *dev)

static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct etnaviv_file_private *ctx;
int ret, i;

@@ -147,7 +139,7 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file)

static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct etnaviv_file_private *ctx = file->driver_priv;
unsigned int i;

@@ -172,7 +164,7 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
#ifdef CONFIG_DEBUG_FS
static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);

etnaviv_gem_describe_objects(priv, m);

@@ -266,7 +258,7 @@ static int show_each_gpu(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct etnaviv_gpu *gpu;
int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) =
node->info_ent->data;
@@ -309,7 +301,7 @@ static void etnaviv_debugfs_init(struct drm_minor *minor)
static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data,
struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_param *args = data;
struct etnaviv_gpu *gpu;

@@ -402,7 +394,7 @@ static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_etnaviv_wait_fence *args = data;
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_timespec *timeout = &args->timeout;
struct etnaviv_gpu *gpu;

@@ -450,7 +442,7 @@ static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data,
static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_gem_wait *args = data;
struct drm_etnaviv_timespec *timeout = &args->timeout;
struct drm_gem_object *obj;
@@ -484,7 +476,7 @@ static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data,
static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_pm_domain *args = data;
struct etnaviv_gpu *gpu;

@@ -501,7 +493,7 @@ static int etnaviv_ioctl_pm_query_dom(struct drm_device *dev, void *data,
static int etnaviv_ioctl_pm_query_sig(struct drm_device *dev, void *data,
struct drm_file *file)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_pm_signal *args = data;
struct etnaviv_gpu *gpu;

@@ -557,20 +549,18 @@ int etnaviv_drm_bind(struct device *dev, bool component)
struct drm_device *drm;
int ret;

- drm = drm_dev_alloc(&etnaviv_drm_driver, dev);
- if (IS_ERR(drm))
- return PTR_ERR(drm);
+ priv = devm_drm_dev_alloc(dev, &etnaviv_drm_driver,
+ struct etnaviv_drm_private, drm);

- priv = etnaviv_alloc_private(dev);
- if (IS_ERR(priv)) {
- ret = PTR_ERR(priv);
- goto out_put;
- }
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ etnaviv_private_init(dev, priv);

- priv->drm = drm;
- drm->dev_private = priv;
etna_drm_priv_ptr = priv;

+ drm = &priv->drm;
+
dma_set_max_seg_size(dev, SZ_2G);

if (component)
@@ -595,9 +585,7 @@ int etnaviv_drm_bind(struct device *dev, bool component)
else
etnaviv_gpu_unbind(dev, NULL, drm);
out_free_priv:
- etnaviv_free_private(priv);
-out_put:
- drm_dev_put(drm);
+ etnaviv_private_fini(priv);

return ret;
}
@@ -605,7 +593,12 @@ int etnaviv_drm_bind(struct device *dev, bool component)
void etnaviv_drm_unbind(struct device *dev, bool component)
{
struct etnaviv_drm_private *priv = etna_drm_priv_ptr;
- struct drm_device *drm = priv->drm;
+ struct drm_device *drm;
+
+ if (!priv)
+ return;
+
+ drm = &priv->drm;

drm_dev_unregister(drm);

@@ -614,11 +607,7 @@ void etnaviv_drm_unbind(struct device *dev, bool component)
else
etnaviv_gpu_unbind(dev, NULL, drm);

- etnaviv_free_private(priv);
-
- drm->dev_private = NULL;
-
- drm_dev_put(drm);
+ etnaviv_private_fini(priv);
}

/*
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index acc2e77ad2db..6c9d934cbcbd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -35,7 +35,7 @@ struct etnaviv_file_private {
};

struct etnaviv_drm_private {
- struct drm_device *drm;
+ struct drm_device drm;
int num_gpus;
struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
gfp_t shm_gfp_mask;
@@ -60,6 +60,12 @@ struct etnaviv_drm_private {
struct list_head gem_list;
};

+static inline struct etnaviv_drm_private *
+to_etnaviv_priv(struct drm_device *ddev)
+{
+ return container_of(ddev, struct etnaviv_drm_private, drm);
+}
+
int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
struct drm_file *file);

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index a72ca0a6883e..eed98bb9e446 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -498,7 +498,7 @@ static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
void etnaviv_gem_free_object(struct drm_gem_object *obj)
{
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
- struct etnaviv_drm_private *priv = obj->dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(obj->dev);
struct etnaviv_vram_mapping *mapping, *tmp;

/* object should not be active */
@@ -529,7 +529,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)

void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);

mutex_lock(&priv->gem_lock);
@@ -596,7 +596,7 @@ static int etnaviv_gem_new_impl(struct drm_device *dev, u32 flags,
int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file,
u32 size, u32 flags, u32 *handle)
{
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_gem_object *obj = NULL;
int ret;

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 3d0f8d182506..6b40a39fb8cd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -413,7 +413,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct etnaviv_file_private *ctx = file->driver_priv;
- struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct drm_etnaviv_gem_submit *args = data;
struct drm_etnaviv_gem_submit_reloc *relocs;
struct drm_etnaviv_gem_submit_pmr *pmrs;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index c5a6d5809e2b..070650ac38ed 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -38,7 +38,7 @@ static const struct platform_device_id gpu_ids[] = {

int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
{
- struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(gpu->drm);

switch (param) {
case ETNAVIV_PARAM_GPU_MODEL:
@@ -785,7 +785,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)

int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
{
- struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(gpu->drm);
dma_addr_t cmdbuf_paddr;
int ret, i;

@@ -1774,7 +1774,7 @@ static const struct thermal_cooling_device_ops cooling_ops = {
int etnaviv_gpu_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
- struct etnaviv_drm_private *priv = drm->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(drm);
struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
int ret;

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 1661d589bf3e..c38272868328 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -490,7 +490,7 @@ void etnaviv_iommu_dump(struct etnaviv_iommu_context *context, void *buf)
int etnaviv_iommu_global_init(struct etnaviv_gpu *gpu)
{
enum etnaviv_iommu_version version = ETNAVIV_IOMMU_V1;
- struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(gpu->drm);
struct etnaviv_iommu_global *global;
struct device *dev = gpu->drm->dev;

@@ -550,7 +550,7 @@ int etnaviv_iommu_global_init(struct etnaviv_gpu *gpu)

void etnaviv_iommu_global_fini(struct etnaviv_gpu *gpu)
{
- struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+ struct etnaviv_drm_private *priv = to_etnaviv_priv(gpu->drm);
struct etnaviv_iommu_global *global = priv->mmu_global;

if (!global)
--
2.34.1

2023-11-29 22:04:07

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 3/8] drm/etnaviv: Allow bypass component framework

From: Sui Jingfeng <[email protected]>

The component helper is used to bind multiple GPU cores to a virtual
master platform device, but there are SoCs and/or chipsets that contain
only one GPU core. On such cases, component framework can be avoided.
The reason is that usperspace programs(such as X server and Mesa) will
search the PCIe device to open precedently. Creating a virtual master
device for PCI(e) GPUs is unnecessary and incurring troubles.

Add additional code paths to allow bypassing the component framework,
which pave the way for us to introduce the PCI device driver wrapper.
The goal is to share as much as possible between the PCI driver code path
and the platform driver code path. Platforms with a single GPU core could
also try non-component code path.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 48 +++++++++++-----
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 1 +
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 83 +++++++++++++++++----------
drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 7 +++
4 files changed, 96 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 41ef7a8b7839..0b68c76d117e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -25,6 +25,8 @@
#include "etnaviv_mmu.h"
#include "etnaviv_perfmon.h"

+static struct etnaviv_drm_private *etna_drm_priv_ptr;
+
/*
* DRM operations:
*/
@@ -545,10 +547,7 @@ static const struct drm_driver etnaviv_drm_driver = {
.minor = 3,
};

-/*
- * Platform driver:
- */
-static int etnaviv_bind(struct device *dev)
+static int etnaviv_drm_bind(struct device *dev, bool component)
{
struct etnaviv_drm_private *priv;
struct drm_device *drm;
@@ -564,13 +563,17 @@ static int etnaviv_bind(struct device *dev)
goto out_put;
}

+ priv->drm = drm;
drm->dev_private = priv;
+ etna_drm_priv_ptr = priv;

dma_set_max_seg_size(dev, SZ_2G);

- dev_set_drvdata(dev, drm);
+ if (component)
+ ret = component_bind_all(dev, drm);
+ else
+ ret = etnaviv_gpu_bind(dev, NULL, drm);

- ret = component_bind_all(dev, drm);
if (ret < 0)
goto out_free_priv;

@@ -583,7 +586,10 @@ static int etnaviv_bind(struct device *dev)
return 0;

out_unbind:
- component_unbind_all(dev, drm);
+ if (component)
+ component_unbind_all(dev, drm);
+ else
+ etnaviv_gpu_unbind(dev, NULL, drm);
out_free_priv:
etnaviv_free_private(priv);
out_put:
@@ -592,14 +598,17 @@ static int etnaviv_bind(struct device *dev)
return ret;
}

-static void etnaviv_unbind(struct device *dev)
+static void etnaviv_drm_unbind(struct device *dev, bool component)
{
- struct drm_device *drm = dev_get_drvdata(dev);
- struct etnaviv_drm_private *priv = drm->dev_private;
+ struct etnaviv_drm_private *priv = etna_drm_priv_ptr;
+ struct drm_device *drm = priv->drm;

drm_dev_unregister(drm);

- component_unbind_all(dev, drm);
+ if (component)
+ component_unbind_all(dev, drm);
+ else
+ etnaviv_gpu_unbind(dev, NULL, drm);

etnaviv_free_private(priv);

@@ -608,9 +617,22 @@ static void etnaviv_unbind(struct device *dev)
drm_dev_put(drm);
}

+/*
+ * Platform driver:
+ */
+static int etnaviv_master_bind(struct device *dev)
+{
+ return etnaviv_drm_bind(dev, true);
+}
+
+static void etnaviv_master_unbind(struct device *dev)
+{
+ return etnaviv_drm_unbind(dev, true);
+}
+
static const struct component_master_ops etnaviv_master_ops = {
- .bind = etnaviv_bind,
- .unbind = etnaviv_unbind,
+ .bind = etnaviv_master_bind,
+ .unbind = etnaviv_master_unbind,
};

static int etnaviv_pdev_probe(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index b3eb1662e90c..e58f82e698de 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -35,6 +35,7 @@ struct etnaviv_file_private {
};

struct etnaviv_drm_private {
+ struct drm_device *drm;
int num_gpus;
struct etnaviv_gpu *gpu[ETNA_MAX_PIPES];
gfp_t shm_gfp_mask;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 4d5819632597..9db0fbfaf41a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1767,8 +1767,7 @@ static const struct thermal_cooling_device_ops cooling_ops = {
.set_cur_state = etnaviv_gpu_cooling_set_cur_state,
};

-static int etnaviv_gpu_bind(struct device *dev, struct device *master,
- void *data)
+int etnaviv_gpu_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
struct etnaviv_drm_private *priv = drm->dev_private;
@@ -1823,8 +1822,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
return ret;
}

-static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
- void *data)
+void etnaviv_gpu_unbind(struct device *dev, struct device *master, void *data)
{
struct etnaviv_gpu *gpu = dev_get_drvdata(dev);

@@ -1869,9 +1867,9 @@ static const struct of_device_id etnaviv_gpu_match[] = {
};
MODULE_DEVICE_TABLE(of, etnaviv_gpu_match);

-static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
+int etnaviv_gpu_driver_create(struct device *dev, void __iomem *mmio,
+ int irq, bool component, bool has_clk)
{
- struct device *dev = &pdev->dev;
struct etnaviv_gpu *gpu;
int err;

@@ -1879,31 +1877,28 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
if (!gpu)
return -ENOMEM;

- gpu->dev = &pdev->dev;
+ gpu->dev = dev;
+ gpu->mmio = mmio;
mutex_init(&gpu->lock);
mutex_init(&gpu->sched_lock);

- /* Map registers: */
- gpu->mmio = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(gpu->mmio))
- return PTR_ERR(gpu->mmio);
-
/* Get Interrupt: */
- gpu->irq = platform_get_irq(pdev, 0);
+ gpu->irq = irq;
if (gpu->irq < 0)
return gpu->irq;

- err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
- dev_name(gpu->dev), gpu);
+ err = devm_request_irq(dev, irq, irq_handler, 0, dev_name(dev), gpu);
if (err) {
dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
return err;
}

/* Get Clocks: */
- err = etnaviv_gpu_clk_get(gpu);
- if (err)
- return err;
+ if (has_clk) {
+ err = etnaviv_gpu_clk_get(gpu);
+ if (err)
+ return err;
+ }

/* TODO: figure out max mapped size */
dev_set_drvdata(dev, gpu);
@@ -1913,24 +1908,27 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
* autosuspend delay is rather arbitary: no measurements have
* yet been performed to determine an appropriate value.
*/
- pm_runtime_use_autosuspend(gpu->dev);
- pm_runtime_set_autosuspend_delay(gpu->dev, 200);
- pm_runtime_enable(gpu->dev);
-
- err = component_add(&pdev->dev, &gpu_ops);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to register component: %d\n", err);
- return err;
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, 200);
+ pm_runtime_enable(dev);
+
+ if (component) {
+ err = component_add(dev, &gpu_ops);
+ if (err < 0) {
+ dev_err(dev, "failed to register component: %d\n", err);
+ return err;
+ }
}

return 0;
}

-static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
+void etnaviv_gpu_driver_destroy(struct device *dev, bool component)
{
- component_del(&pdev->dev, &gpu_ops);
- pm_runtime_disable(&pdev->dev);
- return 0;
+ if (component)
+ component_del(dev, &gpu_ops);
+
+ pm_runtime_disable(dev);
}

static int etnaviv_gpu_rpm_suspend(struct device *dev)
@@ -1984,6 +1982,31 @@ static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume, NULL)
};

+static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ void __iomem *mmio;
+ int irq;
+
+ /* Map registers: */
+ mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ irq = platform_get_irq(pdev, 0);
+
+ return etnaviv_gpu_driver_create(dev, mmio, irq, true, true);
+}
+
+static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ etnaviv_gpu_driver_destroy(dev, true);
+
+ return 0;
+}
+
struct platform_driver etnaviv_gpu_driver = {
.driver = {
.name = "etnaviv-gpu",
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 197e0037732e..407f3a501b17 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -215,6 +215,13 @@ void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch);

+int etnaviv_gpu_bind(struct device *dev, struct device *master, void *data);
+void etnaviv_gpu_unbind(struct device *dev, struct device *master, void *data);
+
+int etnaviv_gpu_driver_create(struct device *dev, void __iomem *mmio,
+ int irq, bool component, bool has_clk);
+void etnaviv_gpu_driver_destroy(struct device *dev, bool component);
+
extern struct platform_driver etnaviv_gpu_driver;

#endif /* __ETNAVIV_GPU_H__ */
--
2.34.1

2023-11-29 22:04:14

by Sui Jingfeng

[permalink] [raw]
Subject: [etnaviv-next v12 8/8] drm/etnaviv: Support binding multiple GPU cores with component

Because the JD9230P discrete GPU has two vivante 3D GPU (GC9200) cores,
the LingJiu GP102 discrete GPU has two separated GPU core (one is 3D and
another one is 2D). The etnaviv_create_platform_device() has been revised
to create a virtual platform device as the representation for the single
GPU core. All virtual gpu devices are bind to the real PCI master device
with the help of component.

Tested with LingJiu GP102 GPU:

etnaviv 0000:05:00.0: LingJiu GP102 has 2 GPU cores
etnaviv 0000:05:00.0: bound etnaviv-gpu,3d.0 (ops gpu_ops [etnaviv])
etnaviv 0000:05:00.0: bound etnaviv-gpu,2d.1 (ops gpu_ops [etnaviv])
etnaviv-gpu etnaviv-gpu,3d.0: model: GC860, revision: 4601
etnaviv-gpu etnaviv-gpu,2d.0: model: GC300, revision: 2000
[drm] Initialized etnaviv 1.3.0 20151214 for 0000:05:00.0 on minor 0

Tested with JEMO JD9230P GPU:

etnaviv 0000:05:00.0: JingJia Micro JD9230P has 2 GPU cores
etnaviv 0000:05:00.0: bound etnaviv-gpu,3d.0 (ops gpu_ops [etnaviv])
etnaviv 0000:05:00.0: bound etnaviv-gpu,3d.1 (ops gpu_ops [etnaviv])
etnaviv-gpu etnaviv-gpu,3d.0: model: GC9200, revision: 6304
etnaviv-gpu etnaviv-gpu,3d.1: model: GC9200, revision: 6304
[drm] Initialized etnaviv 1.3.0 20151214 for 0000:05:00.0 on minor 0

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 37 ++++++-
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 8 ++
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 53 ++++++++--
drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 3 +
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 117 ++++++++++++++++++++--
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h | 19 ++++
6 files changed, 212 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 4a7a451237d5..3652b3017c94 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -571,6 +571,10 @@ int etnaviv_drm_bind(struct device *dev, bool component)
if (ret < 0)
goto out_free_priv;

+ ret = etnaviv_register_irq_handler(dev, priv);
+ if (ret)
+ goto out_unbind;
+
load_gpu(drm);

ret = drm_dev_register(drm, 0);
@@ -623,7 +627,7 @@ static void etnaviv_master_unbind(struct device *dev)
return etnaviv_drm_unbind(dev, true);
}

-static const struct component_master_ops etnaviv_master_ops = {
+const struct component_master_ops etnaviv_master_ops = {
.bind = etnaviv_master_bind,
.unbind = etnaviv_master_unbind,
};
@@ -701,16 +705,36 @@ static struct platform_driver etnaviv_platform_driver = {
},
};

-static int etnaviv_create_platform_device(const char *name,
- struct platform_device **ppdev)
+int etnaviv_create_platform_device(struct device *parent,
+ const char *name, int id,
+ struct resource *pres,
+ void *data,
+ struct platform_device **ppdev)
{
struct platform_device *pdev;
int ret;

- pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
+ pdev = platform_device_alloc(name, id);
if (!pdev)
return -ENOMEM;

+ pdev->dev.parent = parent;
+
+ if (pres) {
+ ret = platform_device_add_resources(pdev, pres, 1);
+ if (ret) {
+ platform_device_put(pdev);
+ return ret;
+ }
+ }
+
+ if (data) {
+ void *pdata = kmalloc(sizeof(void *), GFP_KERNEL);
+
+ *(void **)pdata = data;
+ pdev->dev.platform_data = pdata;
+ }
+
ret = platform_device_add(pdev);
if (ret) {
platform_device_put(pdev);
@@ -763,7 +787,10 @@ static int __init etnaviv_init(void)
if (np) {
of_node_put(np);

- ret = etnaviv_create_platform_device("etnaviv", &etnaviv_drm);
+ ret = etnaviv_create_platform_device(NULL, "etnaviv",
+ PLATFORM_DEVID_NONE,
+ NULL, NULL,
+ &etnaviv_drm);
if (ret)
goto unregister_platform_driver;
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 6c9d934cbcbd..37e2e859856f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -9,6 +9,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/mm_types.h>
+#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/time64.h>
#include <linux/types.h>
@@ -98,8 +99,15 @@ bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
u32 *stream, unsigned int size,
struct drm_etnaviv_gem_submit_reloc *relocs, unsigned int reloc_size);

+int etnaviv_create_platform_device(struct device *parent,
+ const char *name, int id,
+ struct resource *pres,
+ void *data,
+ struct platform_device **ppdev);
+
int etnaviv_drm_bind(struct device *dev, bool component);
void etnaviv_drm_unbind(struct device *dev, bool component);
+extern const struct component_master_ops etnaviv_master_ops;

#ifdef CONFIG_DEBUG_FS
void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 070650ac38ed..f69ea8e1751a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -20,6 +20,7 @@
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
+#include "etnaviv_pci_drv.h"
#include "etnaviv_perfmon.h"
#include "etnaviv_sched.h"
#include "common.xml.h"
@@ -28,6 +29,7 @@
#include "cmdstream.xml.h"

static const struct platform_device_id gpu_ids[] = {
+ { .name = "etnaviv-gpu,3d" },
{ .name = "etnaviv-gpu,2d" },
{ },
};
@@ -1871,6 +1873,33 @@ static const struct of_device_id etnaviv_gpu_match[] = {
};
MODULE_DEVICE_TABLE(of, etnaviv_gpu_match);

+/* dev is a pointer which point to the master device */
+int etnaviv_register_irq_handler(struct device *dev,
+ struct etnaviv_drm_private *priv)
+{
+ int ret;
+ int i;
+
+ if (dev_is_platform(dev)) {
+ for (i = 0; i < priv->num_gpus; i++) {
+ struct etnaviv_gpu *gpu = priv->gpu[i];
+
+ ret = devm_request_irq(dev, gpu->irq, irq_handler, 0,
+ dev_name(dev), priv);
+ if (ret) {
+ dev_err(dev, "failed to request IRQ handler: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "GPU IRQ number: %d\n", gpu->irq);
+ }
+ } else if (IS_ENABLED(CONFIG_DRM_ETNAVIV_PCI_DRIVER)) {
+ ret = etnaviv_pci_register_irq_handler(dev, irq_handler, (void *)priv);
+ }
+
+ return ret;
+}
+
int etnaviv_gpu_driver_create(struct device *dev, void __iomem *mmio,
int irq, bool component, bool has_clk)
{
@@ -1886,16 +1915,7 @@ int etnaviv_gpu_driver_create(struct device *dev, void __iomem *mmio,
mutex_init(&gpu->lock);
mutex_init(&gpu->sched_lock);

- /* Get Interrupt: */
gpu->irq = irq;
- if (gpu->irq < 0)
- return gpu->irq;
-
- err = devm_request_irq(dev, irq, irq_handler, 0, dev_name(dev), gpu);
- if (err) {
- dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err);
- return err;
- }

/* Get Clocks: */
if (has_clk) {
@@ -1989,7 +2009,9 @@ static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ void **pp = (void **)dev->platform_data;
void __iomem *mmio;
+ bool has_clk;
int irq;

/* Map registers: */
@@ -1997,9 +2019,18 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
if (IS_ERR(mmio))
return PTR_ERR(mmio);

- irq = platform_get_irq(pdev, 0);
+ if (pp && dev->parent && IS_ENABLED(CONFIG_DRM_ETNAVIV_PCI_DRIVER)) {
+ has_clk = etnaviv_pci_platform_has_clk(dev, *pp);
+ irq = etnaviv_pci_platform_get_irq_line(dev, *pp);
+ } else {
+ has_clk = true;
+ irq = platform_get_irq(pdev, 0);
+ }
+
+ if (irq < 0)
+ return irq;

- return etnaviv_gpu_driver_create(dev, mmio, irq, true, true);
+ return etnaviv_gpu_driver_create(dev, mmio, irq, true, has_clk);
}

static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 407f3a501b17..2f5e97d2fc85 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -215,6 +215,9 @@ void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch);

+int etnaviv_register_irq_handler(struct device *dev,
+ struct etnaviv_drm_private *priv);
+
int etnaviv_gpu_bind(struct device *dev, struct device *master, void *data);
void etnaviv_gpu_unbind(struct device *dev, struct device *master, void *data);

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
index b55ee6dd723e..ae6a5d931ec4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -1,11 +1,16 @@
// SPDX-License-Identifier: GPL-2.0

+#include <linux/component.h>
#include <linux/pci.h>

#include "etnaviv_drv.h"
#include "etnaviv_gpu.h"
#include "etnaviv_pci_drv.h"

+int etnaviv_component = -1;
+MODULE_PARM_DESC(component, "Force to use component subsystem");
+module_param_named(component, etnaviv_component, int, 0644);
+
enum etnaviv_pci_gpu_chip_id {
GC_CORE_UNKNOWN = 0,
JM9100 = 1,
@@ -103,11 +108,58 @@ gc_core_plaform_data[GC_CORE_PCI_LAST] = {
},
};

+/* dev is a pointer which point to the sub gpu device */
+bool etnaviv_pci_platform_has_clk(struct device *dev, void *data)
+{
+ struct etnaviv_pci_gpu_platform_data *pdata = data;
+
+ if (pdata && pdata->no_clk)
+ return false;
+
+ return true;
+}
+
+/* dev is a pointer which point to the sub gpu device */
+int etnaviv_pci_platform_get_irq_line(struct device *dev, void *data)
+{
+ struct etnaviv_pci_gpu_platform_data *pdata = data;
+
+ if (!dev_is_pci(dev->parent))
+ return -ENODEV;
+
+ if (pdata && pdata->share_irq) {
+ struct pci_dev *parent;
+ int irq;
+
+ parent = to_pci_dev(dev->parent);
+ irq = parent->irq;
+ return irq;
+ }
+
+ return -ENODEV;
+}
+
+/* dev is a pointer which point to the master device */
+int etnaviv_pci_register_irq_handler(struct device *dev,
+ irqreturn_t (*fn)(int irq, void *data),
+ void *data)
+{
+ struct pci_dev *pdev;
+
+ if (!dev_is_pci(dev))
+ return -ENODEV;
+
+ pdev = to_pci_dev(dev);
+
+ return devm_request_irq(dev, pdev->irq, fn, 0, dev_name(dev), data);
+}
+
static int etnaviv_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
enum etnaviv_pci_gpu_chip_id chip_id = ent->driver_data;
struct device *dev = &pdev->dev;
+ bool use_component = false;
const struct etnaviv_pci_gpu_platform_data *pdata;
void __iomem *mmio;
int ret;
@@ -126,18 +178,65 @@ static int etnaviv_pci_probe(struct pci_dev *pdev,

pdata = &gc_core_plaform_data[chip_id];

- /* PCI bar 0 contain the MMIO registers */
- mmio = pcim_iomap(pdev, pdata->mmio_bar, 0);
- if (IS_ERR(mmio))
- return PTR_ERR(mmio);
+ if (etnaviv_component >= 1)
+ use_component = true;
+ else if (etnaviv_component == 0)
+ use_component = false;
+ else
+ use_component = pdata->num_core > 1 ? true : false;

- mmio += pdata->cores[0].offset;
+ if (use_component) {
+ unsigned int n_core = pdata->num_core;
+ struct component_match *matches = NULL;
+ unsigned int i;

- ret = etnaviv_gpu_driver_create(dev, mmio, pdev->irq, false, false);
- if (ret)
- return ret;
+ dev_info(dev, "%s has %u GPU cores\n", pdata->name, n_core);
+
+ /* Create a virtual platform device for sub-component core */
+ for (i = 0; i < n_core; i++) {
+ resource_size_t start, offset, size;
+ struct platform_device *sub_gpu_v;
+ struct resource res;
+
+ start = pci_resource_start(pdev, pdata->mmio_bar);
+ offset = pdata->cores[i].offset;
+ size = pdata->cores[i].size;
+
+ memset(&res, 0, sizeof(res));
+ res.flags = IORESOURCE_MEM;
+ res.name = "reg";
+ res.start = start + offset;
+ res.end = start + offset + size - 1;
+
+ ret = etnaviv_create_platform_device(dev,
+ pdata->cores[i].name,
+ pdata->cores[i].id,
+ &res,
+ (void *)pdata,
+ &sub_gpu_v);
+ if (ret)
+ return ret;
+
+ component_match_add(dev, &matches, component_compare_dev,
+ &sub_gpu_v->dev);
+ }
+
+ ret = component_master_add_with_match(dev, &etnaviv_master_ops, matches);
+ } else {
+ mmio = pcim_iomap(pdev, pdata->mmio_bar, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ mmio += pdata->cores[0].offset;
+
+ ret = etnaviv_gpu_driver_create(dev, mmio, pdev->irq, false, false);
+ if (ret)
+ return ret;
+
+ ret = etnaviv_drm_bind(dev, false);
+ }

- return etnaviv_drm_bind(dev, false);
+ return ret;
}

static void etnaviv_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
index 1db559ee5e9b..fd403c22610b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
@@ -3,16 +3,35 @@
#ifndef __ETNAVIV_PCI_DRV_H__
#define __ETNAVIV_PCI_DRV_H__

+#include <linux/irqreturn.h>
+
#ifdef CONFIG_DRM_ETNAVIV_PCI_DRIVER

int etnaviv_register_pci_driver(void);
void etnaviv_unregister_pci_driver(void);

+bool etnaviv_pci_platform_has_clk(struct device *dev, void *data);
+int etnaviv_pci_platform_get_irq_line(struct device *dev, void *data);
+int etnaviv_pci_register_irq_handler(struct device *dev,
+ irqreturn_t (*fn)(int irq, void *data),
+ void *data);
+
#else

static inline int etnaviv_register_pci_driver(void) { return 0; }
static inline void etnaviv_unregister_pci_driver(void) { }

+static inline bool
+etnaviv_pci_platform_has_clk(struct device *dev, void *data) { return true; }
+
+static inline int
+etnaviv_pci_platform_get_irq_line(struct device *dev, void *data) { return 0; }
+
+static inline int
+etnaviv_pci_register_irq_handler(struct device *dev,
+ irqreturn_t (*fn)(int irq, void *data),
+ void *data) { return 0; }
+
#endif

#endif
--
2.34.1