2023-10-03 11:34:14

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v11 0/5] drm/etnaviv: Add pci device driver wrapper

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 LS3A5000+LS7A1000 board, with another
trivial patchset [1] applied beforehand.

[1] https://patchwork.freedesktop.org/series/119825/

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.

Sui Jingfeng (5):
drm/etnaviv: Add a dedicated function to get various clocks
drm/etnaviv: Add constructor and destructor function for
etnaviv_drm_private
drm/etnaviv: Allow bypass component framework
drm/etnaviv: Add driver support for the PCI devices
drm/etnaviv: Add support for cached coherent caching mode

drivers/gpu/drm/etnaviv/Kconfig | 8 ++
drivers/gpu/drm/etnaviv/Makefile | 2 +
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 131 ++++++++++++++-------
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 12 ++
drivers/gpu/drm/etnaviv/etnaviv_gem.c | 16 ++-
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 134 ++++++++++++++--------
drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 7 ++
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 74 ++++++++++++
drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h | 18 +++
include/uapi/drm/etnaviv_drm.h | 1 +
10 files changed, 314 insertions(+), 89 deletions(-)
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h

--
2.34.1


2023-10-03 11:34:16

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v11 4/5] drm/etnaviv: Add driver support for the PCI devices

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.
This patch adds PCI driver wrapper for this gpu. 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-10-03 11:34:22

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v11 3/5] drm/etnaviv: Allow bypass component framework

Component framework is used to bind multiple GPU cores to a virtual master,
but there are SoC/chipset that contain only one GPU core. In those case,
component framework can be avoided. The reason is that usperspace programs
(such as X server and Mesa) will search the PCI device to use precedently.
Creating a virtual master device for PCI(e) GPUs is unnecessary and
incurring troubles.

This patch add additional code paths to allow bypassing the component
frameworks, which pave the way for us to introduce the PCI device driver
wrapper. The goal is to share the code between the PCI driver and the
platform driver as much as possible. 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 4aa7c59ae581..330f8a272184 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1756,8 +1756,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;
@@ -1812,8 +1811,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);

@@ -1858,9 +1856,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;

@@ -1868,31 +1866,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);
@@ -1902,24 +1897,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)
@@ -1973,6 +1971,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-10-03 11:34:35

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v11 1/5] drm/etnaviv: Add a dedicated function to get various clocks

Because the current implement is platform-dependent, there are systems
which don't has the DT-based clock device drivers support. Such as x86
and Loongarch desktop platform. Don't rage quit if so. For the GPU in
LS7A1000/LS2K1000, the working frequency of the GPU is control by the GFX
PLL hardware. Typically, the GFX PLL will be configured by the platform
BIOS(either UEFI or PMON) on per boot time.

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 9276756e1397..4aa7c59ae581 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1586,6 +1586,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;
@@ -1861,27 +1890,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-10-03 11:34:39

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v11 5/5] drm/etnaviv: Add support for cached coherent caching mode

Loongson CPUs maintain cache coherency by hardware, which means that the
data in the CPU cache is identical to the data in main system memory.
As for the peripheral device, most of Loongson chips choose to define the
peripherals as DMA coherent by default, device drivers do not need to
maintain the coherency between a processor and an I/O device manually.

The above sttement is true for *cached* buffers only, this patch say
nothing about WC buffers, it is likely implement-dependent. WC buffers
can be DMA non-coherent on specific platform.

Also because vivante GPU IP has been integrated into various platform, we
need to do the probe work. this patch add code to test if a specific
platform is cached coherent, utilize such hardware feature where suitable.
And allow userspace to query.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 7 +++++++
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 8 ++++++++
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, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 8db86120b11d..3598e2f840b3 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,12 @@ static struct etnaviv_drm_private *etnaviv_alloc_private(struct device *dev)
return ERR_PTR(-ENOMEM);
}

+ /*
+ * The device_get_dma_attr(dev) == DEV_DMA_COHERENT don't work
+ * on LoongArch platform, so still use dev_is_dma_coherent(dev).
+ */
+ 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..760048c35481 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -46,6 +46,14 @@ struct etnaviv_drm_private {
struct xarray active_contexts;
u32 next_context_id;

+ /*
+ * If true, the GPU is capable of snooping CPU's cache. It means
+ * that cached buffer is coherent for both of the CPU and GPU's
+ * access. And the coherency is guaranteed by platform hardware.
+ * Software enforced coherency does not count here.
+ */
+ 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 330f8a272184..9530dddd4273 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