sh: Optimized cache handling for SH-4/SH-4A caches.

This reworks some of the SH-4 cache handling code to more easily
accomodate newer-style caches (particularly for the > direct-mapped
case), as well as optimizing some of the old code.

Signed-off-by: Richard Curnow <richard.curnow@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 868e68b..731dd61 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -4,6 +4,7 @@
  * CPU init code
  *
  * Copyright (C) 2002, 2003  Paul Mundt
+ * Copyright (C) 2003  Richard Curnow
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -51,7 +52,15 @@
 	ccr = ctrl_inl(CCR);
 
 	/*
-	 * If the cache is already enabled .. flush it.
+	 * At this point we don't know whether the cache is enabled or not - a
+	 * bootloader may have enabled it.  There are at least 2 things that
+	 * could be dirty in the cache at this point:
+	 * 1. kernel command line set up by boot loader
+	 * 2. spilled registers from the prolog of this function
+	 * => before re-initialising the cache, we must do a purge of the whole
+	 * cache out to memory for safety.  As long as nothing is spilled
+	 * during the loop to lines that have already been done, this is safe.
+	 * - RPC
 	 */
 	if (ccr & CCR_CACHE_ENABLE) {
 		unsigned long ways, waysize, addrstart;
@@ -98,6 +107,8 @@
 	/* Force EMODE if possible */
 	if (cpu_data->dcache.ways > 1)
 		flags |= CCR_CACHE_EMODE;
+	else
+		flags &= ~CCR_CACHE_EMODE;
 #endif
 
 #ifdef CONFIG_SH_WRITETHROUGH
@@ -112,6 +123,9 @@
 	/* Turn on OCRAM -- halve the OC */
 	flags |= CCR_CACHE_ORA;
 	cpu_data->dcache.sets >>= 1;
+
+	cpu_data->dcache.way_size = cpu_data->dcache.sets *
+				    cpu_data->dcache.linesz;
 #endif
 
 	ctrl_outl(flags, CCR);
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 42427b7..1208da8 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -113,6 +113,11 @@
 		break;
 	}
 
+#ifdef CONFIG_SH_DIRECT_MAPPED
+	cpu_data->icache.ways = 1;
+	cpu_data->dcache.ways = 1;
+#endif
+
 	/*
 	 * On anything that's not a direct-mapped cache, look to the CVR
 	 * for I/D-cache specifics.
@@ -125,6 +130,9 @@
 			(cpu_data->icache.way_incr - (1 << 5));
 	}
 
+	cpu_data->icache.way_size = cpu_data->icache.sets *
+				    cpu_data->icache.linesz;
+
 	if (cpu_data->dcache.ways > 1) {
 		size = sizes[(cvr >> 16) & 0xf];
 		cpu_data->dcache.way_incr	= (size >> 1);
@@ -133,6 +141,9 @@
 			(cpu_data->dcache.way_incr - (1 << 5));
 	}
 
+	cpu_data->dcache.way_size = cpu_data->dcache.sets *
+				    cpu_data->dcache.linesz;
+
 	return 0;
 }