Re: [PATCH v3] drm/etnaviv: Request pages from DMA32 zone on addressing_limited

2024-09-11 Thread Sui Jingfeng

Humble ping ?

On 9/3/24 10:08, Xiaolei Wang wrote:

Remove __GFP_HIGHMEM when requesting a page from DMA32 zone,
and since all vivante GPUs in the system will share the same
DMA constraints, move the check of whether to get a page from
DMA32 to etnaviv_bind().

Fixes: b72af445cd38 ("drm/etnaviv: request pages from DMA32 zone when needed")
Suggested-by: Sui Jingfeng 
Signed-off-by: Xiaolei Wang 
---

change log

v1:
   
https://patchwork.kernel.org/project/dri-devel/patch/20240806104733.2018783-1-xiaolei.w...@windriver.com/

v2:
   Modify the issue of not retaining GFP_USER in v1 and update the commit log.

v3:
   Use "priv->shm_gfp_mask = GFP_USER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;"
instead of
   "priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;"
and move the check of whether to get a page from DMA32 to etnaviv_bind().

  drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 +-
  drivers/gpu/drm/etnaviv/etnaviv_gpu.c |  8 
  2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6500f3999c5f..8cb2c3ec8e5d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -536,7 +536,15 @@ static int etnaviv_bind(struct device *dev)
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->shm_gfp_mask = GFP_USER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;
+
+   /*
+* If the GPU is part of a system with DMA addressing limitations,
+* request pages for our SHM backend buffers from the DMA32 zone to
+* hopefully avoid performance killing SWIOTLB bounce buffering.
+*/
+   if (dma_addressing_limited(dev))
+   priv->shm_gfp_mask |= GFP_DMA32;
  
  	priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev);

if (IS_ERR(priv->cmdbuf_suballoc)) {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7c7f97793ddd..5e753dd42f72 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -839,14 +839,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
if (ret)
goto fail;
  
-	/*

-* If the GPU is part of a system with DMA addressing limitations,
-* request pages for our SHM backend buffers from the DMA32 zone to
-* hopefully avoid performance killing SWIOTLB bounce buffering.
-*/
-   if (dma_addressing_limited(gpu->dev))
-   priv->shm_gfp_mask |= GFP_DMA32;
-
/* Create buffer: */
ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer,
  PAGE_SIZE);


--
Best regards
Sui



[PATCH v2 5/5] drm/etnaviv: Replace the '&pdev->dev' with 'dev'

2024-09-08 Thread Sui Jingfeng
In the etnaviv_pdev_probe() and etnaviv_gpu_platform_probe() function, the
value of '&pdev->dev' has been cached to the local auto variable 'dev'.
But some callers use 'dev', while the rest use '&pdev->dev'. To keep it
consistent, use 'dev' uniformly.

Tested-by: Christian Gmeiner 
Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 16 
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 7844cd961a29..6591e420a051 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -609,7 +609,7 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
if (!of_device_is_available(core_node))
continue;
 
-   drm_of_component_match_add(&pdev->dev, &match,
+   drm_of_component_match_add(dev, &match,
   component_compare_of, 
core_node);
}
} else {
@@ -632,9 +632,9 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
 * bit to make sure we are allocating the command buffers and
 * TLBs in the lower 4 GiB address space.
 */
-   if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)) ||
-   dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-   dev_dbg(&pdev->dev, "No suitable DMA available\n");
+   if (dma_set_mask(dev, DMA_BIT_MASK(40)) ||
+   dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
+   dev_dbg(dev, "No suitable DMA available\n");
return -ENODEV;
}
 
@@ -645,7 +645,7 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
 */
first_node = etnaviv_of_first_available_node();
if (first_node) {
-   of_dma_configure(&pdev->dev, first_node, true);
+   of_dma_configure(dev, first_node, true);
of_node_put(first_node);
}
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 3c869970cba4..d0df5c53a829 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1862,7 +1862,7 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
if (!gpu)
return -ENOMEM;
 
-   gpu->dev = &pdev->dev;
+   gpu->dev = dev;
mutex_init(&gpu->lock);
mutex_init(&gpu->sched_lock);
 
@@ -1876,8 +1876,8 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
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, gpu->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;
@@ -1914,13 +1914,13 @@ 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);
+   pm_runtime_use_autosuspend(dev);
+   pm_runtime_set_autosuspend_delay(dev, 200);
+   pm_runtime_enable(dev);
 
-   err = component_add(&pdev->dev, &gpu_ops);
+   err = component_add(dev, &gpu_ops);
if (err < 0) {
-   dev_err(&pdev->dev, "failed to register component: %d\n", err);
+   dev_err(dev, "failed to register component: %d\n", err);
return err;
}
 
-- 
2.43.0



[PATCH v2 4/5] drm/etnaviv: Fix missing mutex_destroy()

2024-09-08 Thread Sui Jingfeng
Currently, the calling of mutex_destroy() is ignored on error handling
code path. It is safe for now, since mutex_destroy() actually does
nothing in non-debug builds. But the mutex_destroy() is used to mark
the mutex uninitialized on debug builds, and any subsequent use of the
mutex is forbidden.

It also could lead to problems if mutex_destroy() gets extended, add
missing mutex_destroy() to eliminate potential concerns.

Reviewed-by: Christian Gmeiner 
Signed-off-by: Sui Jingfeng 
---

 v2: Pick up tags and fix one more missing mutex_destroy() 

 drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c | 2 ++
 drivers/gpu/drm/etnaviv/etnaviv_drv.c| 1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c| 1 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c| 5 +
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c| 2 +-
 5 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c 
b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
index 721d633aece9..66a407f1b3ee 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
@@ -55,6 +55,7 @@ etnaviv_cmdbuf_suballoc_new(struct device *dev)
return suballoc;
 
 free_suballoc:
+   mutex_destroy(&suballoc->lock);
kfree(suballoc);
 
return ERR_PTR(ret);
@@ -79,6 +80,7 @@ void etnaviv_cmdbuf_suballoc_destroy(struct 
etnaviv_cmdbuf_suballoc *suballoc)
 {
dma_free_wc(suballoc->dev, SUBALLOC_SIZE, suballoc->vaddr,
suballoc->paddr);
+   mutex_destroy(&suballoc->lock);
kfree(suballoc);
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6500f3999c5f..7844cd961a29 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -564,6 +564,7 @@ static int etnaviv_bind(struct device *dev)
 out_destroy_suballoc:
etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
 out_free_priv:
+   mutex_destroy(&priv->gem_lock);
kfree(priv);
 out_put:
drm_dev_put(drm);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 4ce3d2ea7767..4247a10f8d4f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -514,6 +514,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
etnaviv_obj->ops->release(etnaviv_obj);
drm_gem_object_release(obj);
 
+   mutex_destroy(&etnaviv_obj->lock);
kfree(etnaviv_obj);
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7c7f97793ddd..3c869970cba4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1929,8 +1929,13 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
 
 static void etnaviv_gpu_platform_remove(struct platform_device *pdev)
 {
+   struct etnaviv_gpu *gpu = dev_get_drvdata(&pdev->dev);
+
component_del(&pdev->dev, &gpu_ops);
pm_runtime_disable(&pdev->dev);
+
+   mutex_destroy(&gpu->lock);
+   mutex_destroy(&gpu->sched_lock);
 }
 
 static int etnaviv_gpu_rpm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 1661d589bf3e..02d9408d41bc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -358,7 +358,7 @@ static void etnaviv_iommu_context_free(struct kref *kref)
container_of(kref, struct etnaviv_iommu_context, refcount);
 
etnaviv_cmdbuf_suballoc_unmap(context, &context->cmdbuf_mapping);
-
+   mutex_destroy(&context->lock);
context->global->ops->free(context);
 }
 void etnaviv_iommu_context_put(struct etnaviv_iommu_context *context)
-- 
2.43.0



[PATCH v2 3/5] drm/etnaviv: Drop the header

2024-09-08 Thread Sui Jingfeng
Currently, the etnaviv_gem_submit.c isn't call any runtime power management
functions. So drop this unused header, we can include it back when it
really get used though.

Reviewed-by: Christian Gmeiner 
Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 3d0f8d182506..3c0a5c3e0e3d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -6,7 +6,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
-- 
2.43.0



[PATCH v2 2/5] drm/etnaviv: Use 'unsigned' type to count the number of pages

2024-09-08 Thread Sui Jingfeng
The unpin_user_pages() function takes an 'unsigned long' argument to
store the number of userspace pages, and the struct drm_gem_object::size
is a size_t type. The number of pages can not be negative, hence, use
'unsigned' variable to count the number of pages.

Reviewed-by: Christian Gmeiner 
Signed-off-by: Sui Jingfeng 
---

 v2: Pick up tags and improve commit message

 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 5ffc31f32ac9..4ce3d2ea7767 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -686,7 +686,7 @@ static void etnaviv_gem_userptr_release(struct 
etnaviv_gem_object *etnaviv_obj)
kfree(etnaviv_obj->sgt);
}
if (etnaviv_obj->pages) {
-   int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+   unsigned int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
 
unpin_user_pages(etnaviv_obj->pages, npages);
kvfree(etnaviv_obj->pages);
-- 
2.43.0



[PATCH v2 1/5] drm/etnaviv: Use unsigned type to count the number of pages

2024-09-08 Thread Sui Jingfeng
The drm_prime_pages_to_sg() function takes an 'unsigned int' argument to
store the length of the page vector. The size of the object in number of
CPU pages can not be negative, hence, use 'unsigned' variable to store
the number of pages, instead of the 'signed' one.

Reviewed-by: Christian Gmeiner 
Signed-off-by: Sui Jingfeng 
---

v2: Pick up tags and improve commit message

 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 3524b5811682..6b98200068e4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -17,7 +17,7 @@ static struct lock_class_key etnaviv_prime_lock_class;
 struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-   int npages = obj->size >> PAGE_SHIFT;
+   unsigned int npages = obj->size >> PAGE_SHIFT;
 
if (WARN_ON(!etnaviv_obj->pages))  /* should have already pinned! */
return ERR_PTR(-EINVAL);
-- 
2.43.0



[PATCH v15 17/19] drm/etnaviv: Support to manage dedicated VRAM base on drm_mm

2024-09-08 Thread Sui Jingfeng
The dedicated VRAM is seen as a kind of device memory (IOMEM) at present,
we should use ioremap() to make device memory CPU accessible, we should
also need to implement mmap() driver for userspace. Therefore, we add a
simple drm-mm based range allocator for the upper (GEM object function)
layer.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Makefile   |   1 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c  |  12 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.h  |  11 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.h  |   5 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c | 258 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h |  12 +
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c  |  13 ++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h  |   6 +
 8 files changed, 318 insertions(+)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h

diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 383f181bfc4c..aba2578966ff 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -6,6 +6,7 @@ etnaviv-y := \
etnaviv_drv.o \
etnaviv_dump.o \
etnaviv_gem_prime.o \
+   etnaviv_gem_vram.o \
etnaviv_gem_submit.o \
etnaviv_gem.o \
etnaviv_gpu.o \
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 7fc654f051a3..f10661fe079f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -23,6 +23,7 @@
 #include "etnaviv_drv.h"
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
+#include "etnaviv_gem_vram.h"
 #include "etnaviv_mmu.h"
 #include "etnaviv_pci_drv.h"
 #include "etnaviv_perfmon.h"
@@ -46,6 +47,8 @@ static struct device_node 
*etnaviv_of_first_available_node(void)
 static int etnaviv_private_init(struct device *dev,
struct etnaviv_drm_private *priv)
 {
+   int ret;
+
xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
 
mutex_init(&priv->gem_lock);
@@ -61,6 +64,10 @@ static int etnaviv_private_init(struct device *dev,
 
priv->cached_coherent = dev_is_dma_coherent(dev);
 
+   ret = etnaviv_init_dedicated_vram(dev, priv);
+   if (ret)
+   dev_err(dev, "Failed to init dedicated vram\n");
+
return 0;
 }
 
@@ -74,6 +81,11 @@ static void etnaviv_private_fini(struct etnaviv_drm_private 
*priv)
xa_destroy(&priv->active_contexts);
 
mutex_destroy(&priv->gem_lock);
+
+   if (priv->dedicated_vram) {
+   drm_mm_takedown(&priv->vram.mm);
+   priv->dedicated_vram = false;
+   }
 }
 
 static void load_gpu(struct drm_device *dev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 84f2e79f0a53..b093f832599f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -58,6 +58,17 @@ struct etnaviv_drm_private {
 */
bool cached_coherent;
 
+   /*
+* dedicated VRAM (device memory) resource
+*/
+   struct {
+   struct drm_mm mm;
+   u64 gpu_base;
+   u64 cpu_base;
+   u64 size;
+   } vram;
+   bool dedicated_vram;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index 8d8fc5b3a541..60c2dd19 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -59,6 +59,9 @@ struct etnaviv_gem_object {
u32 last_cpu_prep_op;
 
struct etnaviv_gem_userptr userptr;
+
+   /* dedicated vram, which is physically contiguous */
+   struct drm_mm_node *vram_np;
 };
 
 static inline
@@ -129,4 +132,6 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
u64 va);
 void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping);
 
+u64 etnaviv_obj_gpu_phys_addr(struct etnaviv_gem_object *etnaviv_obj);
+
 #endif /* __ETNAVIV_GEM_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
new file mode 100644
index ..c2942317a64e
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_pci_drv.h"
+
+static struct lock_class_key etnaviv_vram_lock_class;
+
+static u64 etnaviv_obj_cpu_phys_addr(struct etnaviv_gem_object *etnaviv_obj)
+{
+   struct drm_gem_object *obj = &etnaviv_obj->base;
+   struct etnaviv_drm_private *priv = to_etnaviv_priv(obj->dev);
+
+ 

[PATCH v15 19/19] drm/etnaviv: Expose basic sanity tests via debugfs

2024-09-08 Thread Sui Jingfeng
To test the correctess of the implemented vmap() and vunmap() operations,
to see if is works correctly on dedicated VRAM.

Usage:

cd /sys/kernel/debug/dri/etnaviv
cat sanity

My test is able to pass on x86-64 with a JM9230P card, see below log:

Test Write to VRAM 8294400 bytes
Write to VRAM Passed: 8294400 bytes
Test Write to SHMEM 8294400 bytes
Write to SHMEM Passed: 8294400 bytes

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Makefile   |   1 +
 drivers/gpu/drm/etnaviv/etnaviv_debugfs.c  | 118 +
 drivers/gpu/drm/etnaviv/etnaviv_debugfs.h  |  15 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.c  |  12 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem.c  |   5 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.h  |   2 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c |   6 ++
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h |   2 +
 8 files changed, 161 insertions(+)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_debugfs.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_debugfs.h

diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index aba2578966ff..f278e75ee7cd 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -17,6 +17,7 @@ etnaviv-y := \
etnaviv_perfmon.o \
etnaviv_sched.o
 
+etnaviv-$(CONFIG_DEBUG_FS) += etnaviv_debugfs.o
 etnaviv-$(CONFIG_DRM_ETNAVIV_PCI_DRIVER) += etnaviv_pci_drv.o \
pcie_ip_setup.o
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_debugfs.c 
b/drivers/gpu/drm/etnaviv/etnaviv_debugfs.c
new file mode 100644
index ..0cfedbc6574c
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_debugfs.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+
+#include "etnaviv_debugfs.h"
+#include "etnaviv_drv.h"
+#include "etnaviv_gem.h"
+#include "etnaviv_gem_vram.h"
+
+static void bo_test_write_to_vram_by_cpu(void *addr, unsigned int num)
+{
+   u32 val = 0;
+
+   while (num--) {
+   writel(val, addr);
+   ++val;
+   addr += 4;
+   }
+}
+
+static unsigned int bo_test_read_from_vram_by_cpu(void *addr, unsigned int num)
+{
+   unsigned int i = 0;
+
+   while (i < num) {
+   u32 val = readl(addr);
+
+   if (val != i)
+   return i;
+
+   addr += 4;
+   ++i;
+   }
+
+   return 0;
+}
+
+void etnaviv_sanity_test_vram_impl(struct drm_device *drm, struct drm_printer 
*p)
+{
+   struct etnaviv_gem_object *etnaviv_obj;
+   unsigned int size = 1920 * 1080 * 4;
+   void *addr;
+   int ret;
+
+   size = ALIGN(size, PAGE_SIZE);
+
+   drm_printf(p, "Test Write to VRAM %u bytes\n", size);
+
+   ret = etnaviv_gem_new_private(drm, size, ETNA_BO_UNCACHED, false,
+ etnaviv_gem_get_vram_ops(),
+ &etnaviv_obj);
+   if (ret) {
+   drm_printf(p, "create dst bo failed\n");
+   return;
+   }
+
+   addr = etnaviv_gem_vmap(&etnaviv_obj->base);
+   if (!addr) {
+   drm_printf(p, "write to vram by cpu failed: vmap\n");
+   goto out;
+   }
+
+   etnaviv_gem_vunmap(&etnaviv_obj->base);
+
+   addr = etnaviv_gem_vmap(&etnaviv_obj->base);
+
+   bo_test_write_to_vram_by_cpu(addr, size / 4);
+
+   ret = bo_test_read_from_vram_by_cpu(addr, size / 4);
+
+   drm_printf(p, "Write to VRAM %s: %u bytes\n",
+  ret ? "not pass" : "Passed", ret ? ret : size);
+
+   etnaviv_gem_vunmap(&etnaviv_obj->base);
+out:
+   drm_gem_object_put(&etnaviv_obj->base);
+}
+
+void etnaviv_sanity_test_shmem_impl(struct drm_device *drm, struct drm_printer 
*p)
+{
+   struct etnaviv_gem_object *etnaviv_obj;
+   unsigned int size = 1920 * 1080 * 4;
+   void *addr;
+   int ret;
+
+   size = ALIGN(size, PAGE_SIZE);
+
+   drm_printf(p, "Test Write to SHMEM %u bytes\n", size);
+
+   ret = etnaviv_gem_new_private(drm, size, ETNA_BO_CACHED, true,
+ etnaviv_gem_get_shmem_ops(),
+ &etnaviv_obj);
+   if (ret) {
+   drm_printf(p, "create dst bo failed\n");
+   return;
+   }
+
+   addr = etnaviv_gem_vmap(&etnaviv_obj->base);
+   if (!addr) {
+   drm_printf(p, "write to shmem by cpu failed: vmap\n");
+   goto out;
+   }
+
+   etnaviv_gem_vunmap(&etnaviv_obj->base);
+
+   addr = etnaviv_gem_vmap(&etnaviv_obj->base);
+
+   bo_test_write_to_vram_by_cpu(addr, size / 4);
+
+   ret = bo_test_read_from_vram_by_cpu(addr, size / 4);
+
+   drm_printf(p, "Write to SHMEM %s: %u bytes\n&qu

[PATCH v15 18/19] drm/etnaviv: Allow userspace specify the domain of etnaviv GEM buffer object

2024-09-08 Thread Sui Jingfeng
Otherwise we don't know where a etnaviv GEM buffer object should put when
we create it at userspace.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c |  9 +
 include/uapi/drm/etnaviv_drm.h| 12 
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index f10661fe079f..cdc62f64b200 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -331,11 +331,20 @@ static int etnaviv_ioctl_gem_new(struct drm_device *dev, 
void *data,
struct drm_file *file)
 {
struct drm_etnaviv_gem_new *args = data;
+   u32 domain;
+
+   domain = args->flags & ETNA_BO_DOMAIN_MASK;
+
+   args->flags &= ~ETNA_BO_DOMAIN_MASK;
 
if (args->flags & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED |
ETNA_BO_FORCE_MMU))
return -EINVAL;
 
+   if (domain == ETNA_BO_PL_VRAM)
+   return etnaviv_gem_new_vram(dev, file, args->size,
+   args->flags, &args->handle);
+
return etnaviv_gem_new_handle(dev, file, args->size,
args->flags, &args->handle);
 }
diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h
index 61eaa8cd0f5e..00e778c9d312 100644
--- a/include/uapi/drm/etnaviv_drm.h
+++ b/include/uapi/drm/etnaviv_drm.h
@@ -99,6 +99,18 @@ struct drm_etnaviv_param {
 /* map flags */
 #define ETNA_BO_FORCE_MMU0x0010
 
+/* domain (placement) flags */
+#define ETNA_BO_DOMAIN_MASK  0x00f0
+
+/* CPU accessible, GPU accessible pages in dedicated VRAM */
+#define ETNA_BO_PL_VRAM  0x0100
+/* CPU accessible, GPU accessible pages in SHMEM */
+#define ETNA_BO_PL_GTT   0x0200
+/* Userspace allocated memory, at least CPU accessible */
+#define ETNA_BO_PL_USERPTR   0x0800
+/* GPU accessible but CPU not accessible private VRAM pages */
+#define ETNA_BO_PL_PRIV  0x0400
+
 struct drm_etnaviv_gem_new {
__u64 size;   /* in */
__u32 flags;  /* in, mask of ETNA_BO_x */
-- 
2.43.0



[PATCH v15 16/19] drm/etnaviv: Call etnaviv_gem_obj_add() in ernaviv_gem_new_private()

2024-09-08 Thread Sui Jingfeng
The etnaviv_gem_obj_add() a common operation, the 'etnaviv_drm_private::
gem_list' is being used to record(track) all of the etnaviv GEM buffer
object created in this driver.

Once a etnaviv GEM buffer object has been allocated successfully, we
should add it into the global etnaviv_drm_private::gem_list'. Because
we need to free it and remove it free the list if the invoke of the
subsequent functions fail.

The only way that destroy etnaviv GEM buffer object is the implementation
of etnaviv_gem_free_object() function. The etnaviv_gem_free_object() first
remove the etnaviv GEM object from the list, then destroy its mapping and
finally free its memory footprint. Therefore, in order to corresponding
this, we add the freshly created etnaviv GEM buffer object immediately
after it was successfully created.

A benifit is that we only need to call etnaviv_gem_obj_add() once now,
since the ernaviv_gem_new_private() has been unified. Make the
etnaviv_gem_obj_add() static is a next nature thing.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 8 +++-
 drivers/gpu/drm/etnaviv/etnaviv_gem.h   | 1 -
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 --
 3 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 27e4a93c981c..ee799c02d0aa 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -584,7 +584,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
kfree(etnaviv_obj);
 }
 
-void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj)
+static void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object 
*obj)
 {
struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
@@ -719,8 +719,6 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct 
drm_file *file,
 */
mapping_set_gfp_mask(obj->filp->f_mapping, priv->shm_gfp_mask);
 
-   etnaviv_gem_obj_add(dev, obj);
-
ret = drm_gem_handle_create(file, obj, handle);
 
/* drop reference from allocate - handle holds it now */
@@ -751,6 +749,8 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t 
size, u32 flags,
drm_gem_private_object_init(dev, obj, size);
}
 
+   etnaviv_gem_obj_add(dev, obj);
+
*res = to_etnaviv_bo(obj);
 
return 0;
@@ -849,8 +849,6 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct 
drm_file *file,
etnaviv_obj->userptr.mm = current->mm;
etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE);
 
-   etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
-
ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle);
 
/* drop reference from allocate - handle holds it now */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index b174a9e4cc48..8d8fc5b3a541 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -121,7 +121,6 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t 
size, u32 flags,
bool shmem, const struct etnaviv_gem_ops *ops,
struct etnaviv_gem_object **res);
 
-void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
 struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj);
 void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 64a858a0b0cf..04ee31461b8c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -127,8 +127,6 @@ struct drm_gem_object 
*etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
if (ret)
goto fail;
 
-   etnaviv_gem_obj_add(dev, &etnaviv_obj->base);
-
return &etnaviv_obj->base;
 
 fail:
-- 
2.43.0



[PATCH v15 14/19] drm/etnaviv: Add PCIe IP setup code

2024-09-08 Thread Sui Jingfeng
Because some PCIe IP need special setup before its VRAM bar can be usable,
do this with instance specific object function.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Makefile  |   3 +-
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c |  19 
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h |   9 ++
 drivers/gpu/drm/etnaviv/pcie_ip_setup.c   | 109 ++
 4 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/etnaviv/pcie_ip_setup.c

diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 6829e1ebf2db..383f181bfc4c 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -16,6 +16,7 @@ etnaviv-y := \
etnaviv_perfmon.o \
etnaviv_sched.o
 
-etnaviv-$(CONFIG_DRM_ETNAVIV_PCI_DRIVER) += etnaviv_pci_drv.o
+etnaviv-$(CONFIG_DRM_ETNAVIV_PCI_DRIVER) += etnaviv_pci_drv.o \
+   pcie_ip_setup.o
 
 obj-$(CONFIG_DRM_ETNAVIV)  += etnaviv.o
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
index f13f3208120f..9911bfdc41a9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
@@ -5,6 +5,11 @@
 #include "etnaviv_drv.h"
 #include "etnaviv_pci_drv.h"
 
