From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 31 Jan 2024 03:29:01 +0000
Subject: [PATCH] add lvds1024*800

---
 kernel/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c |  229 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 169 insertions(+), 60 deletions(-)

diff --git a/kernel/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c b/kernel/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c
index 7624831..d554950 100644
--- a/kernel/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c
+++ b/kernel/drivers/gpu/arm/bifrost/device/mali_kbase_device_hw.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
 /*
  *
- * (C) COPYRIGHT 2014-2016, 2018-2021 ARM Limited. All rights reserved.
+ * (C) COPYRIGHT 2014-2016, 2018-2022 ARM Limited. All rights reserved.
  *
  * This program is free software and is provided to you under the terms of the
  * GNU General Public License version 2 as published by the Free Software
@@ -28,44 +28,6 @@
 #include <mmu/mali_kbase_mmu.h>
 
 #if !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI)
-void kbase_reg_write(struct kbase_device *kbdev, u32 offset, u32 value)
-{
-	KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
-	KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
-
-	writel(value, kbdev->reg + offset);
-
-#if IS_ENABLED(CONFIG_DEBUG_FS)
-	if (unlikely(kbdev->io_history.enabled))
-		kbase_io_history_add(&kbdev->io_history, kbdev->reg + offset,
-				value, 1);
-#endif /* CONFIG_DEBUG_FS */
-	dev_dbg(kbdev->dev, "w: reg %08x val %08x", offset, value);
-}
-
-KBASE_EXPORT_TEST_API(kbase_reg_write);
-
-u32 kbase_reg_read(struct kbase_device *kbdev, u32 offset)
-{
-	u32 val;
-
-	KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
-	KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
-
-	val = readl(kbdev->reg + offset);
-
-#if IS_ENABLED(CONFIG_DEBUG_FS)
-	if (unlikely(kbdev->io_history.enabled))
-		kbase_io_history_add(&kbdev->io_history, kbdev->reg + offset,
-				val, 0);
-#endif /* CONFIG_DEBUG_FS */
-	dev_dbg(kbdev->dev, "r: reg %08x val %08x", offset, val);
-
-	return val;
-}
-
-KBASE_EXPORT_TEST_API(kbase_reg_read);
-
 bool kbase_is_gpu_removed(struct kbase_device *kbdev)
 {
 	u32 val;
@@ -76,7 +38,145 @@
 }
 #endif /* !IS_ENABLED(CONFIG_MALI_BIFROST_NO_MALI) */
 
