arm: socfpga: agilex5: Enable cache flush for system memory cache in CCU
authorTien Fong Chee <tien.fong.chee@intel.com>
Thu, 8 Aug 2024 08:47:39 +0000 (16:47 +0800)
committerTom Rini <trini@konsulko.com>
Tue, 25 Feb 2025 16:53:56 +0000 (10:53 -0600)
set/way instructions "dc cisw" which is used by the "dcache flush" command
only flushing CPU data caches from L1 -> L2 -> L3 to system memory cache in
cache coherency unit, hence this patch enables data flush from system
memory cache of CCU into DDR memory.

Signed-off-by: Tien Fong Chee <tien.fong.chee@altera.com>
arch/arm/mach-socfpga/Makefile
arch/arm/mach-socfpga/ccu_ncore3.c [new file with mode: 0644]

index 7e37cca..cccba71 100644 (file)
@@ -65,6 +65,7 @@ obj-y += reset_manager_s10.o
 obj-y  += wrap_handoff_soc64.o
 obj-y  += wrap_pll_config_soc64.o
 obj-y  += altera-sysmgr.o
+obj-y  += ccu_ncore3.o
 endif
 
 ifdef CONFIG_TARGET_SOCFPGA_N5X
diff --git a/arch/arm/mach-socfpga/ccu_ncore3.c b/arch/arm/mach-socfpga/ccu_ncore3.c
new file mode 100644 (file)
index 0000000..a399aed
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ *
+ */
+#include <wait_bit.h>
+#include <asm/arch/base_addr_soc64.h>
+#include <linux/bitfield.h>
+
+#define CCU_DMI0_DMIUSMCTCR                            SOCFPGA_CCU_ADDRESS + 0x7300
+#define CCU_DMI0_DMIUSMCMCR                            SOCFPGA_CCU_ADDRESS + 0x7340
+#define CCU_DMI0_DMIUSMCMAR                            SOCFPGA_CCU_ADDRESS + 0x7344
+#define CCU_DMI0_DMIUSMCMCR_MNTOP              GENMASK(3, 0)
+#define MAX_DISTRIBUTED_MEM_INTERFACE  2
+#define FLUSH_ALL_ENTRIES                              0x4
+#define CCU_DMI0_DMIUSMCMCR_ARRAY_ID   GENMASK(21, 16)
+#define ARRAY_ID_TAG                                   0x0
+#define ARRAY_ID_DATA                                  0x1
+#define CACHE_OPERATION_DONE                   BIT(0)
+#define TIMEOUT_200MS                                  200
+
+int __asm_flush_l3_dcache(void)
+{
+       int i;
+       int ret = 0;
+
+       /* Flushing all entries in CCU system memory cache */
+       for (i = 0; i < MAX_DISTRIBUTED_MEM_INTERFACE; i++) {
+               /*
+                * Skipping if the system memory cache is not enabled for
+                * particular DMI
+                */
+               if (!readl((uintptr_t)(CCU_DMI0_DMIUSMCTCR + (i * 0x1000))))
+                       continue;
+
+               writel(FIELD_PREP(CCU_DMI0_DMIUSMCMCR_MNTOP, FLUSH_ALL_ENTRIES) |
+                          FIELD_PREP(CCU_DMI0_DMIUSMCMCR_ARRAY_ID, ARRAY_ID_TAG),
+                          (uintptr_t)(CCU_DMI0_DMIUSMCMCR + (i * 0x1000)));
+
+               /* Wait for cache maintenance operation done */
+               ret = wait_for_bit_le32((const void *)(uintptr_t)(CCU_DMI0_DMIUSMCMAR +
+                               (i * 0x1000)), CACHE_OPERATION_DONE, false, TIMEOUT_200MS,
+                               false);
+               if (ret) {
+                       debug("%s: Timeout while waiting for flushing tag in DMI%d done\n",
+                             __func__, i);
+                       return ret;
+               }
+
+               writel(FIELD_PREP(CCU_DMI0_DMIUSMCMCR_MNTOP, FLUSH_ALL_ENTRIES) |
+                          FIELD_PREP(CCU_DMI0_DMIUSMCMCR_ARRAY_ID, ARRAY_ID_DATA),
+                          (uintptr_t)(CCU_DMI0_DMIUSMCMCR + (i * 0x1000)));
+
+               /* Wait for cache maintenance operation done */
+               ret = wait_for_bit_le32((const void *)(uintptr_t)(CCU_DMI0_DMIUSMCMAR +
+                               (i * 0x1000)), CACHE_OPERATION_DONE, false, TIMEOUT_200MS,
+                               false);
+               if (ret)
+                       debug("%s: Timeout waiting for flushing data in DMI%d done\n",
+                             __func__, i);
+       }
+
+       return ret;
+}