+static const struct etnaviv_pcie_ip_funcs jemo_9_gpu_pcie_ip_funcs = {
+   .init = jemo_pcie_init,
+   .fini = NULL,
+};
+
 static const struct etnaviv_pci_gpu_data
 gccore_platform_data[GCCORE_PCI_CHIP_ID_LAST] = {
{
@@ -18,7 +23,9 @@ gccore_platform_data[GCCORE_PCI_CHIP_ID_LAST] = {
.mmio_bar = 1,
.ip_block = {{0, 0x0090, 0x4000, "etnaviv-gpu,3d"},},
.has_dedicated_vram = true,
+   .has_iatu = true,
.has_display = true,
+   .pcie_ip_funcs = &jemo_9_gpu_pcie_ip_funcs,
.market_name = "JingJia Micro JM9100",
},
{
@@ -30,7 +37,9 @@ gccore_platform_data[GCCORE_PCI_CHIP_ID_LAST] = {
.ip_block = {{0, 0x0090, 0x4000, "etnaviv-gpu,3d"},
 {1, 0x0091, 0x4000, "etnaviv-gpu,3d"},},
.has_dedicated_vram = true,
+   .has_iatu = true,
.has_display = true,
+   .pcie_ip_funcs = &jemo_9_gpu_pcie_ip_funcs,
.market_name = "JingJia Micro JD9230P",
},
{
@@ -42,6 +51,7 @@ gccore_platform_data[GCCORE_PCI_CHIP_ID_LAST] = {
.ip_block = {{0, 0x0004, 0x4000, "etnaviv-gpu,3d"},
 {0, 0x000C, 0x4000, "etnaviv-gpu,2d"},},
.has_dedicated_vram = true,
+   .has_iatu = false,
.has_display = true,
.market_name = "LingJiu GP102",
},
@@ -53,6 +63,7 @@ gccore_platform_data[GCCORE_PCI_CHIP_ID_LAST] = {
.mmio_bar = 0,
.ip_block = {{0, 0, 0x4000, "etnaviv-gpu,3d"},},
.has_dedicated_vram = true,
+   .has_iatu = false,
.has_display = false,
.market_name = "GC1000 in LS7A1000",
},
@@ -83,6 +94,7 @@ static int etnaviv_pci_probe(struct pci_dev *pdev,
 const struct pci_device_id *ent)
 {
const struct etnaviv_pci_gpu_data *pdata;
+   const struct etnaviv_pcie_ip_funcs *pcie_ip_funcs;
struct device *dev = &pdev->dev;
unsigned int i;
unsigned int num_core;
@@ -102,6 +114,13 @@ static int etnaviv_pci_probe(struct pci_dev *pdev,
if (!pdata)
return -ENODEV;
 
+   pcie_ip_funcs = pdata->pcie_ip_funcs;
+   if (pcie_ip_funcs) {
+   ret = pcie_ip_funcs->init(pdev);
+   if (ret)
+   return ret;
+   }
+
num_core = pdata->num_core;
 
dev_info(dev, "%s has %u GPU cores\n", pdata->market_name, num_core);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
index eae8cdea5674..39eb2851355a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
@@ -23,6 +23,11 @@ struct vivante_gc_ip_block {
char compatible[20];
 };
 
+struct etnaviv_pcie_ip_funcs {
+   int (*init)(struct pci_dev *pdev);
+   void (*fini)(struct pci_dev *pdev);
+};
+
 struct etnaviv_pci_gpu_data {
enum etnaviv_pci_chip_id chip_id;
u32 num_core;
@@ -31,13 +36,17 @@ struct etnaviv_pci_gpu_data {
u32 mmio_bar;
struct vivante_gc_ip_block ip_block[ETNA_MAX_IP_BLOCK];
bool has_dedicated_vram;
+   bool has_iatu;
bool has_display;
+   const struct etnaviv_pcie_ip_funcs *pcie_ip_funcs;
char ma

[PATCH v15 15/19] drm/etnaviv: Make more use of the etnaviv_gem_new_private() function

2024-09-08 Thread Sui Jingfeng
Add the 'bool shmem' as the 4th argument of etnaviv_gem_new_private(),
then call etnaviv_gem_new_handle() to allocate the etnaviv_gem_object
instance for us.

A small benefit is to reduce code duplication across different etnaviv
GEM buffer objects. This allow us to reuse etnaviv_gem_new_private()
everywhere, increasing code reusage.

We also should call drm_gem_private_object_fini() to uninitialize an
already allocated GEM object when it initialized failed. Now
etnaviv_gem_new_private() handle this trouble for us, the upper caller
can just use it, no need to worry about error handling anymore.

if true, the drm_gem_object_init() will allocate backing storage for us,
then this is a shmem buffer object. if false, we have to implement driver
specific backing storage.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 28 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.h   |  4 ++-
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c |  2 +-
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 3732288ff530..27e4a93c981c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -697,21 +697,20 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct 
drm_file *file,
u32 size, u32 flags, u32 *handle)
 {
struct etnaviv_drm_private *priv = to_etnaviv_priv(dev);
-   struct drm_gem_object *obj = NULL;
+   struct etnaviv_gem_object *etnaviv_obj;
+   struct drm_gem_object *obj;
int ret;
 
size = PAGE_ALIGN(size);
 
-   ret = etnaviv_gem_new_impl(dev, flags, &etnaviv_gem_shmem_ops, &obj);
+   ret = etnaviv_gem_new_private(dev, size, flags, true,
+ &etnaviv_gem_shmem_ops, &etnaviv_obj);
if (ret)
goto fail;
 
-   lockdep_set_class(&to_etnaviv_bo(obj)->lock, &etnaviv_shm_lock_class);
-
-   ret = drm_gem_object_init(dev, obj, size);
-   if (ret)
-   goto fail;
+   lockdep_set_class(&etnaviv_obj->lock, &etnaviv_shm_lock_class);
 
+   obj = &etnaviv_obj->base;
/*
 * Our buffers are kept pinned, so allocating them from the MOVABLE
 * zone is a really bad idea, and conflicts with CMA. See comments
@@ -732,7 +731,8 @@ int etnaviv_gem_new_handle(struct drm_device *dev, struct 
drm_file *file,
 }
 
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
-   const struct etnaviv_gem_ops *ops, struct etnaviv_gem_object **res)
+   bool shmem, const struct etnaviv_gem_ops *ops,
+   struct etnaviv_gem_object **res)
 {
struct drm_gem_object *obj;
int ret;
@@ -741,7 +741,15 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t 
size, u32 flags,
if (ret)
return ret;
 
-   drm_gem_private_object_init(dev, obj, size);
+   if (shmem) {
+   ret = drm_gem_object_init(dev, obj, size);
+   if (ret) {
+   drm_gem_private_object_fini(obj);
+   return ret;
+   }
+   } else {
+   drm_gem_private_object_init(dev, obj, size);
+   }
 
*res = to_etnaviv_bo(obj);
 
@@ -830,7 +838,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct 
drm_file *file,
struct etnaviv_gem_object *etnaviv_obj;
int ret;
 
-   ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED,
+   ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, false,
  &etnaviv_gem_userptr_ops, &etnaviv_obj);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index f2ac64d8e90b..b174a9e4cc48 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -118,7 +118,9 @@ void etnaviv_submit_put(struct etnaviv_gem_submit * submit);
 int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj,
struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
-   const struct etnaviv_gem_ops *ops, struct etnaviv_gem_object **res);
+   bool shmem, const struct etnaviv_gem_ops *ops,
+   struct etnaviv_gem_object **res);
+
 void etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj);
 struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj);
 void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 0062d808d6a9..64a858a0b0cf 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnavi

[PATCH v15 13/19] drm/etnaviv: Add support for vivante GPU cores attached via PCIe device

2024-09-08 Thread Sui Jingfeng
Previously, component framework is being used to bind multiple platform
(DT) devices to a virtual master. The virtual master is manually created
during probe time. This is fine and works well for embedded SoCs, yet
there have some hardware venders that integrate Vivante GPU IP cores
into their PCIe card. This driver lacks support for PCI(e) devices.

Creating platform device as logical denotation for each GPU IP core, the
manually created platform devices are functional as subcomponen. To
reflects the actual hardware layout, make all of them be child of the PCIe
master device. The master is real for PCIe devices, which is working at
background and spread the device seeds out.

Creating yet an another platform device as component master, offload the
component binding/unbinding affairs to it. The virtual component master
works at foreground, the PCIe device behind it works at background.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Kconfig   |   9 ++
 drivers/gpu/drm/etnaviv/Makefile  |   2 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c |  45 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  11 ++
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c |  73 +++--
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |   4 +
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 185 ++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h |  48 ++
 8 files changed, 355 insertions(+), 22 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..7cb44f72d512 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -15,6 +15,15 @@ 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
+   default n
+   help
+ Compile in support for Vivante GPUs attached via PCIe card.
+ 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 18686b573d77..7fc654f051a3 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -24,6 +24,7 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
+#include "etnaviv_pci_drv.h"
 #include "etnaviv_perfmon.h"
 
 /*
@@ -568,6 +569,10 @@ static int etnaviv_bind(struct device *dev)
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);
@@ -670,16 +675,32 @@ 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 *pdata, unsigned int ndata,
+  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 (pdata && ndata)
+   platform_device_add_data(pdev, pdata, ndata);
+
ret = platform_device_add(pdev);
if (ret) {
platform_device_put(pdev);
@@ -691,7 +712,7 @@ static int etnaviv_create_platform_device(const char *name,
return 0;
 }
 
-static void etnaviv_destroy_platform_device(struct platform_device **ppdev)
+void etnaviv_destroy_platform_device(struct platform_device **ppdev)
 {
struct platform_device *pdev = *ppdev;
 
@@ -703,7 +724,7 @@ static void etnaviv_destroy_platfor

[PATCH v15 12/19] drm/etnaviv: Add support for cached coherent caching mode

2024-09-08 Thread Sui Jingfeng
Many modern CPUs and/or platforms choose to define their peripheral devices
as cached coherent by default, to be specific, the PCH is capable of
snooping CPU's cache. When hit, the peripheral devices will access data
directly from CPU's cache. This means that device drivers do not need to
maintain the coherency issue between a processor and peripheral I/O for
the cached buffers. Hence, it dosen't need us to sync manually on the
software side, which is useful to avoid some overheads, especially for
userspace, but userspace is not known this yet.

Probe the hardware maintained cached coherent support with the
dev_is_dma_coherent() function, and store the result in the
etnaviv_drm_private structure. Since this is a host and/or platform
implementation-defined hardware feature, and is again meant to be shared
by all GPU cores. The probe function can be extended in the future if it
not reflect the hardware perfectly.

Expose it via etnaviv parameter mechanism to let userspace know.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 3 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.h | 9 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 4 
 include/uapi/drm/etnaviv_drm.h| 1 +
 4 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 32ec1b5452ba..18686b573d77 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -57,6 +58,8 @@ static int etnaviv_private_init(struct device *dev,
return -ENOMEM;
}
 
+   priv->cached_coherent = dev_is_dma_coherent(dev);
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index e2a991160cb3..02d706b34752 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
+* peripheral bus masters in the system. It means that both of the
+* CPU and GPU will see the same data if the buffer being accessed
+* is cached. And the coherency is guaranteed by the host platform
+* specific hardwares.
+*/
+   bool cached_coherent;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 0c8e394b569c..89fb36aee779 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_ID0x1c
 #define ETNAVIV_PARAM_GPU_CUSTOMER_ID   0x1d
 #define ETNAVIV_PARAM_GPU_ECO_ID0x1e
+#define ETNAVIV_PARAM_CACHED_COHERENT   0x1f
 
 #define ETNA_MAX_PIPES 4
 
-- 
2.43.0



[PATCH v15 11/19] drm/etnaviv: Add etnaviv_gem_obj_remove() helper

2024-09-08 Thread Sui Jingfeng
Which is corresonding to the etnaviv_gem_obj_add()

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 39cfece67b90..3732288ff530 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -19,6 +19,8 @@
 static struct lock_class_key etnaviv_shm_lock_class;
 static struct lock_class_key etnaviv_userptr_lock_class;
 
+static void etnaviv_gem_obj_remove(struct drm_gem_object *obj);
+
 static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
 {
struct drm_device *dev = etnaviv_obj->base.dev;
@@ -555,15 +557,12 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 {
struct drm_device *drm = obj->dev;
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-   struct etnaviv_drm_private *priv = obj->dev->dev_private;
struct etnaviv_vram_mapping *mapping, *tmp;
 
/* object should not be active */
drm_WARN_ON(drm, is_active(etnaviv_obj));
 
-   mutex_lock(&priv->gem_lock);
-   list_del(&etnaviv_obj->gem_node);
-   mutex_unlock(&priv->gem_lock);
+   etnaviv_gem_obj_remove(obj);
 
list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list,
 obj_node) {
@@ -595,6 +594,16 @@ void etnaviv_gem_obj_add(struct drm_device *dev, struct 
drm_gem_object *obj)
mutex_unlock(&priv->gem_lock);
 }
 
+static void etnaviv_gem_obj_remove(struct drm_gem_object *obj)
+{
+   struct etnaviv_drm_private *priv = to_etnaviv_priv(obj->dev);
+   struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+   mutex_lock(&priv->gem_lock);
+   list_del(&etnaviv_obj->gem_node);
+   mutex_unlock(&priv->gem_lock);
+}
+
 static const struct vm_operations_struct vm_ops = {
.fault = etnaviv_gem_fault,
.open = drm_gem_vm_open,
-- 
2.43.0



[PATCH v15 10/19] drm/etnaviv: Embed struct drm_device into struct etnaviv_drm_private

2024-09-08 Thread Sui Jingfeng
Both the instance of struct drm_device and the instance of struct
etnaviv_drm_private are intended to be shared by all GPU cores, both have
only one instance created across drm/etnaviv driver. After embedded in,
the whole structure can be allocated with devm_drm_dev_alloc(). And the
DRM device created is automatically put on driver detach, so we don't need
to call drm_dev_put() explicitly on driver leave. It's also eliminate the
need to use the .dev_private member, which is deprecated according to the
drm document. We can also use container_of() to retrieve pointer for the
containing structure.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c| 65 
 drivers/gpu/drm/etnaviv/etnaviv_drv.h|  7 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem.c|  4 +-
 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, 39 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 809e5db85df4..32ec1b5452ba 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,14 +41,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);
@@ -58,15 +53,14 @@ 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;
}
 
-   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;
@@ -76,13 +70,11 @@ static void etnaviv_free_private(struct etnaviv_drm_private 
*priv)
xa_destroy(&priv->active_contexts);
 
mutex_destroy(&priv->gem_lock);
-
-   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++) {
@@ -100,7 +92,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;
 
@@ -143,7 +135,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;
 
@@ -168,7 +160,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);
 
@@ -262,7 +254,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;
@@ -305,7 +297,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;
 
@@ -398,7 +390,7 @@ static int etnavi

[PATCH v15 09/19] drm/etnaviv: Add constructor and destructor for the etnaviv_drm_private structure

2024-09-08 Thread Sui Jingfeng
Because there are a lot of data members in the struct etnaviv_drm_private,
which are intended to be shared by all GPU cores. It can be lengthy and
daunting on error handling, the 'gem_lock' of struct etnaviv_drm_private
just be forgeten to destroy on driver leave.

Switch to use the dedicated helpers introduced, etnaviv_bind() and
etnaviv_unbind() gets simplified. Another potential benefit is that
we could put the struct drm_device into struct etnaviv_drm_private
in the future, which made them share the same life time.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 73 +--
 1 file changed, 46 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6591e420a051..809e5db85df4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,6 +41,45 @@ 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);
+
+   mutex_destroy(&priv->gem_lock);
+
+   kfree(priv);
+}
+
 static void load_gpu(struct drm_device *dev)
 {
struct etnaviv_drm_private *priv = dev->dev_private;
@@ -521,35 +560,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,11 +586,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:
-   mutex_destroy(&priv->gem_lock);
-   kfree(priv);
+   etnaviv_free_private(priv);
 out_put:
drm_dev_put(drm);
 
@@ -581,12 +603,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.43.0



[PATCH v15 08/19] drm/etnaviv: Fix wrong caching mode being used for non writecombine buffers

2024-09-08 Thread Sui Jingfeng
In the etnaviv_gem_vmap_impl() function, the driver vmap whatever buffers
with write combine(WC) page property. This is incorrect, as some platforms
are cached coherent. Cached buffers should be mapped with cached page
property.

Fixes: a0a5ab3e99b8 ("drm/etnaviv: call correct function when trying to vmap a 
DMABUF")
Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 1fd2cff20ef4..b899aea64e22 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -393,6 +393,7 @@ static void etnaviv_gem_object_vunmap(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);
 
@@ -400,8 +401,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)
-- 
2.43.0



[PATCH v15 07/19] drm/etnaviv: Add a dedicated helper function to get various clocks

2024-09-08 Thread Sui Jingfeng
Because the current implementation is DT-based, this only works when the
host platform has the DT support. The problem is that some host platforms
does not provide DT-based clocks drivers, as a result, the driver rage
quit.

PLL hardwares are typically provided by the host platform, which is part
of the entire clock tree. The PLL hardware provide clock pulse to the GPU
core, but it's not belong to the GPU corei itself. PLL registers can be
manipulated directly by the device driver. Hence, it may need dedicated
clock driver.

Add a the etnaviv_gpu_clk_get() function to group similar code blocks,
which make it easier to call this function on the platform where it works.

Signed-off-by: Sui Jingfeng 
---
 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 4599dd995e11..eca6a06e9ade 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1609,6 +1609,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;
@@ -1884,27 +1913,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.43.0



[PATCH v15 06/19] drm/etnaviv: Prefer drm_device based drm_WARN_ON() over regular WARN_ON()

2024-09-08 Thread Sui Jingfeng
drm_WARN_ON() acts like WARN_ON(), but with the key difference of
using device specific information so that we know from which device
the warning is originating from.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 9 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c   | 6 +++---
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c   | 7 +--
 4 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 55004fa9fabd..1fd2cff20ef4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -256,7 +256,7 @@ void etnaviv_gem_mapping_unreference(struct 
etnaviv_vram_mapping *mapping)
struct etnaviv_gem_object *etnaviv_obj = mapping->object;
 
mutex_lock(&etnaviv_obj->lock);
-   WARN_ON(mapping->use == 0);
+   drm_WARN_ON(etnaviv_obj->base.dev, mapping->use == 0);
mapping->use -= 1;
mutex_unlock(&etnaviv_obj->lock);
 
@@ -463,7 +463,7 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
 
if (etnaviv_obj->flags & ETNA_BO_CACHED) {
/* fini without a prep is almost certainly a userspace error */
-   WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
+   drm_WARN_ON(dev, etnaviv_obj->last_cpu_prep_op == 0);
dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,
etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
etnaviv_obj->last_cpu_prep_op = 0;
@@ -541,12 +541,13 @@ static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops 
= {
 
 void etnaviv_gem_free_object(struct drm_gem_object *obj)
 {
+   struct drm_device *drm = obj->dev;
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
struct etnaviv_drm_private *priv = obj->dev->dev_private;
struct etnaviv_vram_mapping *mapping, *tmp;
 
/* object should not be active */
-   WARN_ON(is_active(etnaviv_obj));
+   drm_WARN_ON(drm, is_active(etnaviv_obj));
 
mutex_lock(&priv->gem_lock);
list_del(&etnaviv_obj->gem_node);
@@ -556,7 +557,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 obj_node) {
struct etnaviv_iommu_context *context = mapping->context;
 
-   WARN_ON(mapping->use);
+   drm_WARN_ON(drm, mapping->use);
 
if (context)
etnaviv_iommu_unmap_gem(context, mapping);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 8f523cbee60a..0062d808d6a9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -19,7 +19,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
unsigned int npages = obj->size >> PAGE_SHIFT;
 
-   if (WARN_ON(!etnaviv_obj->pages))  /* should have already pinned! */
+   if (drm_WARN_ON(obj->dev, !etnaviv_obj->pages))  /* should have already 
pinned! */
return ERR_PTR(-EINVAL);
 
return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index d0df5c53a829..4599dd995e11 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -686,7 +686,7 @@ static void etnaviv_gpu_start_fe_idleloop(struct 
etnaviv_gpu *gpu,
u16 prefetch;
u32 address;
 
-   WARN_ON(gpu->state != ETNA_GPU_STATE_INITIALIZED);
+   drm_WARN_ON(gpu->drm, gpu->state != ETNA_GPU_STATE_INITIALIZED);
 
/* setup the MMU */
etnaviv_iommu_restore(gpu, context);
@@ -734,8 +734,8 @@ static void etnaviv_gpu_setup_pulse_eater(struct 
etnaviv_gpu *gpu)
 
 static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 {
-   WARN_ON(!(gpu->state == ETNA_GPU_STATE_IDENTIFIED ||
- gpu->state == ETNA_GPU_STATE_RESET));
+   drm_WARN_ON(gpu->drm, !(gpu->state == ETNA_GPU_STATE_IDENTIFIED ||
+   gpu->state == ETNA_GPU_STATE_RESET));
 
if ((etnaviv_is_model_rev(gpu, 0x320, 0x5007) ||
 etnaviv_is_model_rev(gpu, 0x320, 0x5220)) &&
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 02d9408d41bc..ed6c42384856 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -138,9 +138,10 @@ static void etnaviv_iommu_remove_mapping(struct 
etnaviv_iommu_context *context,
 void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping)
 {
struct etnaviv_io

[PATCH v15 05/19] drm/etnaviv: Add contructor and destructor for etnaviv_gem_get_mapping structure

2024-09-08 Thread Sui Jingfeng
Because this make the code more easier to understand, When GPU access the
VRAM, it will allocate a new mapping to use if there don't have one.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 40 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem.h |  6 
 2 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 85d4e7c87a6a..55004fa9fabd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -227,6 +227,30 @@ etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object 
*obj,
return NULL;
 }
 
+static struct etnaviv_vram_mapping *
+etnaviv_gem_vram_mapping_new(struct etnaviv_gem_object *etnaviv_obj)
+{
+   struct etnaviv_vram_mapping *mapping;
+
+   mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+   if (!mapping)
+   return NULL;
+
+   INIT_LIST_HEAD(&mapping->scan_node);
+   mapping->object = etnaviv_obj;
+   mapping->use = 1;
+
+   list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
+
+   return mapping;
+}
+
+static void etnaviv_gem_vram_mapping_destroy(struct etnaviv_vram_mapping 
*mapping)
+{
+   list_del(&mapping->obj_node);
+   kfree(mapping);
+}
+
 void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping)
 {
struct etnaviv_gem_object *etnaviv_obj = mapping->object;
@@ -289,27 +313,20 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get(
 */
mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, NULL);
if (!mapping) {
-   mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+   mapping = etnaviv_gem_vram_mapping_new(etnaviv_obj);
if (!mapping) {
ret = -ENOMEM;
goto out;
}
-
-   INIT_LIST_HEAD(&mapping->scan_node);
-   mapping->object = etnaviv_obj;
} else {
-   list_del(&mapping->obj_node);
+   mapping->use = 1;
}
 
-   mapping->use = 1;
-
ret = etnaviv_iommu_map_gem(mmu_context, etnaviv_obj,
mmu_context->global->memory_base,
mapping, va);
if (ret < 0)
-   kfree(mapping);
-   else
-   list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list);
+   etnaviv_gem_vram_mapping_destroy(mapping);
 
 out:
mutex_unlock(&etnaviv_obj->lock);
@@ -544,8 +561,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
if (context)
etnaviv_iommu_unmap_gem(context, mapping);
 
-   list_del(&mapping->obj_node);
-   kfree(mapping);
+   etnaviv_gem_vram_mapping_destroy(mapping);
}
 
etnaviv_obj->ops->vunmap(etnaviv_obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index d4965de3007c..f2ac64d8e90b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -31,6 +31,12 @@ struct etnaviv_vram_mapping {
u32 iova;
 };
 
+static inline struct etnaviv_vram_mapping *
+to_etnaviv_vram_mapping(struct drm_mm_node *vram)
+{
+   return container_of(vram, struct etnaviv_vram_mapping, vram_node);
+}
+
 struct etnaviv_gem_object {
struct drm_gem_object base;
const struct etnaviv_gem_ops *ops;
-- 
2.43.0



[PATCH v15 04/19] drm/etnaviv: Make etnaviv_gem_prime_vmap() a static function

2024-09-08 Thread Sui Jingfeng
The etnaviv_gem_prime_vmap() function has no caller in the
etnaviv_gem_prime.c file, move it into etnaviv_gem.c file.
While at it, rename it as etnaviv_gem_object_vmap(), since
it is a intermidiate layer function, it has no direct relation
ship with the PRIME. The etnaviv_gem_prime.c file already has
etnaviv_gem_prime_vmap_impl() as the implementation to vmap
a imported GEM buffer object.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.h   |  1 -
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 16 +++-
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 12 
 3 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 2eb2ff13f6e8..c217b54b214c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -55,7 +55,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void 
*data,
 
 int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset);
 struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj);
-int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
 struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device 
*dev,
struct dma_buf_attachment *attach, struct sg_table *sg);
 int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index fad23494d08e..85d4e7c87a6a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -6,6 +6,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -340,6 +341,19 @@ void *etnaviv_gem_vmap(struct drm_gem_object *obj)
return etnaviv_obj->vaddr;
 }
 
+static int etnaviv_gem_object_vmap(struct drm_gem_object *obj,
+  struct iosys_map *map)
+{
+   void *vaddr;
+
+   vaddr = etnaviv_gem_vmap(obj);
+   if (!vaddr)
+   return -ENOMEM;
+   iosys_map_set_vaddr(map, vaddr);
+
+   return 0;
+}
+
 void etnaviv_gem_vunmap(struct drm_gem_object *obj)
 {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
@@ -595,7 +609,7 @@ static const struct drm_gem_object_funcs 
etnaviv_gem_object_funcs = {
.pin = etnaviv_gem_prime_pin,
.unpin = etnaviv_gem_prime_unpin,
.get_sg_table = etnaviv_gem_prime_get_sg_table,
-   .vmap = etnaviv_gem_prime_vmap,
+   .vmap = etnaviv_gem_object_vmap,
.vunmap = etnaviv_gem_object_vunmap,
.mmap = etnaviv_gem_mmap,
.vm_ops = &vm_ops,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index bea50d720450..8f523cbee60a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -25,18 +25,6 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages);
 }
 
-int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map)
-{
-   void *vaddr;
-
-   vaddr = etnaviv_gem_vmap(obj);
-   if (!vaddr)
-   return -ENOMEM;
-   iosys_map_set_vaddr(map, vaddr);
-
-   return 0;
-}
-
 int etnaviv_gem_prime_pin(struct drm_gem_object *obj)
 {
if (!obj->import_attach) {
-- 
2.43.0



[PATCH v15 03/19] drm/etnaviv: Implement drm_gem_object_funcs::vunmap()

2024-09-08 Thread Sui Jingfeng
The vunmap() can be used to release virtual mapping obtained by vmap(),
While the vmap() is used to make a long duration mapping of multiple
physical pages into a contiguous virtual space.

Make the implementation-specific vunmap() operation untangled with the
etnaviv_gem_xxx_release() function. As then, the etnaviv_gem_xxx_release()
only need to responsible for the release page works.

The etnaviv_gem_vunmap() is added for driver internal usa case, where no
DRM GEM framework is involved.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.h   |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 38 -
 drivers/gpu/drm/etnaviv/etnaviv_gem.h   |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 13 ---
 4 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index b3eb1662e90c..2eb2ff13f6e8 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -61,6 +61,7 @@ struct drm_gem_object 
*etnaviv_gem_prime_import_sg_table(struct drm_device *dev,
 int etnaviv_gem_prime_pin(struct drm_gem_object *obj);
 void etnaviv_gem_prime_unpin(struct drm_gem_object *obj);
 void *etnaviv_gem_vmap(struct drm_gem_object *obj);
+void etnaviv_gem_vunmap(struct drm_gem_object *obj);
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
struct drm_etnaviv_timespec *timeout);
 int etnaviv_gem_cpu_fini(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 6bdf72cd9e85..fad23494d08e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -340,6 +340,25 @@ void *etnaviv_gem_vmap(struct drm_gem_object *obj)
return etnaviv_obj->vaddr;
 }
 
+void etnaviv_gem_vunmap(struct drm_gem_object *obj)
+{
+   struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+
+   if (!etnaviv_obj->vaddr)
+   return;
+
+   mutex_lock(&etnaviv_obj->lock);
+   etnaviv_obj->ops->vunmap(etnaviv_obj);
+   etnaviv_obj->vaddr = NULL;
+   mutex_unlock(&etnaviv_obj->lock);
+}
+
+static void etnaviv_gem_object_vunmap(struct drm_gem_object *obj,
+ struct iosys_map *map)
+{
+   etnaviv_gem_vunmap(obj);
+}
+
 static void *etnaviv_gem_vmap_impl(struct etnaviv_gem_object *obj)
 {
struct page **pages;
@@ -471,14 +490,21 @@ void etnaviv_gem_describe_objects(struct 
etnaviv_drm_private *priv,
 
 static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj)
 {
-   vunmap(etnaviv_obj->vaddr);
put_pages(etnaviv_obj);
 }
 
+static void etnaviv_gem_shmem_vunmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+   lockdep_assert_held(&etnaviv_obj->lock);
+
+   vunmap(etnaviv_obj->vaddr);
+}
+
 static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = {
.get_pages = etnaviv_gem_shmem_get_pages,
.release = etnaviv_gem_shmem_release,
.vmap = etnaviv_gem_vmap_impl,
+   .vunmap = etnaviv_gem_shmem_vunmap,
.mmap = etnaviv_gem_mmap_obj,
 };
 
@@ -508,6 +534,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
kfree(mapping);
}
 
+   etnaviv_obj->ops->vunmap(etnaviv_obj);
etnaviv_obj->ops->release(etnaviv_obj);
drm_gem_object_release(obj);
 
@@ -569,6 +596,7 @@ static const struct drm_gem_object_funcs 
etnaviv_gem_object_funcs = {
.unpin = etnaviv_gem_prime_unpin,
.get_sg_table = etnaviv_gem_prime_get_sg_table,
.vmap = etnaviv_gem_prime_vmap,
+   .vunmap = etnaviv_gem_object_vunmap,
.mmap = etnaviv_gem_mmap,
.vm_ops = &vm_ops,
 };
@@ -723,6 +751,13 @@ static void etnaviv_gem_userptr_release(struct 
etnaviv_gem_object *etnaviv_obj)
}
 }
 
+static void etnaviv_gem_userptr_vunmap(struct etnaviv_gem_object *etnaviv_obj)
+{
+   lockdep_assert_held(&etnaviv_obj->lock);
+
+   vunmap(etnaviv_obj->vaddr);
+}
+
 static int etnaviv_gem_userptr_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
struct vm_area_struct *vma)
 {
@@ -733,6 +768,7 @@ static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops 
= {
.get_pages = etnaviv_gem_userptr_get_pages,
.release = etnaviv_gem_userptr_release,
.vmap = etnaviv_gem_vmap_impl,
+   .vunmap = etnaviv_gem_userptr_vunmap,
.mmap = etnaviv_gem_userptr_mmap_obj,
 };
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index 3f8fe19a77cc..d4965de3007c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -65,6 +65,7 @@ struct etnaviv_gem_ops {
int (*get_pages)(struct etnaviv_gem_object *);
void (*release)(struct etnaviv_gem_object *);
void 

[PATCH v15 02/19] drm/etnaviv: Export drm_gem_print_info() and use it

2024-09-08 Thread Sui Jingfeng
This will make the newly implemented etnaviv_gem_object_funcs::print_info
get in use, which improves code sharing and simplifies debugfs. Achieve
better humen readability for debug log.

Use container_of_const() if 'struct etnaviv_gem_object *etnaviv_obj' is a
constant pointer.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/drm_gem.c |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 13 +
 include/drm/drm_gem.h |  2 ++
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index d4bbc5d109c8..9c5c971c1b23 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1160,6 +1160,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned 
int indent,
if (obj->funcs->print_info)
obj->funcs->print_info(p, indent, obj);
 }
+EXPORT_SYMBOL(drm_gem_print_info);
 
 int drm_gem_pin_locked(struct drm_gem_object *obj)
 {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 543d881585b3..6bdf72cd9e85 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2015-2018 Etnaviv Project
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -432,15 +433,11 @@ int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct 
drm_gem_object *obj,
 #ifdef CONFIG_DEBUG_FS
 static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file 
*m)
 {
-   struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+   struct drm_printer p = drm_seq_file_printer(m);
struct dma_resv *robj = obj->resv;
-   unsigned long off = drm_vma_node_start(&obj->vma_node);
int r;
 
-   seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n",
-   etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
-   obj->name, kref_read(&obj->refcount),
-   off, etnaviv_obj->vaddr, obj->size);
+   drm_gem_print_info(&p, 1, obj);
 
r = dma_resv_lock(robj, NULL);
if (r)
@@ -461,7 +458,7 @@ void etnaviv_gem_describe_objects(struct 
etnaviv_drm_private *priv,
list_for_each_entry(etnaviv_obj, &priv->gem_list, gem_node) {
struct drm_gem_object *obj = &etnaviv_obj->base;
 
-   seq_puts(m, "   ");
+   seq_printf(m, "obj[%d]:\n", count);
etnaviv_gem_describe(obj, m);
count++;
size += obj->size;
@@ -556,7 +553,7 @@ static void etnaviv_gem_object_info(struct drm_printer *p,
 {
const struct etnaviv_gem_object *etnaviv_obj;
 
-   etnaviv_obj = container_of(obj, struct etnaviv_gem_object, base);
+   etnaviv_obj = container_of_const(obj, struct etnaviv_gem_object, base);
 
drm_printf_indent(p, indent, "caching mode=%s\n",
  etnaviv_gem_obj_caching_info(etnaviv_obj->flags));
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index bae4865b2101..0791566fab53 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -480,6 +480,8 @@ void drm_gem_vm_close(struct vm_area_struct *vma);
 int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
+   const struct drm_gem_object *obj);
 
 /**
  * drm_gem_object_get - acquire a GEM buffer object reference
-- 
2.43.0



[PATCH v15 01/19] drm/etnaviv: Implement drm_gem_object_funcs::print_info()

2024-09-08 Thread Sui Jingfeng
It will be called by drm_gem_print_info() if implemented, and it can
provide more information about the framebuffer objects.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 32 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem.h |  2 +-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 4247a10f8d4f..543d881585b3 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -534,8 +534,40 @@ static const struct vm_operations_struct vm_ops = {
.close = drm_gem_vm_close,
 };
 
+static const char *etnaviv_gem_obj_caching_info(u32 flags)
+{
+   switch (flags & ETNA_BO_CACHE_MASK) {
+   case ETNA_BO_CACHED:
+   return "cached";
+   case ETNA_BO_UNCACHED:
+   return "uncached";
+   case ETNA_BO_WC:
+   return "write-combine";
+   default:
+   break;
+   }
+
+   return "unknown";
+}
+
+static void etnaviv_gem_object_info(struct drm_printer *p,
+   unsigned int indent,
+   const struct drm_gem_object *obj)
+{
+   const struct etnaviv_gem_object *etnaviv_obj;
+
+   etnaviv_obj = container_of(obj, struct etnaviv_gem_object, base);
+
+   drm_printf_indent(p, indent, "caching mode=%s\n",
+ etnaviv_gem_obj_caching_info(etnaviv_obj->flags));
+   drm_printf_indent(p, indent, "active=%s\n",
+ str_yes_no(is_active(etnaviv_obj)));
+   drm_printf_indent(p, indent, "vaddr=%p\n", etnaviv_obj->vaddr);
+}
+
 static const struct drm_gem_object_funcs etnaviv_gem_object_funcs = {
.free = etnaviv_gem_free_object,
+   .print_info = etnaviv_gem_object_info,
.pin = etnaviv_gem_prime_pin,
.unpin = etnaviv_gem_prime_unpin,
.get_sg_table = etnaviv_gem_prime_get_sg_table,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index a42d260cac2c..3f8fe19a77cc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -68,7 +68,7 @@ struct etnaviv_gem_ops {
int (*mmap)(struct etnaviv_gem_object *, struct vm_area_struct *);
 };
 
-static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
+static inline bool is_active(const struct etnaviv_gem_object *etnaviv_obj)
 {
return atomic_read(&etnaviv_obj->gpu_active) != 0;
 }
-- 
2.43.0



[PATCH v15 00/19] drm/etnaviv: Add driver wrapper for vivante GPUs attached on PCI(e) device

2024-09-08 Thread Sui Jingfeng
drm/etnaviv use the component framework to bind multiple GPU cores to a
virtual master, the virtual master is manually create during driver load
time. This may works well for SoCs, yet there are some PCIe card has the
vivante GPU cores integrated. The driver lacks support for PCIe devices
currently.

Adds PCIe driver wrapper on the top of drm/etnaviv, the component
framework is still being used to bind subdevices, even though there is
only one GPU core. But the process is going to be reversed, we create
virtual platform device for each of the vivante GPU IP core that is
shipped by the PCIe card. Select the PCIe device as parent, generate a
virtual platform device as component master to take over the bind actions.

Sui Jingfeng (19):
  drm/etnaviv: Implement drm_gem_object_funcs::print_info()
  drm/etnaviv: Export drm_gem_print_info() and use it
  drm/etnaviv: Implement drm_gem_object_funcs::vunmap()
  drm/etnaviv: Make etnaviv_gem_prime_vmap() a static function
  drm/etnaviv: Add contructor and destructor for etnaviv_gem_get_mapping
structure
  drm/etnaviv: Prefer drm_device based drm_WARN_ON() over regular
WARN_ON()
  drm/etnaviv: Add a dedicated helper function to get various clocks
  drm/etnaviv: Fix wrong caching mode being used for non writecombine
buffers
  drm/etnaviv: Add constructor and destructor for the
etnaviv_drm_private structure
  drm/etnaviv: Embed struct drm_device into struct etnaviv_drm_private
  drm/etnaviv: Add etnaviv_gem_obj_remove() helper
  drm/etnaviv: Add support for cached coherent caching mode
  drm/etnaviv: Add support for vivante GPU cores attached via PCIe
device
  drm/etnaviv: Add PCIe IP setup code
  drm/etnaviv: Make more use of the etnaviv_gem_new_private() function
  drm/etnaviv: Call etnaviv_gem_obj_add() in ernaviv_gem_new_private()
  drm/etnaviv: Support to manage dedicated VRAM base on drm_mm
  drm/etnaviv: Allow userspace specify the domain of etnaviv GEM buffer
object
  drm/etnaviv: Expose basic sanity tests via debugfs

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:
* Process reviews since V10.
* Provide a side by side implement

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

V13:
* Drop the non-component code path, always use the component framework
  to bind subcomponent GPU core. Even though there is only one core.
* Defer the irq handler register.
* Rebase and improve the commit message

V14:
* Rebase onto etnaviv-next and improve commit message.

V15:
* Plug in a drm-mm based dedicated VRAM range allocator.

 drivers/gpu/drm/drm_gem.c|   1 +
 drivers/gpu/drm/etnaviv/Kconfig  |   9 +
 drivers/gpu/drm/etnaviv/Makefile |   5 +
 drivers/gpu/drm/etnaviv/etnaviv_debugfs.c| 118 +
 drivers/gpu/drm/etnaviv/etnaviv_debugfs.h|  15 ++
 drivers/gpu/drm/etnaviv/etnaviv_drv.c| 183 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.h|  40 ++-
 drivers/gpu/drm/etnaviv/etnaviv_gem.c| 224 
 drivers/gpu/drm/etnaviv/etnaviv_gem.h|  21 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c  |  31 +--
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c |   2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c   | 264 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h   |  14 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c| 136 +++---
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h|   4 +
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c|  11 +-
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c| 217 +++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h|  63 +
 drivers/gpu/drm/etnaviv/pcie_ip_setup.c  | 109 
 include/drm/drm_gem.h|   2 +
 include/uapi/drm/etnaviv_drm.h   |  13 +
 21 files changed, 1308 insertions(+), 174 deletions(-)
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_debugfs.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_debugfs.h
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_gem_vram.h
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c
 create mode 100644 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h
 create mode 100644 drivers/gpu/drm/etnaviv/pcie_ip_setup.c

-- 
2.43.0



[PATCH] drm/etnaviv: Print error message when driver can't get pages

2024-09-08 Thread Sui Jingfeng
This error could happen when the GFP_HIGHUSER flag is set, such an error
can also be seen on the X86 platform. According to the kernel document in
gfp_types.h, "the GFP_HIGHUSER is for userspace allocations that may be
mapped to userspace, it do not need to be directly accessible by the
kernel."

However, drm/etnaviv will use the pages to implement vmap and mmap
operations of the GEM object function. The flag still set at present.
When we can't get pages, it certainly is a bug. Hence, we should print
this kind of error with drm_err() instead of dev_dbg().

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 5c0c9d4e3be1..5ffc31f32ac9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -61,7 +61,7 @@ static int etnaviv_gem_shmem_get_pages(struct 
etnaviv_gem_object *etnaviv_obj)
struct page **p = drm_gem_get_pages(&etnaviv_obj->base);
 
if (IS_ERR(p)) {
-   dev_dbg(dev->dev, "could not get pages: %ld\n", PTR_ERR(p));
+   drm_err(dev, "could not get pages: %ld\n", PTR_ERR(p));
return PTR_ERR(p);
}
 
-- 
2.43.0



Re: [v2] drm/etnaviv: Clear the __GFP_HIGHMEM bit in GFP_HIGHUSER with 32 address

2024-08-30 Thread Sui Jingfeng

Hi, Xiaolei


Thanks for your nice catch! I have more to say.

On 2024/8/16 09:55, Wang, Xiaolei wrote:

Ping ...


32 address -> 32-bit address,

Perhaps, we could improve the commit title a little bit
by writing a more accurate sentence if possible, say:

drm/etnaviv: Properly request pages from DMA32 zone when needed

or

drm/etnaviv: Request pages from DMA32 zone on addressing_limited



thanks
xiaolei


Vivante GPU is a 32-bit GPU, it do can access 40-bit physical address via its 
MMU(IOMMU).
But this is only possible *after* the MMU has been setup(initialized). Before 
GPU page
table is setup(and flush-ed into the GPU's TLB), the device can only access 
32-bit
physical addresses and the addresses has to be physical continues in ranges.

The GPU page tables (GART) and command buffer has to reside in low 4GB address.


diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7c7f97793ddd..0e6bdf2d028b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -844,8 +844,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
   * request pages for our SHM backend buffers from the DMA32 zone to
   * hopefully avoid performance killing SWIOTLB bounce buffering.
   */
-   if (dma_addressing_limited(gpu->dev))
+   if (dma_addressing_limited(gpu->dev)) {
  priv->shm_gfp_mask |= GFP_DMA32;
+   priv->shm_gfp_mask &= ~__GFP_HIGHMEM;
+   }


The code here  still looks itchy and risky,
because for a i.MX8 SoC with multiple vivante GPU core.
We will modify priv->shm_gfp_mask *multiple* time.

For the 2D core and the 3D core have different DMA addressing constraint.
Then, only the last(latest) modify will be effective. This lead to the
probe order dependent.

However this may not be a problem in practice, as usually, all vivante
GPUs in the system will share the same DMA constraints. And the driver
assume that.

But then, we probably still should not modify the global shared GFP
mask multiple time.

Now that we do assume that all vivante GPUs in the system share the
same DMA constraints. And the DMA constraints information has been
assigned to the virtual master. The right time to modify the
`priv->shm_gfp_mask` should be in the etnaviv_bind() function. as
this can eliminate overlap(repeat) stores.


Please consider move the entire if() {} to etnaviv_bind(), just below
where the 'priv->shm_gfp_mask' was initially initialized.

or alternatively we can just hard-code to use low 4GM memmory only:

priv->shm_gfp_mask = GFP_USER | GFP_DMA32 | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;


Best regards,
Sui


  /* Create buffer: */
  ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer,


Re: [v2] drm/etnaviv: Clear the __GFP_HIGHMEM bit in GFP_HIGHUSER with 32 address

2024-08-30 Thread Sui Jingfeng

On 2024/8/31 03:40, Sui Jingfeng wrote:

Hi, Xiaolei


On 2024/8/16 09:55, Wang, Xiaolei wrote:

Ping ...


I think, the more proper fix that Lucas hint
is to modify the 'priv->shm_gfp_mask' variable
in the|etnaviv_bind() function|. Say:
|Use "priv->shm_gfp_mask = GFP_USER | __GFP_RETRY_MAYFAIL | 
__GFP_NOWARN;"|


instead of

|"priv->shm_gfp_mask = ||GFP_HIGHUSER||| __GFP_RETRY_MAYFAIL | 
__GFP_NOWARN;|"





Oops, please ignore the irrelevant(superfluous) "|" characters in my
reply, my Thunderbird mail client has some problem, generate them unreasonably.

Should be:

priv->shm_gfp_mask = GFP_USER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;




Right?


thanks
xiaolei

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c

index 7c7f97793ddd..0e6bdf2d028b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -844,8 +844,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
   * request pages for our SHM backend buffers from the DMA32 
zone to
   * hopefully avoid performance killing SWIOTLB bounce 
buffering.

   */
-   if (dma_addressing_limited(gpu->dev))
+   if (dma_addressing_limited(gpu->dev)) {
  priv->shm_gfp_mask |= GFP_DMA32;
+   priv->shm_gfp_mask &= ~__GFP_HIGHMEM;
+   }

  /* Create buffer: */
  ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer,



--
Best regards,
Sui



Re: [v2] drm/etnaviv: Clear the __GFP_HIGHMEM bit in GFP_HIGHUSER with 32 address

2024-08-30 Thread Sui Jingfeng

Hi, Xiaolei


On 2024/8/16 09:55, Wang, Xiaolei wrote:

Ping ...


I think, the more proper fix that Lucas hint
is to modify the 'priv->shm_gfp_mask' variable
in the|etnaviv_bind() function|. Say:
|Use "priv->shm_gfp_mask = GFP_USER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN;"|

instead of

|"priv->shm_gfp_mask = ||GFP_HIGHUSER||| __GFP_RETRY_MAYFAIL | __GFP_NOWARN;|"


Right?


thanks
xiaolei

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7c7f97793ddd..0e6bdf2d028b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -844,8 +844,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
   * request pages for our SHM backend buffers from the DMA32 zone to
   * hopefully avoid performance killing SWIOTLB bounce buffering.
   */
-   if (dma_addressing_limited(gpu->dev))
+   if (dma_addressing_limited(gpu->dev)) {
  priv->shm_gfp_mask |= GFP_DMA32;
+   priv->shm_gfp_mask &= ~__GFP_HIGHMEM;
+   }

  /* Create buffer: */
  ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer,


--
Best regards,
Sui



[PATCH 0/2] drm/etnaviv: Implement drm_gem_object_funcs::print_info()

2024-08-25 Thread Sui Jingfeng
It will be called by drm_gem_print_info() if have implemented, and this can
provide more information about the framebuffer objects. In order to make
the newly implemented etnaviv_gem_object_funcs::print_info() get in use,
we make the drm_gem_print_info() exported, then we re-implement the
etnaviv_gem_describe() base on it.

Sample Testing Information:

[root@fedora 0]# ls
clients  DPI-1  encoder-1gem_names mmring
crtc-0   DPI-2  framebuffer  gpu   mmu   state
crtc-1   encoder-0  gem  internal_clients  name
[root@fedora 0]# cat framebuffer 
framebuffer[49]:
allocated by = Xorg
refcount=1
format=AR24 little-endian (0x34325241)
modifier=0x0
size=32x32
layers:
size[0]=32x32
pitch[0]=128
offset[0]=0
obj[0]:
name=0
refcount=3
start=00040096
size=16384
imported=no
caching mode=write-combine
active=no
vaddr=
framebuffer[47]:
allocated by = Xorg
refcount=2
format=XR24 little-endian (0x34325258)
modifier=0x0
size=1024x600
layers:
size[0]=1024x600
pitch[0]=4096
offset[0]=0
obj[0]:
name=0
refcount=3
start=0004
size=2457600
imported=no
caching mode=write-combine
active=no
vaddr=

[root@fedora 0]# cat gem
obj[0]:
name=0
refcount=3
start=0004
size=2457600
imported=no
caching mode=write-combine
active=no
vaddr=
obj[1]:
name=0
refcount=3
start=00040096
size=16384
imported=no
caching mode=write-combine
active=no
vaddr=
obj[2]:
name=0
refcount=2
start=00040097
size=16384
imported=no
caching mode=write-combine
active=no
vaddr=
Total 3 objects, 2490368 bytes

Sui Jingfeng (2):
  drm/etnaviv: Implement drm_gem_object_funcs::print_info()
  drm/etnaviv: Export drm_gem_print_info() and use it

 drivers/gpu/drm/drm_gem.c |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 43 ++-
 drivers/gpu/drm/etnaviv/etnaviv_gem.h |  2 +-
 include/drm/drm_gem.h |  2 ++
 4 files changed, 40 insertions(+), 8 deletions(-)

-- 
2.34.1



[PATCH 2/2] drm/etnaviv: Export drm_gem_print_info() and use it

2024-08-25 Thread Sui Jingfeng
This will make the newly implemented etnaviv_gem_object_funcs::print_info
get in use, which improves code sharing and simplifies debugfs. Achieve
better humen readability for debug log.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/drm_gem.c |  1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 11 ---
 include/drm/drm_gem.h |  2 ++
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index d4bbc5d109c8..9c5c971c1b23 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1160,6 +1160,7 @@ void drm_gem_print_info(struct drm_printer *p, unsigned 
int indent,
if (obj->funcs->print_info)
obj->funcs->print_info(p, indent, obj);
 }
+EXPORT_SYMBOL(drm_gem_print_info);
 
 int drm_gem_pin_locked(struct drm_gem_object *obj)
 {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 9a688c95f34d..f2f446d46921 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2015-2018 Etnaviv Project
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -432,15 +433,11 @@ int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct 
drm_gem_object *obj,
 #ifdef CONFIG_DEBUG_FS
 static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file 
*m)
 {
-   struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
+   struct drm_printer p = drm_seq_file_printer(m);
struct dma_resv *robj = obj->resv;
-   unsigned long off = drm_vma_node_start(&obj->vma_node);
int r;
 
-   seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n",
-   etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
-   obj->name, kref_read(&obj->refcount),
-   off, etnaviv_obj->vaddr, obj->size);
+   drm_gem_print_info(&p, 1, obj);
 
r = dma_resv_lock(robj, NULL);
if (r)
@@ -461,7 +458,7 @@ void etnaviv_gem_describe_objects(struct 
etnaviv_drm_private *priv,
list_for_each_entry(etnaviv_obj, &priv->gem_list, gem_node) {
struct drm_gem_object *obj = &etnaviv_obj->base;
 
-   seq_puts(m, "   ");
+   seq_printf(m, "obj[%d]:\n", count);
etnaviv_gem_describe(obj, m);
count++;
size += obj->size;
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index bae4865b2101..0791566fab53 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -480,6 +480,8 @@ void drm_gem_vm_close(struct vm_area_struct *vma);
 int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
+   const struct drm_gem_object *obj);
 
 /**
  * drm_gem_object_get - acquire a GEM buffer object reference
-- 
2.34.1



[PATCH 1/2] drm/etnaviv: Implement drm_gem_object_funcs::print_info()

2024-08-25 Thread Sui Jingfeng
It will be called by drm_gem_print_info() if have implemented, and this can
provide more information about the framebuffer objects.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 32 +++
 drivers/gpu/drm/etnaviv/etnaviv_gem.h |  2 +-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 5c0c9d4e3be1..9a688c95f34d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -533,8 +533,40 @@ static const struct vm_operations_struct vm_ops = {
.close = drm_gem_vm_close,
 };
 
+static const char *etnaviv_gem_obj_caching_info(u32 flags)
+{
+   switch (flags & ETNA_BO_CACHE_MASK) {
+   case ETNA_BO_CACHED:
+   return "cached";
+   case ETNA_BO_UNCACHED:
+   return "uncached";
+   case ETNA_BO_WC:
+   return "write-combine";
+   default:
+   break;
+   }
+
+   return "unknown";
+}
+
+static void etnaviv_gem_object_info(struct drm_printer *p,
+   unsigned int indent,
+   const struct drm_gem_object *obj)
+{
+   const struct etnaviv_gem_object *etnaviv_obj;
+
+   etnaviv_obj = container_of(obj, struct etnaviv_gem_object, base);
+
+   drm_printf_indent(p, indent, "caching mode=%s\n",
+ etnaviv_gem_obj_caching_info(etnaviv_obj->flags));
+   drm_printf_indent(p, indent, "active=%s\n",
+ str_yes_no(is_active(etnaviv_obj)));
+   drm_printf_indent(p, indent, "vaddr=%p\n", etnaviv_obj->vaddr);
+}
+
 static const struct drm_gem_object_funcs etnaviv_gem_object_funcs = {
.free = etnaviv_gem_free_object,
+   .print_info = etnaviv_gem_object_info,
.pin = etnaviv_gem_prime_pin,
.unpin = etnaviv_gem_prime_unpin,
.get_sg_table = etnaviv_gem_prime_get_sg_table,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
index a42d260cac2c..3f8fe19a77cc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h
@@ -68,7 +68,7 @@ struct etnaviv_gem_ops {
int (*mmap)(struct etnaviv_gem_object *, struct vm_area_struct *);
 };
 
-static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj)
+static inline bool is_active(const struct etnaviv_gem_object *etnaviv_obj)
 {
return atomic_read(&etnaviv_obj->gpu_active) != 0;
 }
-- 
2.34.1



[PATCH] drm/etnaviv: Use unsigned type to count the number of userspace pages

2024-08-25 Thread Sui Jingfeng
The unpin_user_pages() function takes an unsigned long argument to store
length of the number of user space pages, and struct drm_gem_object::size
is a size_t type. The number of pages can not be negative, hence, use an
unsigned variable to store the number of pages.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index ce9c9233c4a6..fa0d193cec26 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -695,7 +695,7 @@ static void etnaviv_gem_userptr_release(struct 
etnaviv_gem_object *etnaviv_obj)
kfree(etnaviv_obj->sgt);
}
if (etnaviv_obj->pages) {
-   int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
+   unsigned int npages = etnaviv_obj->base.size >> PAGE_SHIFT;
 
unpin_user_pages(etnaviv_obj->pages, npages);
kvfree(etnaviv_obj->pages);
-- 
2.34.1



[PATCH] drm/etnaviv: Use unsigned type to count the number of pages

2024-08-25 Thread Sui Jingfeng
The drm_prime_pages_to_sg() function takes unsigned int argument to store
length of the page vector, and the type of struct drm_gem_object::size is
a size_t. The size of the object in CPU pages can not be negative, hence,
use unsigned variable to store the number of pages, instead of the signed
type.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 3524b5811682..6b98200068e4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -17,7 +17,7 @@ static struct lock_class_key etnaviv_prime_lock_class;
 struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
-   int npages = obj->size >> PAGE_SHIFT;
+   unsigned int npages = obj->size >> PAGE_SHIFT;
 
if (WARN_ON(!etnaviv_obj->pages))  /* should have already pinned! */
return ERR_PTR(-EINVAL);
-- 
2.34.1



[PATCH] drm/etnaviv: Drop the header

2024-08-25 Thread Sui Jingfeng
Currently, the etnaviv_gem_submit.c isn't call any runtime power management
functions. So drop it, we can re-include it when the header really get used
though.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 3d0f8d182506..3c0a5c3e0e3d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -6,7 +6,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
-- 
2.34.1



[PATCH] drm/etnaviv: Fix missing mutex_destroy()

2024-08-25 Thread Sui Jingfeng
Currently, the calling of mutex_destroy() is ignored on error handling
code path. It is safe for now, since mutex_destroy() actually does
nothing in non-debug builds. But the mutex_destroy() is used to mark
the mutex uninitialized on debug builds, and any subsequent use of the
mutex is forbidden.

It also could lead to problems if mutex_destroy() gets extended, add
missing mutex_destroy() to eliminate potential concerns.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c | 3 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.c| 1 +
 drivers/gpu/drm/etnaviv/etnaviv_gem.c| 1 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c| 5 +
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c| 2 +-
 5 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c 
b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
index 721d633aece9..1edc02022be4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
@@ -79,6 +79,9 @@ void etnaviv_cmdbuf_suballoc_destroy(struct 
etnaviv_cmdbuf_suballoc *suballoc)
 {
dma_free_wc(suballoc->dev, SUBALLOC_SIZE, suballoc->vaddr,
suballoc->paddr);
+
+   mutex_destroy(&suballoc->lock);
+
kfree(suballoc);
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6500f3999c5f..7844cd961a29 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -564,6 +564,7 @@ static int etnaviv_bind(struct device *dev)
 out_destroy_suballoc:
etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
 out_free_priv:
+   mutex_destroy(&priv->gem_lock);
kfree(priv);
 out_put:
drm_dev_put(drm);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index fe665ca20c02..b68e3b235a7d 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -515,6 +515,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
etnaviv_obj->ops->release(etnaviv_obj);
drm_gem_object_release(obj);
 
+   mutex_destroy(&etnaviv_obj->lock);
kfree(etnaviv_obj);
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index af52922ff494..d6acc4c68102 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1929,8 +1929,13 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
 
 static void etnaviv_gpu_platform_remove(struct platform_device *pdev)
 {
+   struct etnaviv_gpu *gpu = dev_get_drvdata(&pdev->dev);
+
component_del(&pdev->dev, &gpu_ops);
pm_runtime_disable(&pdev->dev);
+
+   mutex_destroy(&gpu->lock);
+   mutex_destroy(&gpu->sched_lock);
 }
 
 static int etnaviv_gpu_rpm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index e3be16165c86..ed6c42384856 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -361,7 +361,7 @@ static void etnaviv_iommu_context_free(struct kref *kref)
container_of(kref, struct etnaviv_iommu_context, refcount);
 
etnaviv_cmdbuf_suballoc_unmap(context, &context->cmdbuf_mapping);
-
+   mutex_destroy(&context->lock);
context->global->ops->free(context);
 }
 void etnaviv_iommu_context_put(struct etnaviv_iommu_context *context)
-- 
2.34.1



[PATCH] drm/etnaviv: Prefer drm_device based drm_WARN_ON() over regular WARN_ON()

2024-08-25 Thread Sui Jingfeng
drm_WARN_ON() acts like WARN_ON(), but with the key difference of
using device specific information so that we know from which device
warning is originating from.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c   | 9 +
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c   | 6 +++---
 drivers/gpu/drm/etnaviv/etnaviv_mmu.c   | 7 +--
 4 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index 5c0c9d4e3be1..fe665ca20c02 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -230,7 +230,7 @@ void etnaviv_gem_mapping_unreference(struct 
etnaviv_vram_mapping *mapping)
struct etnaviv_gem_object *etnaviv_obj = mapping->object;
 
mutex_lock(&etnaviv_obj->lock);
-   WARN_ON(mapping->use == 0);
+   drm_WARN_ON(etnaviv_obj->base.dev, mapping->use == 0);
mapping->use -= 1;
mutex_unlock(&etnaviv_obj->lock);
 
@@ -412,7 +412,7 @@ int etnaviv_gem_cpu_fini(struct drm_gem_object *obj)
 
if (etnaviv_obj->flags & ETNA_BO_CACHED) {
/* fini without a prep is almost certainly a userspace error */
-   WARN_ON(etnaviv_obj->last_cpu_prep_op == 0);
+   drm_WARN_ON(dev, etnaviv_obj->last_cpu_prep_op == 0);
dma_sync_sgtable_for_device(dev->dev, etnaviv_obj->sgt,
etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op));
etnaviv_obj->last_cpu_prep_op = 0;
@@ -487,12 +487,13 @@ static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops 
= {
 
 void etnaviv_gem_free_object(struct drm_gem_object *obj)
 {
+   struct drm_device *drm = obj->dev;
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
struct etnaviv_drm_private *priv = obj->dev->dev_private;
struct etnaviv_vram_mapping *mapping, *tmp;
 
/* object should not be active */
-   WARN_ON(is_active(etnaviv_obj));
+   drm_WARN_ON(drm, is_active(etnaviv_obj));
 
mutex_lock(&priv->gem_lock);
list_del(&etnaviv_obj->gem_node);
@@ -502,7 +503,7 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj)
 obj_node) {
struct etnaviv_iommu_context *context = mapping->context;
 
-   WARN_ON(mapping->use);
+   drm_WARN_ON(drm, mapping->use);
 
if (context)
etnaviv_iommu_unmap_gem(context, mapping);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
index 3524b5811682..c651188095b6 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
@@ -19,7 +19,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct 
drm_gem_object *obj)
struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj);
int npages = obj->size >> PAGE_SHIFT;
 
-   if (WARN_ON(!etnaviv_obj->pages))  /* should have already pinned! */
+   if (drm_WARN_ON(obj->dev, !etnaviv_obj->pages))  /* should have already 
pinned! */
return ERR_PTR(-EINVAL);
 
return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7c7f97793ddd..af52922ff494 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -686,7 +686,7 @@ static void etnaviv_gpu_start_fe_idleloop(struct 
etnaviv_gpu *gpu,
u16 prefetch;
u32 address;
 
-   WARN_ON(gpu->state != ETNA_GPU_STATE_INITIALIZED);
+   drm_WARN_ON(gpu->drm, gpu->state != ETNA_GPU_STATE_INITIALIZED);
 
/* setup the MMU */
etnaviv_iommu_restore(gpu, context);
@@ -734,8 +734,8 @@ static void etnaviv_gpu_setup_pulse_eater(struct 
etnaviv_gpu *gpu)
 
 static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 {
-   WARN_ON(!(gpu->state == ETNA_GPU_STATE_IDENTIFIED ||
- gpu->state == ETNA_GPU_STATE_RESET));
+   drm_WARN_ON(gpu->drm, !(gpu->state == ETNA_GPU_STATE_IDENTIFIED ||
+   gpu->state == ETNA_GPU_STATE_RESET));
 
if ((etnaviv_is_model_rev(gpu, 0x320, 0x5007) ||
 etnaviv_is_model_rev(gpu, 0x320, 0x5220)) &&
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index 1661d589bf3e..e3be16165c86 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -138,9 +138,10 @@ static void etnaviv_iommu_remove_mapping(struct 
etnaviv_iommu_context *context,
 void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping)
 {
struct etnaviv_iommu_context *co

Re: [82/86] drm/i915: Move custom hotplug code into separate callback

2024-08-20 Thread Sui Jingfeng

Hi,


On 2024/8/20 15:39, Thomas Zimmermann wrote:

Hi

Am 19.08.24 um 10:52 schrieb Sui Jingfeng:

Hi, Thomas


I love your patch, yet ...


On 2024/8/16 20:23, Thomas Zimmermann wrote:

i915's fbdev contains additional code for hotplugging a display that
cannot be ported to the common fbdev client. Introduce the callback
struct drm_fb_helper.fb_hotplug and implement it for i915. The fbdev
helpers invoke the callback before handing the hotplug event.

Signed-off-by: Thomas Zimmermann 
Cc: Jani Nikula 
Cc: Rodrigo Vivi 
Cc: Joonas Lahtinen 
Cc: Tvrtko Ursulin 
Cc: Lucas De Marchi 
Cc: "Thomas Hellström" 
---
  drivers/gpu/drm/drm_fb_helper.c    |  6 +++
  drivers/gpu/drm/i915/display/intel_fbdev.c | 43 
--

  include/drm/drm_fb_helper.h    | 13 +++
  3 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c 
b/drivers/gpu/drm/drm_fb_helper.c

index d9e539b0fd1a..92926cb02dfb 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1938,6 +1938,12 @@ int drm_fb_helper_hotplug_event(struct 
drm_fb_helper *fb_helper)

  if (!drm_fbdev_emulation || !fb_helper)
  return 0;
  +    if (fb_helper->funcs->fb_hotplug) {


We seems need to check the existence on the 'fb_helper->funcs' here,

For example:


if (fb_helper->funcs && fb_helper->funcs->fb_hotplug) {

Otherwise, it will de-reference NULL pointer.
Can be observed on a trivial driver though,
with no monitor(display) connected.


Indeed. That needs to be fixed. Thank you for noting.



Thanks for you efforts then.


To give some context:  I was hoping to remove drm_fb_helper_funcs at 
some point. 



Yeah, too many helper functions may make peoples daze.


fb_probe is now gone with these patches and fb_dirty can certainly be 
replaced as well. (I once had prototype patches to do that). 



Well, the grammar of "ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);" looks strange, 
It's lengthy and I observed you have cleaned it up at the last patch. 
Which also eliminates one pair "if and else" clause, the codes looks 
more fluent now.



This leaves the new callbacks for 915, for which I don't have a good 
alternative solution. So it seems that drm_fb_helper_funcs will only 
be used by i915/xe in the long term.




Well, since it is a DRM client now, maybe we could try to drop it into struct 
drm_driver.
Just like the '.fbdev_probe' callback, this may help to achieve a 100% 
DRM-based console/logger IMO.

Besides, a lot of DRM driver instances has the DMA/2D acceleration hardware, 
promote it
into drm_driver structure may has the potential to utilize hardware 
acceleration. Drivers
will more easily to have custom implementation. I'm not 100% sure if it will 
only be used
by i915 in the future.

Best regards,
Sui



Re: [68/86] drm/loongson: Run DRM default client setup

2024-08-19 Thread Sui Jingfeng

Hi,


On 2024/8/16 20:23, Thomas Zimmermann wrote:

Call drm_client_setup() to run the kernel's default client setup
for DRM. Set fbdev_probe in struct drm_driver, so that the client
setup can start the common fbdev client.

The loongson driver specifies a preferred color mode of 32. As this
is the default if no format has been given, leave it out entirely.

Signed-off-by: Thomas Zimmermann 



Thanks,


Acked-by: Sui Jingfeng 

--
Best regards,
Sui



Re: [82/86] drm/i915: Move custom hotplug code into separate callback

2024-08-19 Thread Sui Jingfeng

Hi, Thomas


I love your patch, yet ...


On 2024/8/16 20:23, Thomas Zimmermann wrote:

i915's fbdev contains additional code for hotplugging a display that
cannot be ported to the common fbdev client. Introduce the callback
struct drm_fb_helper.fb_hotplug and implement it for i915. The fbdev
helpers invoke the callback before handing the hotplug event.

Signed-off-by: Thomas Zimmermann 
Cc: Jani Nikula 
Cc: Rodrigo Vivi 
Cc: Joonas Lahtinen 
Cc: Tvrtko Ursulin 
Cc: Lucas De Marchi 
Cc: "Thomas Hellström" 
---
  drivers/gpu/drm/drm_fb_helper.c|  6 +++
  drivers/gpu/drm/i915/display/intel_fbdev.c | 43 --
  include/drm/drm_fb_helper.h| 13 +++
  3 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d9e539b0fd1a..92926cb02dfb 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1938,6 +1938,12 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper 
*fb_helper)
if (!drm_fbdev_emulation || !fb_helper)
return 0;
  
+	if (fb_helper->funcs->fb_hotplug) {


We seems need to check the existence on the 'fb_helper->funcs' here,

For example:


if (fb_helper->funcs && fb_helper->funcs->fb_hotplug) {

Otherwise, it will de-reference NULL pointer.
Can be observed on a trivial driver though,
with no monitor(display) connected.



+   err = fb_helper->funcs->fb_hotplug(fb_helper);
+   if (err)
+   return err;
+   }
+
mutex_lock(&fb_helper->lock);
if (fb_helper->deferred_setup) {
err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c 
b/drivers/gpu/drm/i915/display/intel_fbdev.c
index c03fb2a4..abe77ef0bd84 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
@@ -305,10 +305,32 @@ static void intelfb_restore(struct drm_fb_helper 
*fb_helper)
intel_fbdev_invalidate(ifbdev);
  }
  
+static int intelfb_hotplug(struct drm_fb_helper *fb_helper)

+{
+   struct drm_device *dev = fb_helper->client.dev;
+   struct drm_i915_private *dev_priv = to_i915(dev);
+   struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev;
+   bool send_hpd;
+
+   if (!ifbdev)
+   return -EINVAL;
+
+   mutex_lock(&ifbdev->hpd_lock);
+   send_hpd = !ifbdev->hpd_suspended;
+   ifbdev->hpd_waiting = true;
+   mutex_unlock(&ifbdev->hpd_lock);
+
+   if (!send_hpd || !(ifbdev->vma || dev->fb_helper->deferred_setup))
+   return -EAGAIN;
+
+   return 0;
+}
+
  static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
.fb_probe = intelfb_create,
.fb_dirty = intelfb_dirty,
.fb_restore = intelfb_restore,
+   .fb_hotplug = intelfb_hotplug,
  };
  
  /*

@@ -557,25 +579,6 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int 
state, bool synchronous
intel_fbdev_hpd_set_suspend(dev_priv, state);
  }
  
-static int intel_fbdev_output_poll_changed(struct drm_device *dev)

-{
-   struct intel_fbdev *ifbdev = to_i915(dev)->display.fbdev.fbdev;
-   bool send_hpd;
-
-   if (!ifbdev)
-   return -EINVAL;
-
-   mutex_lock(&ifbdev->hpd_lock);
-   send_hpd = !ifbdev->hpd_suspended;
-   ifbdev->hpd_waiting = true;
-   mutex_unlock(&ifbdev->hpd_lock);
-
-   if (send_hpd && (ifbdev->vma || dev->fb_helper->deferred_setup))
-   drm_fb_helper_hotplug_event(dev->fb_helper);
-
-   return 0;
-}
-
  static int intel_fbdev_restore_mode(struct drm_i915_private *dev_priv)
  {
struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev;
@@ -637,7 +640,7 @@ static int intel_fbdev_client_hotplug(struct drm_client_dev 
*client)
int ret;
  
  	if (dev->fb_helper)

-   return intel_fbdev_output_poll_changed(dev);
+   return drm_fb_helper_hotplug_event(fb_helper);
  
  	ret = drm_fb_helper_init(dev, fb_helper);

if (ret)
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 34eb77c18a13..3dcb9a60e408 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -112,6 +112,19 @@ struct drm_fb_helper_funcs {
 * TODO: Fix i915 to not require this callback.
 */
void (*fb_restore)(struct drm_fb_helper *helper);
+
+   /**
+* @fb_hotplug:
+*
+* Driver callback to prepare hotplug event. If set, fbdev
+* emulation will invoke this callback before sending a hotplug
+* event.
+*
+* Only for i915. Do not use in new code.
+*
+* TODO: Fix i915 to not require this callback.
+*/
+   int (*fb_hotplug)(struct drm_fb_helper *helper);
  };
  
  /**


--
Best regards,
Sui



Re: drm/mgag200: Fix VBLANK interrupt handling

2024-07-31 Thread Sui Jingfeng

Hi,


On 2024/7/31 15:09, Thomas Zimmermann wrote:

Fix support for VBLANK interrupts on G200ER, G200EV and G200SE, which
use a slightly different implementation than the others. The original
commits forgot to update the custom helpers when adding interrupt
handling for VBLANK events.

Signed-off-by: Thomas Zimmermann 



LGTM,


Acked-by: sui.jingf...@linux.dev

--
Best regards,
Sui



Re: [PATCH v5 2/2] drm/loongson: Add dummy gpu driver as a subcomponent

2024-07-30 Thread Sui Jingfeng

Hi,

On 2024/7/29 15:15, Markus Elfring wrote:

…

the driver is loaded, drm/loongson driver still need to wait all of

   needs to wait on …?


…

design. Therefore, add a dummy driver for the GPU, …

Is there a need to reconsider the categorisation and usability descriptions
another bit for such a software component?



For honoring the framework and testing the framework purpose.


The GPU can possibly be the master of the all sub-components, this 
definitely need some extra


consideration and negotiation with the DC and the fake master device. 
Depend on  configuration


and user space expectation. The problem should be solved earlier.



Regards,
Markus


--
Best regards,
Sui



Re: [PATCH v5 1/2] drm/loongson: Introduce component framework support

2024-07-30 Thread Sui Jingfeng

Hi,


On 2024/7/29 14:40, Markus Elfring wrote:

…

+++ b/drivers/gpu/drm/loongson/loongson_drv.h
@@ -0,0 +1,108 @@

…

+#ifndef __LOONGSON_DRV_H__
+#define __LOONGSON_DRV_H__

…

I suggest to omit leading underscores from such identifiers.
https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier



I suggest add this rules to the checkpatch.pl script,

It's more safe to follow *after* your suggestion is accepted.

After all, the checkpatch.pl is de-facto standard.

checkpatch.pl is happy about my patch for now.



Regards,
Markus


--
Best regards,
Sui



Re: [PATCH v5 1/2] drm/loongson: Introduce component framework support

2024-07-30 Thread Sui Jingfeng

Hi,


On 2024/7/29 15:37, Markus Elfring wrote:

…

+++ b/drivers/gpu/drm/loongson/loongson_drv.c
@@ -0,0 +1,298 @@

…

+static int loongson_drm_driver_probe(struct platform_device *pdev)
+{

…

+   dev_info(&pdev->dev, "probed\n");

…

+}

…

Do you find such information really relevant?



This helps to see the probe order of all drivers,

this also help us to know the name of the fake master device.



Regards,
Markus


--
Best regards,
Sui



[PATCH v5 2/2] drm/loongson: Add dummy gpu driver as a subcomponent

2024-07-28 Thread Sui Jingfeng
Loongson Graphics are PCIe multifunctional devices, the GPU and the
display controller are two distinct devices. Despite hardware units
that come along with PCIe are already ready to be driven by the time
the driver is loaded, drm/loongson driver still need to wait all of
its dependencies ready before it can register DRM service to user space.
The newly introduced component framework allow us to use loose coupling
design. Therefore, add a dummy driver for the GPU, it is functional as
a subcomponent as well.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile   |   3 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c | 163 
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h |  35 +
 drivers/gpu/drm/loongson/loongson_drv.c |   1 +
 drivers/gpu/drm/loongson/loongson_module.c  |   4 +
 drivers/gpu/drm/loongson/loongson_module.h  |   1 +
 6 files changed, 207 insertions(+)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index 90c6239bd77d..cdc60ec975e4 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -17,6 +17,9 @@ loongson-y := \
lsdc_probe.o \
lsdc_ttm.o
 
+loongson-y += \
+   loonggpu_pci_drv.o
+
 loongson-y += loongson_device.o \
  loongson_drv.o \
  loongson_module.o
diff --git a/drivers/gpu/drm/loongson/loonggpu_pci_drv.c 
b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
new file mode 100644
index ..52785a130b83
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Authors:
+ *  Sui Jingfeng 
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+
+#include "loongson_drv.h"
+#include "loongson_module.h"
+#include "loonggpu_pci_drv.h"
+
+static int loonggpu_get_version(struct loonggpu_device *gpu)
+{
+   u32 hw_info = loong_rreg32(gpu, 0x8C);
+   u8 host_id;
+   u8 revision;
+
+   /* LoongGPU hardware info */
+   gpu->ver_major = (hw_info >> 8) & 0x0F;
+   gpu->ver_minor = (hw_info & 0xF0) >> 4;
+   revision = hw_info & 0x0F;
+   host_id = (hw_info >> 16) & 0xFF;
+
+   drm_info(gpu->drm, "LoongGPU(TM): LG%x%x0, revision: %x, Host: %s\n",
+gpu->ver_major, gpu->ver_minor, revision,
+host_id ? "LS2K2000" : "LS7A2000");
+
+   return 0;
+}
+
+static irqreturn_t loonggpu_irq_handler(int irq, void *arg)
+{
+   struct loonggpu_device *gpu = arg;
+
+   drm_dbg(gpu->drm, "LoongGPU(TM) interrupted\n");
+
+   return IRQ_HANDLED;
+}
+
+static int loonggpu_pci_component_bind(struct device *dev,
+  struct device *master,
+  void *data)
+{
+   struct loonggpu_device *gpu = dev_get_drvdata(dev);
+   struct drm_device *drm = data;
+   struct loongson_drm *ldrm = to_loongson_drm(drm);
+   struct pci_dev *pdev = to_pci_dev(dev);
+   int ret;
+
+   gpu->drm = drm;
+   ldrm->loonggpu = gpu;
+
+   loonggpu_get_version(gpu);
+
+   ret = devm_request_irq(dev,
+  pdev->irq,
+  loonggpu_irq_handler,
+  IRQF_SHARED,
+  dev_name(dev),
+  gpu);
+   if (ret)
+   return ret;
+
+   drm_info(gpu->drm, "LoongGPU(TM) irq: %d\n", pdev->irq);
+
+   return 0;
+}
+
+static void loonggpu_pci_component_unbind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+   dev_dbg(dev, "LoongGPU(TM) unbind\n");
+}
+
+static const struct component_ops loonggpu_pci_component_ops = {
+   .bind = loonggpu_pci_component_bind,
+   .unbind = loonggpu_pci_component_unbind,
+};
+
+static int loonggpu_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+   struct loonggpu_device *gpu;
+   int ret;
+
+   ret = pcim_enable_device(pdev);
+   if (ret)
+   return ret;
+
+   pci_set_master(pdev);
+
+   gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL);
+   if (!gpu)
+   return -ENOMEM;
+
+   gpu->pdev = pdev;
+
+   gpu->reg_base = pcim_iomap(pdev, 0, 0);
+   if (!gpu->reg_base)
+   return -ENOMEM;
+
+   pci_set_drvdata(pdev, gpu);
+
+   dev_info(&pdev->dev, "LoongGPU(TM) PCI driver probed\n");
+
+   return component_add(&pdev->dev, &loonggpu_pci_component_ops);
+}
+
+static void loonggpu_pci_remove(struct pci_dev *pdev)
+{

[PATCH v5 1/2] drm/loongson: Introduce component framework support

2024-07-28 Thread Sui Jingfeng
In some display subsystems, the functionality of a PCIe device might be
too complex to manage with a single driver. A split of the functionality
into child devices can help to achieve better modularity. For example,
KMS drivers who have dependencies on external modules will suffer from
the deferral probe problem. The problem is that the DRM driver has to
tear down everything when it receives '-EPROBE_DEFER', even though the
independent part of the driver is not related to this error.

The idea is to migrate (offload) the dependency to submodules, creating
submodule by creating platform devices manually during driver load time.
Submodules are functional as agents, which will be responsible for
attaching needed external modules for the main body of the whole KMS
driver. Submodules are also responsible for returning '-EPROBE_DEFER'
to the driver core if it needs to do so.

Make LSDC PCI driver as a subcomponent and creating a platform device as
a DRM proxy, which will attach the common DRM routines to our hardware
after all submodules bound. The proxy is a fake master which is working
at the foreground.

Move DRM-related codes into the loongson_drm_master_bind(), move output
related things into the submodule, because the output hardware units are
relatively standalone IPs.

Initialize the GPIO-I2Cs in the driver probe() of the LSDC PCIe device,
tie its lifetime to the LSDC.

Assign GFX PLL, TTM memory manager part, and power management part
to the DRM proxy, as those entities do not belong to the LSDC itself.
They are common resources.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile |   2 +
 drivers/gpu/drm/loongson/loongson_device.c|  30 ++
 drivers/gpu/drm/loongson/loongson_drv.c   | 298 +++
 drivers/gpu/drm/loongson/loongson_drv.h   | 108 ++
 drivers/gpu/drm/loongson/loongson_module.c|  80 +++-
 drivers/gpu/drm/loongson/loongson_module.h|  31 ++
 drivers/gpu/drm/loongson/lsdc_benchmark.c |  12 +-
 drivers/gpu/drm/loongson/lsdc_benchmark.h |   2 +-
 drivers/gpu/drm/loongson/lsdc_crtc.c  |   4 +-
 drivers/gpu/drm/loongson/lsdc_debugfs.c   |  41 +--
 drivers/gpu/drm/loongson/lsdc_drv.c   | 346 +-
 drivers/gpu/drm/loongson/lsdc_drv.h   |  89 +
 drivers/gpu/drm/loongson/lsdc_gem.c   |  42 ++-
 drivers/gpu/drm/loongson/lsdc_gem.h   |  13 +
 drivers/gpu/drm/loongson/lsdc_gfxpll.c|  33 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.h|   3 +-
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  55 ++-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  21 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 183 +
 drivers/gpu/drm/loongson/lsdc_output.h|  33 +-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   6 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  20 +-
 drivers/gpu/drm/loongson/lsdc_pixpll.c|   4 +-
 drivers/gpu/drm/loongson/lsdc_plane.c |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |  70 ++--
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   4 +-
 26 files changed, 1026 insertions(+), 508 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.h
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..90c6239bd77d 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -9,6 +9,7 @@ loongson-y := \
lsdc_gfxpll.o \
lsdc_i2c.o \
lsdc_irq.o \
+   lsdc_output.o \
lsdc_output_7a1000.o \
lsdc_output_7a2000.o \
lsdc_plane.o \
@@ -17,6 +18,7 @@ loongson-y := \
lsdc_ttm.o
 
 loongson-y += loongson_device.o \
+ loongson_drv.o \
  loongson_module.o
 
 obj-$(CONFIG_DRM_LOONGSON) += loongson.o
diff --git a/drivers/gpu/drm/loongson/loongson_device.c 
b/drivers/gpu/drm/loongson/loongson_device.c
index 9986c8a2a255..51de71a9b692 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -4,6 +4,7 @@
  */
 
 #include 
+#include 
 
 #include "lsdc_drv.h"
 
@@ -100,3 +101,32 @@ lsdc_device_probe(struct pci_dev *pdev, enum 
loongson_chip_id chip_id)
 {
return __chip_id_desc_table[chip_id];
 }
+
+static void loongson_device_postfini(void *data)
+{
+   struct platform_device *proxy = data;
+
+   platform_device_unregister(proxy);
+}
+
+int loongson_device_preinit(struct device *parent)
+{
+   struct platform_device *proxy;
+   int ret;
+
+   proxy = platform_device_register_resndata(parent,
+ "loongson.drm.proxy",
+ PLATFORM_DEVID_NONE,
+ NULL, 0,
+ 

[PATCH v5 0/2] drm/loongson: Introduce component framework support

2024-07-28 Thread Sui Jingfeng
125MB/s
Copy bo of 8100KiB 60 times from GTT to VRAM in 104ms: 4673MB/s
Copy bo of 8100KiB 60 times from VRAM to GTT in 13480ms: 36MB/s


Also run IGT kms_flip and fbdev tests, no obvious problems found.

Sui Jingfeng (2):
  drm/loongson: Introduce component framework support
  drm/loongson: Add dummy gpu driver as a subcomponent

 drivers/gpu/drm/loongson/Makefile |   5 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c   | 163 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h   |  35 ++
 drivers/gpu/drm/loongson/loongson_device.c|  30 ++
 drivers/gpu/drm/loongson/loongson_drv.c   | 299 +++
 drivers/gpu/drm/loongson/loongson_drv.h   | 108 ++
 drivers/gpu/drm/loongson/loongson_module.c|  84 -
 drivers/gpu/drm/loongson/loongson_module.h|  32 ++
 drivers/gpu/drm/loongson/lsdc_benchmark.c |  12 +-
 drivers/gpu/drm/loongson/lsdc_benchmark.h |   2 +-
 drivers/gpu/drm/loongson/lsdc_crtc.c  |   4 +-
 drivers/gpu/drm/loongson/lsdc_debugfs.c   |  41 +--
 drivers/gpu/drm/loongson/lsdc_drv.c   | 346 +-
 drivers/gpu/drm/loongson/lsdc_drv.h   |  89 +
 drivers/gpu/drm/loongson/lsdc_gem.c   |  42 ++-
 drivers/gpu/drm/loongson/lsdc_gem.h   |  13 +
 drivers/gpu/drm/loongson/lsdc_gfxpll.c|  33 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.h|   3 +-
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  55 ++-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  21 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 183 +
 drivers/gpu/drm/loongson/lsdc_output.h|  33 +-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   6 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  20 +-
 drivers/gpu/drm/loongson/lsdc_pixpll.c|   4 +-
 drivers/gpu/drm/loongson/lsdc_plane.c |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |  70 ++--
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   4 +-
 28 files changed, 1233 insertions(+), 508 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.h
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

-- 
2.43.0



Re: [PATCH v3 00/19] Add Freescale i.MX8qxp Display Controller support

2024-07-27 Thread Sui Jingfeng

Hi,

On 7/28/24 04:28, Dmitry Baryshkov wrote:

On Sun, Jul 28, 2024 at 03:10:21AM GMT, Sui Jingfeng wrote:

Hi,

On 7/28/24 00:39, Dmitry Baryshkov wrote:

Hi,

This patch series aims to add Freescale i.MX8qxp Display Controller support.

The controller is comprised of three main components that include a blit
engine for 2D graphics accelerations, display controller for display output
processing, as well as a command sequencer.

Previous patch series attempts to do that can be found at:
https://patchwork.freedesktop.org/series/84524/

This series addresses Maxime's comments on the previous one:
a. Split the display controller into multiple internal devices.
 1) List display engine, pixel engine, interrupt controller and more as the
controller's child devices.
 2) List display engine and pixel engine's processing units as their child
devices.

b. Add minimal feature support.
 Only support two display pipelines with primary planes with XR24 fb,
 backed by two fetchunits.  No fetchunit dynamic allocation logic(to be done
 when necessary).

c. Use drm_dev_{enter, exit}().

Since this series changes a lot comparing to the previous one, I choose to
send it with a new patch series, not a new version.

I'm sorry, I have started reviewing v2 without noticing that there is a
v3 already.

Let me summarize my comments:

- You are using OF aliases. Are they documented and acked by DT
maintainers?

- I generally feel that the use of so many small devices to declare
functional blocks is an abuse of the DT. Please consider creating
_small_ units from the driver code directly rather than going throught
the components.


Well, I really don't think so. I don't agree.

I have checked the DTSpec[1] before type, the spec isn't define how
many is considered to be "many", and the spec isn't define to what
extent is think to be "small" as well.


Yeah. However _usually_ we are not defining DT devices for sub-device
components. 


I guess, this depended on their hardware (i.MX8qxp) layout, reflecting
exactly what their hardware's layout is perfectly valid. It also depend
on if specific part of those sub-device will be re-visioned or not. If
only a small part of the whole is re-versioned in the future, we can 
still re-using this same driver with slightly modify(update) the DTS.


The point is to controll the granularity and forward compatibility.


So at least such decisions ought to be described and
explained in the cover letter.


Agree, but I see 08/19 patch has a beautiful schematic. I have learned
a lot when reading it. I can't see any abuse of the DT through this
bulk series anyway.


Comments below are not revelant to Ying's patch series itself.

/**/

By the way, the last time that I have ever seen and feel abuse of the
DT is the aux-bridge.c[1] and aux-hpd-bridge.c[2]. I strongly feel that
those two *small* programs are abuses to the DT and possibily abuse to
the auxiliary bus framework.

1) It's so *small* that it don't even have a hardware entity (physical
   device) to corresponding with. As far as I can see, all hardware
   units in this patch series are bigger than yours. Because your HPD
   bridge is basically a "virtual wire".

   An non-physical-exist wire hold reference to several device node,
   this is the most awful abuse to the DT I have ever seen. In other
   words, despite you want to solve some software problems, but then,
   you could put a device not in the DTS, and let the 'OF' system
   create a device for you. Just like what this series do.

2) I feel your HPD fake bridge driver abuse to the philosophy of
   auxiliary bus [3]. The document of auxiliary bus tell us that

   "These individual devices split from the core cannot live on
the platform bus as they are not physical devices that are
controlled by DT/ACPI"

Which is nearly equivalent to say that devices that are controlled
by DT/ACPI have better ways to enforce the control. When using
auxiliary bus, we *generally* should not messed with DT. See
golden examples[4][5]. At least, their code are able to run on
X86, while the code you write just can't.

[0] https://patchwork.freedesktop.org/patch/60/?series=135786&rev=3
[1] 
https://elixir.bootlin.com/linux/v6.10.2/source/drivers/gpu/drm/bridge/aux-bridge.c
[2] 
https://elixir.bootlin.com/linux/v6.10.2/source/drivers/gpu/drm/bridge/aux-hpd-bridge.c

[3] https://www.kernel.org/doc/html/latest/driver-api/auxiliary_bus.html

[4] https://patchwork.freedesktop.org/series/136431/
[5] https://patchwork.freedesktop.org/series/134837/


Best regards
Sui



[1]
https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.4




--
Best regards
Sui



Re: [PATCH v3 00/19] Add Freescale i.MX8qxp Display Controller support

2024-07-27 Thread Sui Jingfeng

Hi,

On 7/28/24 00:39, Dmitry Baryshkov wrote:

Hi,

This patch series aims to add Freescale i.MX8qxp Display Controller support.

The controller is comprised of three main components that include a blit
engine for 2D graphics accelerations, display controller for display output
processing, as well as a command sequencer.

Previous patch series attempts to do that can be found at:
https://patchwork.freedesktop.org/series/84524/

This series addresses Maxime's comments on the previous one:
a. Split the display controller into multiple internal devices.
1) List display engine, pixel engine, interrupt controller and more as the
   controller's child devices.
2) List display engine and pixel engine's processing units as their child
   devices.

b. Add minimal feature support.
Only support two display pipelines with primary planes with XR24 fb,
backed by two fetchunits.  No fetchunit dynamic allocation logic(to be done
when necessary).

c. Use drm_dev_{enter, exit}().

Since this series changes a lot comparing to the previous one, I choose to
send it with a new patch series, not a new version.

I'm sorry, I have started reviewing v2 without noticing that there is a
v3 already.

Let me summarize my comments:

- You are using OF aliases. Are they documented and acked by DT
   maintainers?

- I generally feel that the use of so many small devices to declare
   functional blocks is an abuse of the DT. Please consider creating
   _small_ units from the driver code directly rather than going throught
   the components. 


Well, I really don't think so. I don't agree.

I have checked the DTSpec[1] before type, the spec isn't define how
many is considered to be "many", and the spec isn't define to what
extent is think to be "small" as well.

[1] 
https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.4


--
Best regards
Sui



Re: [PATCH v4] drm/loongson: Introduce component framework support

2024-07-24 Thread Sui Jingfeng

Hi,


On 7/24/24 15:30, Markus Elfring wrote:

In some display subsystems, the functionality of a PCIe device may too


  might be?


…

of the dirver is loaded, …


  driver?


…

its dependencies ready before it can register the service to userspace.


user space?


…

submodule by creating platform devices manually during driverload time.


  driver load?


…

device as a DRM proxy, which will attach the common drm routines to our


   DRM?


…

While at it, also do some cleanups.


I find such information suspicious.
Is there any need to offer adjustments as separate update steps?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.10#n81


Thanks a lot for review, I will try to fix those problems in the future.


Regards,
Markus


[PATCH v4 1/1] drm/loongson: Introduce component framework support

2024-07-23 Thread Sui Jingfeng
In some display subsystems, the functionality of a PCIe device may too
complex to be managed by a single driver. A split of the functionality
into child devices can help to achieve better modularity. For example,
KMS drivers who have dependencies on external modules will suffer from
the deferral probe problem. The problem is that the DRM driver has to
tear down everything when it receives '-EPROBE_DEFER', even though the
independent part of the driver is not related to this error.

Loongson Graphics are PCIe multifunctional devices, the GPU and the
display controller are two distinct devices. Despite all hardware units
that come along with PCIe are actually ready to be driven by the time
of the dirver is loaded, drm/loongson driver still need to wait all of
its dependencies ready before it can register the service to userspace.

The idea is to migrate (offload) the dependency to submodules, creating
submodule by creating platform devices manually during driverload time.
Submodules are functional as agents, which will be responsible for
attaching needed external modules for the main body of the whole KMS
driver. Submodules are also responsible for returning '-EPROBE_DEFER'
to the driver core if it needs to do so.

Add a dummy GPU driver as a subcomponent, make LSDC PCI driver as a
subcomponent as well. Introduce the component framework to bind those
scatter software and/or hardware entities into one. Creating a platform
device as a DRM proxy, which will attach the common drm routines to our
hardware after all submodules bound. The proxy is the explicit executant
working at the foreground, while the LSDC PCIe device is the master.

Move DRM-related codes into the loongson_drm_master_bind(), move output
related things into the submodule, because the output hardware units are
relatively standalone IPs and the encoder/connector/transcoder may depend
on external modules. While the display controller itself and GPIO-I2Cs
have no dependency on external modules, therefore go with the LSDC PCIe
device. Also assign GFX PLL, TTM memory manager part, and power management
part to loongson drm proxy, as they do not belong to the LSDC itself.

While at it, also do some cleanups.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile |   6 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c   | 163 
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h   |  35 ++
 drivers/gpu/drm/loongson/loongson_device.c|  30 ++
 drivers/gpu/drm/loongson/loongson_drv.c   | 293 +
 drivers/gpu/drm/loongson/loongson_drv.h   |  90 
 drivers/gpu/drm/loongson/loongson_module.c|  84 +++-
 drivers/gpu/drm/loongson/loongson_module.h|  32 ++
 drivers/gpu/drm/loongson/lsdc_benchmark.c |  12 +-
 drivers/gpu/drm/loongson/lsdc_benchmark.h |   2 +-
 drivers/gpu/drm/loongson/lsdc_component.c | 159 +++
 drivers/gpu/drm/loongson/lsdc_crtc.c  |   4 +-
 drivers/gpu/drm/loongson/lsdc_debugfs.c   |  44 +-
 drivers/gpu/drm/loongson/lsdc_drv.c   | 394 ++
 drivers/gpu/drm/loongson/lsdc_drv.h   |  83 +---
 drivers/gpu/drm/loongson/lsdc_gem.c   |  44 +-
 drivers/gpu/drm/loongson/lsdc_gem.h   |  19 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.c|  29 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.h|   3 +-
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  43 +-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  12 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 183 
 drivers/gpu/drm/loongson/lsdc_output.h|  36 +-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |  14 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  20 +-
 drivers/gpu/drm/loongson/lsdc_plane.c |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |  84 ++--
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   4 +-
 28 files changed, 1318 insertions(+), 608 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.h
 create mode 100644 drivers/gpu/drm/loongson/lsdc_component.c
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..1c496713baa9 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -2,6 +2,7 @@
 
 loongson-y := \
lsdc_benchmark.o \
+   lsdc_component.o \
lsdc_crtc.o \
lsdc_debugfs.o \
lsdc_drv.o \
@@ -9,6 +10,7 @@ loongson-y := \
lsdc_gfxpll.o \
lsdc_i2c.o \
lsdc_irq.o \
+   lsdc_output.o \
lsdc_output_7a1000.o \
lsdc_output_7a2000.o \
lsdc_plane.o \
@@ -16,7 +18,11 @@ loongson-y := \
lsdc_probe.o \
lsdc_ttm.o
 
+loongson-y += \
+   loonggpu_pci

[PATCH v4 0/1] drm/loongson: Introduce component framework support

2024-07-23 Thread Sui Jingfeng
fedora :00:06.1]# cat benchmark
Copy bo of 8100KiB 60 times from GTT to GTT in 48ms: 10125MB/s
Copy bo of 8100KiB 60 times from GTT to VRAM in 104ms: 4673MB/s
Copy bo of 8100KiB 60 times from VRAM to GTT in 13480ms: 36MB/s

Also run IGT kms_flip and fbdev tests, no obvious problem found.

Sui Jingfeng (1):
  drm/loongson: Introduce component framework support

 drivers/gpu/drm/loongson/Makefile |   6 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c   | 163 
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h   |  35 ++
 drivers/gpu/drm/loongson/loongson_device.c|  30 ++
 drivers/gpu/drm/loongson/loongson_drv.c   | 293 +
 drivers/gpu/drm/loongson/loongson_drv.h   |  90 
 drivers/gpu/drm/loongson/loongson_module.c|  84 +++-
 drivers/gpu/drm/loongson/loongson_module.h|  32 ++
 drivers/gpu/drm/loongson/lsdc_benchmark.c |  12 +-
 drivers/gpu/drm/loongson/lsdc_benchmark.h |   2 +-
 drivers/gpu/drm/loongson/lsdc_component.c | 159 +++
 drivers/gpu/drm/loongson/lsdc_crtc.c  |   4 +-
 drivers/gpu/drm/loongson/lsdc_debugfs.c   |  44 +-
 drivers/gpu/drm/loongson/lsdc_drv.c   | 394 ++
 drivers/gpu/drm/loongson/lsdc_drv.h   |  83 +---
 drivers/gpu/drm/loongson/lsdc_gem.c   |  44 +-
 drivers/gpu/drm/loongson/lsdc_gem.h   |  19 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.c|  29 +-
 drivers/gpu/drm/loongson/lsdc_gfxpll.h|   3 +-
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  43 +-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  12 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 183 
 drivers/gpu/drm/loongson/lsdc_output.h|  36 +-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |  14 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  20 +-
 drivers/gpu/drm/loongson/lsdc_plane.c |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |  84 ++--
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   4 +-
 28 files changed, 1318 insertions(+), 608 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.h
 create mode 100644 drivers/gpu/drm/loongson/lsdc_component.c
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

-- 
2.43.0



[PATCH v3 0/1]drm/loongson: Introduce component framework support

2024-07-11 Thread Sui Jingfeng
:00:06.1 (ops lsdc_component_ops 
[loongson])
[   10.891851] loongson :00:06.1: [drm] Total 2 outputs
[   10.910159] loongson :00:06.1: [drm] VRAM: 4096 pages ready
[   10.916131] loongson :00:06.1: [drm] GTT: 32768 pages ready
[   10.922391] [drm] Initialized loongson 1.0.0 for :00:06.1 on minor 0
[  379.378990] Console: switching to colour frame buffer device 128x37
[  379.385261] loongson :00:06.1: [drm] fb0: loongsondrmfb frame buffer 
device


Sui Jingfeng (1):
  drm/loongson: Introduce component framework support

 drivers/gpu/drm/loongson/Makefile |   5 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c   | 156 
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h   |  33 +++
 drivers/gpu/drm/loongson/loongson_device.c|   1 +
 drivers/gpu/drm/loongson/loongson_drv.c   | 157 
 drivers/gpu/drm/loongson/loongson_module.c|  38 ++-
 drivers/gpu/drm/loongson/loongson_module.h|  17 ++
 drivers/gpu/drm/loongson/lsdc_drv.c   | 235 --
 drivers/gpu/drm/loongson/lsdc_drv.h   |  56 ++---
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  43 ++--
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  11 +-
 drivers/gpu/drm/loongson/lsdc_irq.c   |  21 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 208 
 drivers/gpu/drm/loongson/lsdc_output.h|  36 ++-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   7 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  17 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   2 +-
 18 files changed, 832 insertions(+), 215 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

-- 
2.43.0



[PATCH v3 1/1] drm/loongson: Introduce component framework support

2024-07-11 Thread Sui Jingfeng
In some display subsystems, the functionality of a PCIe device may too
complex to be managed by a single driver. A split of the functionality
into child devices can help to achieve better modularity. For example,
KMS drivers who has a dependency on external modules will suffer from
the deferral probe problem of those modules. The problem is that the
DRM driver has to tear down everything when it receives '-EPROBE_DEFER',
even though the independent part of the entire driver is not very closely
related.

For Loongson Graphics, the GPU and the display controller are two distinct
PCIe devices. Despite hardware units that come along with PCIe are actually
all ready to be driven, DRM driver still need to wait all of its dependency
ready before it can register the service to userspace.

The idea is to migrate(offload) the dependency to submodule, creating
submodule by creating platform device manually. Such submodules are
functional as agents, which will be responsible for attaching needed
external modules for the main body of entire KMS drive. It's also for
better modularity, as output hardware units are relatively standalone
IPs.

Add dummy GPU driver as a subcomponent, use the component framework to
bind those scatter software/hardware entities into one. Move DRM-related
codes into the loongson_drm_master_bind() function. Move output-related
things into the submodule, since the encoder/connector/ transcoder are
sometimes depend on external module. The display controller and GPIO-I2Cs
go with the PCIe master, as they have no dependency on external modules.

Make lsdc PCI driver as a subcomponent as well, creating a platform device
as proxy. The proxy will responsible attach the common drm routines to our
hardware, which keep the whole drm driver balanced (and fair) enough for
both the DC and GPU.

The lsdc PCI device is the haidden(implicit) parent, while the proxy is
the explicit master, which deal with drm related affairs for its parent.
The master won't bound until all submodules are ready, submodules are
responsible to return '-EPROBE_DEFER' back to the driver core if it needs
to do so.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile |   5 +
 drivers/gpu/drm/loongson/loonggpu_pci_drv.c   | 156 
 drivers/gpu/drm/loongson/loonggpu_pci_drv.h   |  33 +++
 drivers/gpu/drm/loongson/loongson_device.c|   1 +
 drivers/gpu/drm/loongson/loongson_drv.c   | 157 
 drivers/gpu/drm/loongson/loongson_module.c|  38 ++-
 drivers/gpu/drm/loongson/loongson_module.h|  17 ++
 drivers/gpu/drm/loongson/lsdc_drv.c   | 235 --
 drivers/gpu/drm/loongson/lsdc_drv.h   |  56 ++---
 drivers/gpu/drm/loongson/lsdc_i2c.c   |  43 ++--
 drivers/gpu/drm/loongson/lsdc_i2c.h   |  11 +-
 drivers/gpu/drm/loongson/lsdc_irq.c   |  21 +-
 drivers/gpu/drm/loongson/lsdc_output.c| 208 
 drivers/gpu/drm/loongson/lsdc_output.h|  36 ++-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   7 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  17 +-
 drivers/gpu/drm/loongson/lsdc_ttm.c   |   4 +-
 drivers/gpu/drm/loongson/lsdc_ttm.h   |   2 +-
 18 files changed, 832 insertions(+), 215 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loonggpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..cdc60ec975e4 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -9,6 +9,7 @@ loongson-y := \
lsdc_gfxpll.o \
lsdc_i2c.o \
lsdc_irq.o \
+   lsdc_output.o \
lsdc_output_7a1000.o \
lsdc_output_7a2000.o \
lsdc_plane.o \
@@ -16,7 +17,11 @@ loongson-y := \
lsdc_probe.o \
lsdc_ttm.o
 
+loongson-y += \
+   loonggpu_pci_drv.o
+
 loongson-y += loongson_device.o \
+ loongson_drv.o \
  loongson_module.o
 
 obj-$(CONFIG_DRM_LOONGSON) += loongson.o
diff --git a/drivers/gpu/drm/loongson/loonggpu_pci_drv.c 
b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
new file mode 100644
index ..a34c213171e0
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Authors:
+ *  Sui Jingfeng 
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+
+#include "loongson_module.h"
+#include "loonggpu_pci_drv.h"
+
+static int loonggpu_get_version(struct loonggpu_device *gpu)
+{
+   u32 hw_info = loong_rreg32(gpu, 0x8C);
+   u8 host_id;
+   u8 revision;
+
+   /* LoongGPU hardware info */
+   gpu->ver_major = (hw_info >> 8) & 0x0F;
+   gpu->ver_minor = (hw_info & 0xF0) >

Re: [etnaviv-next v14 0/8] drm/etnaviv: Add driver wrapper for vivante GPUs attached on PCI(e) device

2024-06-25 Thread Sui Jingfeng

Hi,

On 6/25/24 11:18, Icenowy Zheng wrote:

在 2024-05-20星期一的 00:53 +0800,Sui Jingfeng写道:

drm/etnaviv use the component framework to bind multiple GPU cores to
a
virtual master, the virtual master is manually create during driver
load
time. This works well for various SoCs, yet there are some PCIe card
has
the vivante GPU cores integrated. The driver lacks the support for
PCIe
devices currently.

Adds PCIe driver wrapper on the top of what drm/etnaviv already has,
the
component framework is still being used to bind subdevices, even
though
there is only one GPU core. But the process is going to be reversed,
we
create virtual platform device for each of the vivante GPU IP core
shipped
by the PCIe master. The PCIe master is real, bind all the virtual
child
to the master with component framework.


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)
 * Fix 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.

V13:
 * Drop the non-component code path, always use the component
framework
   to bind subcomponent GPU core. Even though there is only
one core.
 * Defer the irq handler register.
 * Rebase and improve the commit message

V14:
 * Rebase onto etnaviv-next and improve commit message.

Tested with JD9230P GPU and LingJiu GP102 GPU.


BTW how should VRAM and displayed related parts be handled on these
dGPUs?


Emm, I can only say I have no ideas.

Thanks for Christian's tested-by, but I'm a bit worry about if etnaviv
folks really like(or need) this. In the past, we started to contribute
before we know the policy/framework very well. I have to managed to
make things work before knowing the full picture. We developing drivers
in a rather rapid way and rather wild. Sometime, we do it just for fun. 
As the card don't has a usable driver, we want do something and we do

have already learned the framework and knowledge.

But now as we know a bit more, I actually don't intend to brings
concerns to other people. So only first 6 patch (or only part of them)
are requested to be merged, patch 0007 or patch 0008 can just leave it
there to be reviewed a bit longer if something is unsure.

Its totally up to etnaviv folks, I don't mind. Thanks for the nice
project.

--
Best regards
Sui


Re: [PATCH v3] software node: Implement device_get_match_data fwnode callback

2024-06-23 Thread Sui Jingfeng

Hi,

On 6/23/24 03:29, Dmitry Torokhov wrote:

In case of non-OF match (which

includes the case where you use software nodes) the match data is coming
from matching spi_device_id entry in the driver.


We don't care about much how it is probed now, rather, after the driver
probed by a non-OF way, how does the additional devices properties
can be get?


Say:

1) "device_property_read_u32(dev, "rotation", &rotation);" and
2) "!device_property_read_string(dev, "pervasive,thermal-zone",
&thermal_zone))"


For those spi/i2c/platform devices, what we argues are that
those drivers really should just depend on "OF" before we have
a reliable fwnode API backend to redirect to.
They are working fine without such restriction now, 



You still *NOT* answer where the additional devices properties[1][2]
can be acquire.

[1] device_property_read_u32(dev, "rotation", &rotation)

[2] device_property_read_string(dev, "pervasive,thermal-zone", 
&thermal_zone))




