From a2615b3b161929df1ae151585d4638cc4ab09bf9 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Sat, 4 Feb 2023 14:29:20 -0600
Subject: [PATCH 05/68] riscv: cpu: thead: Add CPU-specific cache operations

Use the vendor CSRs for enabling/disabling the caches, and the ISA
extension for cache maintenance.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/riscv/cpu/thead/Kconfig  |  2 +
 arch/riscv/cpu/thead/Makefile |  1 +
 arch/riscv/cpu/thead/cache.c  | 96 +++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+)
 create mode 100644 arch/riscv/cpu/thead/cache.c

--- a/arch/riscv/cpu/thead/Kconfig
+++ b/arch/riscv/cpu/thead/Kconfig
@@ -2,6 +2,8 @@
 
 config THEAD_C906
 	bool
+	select SYS_CACHE_SHIFT_6
 
 config THEAD_E906
 	bool
+	select SYS_CACHE_SHIFT_5
--- a/arch/riscv/cpu/thead/Makefile
+++ b/arch/riscv/cpu/thead/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
 
+obj-y += cache.o
 obj-y += cpu.o
 obj-y += dram.o
--- /dev/null
+++ b/arch/riscv/cpu/thead/cache.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <cpu_func.h>
+#include <asm/cache.h>
+#include <asm/csr.h>
+#include <linux/bitops.h>
+
+#include "thead_csr.h"
+
+#define THEAD_SYNC_I		".long 0x01a0000b"
+#define THEAD_DCACHE_CIALL	".long 0x0030000b"
+#define THEAD_DCACHE_CIPA_A0	".long 0x02b5000b"
+#define THEAD_DCACHE_IALL	".long 0x0020000b"
+#define THEAD_DCACHE_IPA_A0	".long 0x02a5000b"
+#define THEAD_ICACHE_IPA_A0	".long 0x0385000b"
+
+static inline void sync_i(void)
+{
+	asm volatile (THEAD_SYNC_I ::: "memory");
+}
+
+void flush_dcache_all(void)
+{
+	asm volatile (THEAD_DCACHE_CIALL ::: "memory");
+	sync_i();
+}
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
+
+	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
+		asm volatile (THEAD_DCACHE_CIPA_A0 :: "r" (addr) : "memory");
+	sync_i();
+}
+
+void invalidate_dcache_all(void)
+{
+	asm volatile (THEAD_DCACHE_IALL ::: "memory");
+	sync_i();
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
+
+	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
+		asm volatile (THEAD_DCACHE_IPA_A0 :: "r" (addr) : "memory");
+	sync_i();
+}
+
+void invalidate_icache_range(unsigned long start, unsigned long end)
+{
+	register ulong addr asm ("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
+
+	for (; addr < end; addr += CONFIG_SYS_CACHELINE_SIZE)
+		asm volatile (THEAD_ICACHE_IPA_A0 :: "r" (addr) : "memory");
+	sync_i();
+}
+
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
+
+void icache_enable(void)
+{
+	invalidate_icache_all();
+	csr_set(CSR_MHCR, MHCR_IE);
+}
+
+void icache_disable(void)
+{
+	csr_clear(CSR_MHCR, MHCR_IE);
+}
+
+int icache_status(void)
+{
+	return csr_read(CSR_MHCR) & MHCR_IE;
+}
+
+void dcache_enable(void)
+{
+	invalidate_dcache_all();
+	csr_set(CSR_MHCR, MHCR_DE);
+}
+
+void dcache_disable(void)
+{
+	flush_dcache_all();
+	csr_clear(CSR_MHCR, MHCR_DE);
+}
+
+int dcache_status(void)
+{
+	return csr_read(CSR_MHCR) & MHCR_DE;
+}
+
+#endif