-void kbase_gpu_start_cache_clean_nolock(struct kbase_device *kbdev)
+static int busy_wait_on_irq(struct kbase_device *kbdev, u32 irq_bit)
+{
+	char *irq_flag_name;
+	/* Previously MMU-AS command was used for L2 cache flush on page-table update.
+	 * And we're using the same max-loops count for GPU command, because amount of
+	 * L2 cache flush overhead are same between them.
+	 */
+	unsigned int max_loops = KBASE_AS_INACTIVE_MAX_LOOPS;
+
+	/* Wait for the GPU cache clean operation to complete */
+	while (--max_loops &&
+	       !(kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) & irq_bit)) {
+		;
+	}
+
+	/* reset gpu if time-out occurred */
+	if (max_loops == 0) {
+		switch (irq_bit) {
+		case CLEAN_CACHES_COMPLETED:
+			irq_flag_name = "CLEAN_CACHES_COMPLETED";
+			break;
+		case FLUSH_PA_RANGE_COMPLETED:
+			irq_flag_name = "FLUSH_PA_RANGE_COMPLETED";
+			break;
+		default:
+			irq_flag_name = "UNKNOWN";
+			break;
+		}
+
+		dev_err(kbdev->dev,
+			"Stuck waiting on %s bit, might be caused by slow/unstable GPU clock or possible faulty FPGA connector\n",
+			irq_flag_name);
+
+		if (kbase_prepare_to_reset_gpu_locked(kbdev, RESET_FLAGS_NONE))
+			kbase_reset_gpu_locked(kbdev);
+		return -EBUSY;
+	}
+
+	/* Clear the interrupt bit. */
+	KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, irq_bit);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), irq_bit);
+
+	return 0;
+}
+
+#if MALI_USE_CSF
+#define U64_LO_MASK ((1ULL << 32) - 1)
+#define U64_HI_MASK (~U64_LO_MASK)
+
+int kbase_gpu_cache_flush_pa_range_and_busy_wait(struct kbase_device *kbdev, phys_addr_t phys,
+						 size_t nr_bytes, u32 flush_op)
+{
+	u64 start_pa, end_pa;
+	int ret = 0;
+
+	lockdep_assert_held(&kbdev->hwaccess_lock);
+
+	/* 1. Clear the interrupt FLUSH_PA_RANGE_COMPLETED bit. */
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), FLUSH_PA_RANGE_COMPLETED);
+
+	/* 2. Issue GPU_CONTROL.COMMAND.FLUSH_PA_RANGE operation. */
+	start_pa = phys;
+	end_pa = start_pa + nr_bytes - 1;
+
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND_ARG0_LO), start_pa & U64_LO_MASK);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND_ARG0_HI),
+			(start_pa & U64_HI_MASK) >> 32);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND_ARG1_LO), end_pa & U64_LO_MASK);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND_ARG1_HI), (end_pa & U64_HI_MASK) >> 32);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), flush_op);
+
+	/* 3. Busy-wait irq status to be enabled. */
+	ret = busy_wait_on_irq(kbdev, (u32)FLUSH_PA_RANGE_COMPLETED);
+
+	return ret;
+}
+#endif /* MALI_USE_CSF */
+
+int kbase_gpu_cache_flush_and_busy_wait(struct kbase_device *kbdev,
+					u32 flush_op)
+{
+	int need_to_wake_up = 0;
+	int ret = 0;
+
+	/* hwaccess_lock must be held to avoid any sync issue with
+	 * kbase_gpu_start_cache_clean() / kbase_clean_caches_done()
+	 */
+	lockdep_assert_held(&kbdev->hwaccess_lock);
+
+	/* 1. Check if kbdev->cache_clean_in_progress is set.
+	 *    If it is set, it means there are threads waiting for
+	 *    CLEAN_CACHES_COMPLETED irq to be raised and that the
+	 *    corresponding irq mask bit is set.
+	 *    We'll clear the irq mask bit and busy-wait for the cache
+	 *    clean operation to complete before submitting the cache
+	 *    clean command required after the GPU page table update.
+	 *    Pended flush commands will be merged to requested command.
+	 */
+	if (kbdev->cache_clean_in_progress) {
+		/* disable irq first */
+		u32 irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK));
+		kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
+				irq_mask & ~CLEAN_CACHES_COMPLETED);
+
+		/* busy wait irq status to be enabled */
+		ret = busy_wait_on_irq(kbdev, (u32)CLEAN_CACHES_COMPLETED);
+		if (ret)
+			return ret;
+
+		/* merge pended command if there's any */
+		flush_op = GPU_COMMAND_FLUSH_CACHE_MERGE(
+			kbdev->cache_clean_queued, flush_op);
+
+		/* enable wake up notify flag */
+		need_to_wake_up = 1;
+	} else {
+		/* Clear the interrupt CLEAN_CACHES_COMPLETED bit. */
+		kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR),
+				CLEAN_CACHES_COMPLETED);
+	}
+
+	/* 2. Issue GPU_CONTROL.COMMAND.FLUSH_CACHE operation. */
+	KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, flush_op);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), flush_op);
+
+	/* 3. Busy-wait irq status to be enabled. */
+	ret = busy_wait_on_irq(kbdev, (u32)CLEAN_CACHES_COMPLETED);
+	if (ret)
+		return ret;
+
+	/* 4. Wake-up blocked threads when there is any. */
+	if (need_to_wake_up)
+		kbase_gpu_cache_clean_wait_complete(kbdev);
+
+	return ret;
+}
+
+void kbase_gpu_start_cache_clean_nolock(struct kbase_device *kbdev,
+					u32 flush_op)
 {
 	u32 irq_mask;
 
@@ -85,10 +185,11 @@
 	if (kbdev->cache_clean_in_progress) {
 		/* If this is called while another clean is in progress, we
 		 * can't rely on the current one to flush any new changes in
-		 * the cache. Instead, trigger another cache clean immediately
-		 * after this one finishes.
+		 * the cache. Instead, accumulate all cache clean operations
+		 * and trigger that immediately after this one finishes.
 		 */
-		kbdev->cache_clean_queued = true;
+		kbdev->cache_clean_queued = GPU_COMMAND_FLUSH_CACHE_MERGE(
+			kbdev->cache_clean_queued, flush_op);
 		return;
 	}
 
@@ -97,19 +198,18 @@
 	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
 				irq_mask | CLEAN_CACHES_COMPLETED);
 
-	KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, 0);
-	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
-					GPU_COMMAND_CLEAN_INV_CACHES);
+	KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, flush_op);
+	kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), flush_op);
 
 	kbdev->cache_clean_in_progress = true;
 }
 
-void kbase_gpu_start_cache_clean(struct kbase_device *kbdev)
+void kbase_gpu_start_cache_clean(struct kbase_device *kbdev, u32 flush_op)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
-	kbase_gpu_start_cache_clean_nolock(kbdev);
+	kbase_gpu_start_cache_clean_nolock(kbdev, flush_op);
 	spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
 }
 
@@ -117,7 +217,7 @@
 {
 	lockdep_assert_held(&kbdev->hwaccess_lock);
 
-	kbdev->cache_clean_queued = false;
+	kbdev->cache_clean_queued = 0;
 	kbdev->cache_clean_in_progress = false;
 	wake_up(&kbdev->cache_clean_wait);
 }
@@ -129,19 +229,28 @@
 
 	spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
 
-	if (kbdev->cache_clean_queued) {
-		kbdev->cache_clean_queued = false;
+	if (kbdev->cache_clean_in_progress) {
+		/* Clear the interrupt CLEAN_CACHES_COMPLETED bit if set.
+		 * It might have already been done by kbase_gpu_cache_flush_and_busy_wait.
+		 */
+		KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, CLEAN_CACHES_COMPLETED);
+		kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), CLEAN_CACHES_COMPLETED);
 
-		KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, 0);
-		kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
-				GPU_COMMAND_CLEAN_INV_CACHES);
-	} else {
-		/* Disable interrupt */
-		irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK));
-		kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
-				irq_mask & ~CLEAN_CACHES_COMPLETED);
+		if (kbdev->cache_clean_queued) {
+			u32 pended_flush_op = kbdev->cache_clean_queued;
 
-		kbase_gpu_cache_clean_wait_complete(kbdev);
+			kbdev->cache_clean_queued = 0;
+
+			KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, pended_flush_op);
+			kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), pended_flush_op);
+		} else {
+			/* Disable interrupt */
+			irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK));
+			kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
+					irq_mask & ~CLEAN_CACHES_COMPLETED);
+
+			kbase_gpu_cache_clean_wait_complete(kbdev);
+		}
 	}
 
 	spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);

--
Gitblit v1.6.2