so I see absolutely no reason imposing this restriction.


The reason is rigorous.

You are acclaiming that works by hardcode or by ignoring the flaws
is fine, then all driver are working fine by *your* standard.

Your personal standard has nothing to do with this patch.


Where the additional device_property_read_() calls redirect to?

What if users want to invoke more device_property_read_() function?

They are being directed to first the primary FW node instance, which may
be either OF, ACPI, or SW node, and then, if property is not present
there, to the secondary FW node, which can be either again.



What I'm asking is, on the non-OF and no-ACPI cases, where's those
device_property_read_xxx() calls can be directed to?


At no point ->device_get_match_data() callback in involved in this
process.



The patch is written for people who need it, not for people who don't.

It will be involved if the device is associated with software node.
Its for fwnode API user to get a consistent experience, that is
to get a matching data without introduce extra/duplicated match
mechanism.

The patch is focus on fixing the undefined behavior, is discussing
the correct way to consolidate the fwnode API. Its not going to
discuss how does the those *old" and/or how does those non-fwnode
systems works.

Its NOT discussing how does the driver itself can be probed, a driver
can be probed multiple way and is another question. Being probed and
extract matching data can two different thing and is perfectly valid.

Your problem is that you are not fully understand what other people
does before you rush into the discussion. You are putting restrictions
onto other people, while leaving the problem itself there unsolved.

Its not a place to express your personal value or you personal status,
such as, you are "ready" or "not ready" for something. Or persuading
somebody should get used to what or teaching people to talks with a
whatever tone like a God.

None of those junk words are technical, I can not see constructive
ideas.

Thanks.


Re: [PATCH v3] software node: Implement device_get_match_data fwnode callback

2024-06-22 Thread Sui Jingfeng

Hi,

On 6/22/24 03:58, Dmitry Torokhov wrote:

Hi Sui,

On Sun, Apr 28, 2024 at 04:36:50AM +0800, Sui Jingfeng wrote:

Because the software node backend of the fwnode API framework lacks an
implementation for the .device_get_match_data function callback. This
makes it difficult to use(and/or test) a few drivers that originates
from DT world on the non-DT platform.

Implement the .device_get_match_data fwnode callback, which helps to keep
the three backends of the fwnode API aligned as much as possible. This is
also a fundamental step to make a few drivers OF-independent truely
possible.

Device drivers or platform setup codes are expected to provide a software
node string property, named as "compatible". At this moment, the value of
this string property is being used to match against the compatible entries
in the of_device_id table. It can be extended in the future though.


I am sorry, but this is not really correct. 


I fine if the maintainers of fwnode API want to reject this, but got
rejected is not really equals to "not correct".

Software nodes are used to

augment missing or incomplete parameters, but are never primary objects
in the matching process. Sometimes "compatible" property is used with
software nodes, but it does not participate in the matching process. > There 
are several ways for various buses to match a device and a driver,
but none of them operate on software nodes. 


It's not participate in the matching process in the *past*, but what
we present is something *new*. I fine if you adhere to *old* and/or
*subsystem-dependent* approach, but there really no need to persuade
other people to follow your "old" idea.

Consider for example how

devices on SPI bus are matched (see
drivers/spi/spi.c::spi_match_device()):



This only make the driver be able to probed in a non-DT way, but
it doesn't tell how does the *additional device properties* can
be get. This is the key point.



1. OF/device tree based match. It *requires* the device to have
dev->of_node which is coming from a DTB. It does not work on software
nodes. In case of match the match data should come from of_device_id
entry.

2. ACPI-based match. The match is done based either on OF-compatible
data (which includes "compatible" property) in _DSD (if driver supports
OF-based matching), or based on HID/CID data. In the latter case the
match data is coming from acpi_device_id entry.

3. Name-based match, typically used for board-instantiated devices. In
this case match is done by comparing device name under which it was
instantiated against names listed in the drivers id_table. The match
data is coming from spi_device_id entry.


The statements here sound right, but it's useless. Because the problems
isn't solved yet, nor does you words point out a practical approach.


Similar matching processes are implemented for i2c and platform buses,
as well as others.

Your patch is effectively hijacks the #3 matching process and
substitutes the bus-specific match data (from
spi_device_id/i2c_device_id/etc) with OF data. This is not expected and


Please stop *contaminating* other people's patch, if you have better
idea you can posting it. My patch open a new door, and there do have
programmer in requesting(need) this in the past.



while we may want this in a long term (so we can eventually remove these
bus-specific device ids and only have ACPI/OF ones) I do not think we
are ready for this yet. At the very least this needs to be very clearly
documented.


This is your *personal* wants, if you want to remove something,
just do it. Keep quiet if you are not ready. Exposing your concerns
doesn't help to solve any problems.

Or, if you want it to be clear, you can contribute to Documentation/
gpu/todo.rst. Other peoples help you to become clear there, thanks.

Please note that we are talking about the completeness of the fwnode
APIs, what's you say above has nothing to do the device fwnode APIs.
Hence, is not revelant to my patch, again is out of scope.



Fixes: ffb42e64561e ("drm/tiny/repaper: Make driver OF-independent")
Fixes: 5703d6ae9573 ("drm/tiny/st7735r: Make driver OF-independent")


As other people mentioned this patch does not fix the aforementioned
commits because they are not broken. 


You still not really understand what other people does, I'm not saying
it broken. I'm talking about the completeness.

In case of non-OF match (which

includes the case where you use software nodes) the match data is coming
from matching spi_device_id entry in the driver.



We don't care about much how it is probed now, rather, after the driver
probed by a non-OF way, how does the additional devices properties
can be get?


Say:

1) "device_property_read_u32(dev, "rotation", &rotation);" and
2) "!device_property_read_string(dev, "pervasive,thermal-zone", 
&thermal_zone))&qu

Re: [PATCH v8 3/3] drm/mediatek: Implement OF graphs support for display paths

2024-06-18 Thread Sui Jingfeng

Hi,


On 6/18/24 18:17, AngeloGioacchino Del Regno wrote:

It is impossible to add each and every possible DDP path combination
for each and every possible combination of SoC and board: right now,
this driver hardcodes configuration for 10 SoCs and this is going to
grow larger and larger, and with new hacks like the introduction of
mtk_drm_route which is anyway not enough for all final routes as the
DSI cannot be connected to MERGE if it's not a dual-DSI, or enabling
DSC preventively doesn't work if the display doesn't support it, or
others.

Since practically all display IPs in MediaTek SoCs support being
interconnected with different instances of other, or the same, IPs
or with different IPs and in different combinations, the final DDP
pipeline is effectively a board specific configuration.

Implement OF graphs support to the mediatek-drm drivers, allowing to
stop hardcoding the paths, and preventing this driver to get a huge
amount of arrays for each board and SoC combination, also paving the
way to share the same mtk_mmsys_driver_data between multiple SoCs,
making it more straightforward to add support for new chips.

Reviewed-by: Alexandre Mergnat 
Tested-by: Alexandre Mergnat 
Signed-off-by: AngeloGioacchino Del Regno 



Acked-by: Sui Jingfeng 


Re: [v4,1/2] drm/bridge: sii902x: Fix mode_valid hook

2024-05-31 Thread Sui Jingfeng

Hi, Jayesh


On 5/31/24 21:33, Sam Ravnborg wrote:

Hi Jayesh,


+
   static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set,
@@ -516,6 +529,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = 
{
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts,
.atomic_check = sii902x_bridge_atomic_check,
+   .mode_valid = sii902x_bridge_mode_valid,


As you have the possibility to test the driver, it would be nice with a
follow-up patch that replaces the use of enable() / disable() with the
atomic counterparts.

enable() / disable() are deprecated, so it is nice to reduce their use.


I agree with Sam.

Please using atomic uniformally with a follow-up patch, the mixed
using of atomic API and non atomic API is a little bit confusing IMO.



Sam


Re: [v4,1/2] drm/bridge: sii902x: Fix mode_valid hook

2024-05-31 Thread Sui Jingfeng

Hi,


On 5/30/24 17:29, Jayesh Choudhary wrote:

Currently, mode_valid hook returns all mode as valid and it is
defined only in drm_connector_helper_funcs. With the introduction of
'DRM_BRIDGE_ATTACH_NO_CONNECTOR', connector is not initialized in
bridge_attach call for cases when the encoder has this flag enabled.
So move the mode_valid hook to drm_bridge_funcs with proper clock
checks for maximum and minimum pixel clock supported by the bridge.

Signed-off-by: Jayesh Choudhary 



Acked-by: Sui Jingfeng 



---
  drivers/gpu/drm/bridge/sii902x.c | 32 +++-
  1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 2fbeda9025bf..6a6055a4ccf9 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -163,6 +163,14 @@
  
  #define SII902X_AUDIO_PORT_INDEX		3
  
+/*

+ * The maximum resolution supported by the HDMI bridge is 1080p@60Hz
+ * and 1920x1200 requiring a pixel clock of 165MHz and the minimum
+ * resolution supported is 480p@60Hz requiring a pixel clock of 25MHz
+ */
+#define SII902X_MIN_PIXEL_CLOCK_KHZ25000
+#define SII902X_MAX_PIXEL_CLOCK_KHZ165000
+


This bridge can drive 2560x1080@75Hz monitor(LG 34BL650), the pixel
clock can up to 181250 kHz. I remember that I have tested the native
mode with LS2K1000 SoC, and it do works in practice. And there are
also has 320x240 panels, maybe it's also usuable with this HDMI
transmitter

Well, the datasheet mentioned that it supports up to 165 MHz
dual-edge and single-edge modes. So I'm not against your patch,
just mention it to let you know.



  struct sii902x {
struct i2c_client *i2c;
struct regmap *regmap;
@@ -310,17 +318,8 @@ static int sii902x_get_modes(struct drm_connector 
*connector)
return num;
  }
  
-static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,

-  struct drm_display_mode *mode)
-{
-   /* TODO: check mode */
-
-   return MODE_OK;
-}
-
  static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs 
= {
.get_modes = sii902x_get_modes,
-   .mode_valid = sii902x_mode_valid,
  };
  
  static void sii902x_bridge_disable(struct drm_bridge *bridge)

@@ -504,6 +503,20 @@ static int sii902x_bridge_atomic_check(struct drm_bridge 
*bridge,
return 0;
  }
  
+static enum drm_mode_status

+sii902x_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   if (mode->clock < SII902X_MIN_PIXEL_CLOCK_KHZ)
+   return MODE_CLOCK_LOW;
+
+   if (mode->clock > SII902X_MAX_PIXEL_CLOCK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   return MODE_OK;
+}
+
  static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set,
@@ -516,6 +529,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = 
{
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts,
.atomic_check = sii902x_bridge_atomic_check,
+   .mode_valid = sii902x_bridge_mode_valid,
  };
  
  static int sii902x_mute(struct sii902x *sii902x, bool mute)


--
Best regards
Sui


Re: [PATCH v4 0/2] Add mode_valid and atomic_check hooks for sii902x bridge

2024-05-31 Thread Sui Jingfeng

Hi,

On 5/30/24 17:29, Jayesh Choudhary wrote:

Move the mode_valid hook to drm_bridge_funcs structure to take care
of the case when the encoder attaches the bridge chain with the
DRM_BRIDGE_ATTACH_NO_CONNECTOR flag in which case, the connector is not
initialized in the bridge's attach call and mode_valid is not called.


Good catch, as modes being supported is actually a capability of the
bridge itself. The move make the driver reflect the hardware more.


Re: MAINTAINERS: drm: Drop sam as panel reviewer

2024-05-31 Thread Sui Jingfeng

Hi,

On 5/31/24 05:14, Sam Ravnborg wrote:

Drop myself as reviewer of panel patches, to reflect the reality.



We lost one kindness reviewer for drivers of panel, unhappy!
Not sure if it is proper to give you a NAK here. :(

Best regards,
Sui


Signed-off-by: Sam Ravnborg 
Cc: Neil Armstrong 
---
  MAINTAINERS | 1 -
  1 file changed, 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index ac285040578e..38978699bef5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7567,7 +7567,6 @@ F:include/drm/gpu_scheduler.h
  DRM PANEL DRIVERS
  M:Neil Armstrong 
  R:Jessica Zhang 
-R: Sam Ravnborg 
  L:dri-devel@lists.freedesktop.org
  S:Maintained
  T:git https://gitlab.freedesktop.org/drm/misc/kernel.git





Re: [resend,v2] drm: renesas: shmobile: Call drm_helper_force_disable_all() at shutdown time

2024-05-29 Thread Sui Jingfeng

Hi,


On 2024/5/29 20:16, Geert Uytterhoeven wrote:

From: Douglas Anderson 

Based on grepping through the source code, this driver appears to be
missing a call to drm_atomic_helper_shutdown() at system shutdown time.
This is important because drm_helper_force_disable_all() will cause
panels to get disabled cleanly which may be important for their power
sequencing.  Future changes will remove any custom powering off in
individual panel drivers so the DRM drivers need to start getting this
right.

The fact that we should call drm_atomic_helper_shutdown() in the case of
OS shutdown comes straight out of the kernel doc "driver instance
overview" in drm_drv.c.



True, looks safer.



Suggested-by: Maxime Ripard 
Signed-off-by: Douglas Anderson 
Link: 
https://lore.kernel.org/r/20230901164111.RFT.15.Iaf638a1d4c8b3c307a6192efabb4cbb06b195f15@changeid
[geert: s/drm_helper_force_disable_all/drm_atomic_helper_shutdown/]
[geert: shmob_drm_remove() already calls drm_atomic_helper_shutdown]
Signed-off-by: Geert Uytterhoeven 
Reviewed-by: Laurent Pinchart 


Reviewed-by: Sui Jingfeng 

Best regards,
Sui



Re: drm: renesas: rcar-du: Add drm_panic support for non-vsp

2024-05-29 Thread Sui Jingfeng

Hi,


On 5/27/24 21:35, Geert Uytterhoeven wrote:

Add support for the drm_panic module for DU variants not using the
VSP-compositor, to display a message on the screen when a kernel panic
occurs.

Signed-off-by: Geert Uytterhoeven 
Reviewed-by: Jocelyn Falempe 


After all concerns resolved:


Acked-by: Sui Jingfeng 


---
Tested on Koelsch (R-Car M2-W).

Support for DU variants using the VSP-compositor is more convoluted,
and left to the DU experts.
---
  drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c | 14 --
  1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c 
b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c
index e445fac8e0b46c21..c546ab0805d656f6 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_plane.c
@@ -680,6 +680,12 @@ static const struct drm_plane_helper_funcs 
rcar_du_plane_helper_funcs = {
.atomic_update = rcar_du_plane_atomic_update,
  };
  
+static const struct drm_plane_helper_funcs rcar_du_primary_plane_helper_funcs = {

+   .atomic_check = rcar_du_plane_atomic_check,
+   .atomic_update = rcar_du_plane_atomic_update,
+   .get_scanout_buffer = drm_fb_dma_get_scanout_buffer,
+};
+
  static struct drm_plane_state *
  rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
  {
@@ -812,8 +818,12 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
if (ret < 0)
return ret;
  
-		drm_plane_helper_add(&plane->plane,

-&rcar_du_plane_helper_funcs);
+   if (type == DRM_PLANE_TYPE_PRIMARY)
+   drm_plane_helper_add(&plane->plane,
+
&rcar_du_primary_plane_helper_funcs);
+   else
+   drm_plane_helper_add(&plane->plane,
+&rcar_du_plane_helper_funcs);



Maybe we could do some untangle, but this is not a strong requirement.
Thanks.

Best regards
Sui


drm_plane_create_alpha_property(&plane->plane);
  





Re: drm: renesas: shmobile: Add drm_panic support

2024-05-29 Thread Sui Jingfeng

Hi,


On 5/27/24 21:34, Geert Uytterhoeven wrote:

Add support for the drm_panic module, which displays a message on
the screen when a kernel panic occurs.

Signed-off-by: Geert Uytterhoeven 
Reviewed-by: Jocelyn Falempe 



Acked-by: Sui Jingfeng 


---
Tested on Armadillo-800-EVA.
---
  drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 14 +-
  1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c 
b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
index 07ad17d24294d5e6..9d166ab2af8bd231 100644
--- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
@@ -273,6 +273,13 @@ static const struct drm_plane_helper_funcs 
shmob_drm_plane_helper_funcs = {
.atomic_disable = shmob_drm_plane_atomic_disable,
  };
  
+static const struct drm_plane_helper_funcs shmob_drm_primary_plane_helper_funcs = {

+   .atomic_check = shmob_drm_plane_atomic_check,
+   .atomic_update = shmob_drm_plane_atomic_update,
+   .atomic_disable = shmob_drm_plane_atomic_disable,
+   .get_scanout_buffer = drm_fb_dma_get_scanout_buffer,
+};
+
  static const struct drm_plane_funcs shmob_drm_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -310,7 +317,12 @@ struct drm_plane *shmob_drm_plane_create(struct 
shmob_drm_device *sdev,



Maybe a shmob_drm_plane_create_primary_plane() plus a
shmob_drm_plane_create_overlay().

I remember Thomas told this way or something similiar, call untangle.



splane->index = index;
  
-	drm_plane_helper_add(&splane->base, &shmob_drm_plane_helper_funcs);

+   if (type == DRM_PLANE_TYPE_PRIMARY)
+   drm_plane_helper_add(&splane->base,
+&shmob_drm_primary_plane_helper_funcs);
+   else
+   drm_plane_helper_add(&splane->base,
+&shmob_drm_plane_helper_funcs);
  
  	return &splane->base;

  }



Anyway, it looks good to me.


Best regards
Sui


Re: drm/tests: Add a missing Kconfig select

2024-05-29 Thread Sui Jingfeng

Hi,

On 5/29/24 17:19, Thomas Hellström wrote:

Fix the following warning:

WARNING: unmet direct dependencies detected for DRM_DISPLAY_HDMI_STATE_HELPER
   Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DRM_DISPLAY_HELPER [=y] && 
DRM_DISPLAY_HDMI_HELPER [=n]
   Selected by [y]:
   - DRM_KUNIT_TEST [=y] && HAS_IOMEM [=y] && DRM [=y] && KUNIT [=y] && MMU [=y]

Signed-off-by: Thomas Hellström 
Fixes: 54cb39e2293b ("drm/connector: hdmi: Create an HDMI sub-state")
Cc: Maxime Ripard 
Cc: dri-devel@lists.freedesktop.org


Acked-by: Sui Jingfeng 


Re: [v15,06/29] drm/tests: Add output bpc tests

2024-05-27 Thread Sui Jingfeng

Hi,


On 5/27/24 21:57, Maxime Ripard wrote:

Now that we're tracking the output bpc count in the connector state,
let's add a few tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 


Tested-by: Sui Jingfeng 


Re: [v15,06/29] drm/tests: Add output bpc tests

2024-05-27 Thread Sui Jingfeng
0x02, 0x03, 0x1b, 0x81,
+  0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0x4a, 0x6d, 0x03, 0x0c,
+  0x00, 0x12, 0x34, 0x00, 0x28, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xd0
+};
+
+#endif // DRM_KUNIT_EDID_H_


--
Best regards
Sui Jingfeng



Re: [PATCH v6 02/10] drm/bridge: Set firmware node of drm_bridge instances automatically

2024-05-26 Thread Sui Jingfeng

Hi,


On 5/27/24 07:33, kernel test robot wrote:

Hi Sui,

kernel test robot noticed the following build errors:

[auto build test ERROR on drm-exynos/exynos-drm-next]
[also build test ERROR on linus/master v6.10-rc1 next-20240523]
[cannot apply to shawnguo/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:
https://github.com/intel-lab-lkp/linux/commits/Sui-Jingfeng/drm-bridge-Allow-using-fwnode-APIs-to-get-the-next-bridge/20240527-042402
base:   https://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git 
exynos-drm-next
patch link:
https://lore.kernel.org/r/20240526202115.129049-3-sui.jingfeng%40linux.dev
patch subject: [PATCH v6 02/10] drm/bridge: Set firmware node of drm_bridge 
instances automatically
config: arm-defconfig 
(https://download.01.org/0day-ci/archive/20240527/202405270622.vdmbp9fr-...@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project 
f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build): 
(https://download.01.org/0day-ci/archive/20240527/202405270622.vdmbp9fr-...@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot 
| Closes: 
https://lore.kernel.org/oe-kbuild-all/202405270622.vdmbp9fr-...@intel.com/

All errors (new ones prefixed by >>):


drivers/gpu/drm/omapdrm/dss/hdmi5.c:487:49: error: expected identifier

drm_bridge_add(&hdmi->bridge, &hdmi->pdev->dev.);
   ^
1 error generated.


vim +487 drivers/gpu/drm/omapdrm/dss/hdmi5.c

480 
481 static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
482 {
483 hdmi->bridge.funcs = &hdmi5_bridge_funcs;
484 hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
485 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
486 
  > 487  drm_bridge_add(&hdmi->bridge, &hdmi->pdev->dev.);
488 }
489 




Sorry, my bad. I have do compile test on ARM64 before posting.
checkpatch.pl report a style problem, then I manually modify this
patch, accidentally add the tail '.' character. Will be fixed
at the next version.

--
Best regards
Sui


Re: [PATCH v6 02/10] drm/bridge: Set firmware node of drm_bridge instances automatically

2024-05-26 Thread Sui Jingfeng

Hi,


On 5/27/24 05:19, Dmitry Baryshkov wrote:

On Mon, May 27, 2024 at 04:21:07AM +0800, Sui Jingfeng wrote:

Normally, the drm_bridge::of_node won't be used by bridge driver instances
themselves. Rather, it is mainly used by other modules to find associated
drm bridge drvier. Therefore, adding a drm bridge to the global bridge list
and setting 'of_node' field of a drm bridge share the same goal. Both are
for finding purpose, therefore better to group them to one function.

Update the drm_bridge_add() interface and implementation to achieve such
goal atomically, new implementation will fetch the device node from the
backing device of the drm bridge driver automatically. For the majority
cases, which is one device backing one drm bridge driver, this model works
well. Drivers still can set it manually by passing NULL if this model
doesn't fit.

While at it, Add a 'struct device *' pointer to the drm_bridge structure.
As it already being passed in by both of drm_bridge_add() and
devm_drm_bridge_add(). A lot of driver instances has already added it into
their derived structure, promote it into drm_bridge core helps to reduce
a batch of boilerplates.

Signed-off-by: Sui Jingfeng 
---


[trimmed]


@@ -231,7 +243,7 @@ static void drm_bridge_remove_void(void *bridge)
   */
  int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge)
  {
-   drm_bridge_add(bridge);
+   drm_bridge_add(bridge, dev);
return devm_add_action_or_reset(dev, drm_bridge_remove_void, bridge);


This breaks aux-hpd-bridge, which gets of_node as an external pointer
rather than dev->of_node.



Yes, you are right. I forget to modify that driver.
My bad, will be fixed at the next version.

--
Best regards
Sui


[PATCH v6 10/10] drm/bridge: ch7033: Switch to use fwnode based APIs

2024-05-26 Thread Sui Jingfeng
Use the freshly created helper to replace the use of DT-dependent APIs,
also print error log if the fwnode graph is not complete which is benefit
to debug.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/chrontel-ch7033.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c 
b/drivers/gpu/drm/bridge/chrontel-ch7033.c
index c6374440af7f..35dd2e6ba6c0 100644
--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c
+++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c
@@ -531,6 +531,7 @@ static const struct regmap_config ch7033_regmap_config = {
 static int ch7033_probe(struct i2c_client *client)
 {
struct device *dev = &client->dev;
+   struct fwnode_handle *fwnode = dev_fwnode(dev);
struct ch7033_priv *priv;
unsigned int val;
int ret;
@@ -541,10 +542,15 @@ static int ch7033_probe(struct i2c_client *client)
 
dev_set_drvdata(dev, priv);
 
-   ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
- &priv->next_bridge);
-   if (ret)
+   priv->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+   if (IS_ERR(priv->next_bridge)) {
+   ret = PTR_ERR(priv->next_bridge);
+   dev_err(dev, "Error in founding the next bridge: %d\n", ret);
return ret;
+   } else if (!priv->next_bridge) {
+   dev_dbg(dev, "Next bridge not found, deferring probe\n");
+   return -EPROBE_DEFER;
+   }
 
priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);
if (IS_ERR(priv->regmap)) {
-- 
2.34.1



[PATCH v6 08/10] drm/bridge: tfp410: Use fwnode APIs to acquire device properties

2024-05-26 Thread Sui Jingfeng
Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
No functional changes for DT-based systems.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/ti-tfp410.c | 39 +++---
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c 
b/drivers/gpu/drm/bridge/ti-tfp410.c
index 04a341133488..a1fae5e9dafd 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -261,8 +261,9 @@ static const struct drm_bridge_timings 
tfp410_default_timings = {
 
 static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
 {
+   struct fwnode_handle *fwnode = dev_fwnode(dvi->dev);
struct drm_bridge_timings *timings = &dvi->timings;
-   struct device_node *ep;
+   struct fwnode_handle *ep;
u32 pclk_sample = 0;
u32 bus_width = 24;
u32 deskew = 0;
@@ -283,14 +284,14 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool 
i2c)
 * and EDGE pins. They are specified in DT through endpoint properties
 * and vendor-specific properties.
 */
-   ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 0, 0);
+   ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
if (!ep)
return -EINVAL;
 
/* Get the sampling edge from the endpoint. */
-   of_property_read_u32(ep, "pclk-sample", &pclk_sample);
-   of_property_read_u32(ep, "bus-width", &bus_width);
-   of_node_put(ep);
+   fwnode_property_read_u32(ep, "pclk-sample", &pclk_sample);
+   fwnode_property_read_u32(ep, "bus-width", &bus_width);
+   fwnode_handle_put(ep);
 
timings->input_bus_flags = DRM_BUS_FLAG_DE_HIGH;
 
@@ -319,7 +320,7 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool 
i2c)
}
 
/* Get the setup and hold time from vendor-specific properties. */
-   of_property_read_u32(dvi->dev->of_node, "ti,deskew", &deskew);
+   fwnode_property_read_u32(fwnode, "ti,deskew", &deskew);
if (deskew > 7)
return -EINVAL;
 
@@ -331,12 +332,12 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool 
i2c)
 
 static int tfp410_init(struct device *dev, bool i2c)
 {
-   struct device_node *node;
+   struct fwnode_handle *fwnode = dev_fwnode(dev);
struct tfp410 *dvi;
int ret;
 
-   if (!dev->of_node) {
-   dev_err(dev, "device-tree data is missing\n");
+   if (!fwnode) {
+   dev_err(dev, "firmware data is missing\n");
return -ENXIO;
}
 
@@ -356,15 +357,15 @@ static int tfp410_init(struct device *dev, bool i2c)
return ret;
 
/* Get the next bridge, connected to port@1. */
-   node = of_graph_get_remote_node(dev->of_node, 1, -1);
-   if (!node)
-   return -ENODEV;
-
-   dvi->next_bridge = of_drm_find_bridge(node);
-   of_node_put(node);
-
-   if (!dvi->next_bridge)
+   dvi->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+   if (IS_ERR(dvi->next_bridge)) {
+   ret = PTR_ERR(dvi->next_bridge);
+   dev_err(dev, "Error in founding the next bridge: %d\n", ret);
+   return ret;
+   } else if (!dvi->next_bridge) {
+   dev_dbg(dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
+   }
 
/* Get the powerdown GPIO. */
dvi->powerdown = devm_gpiod_get_optional(dev, "powerdown",
@@ -416,10 +417,10 @@ static struct platform_driver tfp410_platform_driver = {
 /* There is currently no i2c functionality. */
 static int tfp410_i2c_probe(struct i2c_client *client)
 {
+   struct fwnode_handle *fwnode = dev_fwnode(&client->dev);
int reg;
 
-   if (!client->dev.of_node ||
-   of_property_read_u32(client->dev.of_node, "reg", ®)) {
+   if (!fwnode || fwnode_property_read_u32(fwnode, "reg", ®)) {
dev_err(&client->dev,
"Can't get i2c reg property from device-tree\n");
return -ENXIO;
-- 
2.34.1



[PATCH v6 09/10] drm/bridge: sii9234: Use fwnode APIs to abstract DT dependent API away

2024-05-26 Thread Sui Jingfeng
Switch to use the freshly created drm_bridge_set_node() helper, no
functional changes. The reason behind of this introduction is that
the name 'of_node' itself has a smell of DT dependent, and it is a
internal memeber, when there has helper function, we should use the
revelant helper and avoid directly referencing and/or dereferencing
it.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/sii9234.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c
index 7d2bbc31bac9..d930c093abb3 100644
--- a/drivers/gpu/drm/bridge/sii9234.c
+++ b/drivers/gpu/drm/bridge/sii9234.c
@@ -817,10 +817,11 @@ static int sii9234_init_resources(struct sii9234 *ctx,
  struct i2c_client *client)
 {
struct i2c_adapter *adapter = client->adapter;
+   struct fwnode_handle *fwnode = dev_fwnode(ctx->dev);
int ret;
 
-   if (!ctx->dev->of_node) {
-   dev_err(ctx->dev, "not DT device\n");
+   if (!fwnode) {
+   dev_err(ctx->dev, "firmware data is missing\n");
return -ENODEV;
}
 
-- 
2.34.1



[PATCH v6 07/10] drm-bridge: it66121: Use fwnode APIs to acquire device properties

2024-05-26 Thread Sui Jingfeng
Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
A side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/ite-it66121.c | 55 +---
 1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it66121.c 
b/drivers/gpu/drm/bridge/ite-it66121.c
index 8e4fc082bb8c..3fa650f7fec9 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -15,7 +15,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1480,7 +1479,7 @@ static int it66121_audio_codec_init(struct it66121_ctx 
*ctx, struct device *dev)
 
dev_dbg(dev, "%s\n", __func__);
 
-   if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+   if (!fwnode_property_present(dev_fwnode(dev), "#sound-dai-cells")) {
dev_info(dev, "No \"#sound-dai-cells\", no audio\n");
return 0;
}
@@ -1503,13 +1502,36 @@ static const char * const it66121_supplies[] = {
"vcn33", "vcn18", "vrf12"
 };
 
+static int it66121_read_bus_width(struct fwnode_handle *fwnode, u32 *bus_width)
+{
+   struct fwnode_handle *endpoint;
+   u32 val;
+   int ret;
+
+   endpoint = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
+   if (!endpoint)
+   return -EINVAL;
+
+   ret = fwnode_property_read_u32(endpoint, "bus-width", &val);
+   fwnode_handle_put(endpoint);
+   if (ret)
+   return ret;
+
+   if (val != 12 && val != 24)
+   return -EINVAL;
+
+   *bus_width = val;
+
+   return 0;
+}
+
 static int it66121_probe(struct i2c_client *client)
 {
u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
-   struct device_node *ep;
int ret;
struct it66121_ctx *ctx;
struct device *dev = &client->dev;
+   struct fwnode_handle *fwnode = dev_fwnode(dev);
 
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C check functionality failed.\n");
@@ -1520,29 +1542,20 @@ static int it66121_probe(struct i2c_client *client)
if (!ctx)
return -ENOMEM;
 
-   ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
-   if (!ep)
-   return -EINVAL;
-
ctx->dev = dev;
ctx->client = client;
ctx->info = i2c_get_match_data(client);
 
-   of_property_read_u32(ep, "bus-width", &ctx->bus_width);
-   of_node_put(ep);
-
-   if (ctx->bus_width != 12 && ctx->bus_width != 24)
-   return -EINVAL;
-
-   ep = of_graph_get_remote_node(dev->of_node, 1, -1);
-   if (!ep) {
-   dev_err(ctx->dev, "The endpoint is unconnected\n");
-   return -EINVAL;
-   }
+   ret = it66121_read_bus_width(fwnode, &ctx->bus_width);
+   if (ret)
+   return ret;
 
-   ctx->next_bridge = of_drm_find_bridge(ep);
-   of_node_put(ep);
-   if (!ctx->next_bridge) {
+   ctx->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+   if (IS_ERR(ctx->next_bridge)) {
+   ret = PTR_ERR(ctx->next_bridge);
+   dev_err(dev, "Error in founding the next bridge: %d\n", ret);
+   return ret;
+   } else if (!ctx->next_bridge) {
dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
}
-- 
2.34.1



[PATCH v6 06/10] drm/bridge: sii902x: Switch to use fwnode APIs to acquire device properties

2024-05-26 Thread Sui Jingfeng
Make this driver less DT-dependent by calling the freshly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
One side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/sii902x.c | 43 +++-
 1 file changed, 15 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index f4808838717a..975511d623a4 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -827,20 +827,17 @@ static int sii902x_audio_codec_init(struct sii902x 
*sii902x,
.spdif = 0,
.max_i2s_channels = 0,
};
+   struct fwnode_handle *fwnode = dev_fwnode(dev);
u8 lanes[4];
int num_lanes, i;
 
-   if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+   if (!fwnode_property_present(fwnode, "#sound-dai-cells")) {
dev_dbg(dev, "%s: No \"#sound-dai-cells\", no audio\n",
__func__);
return 0;
}
 
-   num_lanes = of_property_read_variable_u8_array(dev->of_node,
-  "sil,i2s-data-lanes",
-  lanes, 1,
-  ARRAY_SIZE(lanes));
-
+   num_lanes = fwnode_property_count_u8(fwnode, "sil,i2s-data-lanes");
if (num_lanes == -EINVAL) {
dev_dbg(dev,
"%s: No \"sil,i2s-data-lanes\", use default <0>\n",
@@ -852,7 +849,11 @@ static int sii902x_audio_codec_init(struct sii902x 
*sii902x,
"%s: Error gettin \"sil,i2s-data-lanes\": %d\n",
__func__, num_lanes);
return num_lanes;
+   } else {
+   fwnode_property_read_u8_array(fwnode, "sil,i2s-data-lanes",
+ lanes, num_lanes);
}
+
codec_data.max_i2s_channels = 2 * num_lanes;
 
for (i = 0; i < num_lanes; i++)
@@ -1117,7 +1118,6 @@ static int sii902x_init(struct sii902x *sii902x)
 static int sii902x_probe(struct i2c_client *client)
 {
struct device *dev = &client->dev;
-   struct device_node *endpoint;
struct sii902x *sii902x;
static const char * const supplies[] = {"iovcc", "cvcc12"};
int ret;
@@ -1146,27 +1146,14 @@ static int sii902x_probe(struct i2c_client *client)
return PTR_ERR(sii902x->reset_gpio);
}
 
-   endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
-   if (endpoint) {
-   struct device_node *remote = 
of_graph_get_remote_port_parent(endpoint);
-
-   of_node_put(endpoint);
-   if (!remote) {
-   dev_err(dev, "Endpoint in port@1 unconnected\n");
-   return -ENODEV;
-   }
-
-   if (!of_device_is_available(remote)) {
-   dev_err(dev, "port@1 remote device is disabled\n");
-   of_node_put(remote);
-   return -ENODEV;
-   }
-
-   sii902x->next_bridge = of_drm_find_bridge(remote);
-   of_node_put(remote);
-   if (!sii902x->next_bridge)
-   return dev_err_probe(dev, -EPROBE_DEFER,
-"Failed to find remote bridge\n");
+   sii902x->next_bridge = 
drm_bridge_find_next_bridge_by_fwnode(dev_fwnode(dev), 1);
+   if (!sii902x->next_bridge) {
+   return dev_err_probe(dev, -EPROBE_DEFER,
+"Failed to find the next bridge\n");
+   } else if (IS_ERR(sii902x->next_bridge)) {
+   ret = PTR_ERR(sii902x->next_bridge);
+   dev_err(dev, "Error on find the next bridge: %d\n", ret);
+   return ret;
}
 
mutex_init(&sii902x->mutex);
-- 
2.34.1



[PATCH v6 05/10] drm/bridge: display-connector: Use fwnode APIs to acquire device properties

2024-05-26 Thread Sui Jingfeng
Switch to use the fwnode APIs, which is a fundamental step to make this
driver OF-independent possible. No functional changes for DT-based systems.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/display-connector.c | 23 +++---
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/display-connector.c 
b/drivers/gpu/drm/bridge/display-connector.c
index fb1e97d385fe..7436e7cd53fc 100644
--- a/drivers/gpu/drm/bridge/display-connector.c
+++ b/drivers/gpu/drm/bridge/display-connector.c
@@ -9,7 +9,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 
@@ -204,6 +203,7 @@ static int display_connector_get_supply(struct 
platform_device *pdev,
 
 static int display_connector_probe(struct platform_device *pdev)
 {
+   struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
struct display_connector *conn;
unsigned int type;
const char *label = NULL;
@@ -215,15 +215,15 @@ static int display_connector_probe(struct platform_device 
*pdev)
 
platform_set_drvdata(pdev, conn);
 
-   type = (uintptr_t)of_device_get_match_data(&pdev->dev);
+   type = (uintptr_t)device_get_match_data(&pdev->dev);
 
/* Get the exact connector type. */
switch (type) {
case DRM_MODE_CONNECTOR_DVII: {
bool analog, digital;
 
-   analog = of_property_read_bool(pdev->dev.of_node, "analog");
-   digital = of_property_read_bool(pdev->dev.of_node, "digital");
+   analog = fwnode_property_present(fwnode, "analog");
+   digital = fwnode_property_present(fwnode, "digital");
if (analog && !digital) {
conn->bridge.type = DRM_MODE_CONNECTOR_DVIA;
} else if (!analog && digital) {
@@ -240,8 +240,7 @@ static int display_connector_probe(struct platform_device 
*pdev)
case DRM_MODE_CONNECTOR_HDMIA: {
const char *hdmi_type;
 
-   ret = of_property_read_string(pdev->dev.of_node, "type",
- &hdmi_type);
+   ret = fwnode_property_read_string(fwnode, "type", &hdmi_type);
if (ret < 0) {
dev_err(&pdev->dev, "HDMI connector with no type\n");
return -EINVAL;
@@ -271,7 +270,7 @@ static int display_connector_probe(struct platform_device 
*pdev)
conn->bridge.interlace_allowed = true;
 
/* Get the optional connector label. */
-   of_property_read_string(pdev->dev.of_node, "label", &label);
+   fwnode_property_read_string(fwnode, "label", &label);
 
/*
 * Get the HPD GPIO for DVI, HDMI and DP connectors. If the GPIO can 
provide
@@ -309,12 +308,12 @@ static int display_connector_probe(struct platform_device 
*pdev)
if (type == DRM_MODE_CONNECTOR_DVII ||
type == DRM_MODE_CONNECTOR_HDMIA ||
type == DRM_MODE_CONNECTOR_VGA) {
-   struct device_node *phandle;
+   struct fwnode_handle *phandle;
 
-   phandle = of_parse_phandle(pdev->dev.of_node, "ddc-i2c-bus", 0);
-   if (phandle) {
-   conn->bridge.ddc = of_get_i2c_adapter_by_node(phandle);
-   of_node_put(phandle);
+   phandle = fwnode_find_reference(fwnode, "ddc-i2c-bus", 0);
+   if (!IS_ERR(phandle)) {
+   conn->bridge.ddc = i2c_get_adapter_by_fwnode(phandle);
+   fwnode_handle_put(phandle);
if (!conn->bridge.ddc)
return -EPROBE_DEFER;
} else {
-- 
2.34.1



[PATCH v6 02/10] drm/bridge: Set firmware node of drm_bridge instances automatically

2024-05-26 Thread Sui Jingfeng
Normally, the drm_bridge::of_node won't be used by bridge driver instances
themselves. Rather, it is mainly used by other modules to find associated
drm bridge drvier. Therefore, adding a drm bridge to the global bridge list
and setting 'of_node' field of a drm bridge share the same goal. Both are
for finding purpose, therefore better to group them to one function.

Update the drm_bridge_add() interface and implementation to achieve such
goal atomically, new implementation will fetch the device node from the
backing device of the drm bridge driver automatically. For the majority
cases, which is one device backing one drm bridge driver, this model works
well. Drivers still can set it manually by passing NULL if this model
doesn't fit.

While at it, Add a 'struct device *' pointer to the drm_bridge structure.
As it already being passed in by both of drm_bridge_add() and
devm_drm_bridge_add(). A lot of driver instances has already added it into
their derived structure, promote it into drm_bridge core helps to reduce
a batch of boilerplates.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c |  3 +--
 .../gpu/drm/bridge/analogix/analogix-anx6345.c   |  4 +---
 .../gpu/drm/bridge/analogix/analogix-anx78xx.c   |  4 +---
 drivers/gpu/drm/bridge/analogix/anx7625.c|  3 +--
 drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c   |  3 +--
 .../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c  |  3 +--
 drivers/gpu/drm/bridge/chipone-icn6211.c |  5 ++---
 drivers/gpu/drm/bridge/chrontel-ch7033.c |  3 +--
 drivers/gpu/drm/bridge/cros-ec-anx7688.c |  4 +---
 drivers/gpu/drm/bridge/display-connector.c   |  3 +--
 drivers/gpu/drm/bridge/fsl-ldb.c |  3 +--
 drivers/gpu/drm/bridge/imx/imx-ldb-helper.c  |  3 ++-
 drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c |  3 +--
 .../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c  |  3 ++-
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c  |  3 +--
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c |  3 +--
 drivers/gpu/drm/bridge/ite-it6505.c  |  3 +--
 drivers/gpu/drm/bridge/ite-it66121.c |  3 +--
 drivers/gpu/drm/bridge/lontium-lt8912b.c |  3 +--
 drivers/gpu/drm/bridge/lontium-lt9211.c  |  3 +--
 drivers/gpu/drm/bridge/lontium-lt9611.c  |  3 +--
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c   |  3 +--
 drivers/gpu/drm/bridge/lvds-codec.c  |  3 +--
 .../drm/bridge/megachips-stdp-ge-b850v3-fw.c |  3 +--
 drivers/gpu/drm/bridge/microchip-lvds.c  |  3 +--
 drivers/gpu/drm/bridge/nwl-dsi.c |  3 +--
 drivers/gpu/drm/bridge/nxp-ptn3460.c |  3 +--
 drivers/gpu/drm/bridge/panel.c   |  3 +--
 drivers/gpu/drm/bridge/parade-ps8622.c   |  3 +--
 drivers/gpu/drm/bridge/parade-ps8640.c   |  1 -
 drivers/gpu/drm/bridge/samsung-dsim.c|  3 +--
 drivers/gpu/drm/bridge/sii902x.c |  3 +--
 drivers/gpu/drm/bridge/sii9234.c |  3 +--
 drivers/gpu/drm/bridge/sil-sii8620.c |  3 +--
 drivers/gpu/drm/bridge/simple-bridge.c   |  3 +--
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c|  3 +--
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c|  3 +--
 drivers/gpu/drm/bridge/tc358762.c|  3 +--
 drivers/gpu/drm/bridge/tc358764.c|  3 +--
 drivers/gpu/drm/bridge/tc358767.c|  3 +--
 drivers/gpu/drm/bridge/tc358768.c|  3 +--
 drivers/gpu/drm/bridge/tc358775.c|  3 +--
 drivers/gpu/drm/bridge/thc63lvd1024.c|  3 +--
 drivers/gpu/drm/bridge/ti-dlpc3433.c |  3 +--
 drivers/gpu/drm/bridge/ti-sn65dsi83.c|  3 +--
 drivers/gpu/drm/bridge/ti-sn65dsi86.c|  3 +--
 drivers/gpu/drm/bridge/ti-tfp410.c   |  3 +--
 drivers/gpu/drm/bridge/ti-tpd12s015.c|  3 +--
 drivers/gpu/drm/drm_bridge.c | 16 ++--
 drivers/gpu/drm/exynos/exynos_drm_mic.c  |  3 +--
 drivers/gpu/drm/i2c/tda998x_drv.c|  5 +
 drivers/gpu/drm/mcde/mcde_dsi.c  |  3 +--
 drivers/gpu/drm/mediatek/mtk_dsi.c   |  3 +--
 drivers/gpu/drm/mediatek/mtk_hdmi.c  |  3 +--
 drivers/gpu/drm/meson/meson_encoder_cvbs.c   |  3 +--
 drivers/gpu/drm/meson/meson_encoder_dsi.c|  3 +--
 drivers/gpu/drm/meson/meson_encoder_hdmi.c   |  3 +--
 drivers/gpu/drm/omapdrm/dss/dpi.c|  3 +--
 drivers/gpu/drm/omapdrm/dss/dsi.c|  3 +--
 drivers/gpu/drm/omapdrm/dss/hdmi4.c  |  3 +--
 drivers/gpu/drm/omapdrm/dss/hdmi5.c  |  3 +--
 drivers/gpu/drm/omapdrm/dss/sdi.c|  3 +--
 drivers/gpu/drm/omapdrm/dss/venc.c   |  3 +--
 drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c  |  3 +--
 drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c  |  3 +--
 drivers/gpu/drm/renesas

[PATCH v6 04/10] drm/bridge: simple-bridge: Use fwnode APIs to acquire device properties

2024-05-26 Thread Sui Jingfeng
Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
A side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/bridge/simple-bridge.c | 21 +
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/simple-bridge.c 
b/drivers/gpu/drm/bridge/simple-bridge.c
index fd7de9b6f80e..e7348ee6daf7 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -8,8 +8,6 @@
 
 #include 
 #include 
-#include 
-#include 
 #include 
 #include 
 
@@ -164,33 +162,32 @@ static const struct drm_bridge_funcs 
simple_bridge_bridge_funcs = {
 
 static int simple_bridge_probe(struct platform_device *pdev)
 {
+   struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
struct simple_bridge *sbridge;
-   struct device_node *remote;
+   int ret;
 
sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL);
if (!sbridge)
return -ENOMEM;
platform_set_drvdata(pdev, sbridge);
 
-   sbridge->info = of_device_get_match_data(&pdev->dev);
+   sbridge->info = device_get_match_data(&pdev->dev);
 
/* Get the next bridge in the pipeline. */
-   remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);
-   if (!remote)
-   return -EINVAL;
-
-   sbridge->next_bridge = of_drm_find_bridge(remote);
-   of_node_put(remote);
-
+   sbridge->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
if (!sbridge->next_bridge) {
dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
+   } else if (IS_ERR(sbridge->next_bridge)) {
+   ret = PTR_ERR(sbridge->next_bridge);
+   dev_err(&pdev->dev, "Error on finding the next bridge: %d\n", 
ret);
+   return ret;
}
 
/* Get the regulator and GPIO resources. */
sbridge->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
if (IS_ERR(sbridge->vdd)) {
-   int ret = PTR_ERR(sbridge->vdd);
+   ret = PTR_ERR(sbridge->vdd);
if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
sbridge->vdd = NULL;
-- 
2.34.1



[PATCH v6 03/10] drm/bridge: Implement of_drm_find_bridge() on the top of drm_bridge_find_by_fwnode()

2024-05-26 Thread Sui Jingfeng
Before applying this patch, people may worry about the OF and non-OF API
will have a risk to diverge. Eliminate the risk by reimplement the
of_drm_find_bridge() on the top of drm_bridge_find_by_fwnode(). As for now
the fundamental searching method is unique.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/drm_bridge.c | 29 -
 include/drm/drm_bridge.h | 14 +-
 2 files changed, 5 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 7759ca066db4..4c5584922d3c 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1346,35 +1346,6 @@ void drm_bridge_hpd_notify(struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL_GPL(drm_bridge_hpd_notify);
 
-#ifdef CONFIG_OF
-/**
- * of_drm_find_bridge - find the bridge corresponding to the device node in
- * the global bridge list
- *
- * @np: device node
- *
- * RETURNS:
- * drm_bridge control struct on success, NULL on failure
- */
-struct drm_bridge *of_drm_find_bridge(struct device_node *np)
-{
-   struct drm_bridge *bridge;
-
-   mutex_lock(&bridge_lock);
-
-   list_for_each_entry(bridge, &bridge_list, list) {
-   if (bridge->of_node == np) {
-   mutex_unlock(&bridge_lock);
-   return bridge;
-   }
-   }
-
-   mutex_unlock(&bridge_lock);
-   return NULL;
-}
-EXPORT_SYMBOL(of_drm_find_bridge);
-#endif
-
 /**
  * drm_bridge_find_by_fwnode - Find the bridge corresponding to the fwnode
  *
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 7b592cf30340..8d743dfe782c 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -791,21 +791,17 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct 
drm_bridge *bridge,
  struct drm_bridge *previous,
  enum drm_bridge_attach_flags flags);
 
-#ifdef CONFIG_OF
-struct drm_bridge *of_drm_find_bridge(struct device_node *np);
-#else
-static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
-{
-   return NULL;
-}
-#endif
-
 struct drm_bridge *
 drm_bridge_find_by_fwnode(struct fwnode_handle *fwnode);
 
 struct drm_bridge *
 drm_bridge_find_next_bridge_by_fwnode(struct fwnode_handle *fwnode, u32 port);
 
+static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
+{
+   return drm_bridge_find_by_fwnode(of_fwnode_handle(np));
+}
+
 /**
  * drm_bridge_get_next_bridge() - Get the next bridge in the chain
  * @bridge: bridge object
-- 
2.34.1



[PATCH v6 01/10] drm/bridge: Allow using fwnode APIs to get the next bridge

2024-05-26 Thread Sui Jingfeng
The various display bridge drivers rely on 'OF' infrastructures to
works very well, yet there are some platforms and/or devices lack of
'OF' support. Such as virtual display drivers, USB display apapters
and ACPI based systems etc.

Add fwnode based helpers to fill the niche, this allows part of display
bridge drivers to work across systems. As the fwnode APIs has wider
coverage than DT counterpart, and fwnode graphs are compatible with
OF graphs. So the newly created helpers can be used on all systems
in theory, assumed that there has valid OF/fwnode graphs established.

Note, the involved drm bridge instance should also has the fwnode
assigned, so that the user of it could find it via the fwnode handle.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/drm_bridge.c | 74 
 include/drm/drm_bridge.h | 11 +-
 2 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 584d109330ab..cef5bc88ee60 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1363,6 +1363,80 @@ struct drm_bridge *of_drm_find_bridge(struct device_node 
*np)
 EXPORT_SYMBOL(of_drm_find_bridge);
 #endif
 
+/**
+ * drm_bridge_find_by_fwnode - Find the bridge corresponding to the fwnode
+ *
+ * @fwnode: fwnode for which to find the matching drm_bridge
+ *
+ * This function looks up a drm_bridge in the global bridge list, based on
+ * its associated fwnode. Drivers who want to use this function should has
+ * fwnode handle assigned to the fwnode member of the struct drm_bridge
+ * instance.
+ *
+ * Returns:
+ *  * A reference to the requested drm_bridge object on success, or
+ *  * %NULL otherwise (object does not exist or the driver of requested
+ *bridge not probed yet).
+ */
+struct drm_bridge *drm_bridge_find_by_fwnode(struct fwnode_handle *fwnode)
+{
+   struct drm_bridge *ret = NULL;
+   struct drm_bridge *bridge;
+
+   if (!fwnode)
+   return NULL;
+
+   mutex_lock(&bridge_lock);
+
+   list_for_each_entry(bridge, &bridge_list, list) {
+   if (bridge->fwnode == fwnode) {
+   ret = bridge;
+   break;
+   }
+   }
+
+   mutex_unlock(&bridge_lock);
+
+   return ret;
+}
+EXPORT_SYMBOL_GPL(drm_bridge_find_by_fwnode);
+
+/**
+ * drm_bridge_find_next_bridge_by_fwnode - Find the next bridge by fwnode
+ * @fwnode: fwnode pointer to the current device.
+ * @port: identifier of the port node of the next bridge is connected.
+ *
+ * This function find the next bridge of the current node the fwnode
+ * pointed to, assumed that the fwnode graph has been well established.
+ *
+ * Returns:
+ *  * A reference to the requested drm_bridge object on success, or
+ *  * -%ENODEV if the fwnode graph or OF graph is not complete, or
+ *  * %NULL if object does not exist or the next bridge is not ready yet.
+ */
+struct drm_bridge *
+drm_bridge_find_next_bridge_by_fwnode(struct fwnode_handle *fwnode, u32 port)
+{
+   struct drm_bridge *bridge;
+   struct fwnode_handle *ep;
+   struct fwnode_handle *remote;
+
+   ep = fwnode_graph_get_endpoint_by_id(fwnode, port, 0, 0);
+   if (!ep)
+   return ERR_PTR(-ENODEV);
+
+   remote = fwnode_graph_get_remote_port_parent(ep);
+   fwnode_handle_put(ep);
+   if (!remote)
+   return ERR_PTR(-ENODEV);
+
+   bridge = drm_bridge_find_by_fwnode(remote);
+   fwnode_handle_put(remote);
+
+   return bridge;
+}
+EXPORT_SYMBOL_GPL(drm_bridge_find_next_bridge_by_fwnode);
+
 MODULE_AUTHOR("Ajay Kumar ");
 MODULE_DESCRIPTION("DRM bridge infrastructure");
 MODULE_LICENSE("GPL and additional rights");
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4baca0d9107b..725d6dddaf36 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -26,14 +26,13 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
 #include 
 #include 
 
-struct device_node;
-
 struct drm_bridge;
 struct drm_bridge_timings;
 struct drm_connector;
@@ -721,6 +720,8 @@ struct drm_bridge {
struct list_head chain_node;
/** @of_node: device node pointer to the bridge */
struct device_node *of_node;
+   /** @fwnode: fwnode pointer to the bridge */
+   struct fwnode_handle *fwnode;
/** @list: to keep track of all added bridges */
struct list_head list;
/**
@@ -797,6 +798,12 @@ static inline struct drm_bridge *of_drm_find_bridge(struct 
device_node *np)
 }
 #endif
 
+struct drm_bridge *
+drm_bridge_find_by_fwnode(struct fwnode_handle *fwnode);
+
+struct drm_bridge *
+drm_bridge_find_next_bridge_by_fwnode(struct fwnode_handle *fwnode, u32 port);
+
 /**
  * drm_bridge_get_next_bridge() - Get the next bridge in the chain
  * @bridge: bridge object
-- 
2.34.1



[PATCH v6 00/10] drm/bridge: Allow using fwnode API to get the next bridge

2024-05-26 Thread Sui Jingfeng
Currently, the various display bridge drivers rely on OF infrastructures
to works very well, yet there are platforms and/or devices absence of 'OF'
support. Such as virtual display drivers, USB display apapters and ACPI
based systems etc.

Add fwnode based helpers to fill the niche, this allows part of the display
bridge drivers to work across systems. As the fwnode API has wider coverage
than DT counterpart and the fwnode graphs are compatible with the OF graph,
so the provided helpers can be used on all systems in theory. Assumed that
fwnode graphs are well established on the system.

Tested on TI BeaglePlay board.

v1 -> v2:
 * Modify it66121 to switch togather
 * Drop the 'side-by-side' implement
 * Add drm_bridge_find_next_bridge_by_fwnode() helper
 * Add drm_bridge_set_node() helper

v2 -> v3:
 * Read kernel-doc and improve function comments (Dmitry)
 * Drop the 'port' argument of it66121_read_bus_width() (Dmitry)
 * drm-bridge: sii902x get nuked

v3 -> v4:
 * drm-bridge: tfp410 get nuked
 * Add platform module alias
 * Rebase and improve commit message and function comments

v4 -> v5:
 * Modify sii9234, ch7033 and ANX7688
 * Trivial fixes

v5 -> v6:
 * Implement the same thing with no boilerplate introduced
 * Add 'struct device *' field to the drm_bridge structure
 * Re-implement of_drm_find_bridge() with drm_bridge_find_by_fwnode()

Sui Jingfeng (10):
  drm/bridge: Allow using fwnode APIs to get the next bridge
  drm/bridge: Set firmware node of drm_bridge instances automatically
  drm/bridge: Implement of_drm_find_bridge() on the top of
drm_bridge_find_by_fwnode()
  drm/bridge: simple-bridge: Use fwnode APIs to acquire device
properties
  drm/bridge: display-connector: Use fwnode APIs to acquire device
properties
  drm/bridge: sii902x: Switch to use fwnode APIs to acquire device
properties
  drm-bridge: it66121: Use fwnode APIs to acquire device properties
  drm/bridge: tfp410: Use fwnode APIs to acquire device properties
  drm/bridge: sii9234: Use fwnode APIs to abstract DT dependent API away
  drm/bridge: ch7033: Switch to use fwnode based APIs

 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c  |  3 +-
 .../drm/bridge/analogix/analogix-anx6345.c|  4 +-
 .../drm/bridge/analogix/analogix-anx78xx.c|  4 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c |  3 +-
 .../gpu/drm/bridge/cadence/cdns-dsi-core.c|  3 +-
 .../drm/bridge/cadence/cdns-mhdp8546-core.c   |  3 +-
 drivers/gpu/drm/bridge/chipone-icn6211.c  |  5 +-
 drivers/gpu/drm/bridge/chrontel-ch7033.c  | 15 ++--
 drivers/gpu/drm/bridge/cros-ec-anx7688.c  |  4 +-
 drivers/gpu/drm/bridge/display-connector.c| 26 +++---
 drivers/gpu/drm/bridge/fsl-ldb.c  |  3 +-
 drivers/gpu/drm/bridge/imx/imx-ldb-helper.c   |  3 +-
 drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c  |  3 +-
 .../drm/bridge/imx/imx8qxp-pixel-combiner.c   |  3 +-
 .../gpu/drm/bridge/imx/imx8qxp-pixel-link.c   |  3 +-
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c  |  3 +-
 drivers/gpu/drm/bridge/ite-it6505.c   |  3 +-
 drivers/gpu/drm/bridge/ite-it66121.c  | 58 -
 drivers/gpu/drm/bridge/lontium-lt8912b.c  |  3 +-
 drivers/gpu/drm/bridge/lontium-lt9211.c   |  3 +-
 drivers/gpu/drm/bridge/lontium-lt9611.c   |  3 +-
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c|  3 +-
 drivers/gpu/drm/bridge/lvds-codec.c   |  3 +-
 .../bridge/megachips-stdp-ge-b850v3-fw.c  |  3 +-
 drivers/gpu/drm/bridge/microchip-lvds.c   |  3 +-
 drivers/gpu/drm/bridge/nwl-dsi.c  |  3 +-
 drivers/gpu/drm/bridge/nxp-ptn3460.c  |  3 +-
 drivers/gpu/drm/bridge/panel.c|  3 +-
 drivers/gpu/drm/bridge/parade-ps8622.c|  3 +-
 drivers/gpu/drm/bridge/parade-ps8640.c|  1 -
 drivers/gpu/drm/bridge/samsung-dsim.c |  3 +-
 drivers/gpu/drm/bridge/sii902x.c  | 46 --
 drivers/gpu/drm/bridge/sii9234.c  |  8 +-
 drivers/gpu/drm/bridge/sil-sii8620.c  |  3 +-
 drivers/gpu/drm/bridge/simple-bridge.c| 24 +++--
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c |  3 +-
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c |  3 +-
 drivers/gpu/drm/bridge/tc358762.c |  3 +-
 drivers/gpu/drm/bridge/tc358764.c |  3 +-
 drivers/gpu/drm/bridge/tc358767.c |  3 +-
 drivers/gpu/drm/bridge/tc358768.c |  3 +-
 drivers/gpu/drm/bridge/tc358775.c |  3 +-
 drivers/gpu/drm/bridge/thc63lvd1024.c |  3 +-
 drivers/gpu/drm/bridge/ti-dlpc3433.c  |  3 +-
 drivers/gpu/drm/bridge/ti-sn65dsi83.c |  3 +-
 drivers/gpu/drm/bridge/ti-sn65dsi86.c |  3 +-
 drivers/gpu/drm/bridge/ti-tfp410.c| 42 -
 drivers/gpu/drm/bridge/ti-tpd12s015.c |  3 +-
 drivers/gpu/drm/drm_bridge.c

[PATCH v2 3/3] drm/loongson: Add dummy gpu driver as a subcomponent

2024-05-26 Thread Sui Jingfeng
Loongson Graphics are PCIe multi-functional devices, the GPU device and
the display controller are two distinct devices. Drivers of them should
loose coupling, but still be able to works togather to provide a unified
service to userspace.

Add a dummy driver for the GPU, it functional as a subcomponent as well.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile|  3 +
 drivers/gpu/drm/loongson/loong_gpu_pci_drv.c | 90 
 drivers/gpu/drm/loongson/loong_gpu_pci_drv.h | 27 ++
 drivers/gpu/drm/loongson/loongson_module.c   |  9 ++
 drivers/gpu/drm/loongson/loongson_module.h   |  7 ++
 drivers/gpu/drm/loongson/lsdc_drv.c  | 12 ++-
 drivers/gpu/drm/loongson/lsdc_drv.h  |  8 +-
 7 files changed, 149 insertions(+), 7 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loong_gpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loong_gpu_pci_drv.h

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index e15cb9bff378..4f4c1c42bbba 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -17,6 +17,9 @@ loongson-y := \
lsdc_probe.o \
lsdc_ttm.o
 
+loongson-y += \
+   loong_gpu_pci_drv.o
+
 loongson-y += loongson_device.o \
  loongson_module.o
 
diff --git a/drivers/gpu/drm/loongson/loong_gpu_pci_drv.c 
b/drivers/gpu/drm/loongson/loong_gpu_pci_drv.c
new file mode 100644
index ..4ae6a5807d1d
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loong_gpu_pci_drv.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include 
+#include 
+
+#include 
+#include 
+
+#include "loongson_module.h"
+#include "loong_gpu_pci_drv.h"
+
+static int loong_gpu_bind(struct device *dev, struct device *master, void 
*data)
+{
+   struct drm_device *drm = data;
+   struct loong_gpu_device *gpu;
+   u32 hw_info;
+   u8 host_id;
+   u8 revision;
+
+   gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
+   if (!gpu)
+   return -ENOMEM;
+
+   gpu->reg_base = pcim_iomap(to_pci_dev(dev), 0, 0);
+   if (!gpu->reg_base)
+   return -ENOMEM;
+
+   hw_info = loong_rreg32(gpu, 0x8C);
+
+   gpu->ver_major = (hw_info >> 8) * 0x0F;
+   gpu->ver_minor = (hw_info & 0xF0) >> 4;
+   revision = hw_info & 0x0F;
+   host_id = (hw_info >> 16) & 0xFF;
+
+   drm_info(drm, "Found LoongGPU: LG%x%x0, revision: %x, Host: %s\n",
+gpu->ver_major, gpu->ver_minor, revision,
+host_id ? "LS2K2000" : "LS7A2000");
+
+   dev_set_drvdata(dev, gpu);
+
+   return 0;
+}
+
+static void loong_gpu_unbind(struct device *dev, struct device *master, void 
*data)
+{
+   struct loong_gpu_device *gpu = dev_get_drvdata(dev);
+
+   if (gpu) {
+   pcim_iounmap(to_pci_dev(dev), gpu->reg_base);
+   devm_kfree(dev, gpu);
+   }
+}
+
+static const struct component_ops loong_gpu_component_ops = {
+   .bind = loong_gpu_bind,
+   .unbind = loong_gpu_unbind,
+};
+
+static int loong_gpu_pci_probe(struct pci_dev *pdev,
+  const struct pci_device_id *ent)
+{
+   int ret;
+
+   ret = pcim_enable_device(pdev);
+   if (ret)
+   return ret;
+
+   pci_set_master(pdev);
+
+   return component_add(&pdev->dev, &loong_gpu_component_ops);
+}
+
+static void loong_gpu_pci_remove(struct pci_dev *pdev)
+{
+   component_del(&pdev->dev, &loong_gpu_component_ops);
+}
+
+static const struct pci_device_id loong_gpu_pci_id_list[] = {
+   {PCI_VDEVICE(LOONGSON, 0x7a25), CHIP_LS7A2000},
+   { },
+};
+
+struct pci_driver loong_gpu_pci_driver = {
+   .name = "loong",
+   .id_table = loong_gpu_pci_id_list,
+   .probe = loong_gpu_pci_probe,
+   .remove = loong_gpu_pci_remove,
+};
+
+MODULE_DEVICE_TABLE(pci, loong_gpu_pci_id_list);
diff --git a/drivers/gpu/drm/loongson/loong_gpu_pci_drv.h 
b/drivers/gpu/drm/loongson/loong_gpu_pci_drv.h
new file mode 100644
index ..f620820ab263
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loong_gpu_pci_drv.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __LOONG_GPU_PCI_DRV_H__
+#define __LOONG_GPU_PCI_DRV_H__
+
+#include 
+
+struct loong_gpu_device {
+   struct pci_dev *pdev;
+   void __iomem *reg_base;
+
+   u32 ver_major;
+   u32 ver_minor;
+   u32 revision;
+};
+
+static inline u32 loong_rreg32(struct loong_gpu_device *ldev, u32 offset)
+{
+   return readl(ldev->reg_base + offset);
+}
+
+static inline void loong_wreg32(struct loong_gpu_device *ldev, u32 offset, u32 
val)
+{
+   writel(val, ldev->reg_base + offset);
+}
+
+#endif
diff --git a/drivers/gpu/drm/loongson/loongson_module.c 
b/drivers/gpu/drm/loongson/loongson_module.c
index 037fa7ffe9c9..d4c0d5ce

[PATCH v2 2/3] drm/loongson: Introduce component framework support

2024-05-26 Thread Sui Jingfeng
Hardware units come with PCIe are actually all ready to be driven, but
there has some board specific modules could return '-EPROBE_DEFER'.
However, the driver needs all of the subcompoments ready to use before
it can register the drm service to userspace.

Introduce the component framework to tackle such problems, move DRM
device related code into loongson_drm_master_bind() function. Move
output related things into subdriver. Display controller and GPIO-I2C
goes with the PCIe master, sinch they has no dependency on exterinal
modules.

While the outputs drivers, such as encoders and conectors, may has some
dependency on exterinal modules. Those hardware units are relatively
independent hardware IPs from the CRTC. Hence, offload them to submodules.
This design allows subdriver return '-EPROBE_DEFER' to the driver core
if it need to do so, the master drvier won't bind until all submodules
are ready.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/Makefile |   1 +
 drivers/gpu/drm/loongson/loongson_module.c|  17 +-
 drivers/gpu/drm/loongson/loongson_module.h|   1 +
 drivers/gpu/drm/loongson/lsdc_drv.c   | 205 +++---
 drivers/gpu/drm/loongson/lsdc_drv.h   |  31 +--
 drivers/gpu/drm/loongson/lsdc_i2c.c   |   5 +-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |   3 -
 drivers/gpu/drm/loongson/lsdc_output.c| 176 +++
 drivers/gpu/drm/loongson/lsdc_output.h|  38 +++-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   3 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  17 +-
 11 files changed, 367 insertions(+), 130 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

diff --git a/drivers/gpu/drm/loongson/Makefile 
b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..e15cb9bff378 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -9,6 +9,7 @@ loongson-y := \
lsdc_gfxpll.o \
lsdc_i2c.o \
lsdc_irq.o \
+   lsdc_output.o \
lsdc_output_7a1000.o \
lsdc_output_7a2000.o \
lsdc_plane.o \
diff --git a/drivers/gpu/drm/loongson/loongson_module.c 
b/drivers/gpu/drm/loongson/loongson_module.c
index d2a51bd395f6..037fa7ffe9c9 100644
--- a/drivers/gpu/drm/loongson/loongson_module.c
+++ b/drivers/gpu/drm/loongson/loongson_module.c
@@ -4,6 +4,7 @@
  */
 
 #include 
+#include 
 
 #include 
 
@@ -19,15 +20,29 @@ module_param_named(vblank, loongson_vblank, int, 0400);
 
 static int __init loongson_module_init(void)
 {
+   int ret;
+
if (!loongson_modeset || video_firmware_drivers_only())
return -ENODEV;
 
-   return pci_register_driver(&lsdc_pci_driver);
+   ret = platform_driver_register(&lsdc_output_port_platform_driver);
+   if (ret)
+   return ret;
+
+   ret = pci_register_driver(&lsdc_pci_driver);
+   if (ret) {
+   platform_driver_unregister(&lsdc_output_port_platform_driver);
+   return ret;
+   }
+
+   return 0;
 }
 module_init(loongson_module_init);
 
 static void __exit loongson_module_exit(void)
 {
pci_unregister_driver(&lsdc_pci_driver);
+
+   platform_driver_unregister(&lsdc_output_port_platform_driver);
 }
 module_exit(loongson_module_exit);
diff --git a/drivers/gpu/drm/loongson/loongson_module.h 
b/drivers/gpu/drm/loongson/loongson_module.h
index 931c17521bf0..8dc71b98f5cc 100644
--- a/drivers/gpu/drm/loongson/loongson_module.h
+++ b/drivers/gpu/drm/loongson/loongson_module.h
@@ -8,5 +8,6 @@
 
 extern int loongson_vblank;
 extern struct pci_driver lsdc_pci_driver;
+extern struct platform_driver lsdc_output_port_platform_driver;
 
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c 
b/drivers/gpu/drm/loongson/lsdc_drv.c
index adc7344d2f80..02429c95bd1a 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -3,7 +3,9 @@
  * Copyright (C) 2023 Loongson Technology Corporation Limited
  */
 
+#include 
 #include 
+#include 
 #include 
 
 #include 
@@ -67,31 +69,6 @@ static int lsdc_modeset_init(struct lsdc_device *ldev,
unsigned int i;
int ret;
 
-   for (i = 0; i < num_crtc; i++) {
-   dispipe = &ldev->dispipe[i];
-
-   /* We need an index before crtc is initialized */
-   dispipe->index = i;
-
-   ret = funcs->create_i2c(ddev, dispipe, i);
-   if (ret)
-   return ret;
-   }
-
-   for (i = 0; i < num_crtc; i++) {
-   struct i2c_adapter *ddc = NULL;
-
-   dispipe = &ldev->dispipe[i];
-   if (dispipe->li2c)
-   ddc = &dispipe->li2c->adapter;
-
-   ret = funcs->output_init(ddev, dispipe, ddc, i);
-   if (ret)
-   return ret;
-
-   ldev->num_output++;
-

[PATCH v2 1/3] drm/loongson: Add a helper for creating child devices

2024-05-26 Thread Sui Jingfeng
In some display subsystems, the functionality of a PCIe device may too
complex to be managed by a single driver. A split of the functionality
into child devices can helpful to achieve better modularity.

Another benefit is that we could migrate the dependency on exterinal
modules to a submodule level with the helper created. For example, it's
not uncommon that some exterinal module will return -EPROBE_DEFER to our
driver during probe time. KMS driver has to tear down everything when it
receives -EPROBE_DEFER, the problem is that it's completely not necessary
and rising cyclic dependency problems if not process correctly.

Add the loongson_create_platform_device() function, which allows the KMS
driver to create sub-devices for it. The manually created decice acts as
agents for the principal part, migrate the potential issue to submodule.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/loongson/loongson_device.c | 42 ++
 drivers/gpu/drm/loongson/lsdc_drv.h|  6 
 2 files changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/loongson/loongson_device.c 
b/drivers/gpu/drm/loongson/loongson_device.c
index 9986c8a2a255..b268549d643e 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -4,6 +4,7 @@
  */
 
 #include 
+#include 
 
 #include "lsdc_drv.h"
 
@@ -100,3 +101,44 @@ lsdc_device_probe(struct pci_dev *pdev, enum 
loongson_chip_id chip_id)
 {
return __chip_id_desc_table[chip_id];
 }
+
+int loongson_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, 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);
+   return ret;
+   }
+
+   *ppdev = pdev;
+
+   return 0;
+}
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h 
b/drivers/gpu/drm/loongson/lsdc_drv.h
index fbf2d760ef27..a2c6b496a69f 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -47,6 +47,12 @@ enum loongson_chip_id {
 const struct lsdc_desc *
 lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip);
 
+int loongson_create_platform_device(struct device *parent,
+   const char *name, int id,
+   struct resource *pres,
+   void *data,
+   struct platform_device **ppdev);
+
 struct lsdc_kms_funcs;
 
 /* DC specific */
-- 
2.34.1



[PATCH v2 0/3] drm/loongson: Introduce component framework support

2024-05-26 Thread Sui Jingfeng
Introduce component framework to bind child and sibling devices, for better
modularity and offload the deferral probe issue to submodule if it need to
attach exterinal module someday. Also for better reflect the hardware
layout.

Hardware units that come with PCIe are all ready to drive, but there are
some board specific modules will return -EPROBE_DEFER to us. We need all
submodules ready to use before we can register the drm device to userspace.

The idea is to device the exterinal module dependent part and exterinal
module independent part. For example, the display controller and the
GPIO-I2C just belong to exterinal module independent part. While the
outputs are just belong to exterinal module dependent part.

We abstract the output ports as child devices, the output ports may
consists of encoder phy and level shifter. Well, the GPU are standalone
siblings relative to the DC. Those units are relatively separated
hardware units from display controller itself.

By design, the display controller PCI(e) is selected as master, gpio-i2c
go with master. Manually created virtual subdevice functional as agents
for the master, it could return the -EPROBE_DEFER back to the drvier core.
This allows the master don't have to tear down everything, thereore
majority setups work can be preserved. The potential cyclic dependency
problem can be solved then.

v1 -> v2:
* Squash patch 0002 and patch 0003 into one
* Fill type and improve commit message

Sui Jingfeng (3):
  drm/loongson: Add a helper for creating child devices
  drm/loongson: Introduce component framework support
  drm/loongson: Add dummy gpu driver as a subcomponent

 drivers/gpu/drm/loongson/Makefile |   4 +
 drivers/gpu/drm/loongson/loong_gpu_pci_drv.c  |  90 
 drivers/gpu/drm/loongson/loong_gpu_pci_drv.h  |  27 +++
 drivers/gpu/drm/loongson/loongson_device.c|  42 
 drivers/gpu/drm/loongson/loongson_module.c|  26 ++-
 drivers/gpu/drm/loongson/loongson_module.h|   8 +
 drivers/gpu/drm/loongson/lsdc_drv.c   | 217 +++---
 drivers/gpu/drm/loongson/lsdc_drv.h   |  45 +---
 drivers/gpu/drm/loongson/lsdc_i2c.c   |   5 +-
 drivers/gpu/drm/loongson/lsdc_i2c.h   |   3 -
 drivers/gpu/drm/loongson/lsdc_output.c| 176 ++
 drivers/gpu/drm/loongson/lsdc_output.h|  38 ++-
 drivers/gpu/drm/loongson/lsdc_output_7a1000.c |   3 +-
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c |  17 +-
 14 files changed, 564 insertions(+), 137 deletions(-)
 create mode 100644 drivers/gpu/drm/loongson/loong_gpu_pci_drv.c
 create mode 100644 drivers/gpu/drm/loongson/loong_gpu_pci_drv.h
 create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c

-- 
2.34.1



Re: [v14,06/28] drm/tests: Add output bpc tests

2024-05-23 Thread Sui Jingfeng

Hi, Maxime


I love you patch, yet it generates warnning calltrace. Despite it's
just a warning but it can overwhelm when we run kunit tests. Hence,
I suggest switch to the drm_atomic_connector_get_property() function.

Logs are pasted as below for easier to ready.


 [ cut here ]
 WARNING: CPU: 3 PID: 1264 at drivers/gpu/drm/drm_mode_object.c:354 
drm_object_property_get_value+0x2c/0x34
 Modules linked in: drm_connector_test drm_display_helper 
drm_kunit_helpers kunit rfkill ip_set nf_tables nfnetlink vfat fat uas 
usb_storage kvm efi_pstore pstore spi_loongson_pci spi_loongson_core 
fuse efivarfs [last unloaded: drm_connector_test]
 CPU: 3 PID: 1264 Comm: kunit_try_catch Tainted: G N 
6.9.0+ #443
 Hardware name: Loongson 
Loongson-3A6000-HV-7A2000-XA61200/Loongson-3A6000-HV-7A2000-XA61200, 
BIOS Loongson-UDK2018-V4.0.05636-stable202311 12/
 pc 93469fec ra 8225afdc tp 90011fc54000 sp 
90011fc57d80
 a0 90010aa84658 a1 900104432a00 a2 90011fc57d98 a3 
90011fc57d98
 a4 900104432a4c a5 93f14e98 a6 0008 a7 
fffe
 t0 0010 t1 90010aa84000 t2  t3 
c0c0c0c0
 t4 c0c0c0c0 t5 0220 t6 0001 t7 
00107203
 t8 00107303 u0 0008 s9 9001000ebe60 s0 
90010aa84000
 s1 9001470679c8 s2 900104432a00 s3 82284000 s4 
90010aa84658
 s5 90010aa84618 s6 1000 s7 0001 s8 

ra: 8225afdc drm_test_connector_hdmi_init_bpc_8+0xcc/0x2d0 
[drm_connector_test]

   ERA: 93469fec drm_object_property_get_value+0x2c/0x34
  CRMD: 00b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE)
  PRMD: 0004 (PPLV0 +PIE -PWE)
  EUEN:  (-FPE -SXE -ASXE -BTE)
  ECFG: 00071c1c (LIE=2-4,10-12 VS=7)
 ESTAT: 000c [BRK] (IS= ECode=12 EsubCode=0)
  PRID: 0014d000 (Loongson-64bit, Loongson-3A6000-HV)
 CPU: 3 PID: 1264 Comm: kunit_try_catch Tainted: G N 
6.9.0+ #443
 Hardware name: Loongson 
Loongson-3A6000-HV-7A2000-XA61200/Loongson-3A6000-HV-7A2000-XA61200, 
BIOS Loongson-UDK2018-V4.0.05636-stable202311 12/
 Stack : 94065000  92ac339c 
90011fc54000
 90011fc579f0 90011fc579f8  
90011fc57b38
 90011fc57b30 90011fc57b30 90011fc57940 
0001
 0001 90011fc579f8 18e7bf3ffb6e59df 
900100328a00
 0001 0003 0434 
4c206e6f73676e6f
 6f4c203a656d616e 000d0ad3 0704c000 
9001000ebe60
   93ee6ab0 
94065000
  90010aa84618 1000 
0001
   92ac33b4 
7dd80078
 00b0 0004  
00071c1c

 ...
 Call Trace:
 [<92ac33b4>] show_stack+0x5c/0x180
 [<93b1ed2c>] dump_stack_lvl+0x70/0xa0
 [<93b01fd8>] __warn+0x84/0xc8
 [<93ad282c>] report_bug+0x19c/0x204
 [<93b1fe00>] do_bp+0x264/0x2b4
 [<>] 0x0
 [<93469fec>] drm_object_property_get_value+0x2c/0x34
 [] drm_test_connector_hdmi_init_bpc_8+0xcc/0x2d0 
[drm_connector_test]

 [] kunit_try_run_case+0x7c/0x18c [kunit]
 [] kunit_generic_run_threadfn_adapter+0x1c/0x28 [kunit]
 [<92b06238>] kthread+0x124/0x130
 [<92ac1248>] ret_from_kernel_thread+0xc/0xa4

 ---[ end trace  ]---
 [ cut here ]


On 5/21/24 18:13, Maxime Ripard wrote:

Now that we're tracking the output bpc count in the connector state,
let's add a few tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
Reviewed-by: Dmitry Baryshkov 
---
  drivers/gpu/drm/Kconfig|   1 +
  drivers/gpu/drm/tests/Makefile |   1 +
  drivers/gpu/drm/tests/drm_connector_test.c | 140 +++
  drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 438 +
  drivers/gpu/drm/tests/drm_kunit_edid.h | 106 +
  5 files changed, 686 insertions(+)



[...]


+
+/*
+ * Test that the registration of a connector with a maximum bpc count of
+ * 8 succeeds, registers the max bpc property, but doesn't register the
+ * HDR output metadata one.
+ */
+static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector *connector = &priv->connector;
+   struct drm_property *prop;
+   uint64_t val;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(&priv->drm, connector,
+  &dummy_funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  &priv->ddc,
+   

Re: [v5,3/3] drm/mediatek: Implement OF graphs support for display paths

2024-05-22 Thread Sui Jingfeng

Hi,


On 5/21/24 15:57, AngeloGioacchino Del Regno wrote:

+static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node 
*node,
+struct mtk_mmsys_driver_data *data)
+{
+   struct device_node *ep_node;
+   struct of_endpoint of_ep;
+   bool output_present[MAX_CRTC] = { false };
+   int ret;
+
+   for_each_endpoint_of_node(node, ep_node) {
+   ret = of_graph_parse_endpoint(ep_node, &of_ep);
+   of_node_put(ep_node);


There is going to *double* decline the reference counter, as the 
__of_get_next_child() will decrease the reference counter for us

on the next iteration.



+   if (ret) {
+   dev_err_probe(dev, ret, "Cannot parse endpoint\n");
+   break;
+   }


Move the 'of_node_put(ep_node)' into brace '{}' here, if we really cares
about the reference count.


+
+   if (of_ep.id >= MAX_CRTC) {


ditto ?


+   ret = dev_err_probe(dev, -EINVAL,
+   "Invalid endpoint%u number\n", 
of_ep.port);
+   break;
+   }
+
+   output_present[of_ep.id] = true;
+   }
+
+   if (ret)
+   return ret;
+
+   if (output_present[CRTC_MAIN]) {
+   ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_MAIN,
+   &data->main_path, 
&data->main_len);
+   if (ret)
+   return ret;
+   }
+
+   if (output_present[CRTC_EXT]) {
+   ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_EXT,
+   &data->ext_path, 
&data->ext_len);
+   if (ret)
+   return ret;
+   }
+
+   if (output_present[CRTC_THIRD]) {
+   ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_THIRD,
+   &data->third_path, 
&data->third_len);
+   if (ret)
+   return ret;
+   }
+
+   return 0;
+}
+


--
Best regards
Sui Jingfeng



Re: [v5,3/3] drm/mediatek: Implement OF graphs support for display paths

2024-05-22 Thread Sui Jingfeng

Hi,


On 5/21/24 15:57, AngeloGioacchino Del Regno wrote:

+static int mtk_drm_of_get_ddp_comp_type(struct device_node *node, enum 
mtk_ddp_comp_type *ctype)
+{
+   const struct of_device_id *of_id = of_match_node(mtk_ddp_comp_dt_ids, 
node);
+
+   if (!of_id)
+   return -EINVAL;
+
+   *ctype = (enum mtk_ddp_comp_type)((uintptr_t)of_id->data);
+
+   return 0;
+}
+
+static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
+int output_port, enum mtk_crtc_path 
crtc_path,
+struct device_node **next, unsigned int 
*cid)
+{
+   struct device_node *ep_dev_node, *ep_out;
+   enum mtk_ddp_comp_type comp_type;
+   int ret;
+
+   ep_out = of_graph_get_endpoint_by_regs(node, output_port, crtc_path);
+   if (!ep_out)
+   return -ENOENT;
+
+   ep_dev_node = of_graph_get_remote_port_parent(ep_out);


below here, 'ep_out' will not be used anymore.

of_node_put(ep_out);

Maybe we should call it under a error handling tag?
But this is trivial problem.


+   if (!ep_dev_node)
+   return -EINVAL;
+
+   /*
+* Pass the next node pointer regardless of failures in the later code
+* so that if this function is called in a loop it will walk through all
+* of the subsequent endpoints anyway.
+*/
+   *next = ep_dev_node;
+
+   if (!of_device_is_available(ep_dev_node))
+   return -ENODEV;
+
+   ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
+   if (ret) {
+   if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
+   *cid = (unsigned int)DDP_COMPONENT_DRM_OVL_ADAPTOR;
+   return 0;
+   }
+   return ret;
+   }
+
+   ret = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+   if (ret < 0)
+   return ret;
+
+   /* All ok! Pass the Component ID to the caller. */
+   *cid = (unsigned int)ret;
+
+   return 0;
+}
+


--
Best regards
Sui Jingfeng



Re: [v5,3/3] drm/mediatek: Implement OF graphs support for display paths

2024-05-22 Thread Sui Jingfeng

Hi,


On 5/22/24 19:48, Sui Jingfeng wrote:

if the not bridge is not ready



'not' -> 'next'


Re: [v5,3/3] drm/mediatek: Implement OF graphs support for display paths

2024-05-22 Thread Sui Jingfeng

Hi,

Looks good to me in overall!

On 5/21/24 15:57, AngeloGioacchino Del Regno wrote:

It is impossible to add each and every possible DDP path combination
for each and every possible combination of SoC and board: right now,
this driver hardcodes configuration for 10 SoCs and this is going to
grow larger and larger, and with new hacks like the introduction of
mtk_drm_route which is anyway not enough for all final routes as the
DSI cannot be connected to MERGE if it's not a dual-DSI, or enabling
DSC preventively doesn't work if the display doesn't support it, or
others.

Since practically all display IPs in MediaTek SoCs support being
interconnected with different instances of other, or the same, IPs
or with different IPs and in different combinations, the final DDP
pipeline is effectively a board specific configuration.

Implement OF graphs support to the mediatek-drm drivers, allowing to
stop hardcoding the paths, and preventing this driver to get a huge
amount of arrays for each board and SoC combination, also paving the
way to share the same mtk_mmsys_driver_data between multiple SoCs,
making it more straightforward to add support for new chips.

Reviewed-by: Alexandre Mergnat 
Tested-by: Alexandre Mergnat 
Signed-off-by: AngeloGioacchino Del Regno 

---
  drivers/gpu/drm/mediatek/mtk_disp_drv.h   |   1 +
  .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   |  40 ++-
  drivers/gpu/drm/mediatek/mtk_dpi.c|  16 +-
  drivers/gpu/drm/mediatek/mtk_drm_drv.c| 282 --
  drivers/gpu/drm/mediatek/mtk_drm_drv.h|   2 +-
  drivers/gpu/drm/mediatek/mtk_dsi.c|  10 +-
  6 files changed, 313 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 082ac18fe04a..94843974851f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -108,6 +108,7 @@ size_t mtk_ovl_get_num_formats(struct device *dev);
  
  void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);

  void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex);
+bool mtk_ovl_adaptor_is_comp_present(struct device_node *node);
  void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev,
 unsigned int next);
  void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index 02dd7dcdfedb..400519d1ca1f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -491,6 +491,38 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == data;
  }
  
+static int ovl_adaptor_of_get_ddp_comp_type(struct device_node *node,

+   enum mtk_ovl_adaptor_comp_type 
*ctype)
+{
+   const struct of_device_id *of_id = 
of_match_node(mtk_ovl_adaptor_comp_dt_ids, node);
+
+   if (!of_id)
+   return -EINVAL;
+
+   *ctype = (enum mtk_ovl_adaptor_comp_type)((uintptr_t)of_id->data);
+
+   return 0;
+}
+
+bool mtk_ovl_adaptor_is_comp_present(struct device_node *node)
+{
+   enum mtk_ovl_adaptor_comp_type type;
+   int ret;
+
+   ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
+   if (ret)
+   return false;
+
+   if (type >= OVL_ADAPTOR_TYPE_NUM)
+   return false;
+
+   /*
+* ETHDR and Padding are used exclusively in OVL Adaptor: if this
+* component is not one of those, it's likely not an OVL Adaptor path.
+*/
+   return type == OVL_ADAPTOR_TYPE_ETHDR || type == 
OVL_ADAPTOR_TYPE_PADDING;
+}
+
  static int ovl_adaptor_comp_init(struct device *dev, struct component_match 
**match)
  {
struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
@@ -500,12 +532,11 @@ static int ovl_adaptor_comp_init(struct device *dev, 
struct component_match **ma
parent = dev->parent->parent->of_node->parent;
  
  	for_each_child_of_node(parent, node) {

-   const struct of_device_id *of_id;
enum mtk_ovl_adaptor_comp_type type;
-   int id;
+   int id, ret;
  
-		of_id = of_match_node(mtk_ovl_adaptor_comp_dt_ids, node);

-   if (!of_id)
+   ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
+   if (ret)
continue;
  
  		if (!of_device_is_available(node)) {

@@ -514,7 +545,6 @@ static int ovl_adaptor_comp_init(struct device *dev, struct 
component_match **ma
continue;
}
  
-		type = (enum mtk_ovl_adaptor_comp_type)(uintptr_t)of_id->data;

id = ovl_adaptor_comp_get_id(dev, node, type);
if (id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
diff --git a/drivers/gpu/dr

Re: [PATCH] drm/bridge: adv7511: Exit interrupt handling when necessary

2024-05-20 Thread Sui Jingfeng

Hi,


On 5/20/24 19:13, Dmitry Baryshkov wrote:

On Mon, 20 May 2024 at 14:11, Sui Jingfeng  wrote:


Hi,

On 5/20/24 06:11, Dmitry Baryshkov wrote:

On Thu, May 16, 2024 at 06:10:06PM +0800, Liu Ying wrote:

Commit f3d9683346d6 ("drm/bridge: adv7511: Allow IRQ to share GPIO pins")
fails to consider the case where adv7511->i2c_main->irq is zero, i.e.,
no interrupt requested at all.

Without interrupt, adv7511_wait_for_edid() could return -EIO sometimes,
because it polls adv7511->edid_read flag by calling adv7511_irq_process()
a few times, but adv7511_irq_process() happens to refuse to handle
interrupt by returning -ENODATA.  Hence, EDID retrieval fails randomly.

Fix the issue by checking adv7511->i2c_main->irq before exiting interrupt
handling from adv7511_irq_process().

Fixes: f3d9683346d6 ("drm/bridge: adv7511: Allow IRQ to share GPIO pins")
Signed-off-by: Liu Ying 
---
   drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 3 ++-
   1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 6089b0bb9321..2074fa3c1b7b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -479,7 +479,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511, 
bool process_hpd)
  return ret;

  /* If there is no IRQ to handle, exit indicating no IRQ data */
-if (!(irq0 & (ADV7511_INT0_HPD | ADV7511_INT0_EDID_READY)) &&
+if (adv7511->i2c_main->irq &&
+!(irq0 & (ADV7511_INT0_HPD | ADV7511_INT0_EDID_READY)) &&
  !(irq1 & ADV7511_INT1_DDC_ERROR))
  return -ENODATA;


I think it might be better to handle -ENODATA in adv7511_wait_for_edid()
instead. WDYT?



I think this is may deserve another patch.


My point is that the IRQ handler is fine to remove -ENODATA here,


[...]

there is no pending IRQ that can be handled. 


But there may has other things need to do in the adv7511_irq_process()
function.

So instead of continuing
the execution when we know that IRQ bits are not set, 


Even when IRQ bits are not set, it just means that there is no HPD
and no EDID ready-to-read signal. HDMI CEC interrupts still need
to process.


it's better to

ignore -ENODATA in the calling code and go on with msleep().



So, It's confusing to ignore the -ENODATA here.

--
Best regards
Sui


Re: [PATCH] drm/bridge: adv7511: Exit interrupt handling when necessary

2024-05-20 Thread Sui Jingfeng

Hi,

On 5/20/24 06:11, Dmitry Baryshkov wrote:

On Thu, May 16, 2024 at 06:10:06PM +0800, Liu Ying wrote:

Commit f3d9683346d6 ("drm/bridge: adv7511: Allow IRQ to share GPIO pins")
fails to consider the case where adv7511->i2c_main->irq is zero, i.e.,
no interrupt requested at all.

Without interrupt, adv7511_wait_for_edid() could return -EIO sometimes,
because it polls adv7511->edid_read flag by calling adv7511_irq_process()
a few times, but adv7511_irq_process() happens to refuse to handle
interrupt by returning -ENODATA.  Hence, EDID retrieval fails randomly.

Fix the issue by checking adv7511->i2c_main->irq before exiting interrupt
handling from adv7511_irq_process().

Fixes: f3d9683346d6 ("drm/bridge: adv7511: Allow IRQ to share GPIO pins")
Signed-off-by: Liu Ying 
---
  drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c 
b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 6089b0bb9321..2074fa3c1b7b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -479,7 +479,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511, 
bool process_hpd)
return ret;
  
  	/* If there is no IRQ to handle, exit indicating no IRQ data */

-   if (!(irq0 & (ADV7511_INT0_HPD | ADV7511_INT0_EDID_READY)) &&
+   if (adv7511->i2c_main->irq &&
+   !(irq0 & (ADV7511_INT0_HPD | ADV7511_INT0_EDID_READY)) &&
!(irq1 & ADV7511_INT1_DDC_ERROR))
return -ENODATA;


I think it might be better to handle -ENODATA in adv7511_wait_for_edid()
instead. WDYT?



I think this is may deserve another patch.

--
Best regards
Sui


[etnaviv-next v14 8/8] drm/etnaviv: Add support for vivante GPU cores attached via PCIe device

2024-05-19 Thread Sui Jingfeng
Previouly, the component framework is being used to bind multiple platform
GPU devices to a virtual master. The virtual master is manually created by
the driver, and is also a platform device. This is fine and works well for
various SoCs, yet there some hardware venders integrate Vivante GPU cores
into PCIe card and the driver lacks the support for PCIe devices.

Create virtual platform devices as a representation for each GPU IP core,
the manually created platform devices are functional as subcomponent, and
all of them are child of the PCIe master device. The master is real for
PCIe devices, as the PCIe device has already been created by the time the
etnaviv.ko is loaded. Hence, bind all of the virtual child to the real
master, this design reflects the hardware layout perfectly and is
extensible.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/Kconfig   |   9 ++
 drivers/gpu/drm/etnaviv/Makefile  |   2 +
 drivers/gpu/drm/etnaviv/etnaviv_drv.c |  12 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |   2 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c |  75 --
 drivers/gpu/drm/etnaviv/etnaviv_gpu.h |   4 +
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.c | 161 ++
 drivers/gpu/drm/etnaviv/etnaviv_pci_drv.h |  44 ++
 8 files changed, 293 insertions(+), 16 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..7cb44f72d512 100644
--- a/drivers/gpu/drm/etnaviv/Kconfig
+++ b/drivers/gpu/drm/etnaviv/Kconfig
@@ -15,6 +15,15 @@ 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
+   default n
+   help
+ Compile in support for Vivante GPUs attached via PCIe card.
+ 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 dc3556aad134..90ee60b00c24 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -24,6 +24,7 @@
 #include "etnaviv_gpu.h"
 #include "etnaviv_gem.h"
 #include "etnaviv_mmu.h"
+#include "etnaviv_pci_drv.h"
 #include "etnaviv_perfmon.h"
 
 /*
@@ -568,6 +569,10 @@ static int etnaviv_bind(struct device *dev)
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);
@@ -596,7 +601,7 @@ static void etnaviv_unbind(struct device *dev)
etnaviv_private_fini(priv);
 }
 
-static const struct component_master_ops etnaviv_master_ops = {
+const struct component_master_ops etnaviv_master_ops = {
.bind = etnaviv_bind,
.unbind = etnaviv_unbind,
 };
@@ -740,6 +745,10 @@ static int __init etnaviv_init(void)
if (ret != 0)
goto unregister_gpu_driver;
 
+   ret = etnaviv_register_pci_driver();
+   if (ret)
+   goto unregister_platform_driver;
+
/*
 * If the DT contains at least one available GPU device, instantiate
 * the DRM platform device.
@@ -769,6 +778,7 @@ module_init(etnaviv_init);
 static void __exit etnaviv_exit(void)
 {
etnaviv_destroy_platform_device(&etnaviv_drm);
+   etnaviv_unregister_pci_driver();
platform_driver_unregister(&etnaviv_platform_driver);
platform_driver_unregister(&etnaviv_gpu_driver);
 }
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 4612843ff9f6..6db26d384cbe 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -27,6 +27,8 @@ struct etnaviv_gem_object;
 struct etnaviv_gem_submit;
 struct etnaviv_iommu_global;
 
+extern const struct component_master_ops etnaviv_master_ops;
+
 #define ETNAVIV_SOFTPIN_START_ADDRESS  SZ_4M /* must be >= SUBALLOC_SIZE */
 
 struct etnaviv_file_private {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 3a14e187388a..2b5955693fbb 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1

[etnaviv-next v14 7/8] drm/etnaviv: Allow creating subdevices and pass platform specific data

2024-05-19 Thread Sui Jingfeng
Because some hardware are too complex to be managed by a monolithic driver,
a split of the functionality into child devices can helps to achieve better
modularity.

We will use this function to create subdevice as a repensentation of a
single hardware ip block, so that the same modular approach that works
for ARM-SoC can also works for PCIe cards.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 33 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |  9 
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 863faac2ea19..dc3556aad134 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -670,16 +670,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);
@@ -691,7 +711,7 @@ static int etnaviv_create_platform_device(const char *name,
return 0;
 }
 
-static void etnaviv_destroy_platform_device(struct platform_device **ppdev)
+void etnaviv_destroy_platform_device(struct platform_device **ppdev)
 {
struct platform_device *pdev = *ppdev;
 
@@ -728,7 +748,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 4b59fdb457b7..4612843ff9f6 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -98,6 +99,14 @@ 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);
+
+void etnaviv_destroy_platform_device(struct platform_device **ppdev);
+
 #ifdef CONFIG_DEBUG_FS
 void etnaviv_gem_describe_objects(struct etnaviv_drm_private *priv,
struct seq_file *m);
-- 
2.34.1



[etnaviv-next v14 6/8] drm/etnaviv: Replace the '&pdev->dev' with 'dev'

2024-05-19 Thread Sui Jingfeng
In the etnaviv_pdev_probe(), etnaviv_gpu_platform_probe() function, the
value of '&pdev->dev' has been cached to the 'dev' local auto variable.
But part of callers use 'dev' as argument, while the rest use '&pdev->dev'.

To keep it consistent, use 'dev' uniformly.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 +-
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 16 
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 986fd68b489a..863faac2ea19 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -614,7 +614,7 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
if (!of_device_is_available(core_node))
continue;
 
-   drm_of_component_match_add(&pdev->dev, &match,
+   drm_of_component_match_add(dev, &match,
   component_compare_of, 
core_node);
}
} else {
@@ -637,9 +637,9 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
 * bit to make sure we are allocating the command buffers and
 * TLBs in the lower 4 GiB address space.
 */
-   if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)) ||
-   dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-   dev_dbg(&pdev->dev, "No suitable DMA available\n");
+   if (dma_set_mask(dev, DMA_BIT_MASK(40)) ||
+   dma_set_coherent_mask(dev, DMA_BIT_MASK(32))) {
+   dev_dbg(dev, "No suitable DMA available\n");
return -ENODEV;
}
 
@@ -650,7 +650,7 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
 */
first_node = etnaviv_of_first_available_node();
if (first_node) {
-   of_dma_configure(&pdev->dev, first_node, true);
+   of_dma_configure(dev, first_node, true);
of_node_put(first_node);
}
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index aa15682f94db..3a14e187388a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1891,7 +1891,7 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
if (!gpu)
return -ENOMEM;
 
-   gpu->dev = &pdev->dev;
+   gpu->dev = dev;
mutex_init(&gpu->lock);
mutex_init(&gpu->sched_lock);
 
@@ -1905,8 +1905,8 @@ static int etnaviv_gpu_platform_probe(struct 
platform_device *pdev)
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, gpu->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;
@@ -1925,13 +1925,13 @@ 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);
+   pm_runtime_use_autosuspend(dev);
+   pm_runtime_set_autosuspend_delay(dev, 200);
+   pm_runtime_enable(dev);
 
-   err = component_add(&pdev->dev, &gpu_ops);
+   err = component_add(dev, &gpu_ops);
if (err < 0) {
-   dev_err(&pdev->dev, "failed to register component: %d\n", err);
+   dev_err(dev, "failed to register component: %d\n", err);
return err;
}
 
-- 
2.34.1



[etnaviv-next v14 5/8] drm/etnaviv: Add support for cached coherent caching mode

2024-05-19 Thread Sui Jingfeng
Many modern CPUs and/or platforms choose to define their peripheral devices
as cached coherent by default, to be specific, the PCH is capable of
snooping CPU's cache. When hit the peripheral devices will access data
directly from CPU's cache. This means that device drivers do not need to
maintain the coherency issue between a processor and peripheral I/O for
the cached buffers. Hence, it dosen't need us to sync manually on the
software side, which is useful to avoid some overheads, especially for
userspace, but userspace is not known yet.

Probe the hardware maintained cached coherent support of the host platform
with the dev_is_dma_coherent() function, and store the result in struct
etnaviv_drm_private. As this is a platform implementation-defined hardware
feature and again is meant to be shared by all GPU cores. And expose it
via etnaviv parameter mechanism to let userspace know.

Please note that write-combine mapping out of scope of the discussion
and therefore is not being addressed.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 3 +++
 drivers/gpu/drm/etnaviv/etnaviv_drv.h | 9 +
 drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 4 
 include/uapi/drm/etnaviv_drm.h| 1 +
 4 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index e3eb31ba9a2b..986fd68b489a 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -57,6 +58,8 @@ static int etnaviv_private_init(struct device *dev,
return -ENOMEM;
}
 
+   priv->cached_coherent = dev_is_dma_coherent(dev);
+
return 0;
 }
 
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 1f9b50b5a6aa..4b59fdb457b7 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
+* peripheral bus masters in the system. It means that both of the
+* CPU and GPU will see the same data if the buffer being accessed
+* is cached. And the coherency is guaranteed by the host platform
+* specific hardwares.
+*/
+   bool cached_coherent;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 02d7efdc82c0..aa15682f94db 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_ID0x1c
 #define ETNAVIV_PARAM_GPU_CUSTOMER_ID   0x1d
 #define ETNAVIV_PARAM_GPU_ECO_ID0x1e
+#define ETNAVIV_PARAM_CACHED_COHERENT   0x1f
 
 #define ETNA_MAX_PIPES 4
 
-- 
2.34.1



[etnaviv-next v14 4/8] drm/etnaviv: Fix wrong cache property being used for vmap()

2024-05-19 Thread Sui Jingfeng
In the etnaviv_gem_vmap_impl() function, the driver vmap whatever buffers
with Write-Combine page property. This is unreasonable, as some platforms
are cached coherent. And cached buffers should be mapped with cached page
property.

Fixes: a0a5ab3e99b8 ("drm/etnaviv: call correct function when trying to vmap a 
DMABUF")
Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index aa95a5e98374..eed98bb9e446 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)
-- 
2.34.1



[etnaviv-next v14 3/8] drm/etnaviv: Embed struct drm_device into struct etnaviv_drm_private

2024-05-19 Thread Sui Jingfeng
Both the instance of struct drm_device and the instance of struct
etnaviv_drm_private are intended to be shared by all GPU cores, both have
only one instance created across drm/etnaviv driver. After embedded in,
the whole structure can be allocated with devm_drm_dev_alloc(). And the
DRM device created is automatically put on driver detach, so we don't need
to call drm_dev_put() explicitly on driver leave. It's also eliminate the
need to use the .dev_private member, which is deprecated according to the
drm document. We can also use container_of() to retrieve pointer for the
containing structure.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c| 65 
 drivers/gpu/drm/etnaviv/etnaviv_drv.h|  7 +++
 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, 40 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 22c78bc944c4..e3eb31ba9a2b 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,14 +41,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);
@@ -58,15 +53,14 @@ 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;
}
 
-   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;
@@ -76,13 +70,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++) {
@@ -100,7 +92,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;
 
@@ -143,7 +135,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;
 
@@ -168,7 +160,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);
 
@@ -262,7 +254,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;
@@ -305,7 +297,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;
 
@@

[etnaviv-next v14 2/8] drm/etnaviv: Add constructor and destructor for the etnaviv_drm_private structure

2024-05-19 Thread Sui Jingfeng
Because there are a lot of data members in the struct etnaviv_drm_private,
which are intended to be shared by all GPU cores. It can be lengthy and
daunting on error handling, the 'gem_lock' of struct etnaviv_drm_private
just be forgeten to destroy on driver leave.

Switch to use the dedicated helpers introduced, etnaviv_bind() and
etnaviv_unbind() gets simplified. Another potential benefit is that
we could put the struct drm_device into struct etnaviv_drm_private
in the future, which made them share the same life time.

Signed-off-by: Sui Jingfeng 
---
 drivers/gpu/drm/etnaviv/etnaviv_drv.c | 72 +--
 1 file changed, 46 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c 
b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 6500f3999c5f..22c78bc944c4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -41,6 +41,45 @@ 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;
+
+   mutex_destroy(&priv->gem_lock);
+
+   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 +560,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 +586,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 +603,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



  1   2   3   4   5   6   7   8   9   10   >