Hello,
Here is a patch to add support for the new SandCraft SR7100 processor. The
SR7100 is a faster pin compatible replacement for the RM7000 family of
chips but implements MIPS64 and has a different cache configuration.
This patch includes a fix for 1 errata in current chips, the wait
instruction doesn't work quite right. It is possible to omit this (ugly!)
fix but the CPU runs a little hot.. :>
The patch is against the linux_2_4 branch of CVS, I have not yet tried
HEAD..
Jason
diff --exclude CVS -bBrNu ./arch/mips/Makefile
../linux_2_4_branch/arch/mips/Makefile
--- ./arch/mips/Makefile Fri Jan 18 23:35:38 2002
+++ ../linux_2_4_branch/arch/mips/Makefile Fri Jan 18 23:38:57 2002
@@ -93,6 +93,9 @@
MODFLAGS += -msb1-pass1-workarounds
endif
endif
+ifdef CONFIG_CPU_SR7100
+GCCFLAGS += -mcpu=r5000 -mips2 -Wa,--trap
+endif
GCCFLAGS += -pipe
diff --exclude CVS -bBrNu ./arch/mips/config.in
../linux_2_4_branch/arch/mips/config.in
--- ./arch/mips/config.in Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/config.in Fri Jan 18 23:39:09 2002
@@ -331,6 +331,7 @@
R5000 CONFIG_CPU_R5000 \
R5432 CONFIG_CPU_R5432 \
RM7000 CONFIG_CPU_RM7000 \
+ SR7100 CONFIG_CPU_SR7100 \
R52xx CONFIG_CPU_NEVADA \
R10000 CONFIG_CPU_R10000 \
SB1 CONFIG_CPU_SB1 \
diff --exclude CVS -bBrNu ./arch/mips/kernel/Makefile
../linux_2_4_branch/arch/mips/kernel/Makefile
--- ./arch/mips/kernel/Makefile Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/kernel/Makefile Sat Jan 12 15:54:45 2002
@@ -39,6 +39,7 @@
obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_SR7100) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
obj-$(CONFIG_SMP) += smp.o
diff --exclude CVS -bBrNu ./arch/mips/kernel/entry.S
../linux_2_4_branch/arch/mips/kernel/entry.S
--- ./arch/mips/kernel/entry.S Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/kernel/entry.S Sun Jan 13 00:57:24 2002
@@ -50,7 +50,29 @@
lw t0, PT_STATUS(sp) # returning to kernel mode?
andi t0, t0, KU_USER
bnez t0, ret_from_sys_call
+EXPORT(ret_from_irq_sr7100)
j restore_all
+
+/* SR7100 Errata: The wait instruction that does not advance EPC. The solution
+ is to check if epc is pointing at a wait instruction and if so, skip it.
+ This must be after ret_from_irq. The setup code will nop out the jump above
+ so we fall through. wait instructions are only fixed if they are in the
+ kernel */
+#ifdef CONFIG_CPU_SR7100
+ // Fetch EPC
+ lw t0,PT_EPC(sp)
+
+ // Is the instruction a wait?
+ li t2,0x42000000
+ lw t1,0(t0)
+ ori t2,t2,0x20
+ bne t1,t2,restore_all
+
+ // Yep, go to the next instruction
+ addu t1,t0,4
+ sw t1,PT_EPC(sp)
+ j restore_all
+#endif
reschedule: jal schedule
diff --exclude CVS -bBrNu ./arch/mips/kernel/setup.c
../linux_2_4_branch/arch/mips/kernel/setup.c
--- ./arch/mips/kernel/setup.c Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/kernel/setup.c Fri Jan 18 23:40:56 2002
@@ -46,6 +46,7 @@
#ifndef CONFIG_SMP
struct cpuinfo_mips cpu_data[1];
#endif
+#include <asm/cacheops.h>
/*
* Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
@@ -121,10 +122,12 @@
extern void SetUpBootInfo(void);
extern void loadmmu(void);
extern asmlinkage void start_kernel(void);
+extern asmlinkage void ret_from_irq_sr7100(void);
extern void prom_init(int, char **, char **, int *);
static struct resource code_resource = { "Kernel code" };
static struct resource data_resource = { "Kernel data" };
+static void sr7100_wait(void);
static inline void check_wait(void)
{
@@ -153,6 +156,11 @@
cpu_wait = r4k_wait;
printk(" available.\n");
break;
+
+ case CPU_SR7100:
+ cpu_wait = sr7100_wait;
+ printk(" errata work around.\n");
+ break;
default:
printk(" unavailable.\n");
break;
@@ -519,6 +527,21 @@
break;
}
break;
+
+ case PRID_COMP_SANDCRAFT:
+ mips_cpu.cputype = CPU_UNKNOWN;
+ switch (mips_cpu.processor_id & 0xff00) {
+ case PRID_IMP_SR7100:
+ mips_cpu.cputype = CPU_SR7100;
+ mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+ MIPS_CPU_4KTLB | MIPS_CPU_FPU |
+ MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+ MIPS_CPU_MCHECK;
+ mips_cpu.scache.ways = 8;
+ break;
+ }
+ break;
default:
mips_cpu.cputype = CPU_UNKNOWN;
}
@@ -802,6 +825,7 @@
hp_setup();
break;
#endif
+
default:
panic("Unsupported architecture");
}
@@ -986,6 +1010,39 @@
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
+}
+
+/* Fix the sr7100 wait errata. We have a special ret_from_irq that is executed
+ when a jump is converted to a nop. Before we wait we do that conversion.
+ This engages the code that detects the errata. This way we don't loose any
+ speed in the normal case. Though it does make the timing race with wait
+ longer.. */
+static void sr7100_wait(void)
+{
+ u32 *jump = ((u32 *)&ret_from_irq_sr7100);
+ __asm__ __volatile__
+ (
+ ".set push\n\t"
+ ".set noat\n\t"
+ ".set noreorder\n\t"
+ ".set mips3\n\t"
+ "lw $1,0(%0)\n\t"
+ "sw $0,0(%0)\n\t"
+
+ // No snoopy i/d cache..
+ "cache %1,0(%0)\n\t"
+ "cache %2,0(%0)\n\t"
+
+ "wait\n\t"
+ "sw $1,0(%0)\n\t"
+
+ "cache %1,0(%0)\n\t"
+ "cache %2,0(%0)\n\t"
+
+ ".set pop\n\t"
+ :
+ : "r" (jump), "i"(Hit_Writeback_D), "i"(Hit_Invalidate_I)
+ : "$1");
}
int __init fpu_disable(char *s)
diff --exclude CVS -bBrNu ./arch/mips/mm/Makefile
../linux_2_4_branch/arch/mips/mm/Makefile
--- ./arch/mips/mm/Makefile Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/mm/Makefile Sat Jan 12 15:59:04 2002
@@ -30,6 +30,7 @@
obj-$(CONFIG_CPU_R10000) += pg-andes.o c-andes.o tlb-r4k.o tlbex-r4k.o
obj-$(CONFIG_CPU_MIPS32) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o
obj-$(CONFIG_CPU_MIPS64) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o
+obj-$(CONFIG_CPU_SR7100) += pg-mips32.o c-sr7100.o tlb-r4k.o tlbex-r4k.o
obj-$(CONFIG_CPU_SB1) += pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o
obj-$(CONFIG_SGI_IP22) += umap.o
diff --exclude CVS -bBrNu ./arch/mips/mm/c-sr7100.c
../linux_2_4_branch/arch/mips/mm/c-sr7100.c
--- ./arch/mips/mm/c-sr7100.c Wed Dec 31 17:00:00 1969
+++ ../linux_2_4_branch/arch/mips/mm/c-sr7100.c Fri Jan 18 23:43:40 2002
@@ -0,0 +1,584 @@
+/*
+ Jason Gunthorpe <jgg@yottayotta.com>
+ Copyright (C) 2002 YottaYotta. Inc.
+
+ Based on c-mips32:
+ Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+
+ 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
+ for more details.
+
+ Sandcraft SR7100 cache routines.
+ The SR7100 is a MIPS64 compatible CPU with 4 caches:
+ * 4 way 32K primary ICache - virtually indexed/physically tagged
+ * 4 way 32K primary DCache - virtually indexed/physically tagged
+ * 8 way 512K secondary cache - physically indexed/taged
+ * 8 way up to 16M tertiary cache - physically indexed/taged (and off chip)
+
+ ICache and DCache do not have any sort of snooping. Unlike the RM7k,
+ the virtual index is 13 bits, and we use a 4k page size. This means you
+ can have cache aliasing effects, so they have to be treated as virtually
+ tagged. (unless that can be solved elsewhere, should investigate)
+
+ Note that on this chip all the _SD type cache ops (ie Hit_Writeback_Inv_SD)
+ are really just _S. This is in line with what the MIPS64 spec permits.
+ Also, the line size of the tertiary cache is really the block size. The
+ line size is always 32 bytes. The chip can tag partial blocks and the cache
+ op instructions work on those partial blocks too.
+
+ See ./Documentation/cachetlb.txt
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/bcache.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+
+// Should move to mipsregs.h
+#define read_32bit_cp0_registerx(source,sel) \
+({ int __res; \
+ __asm__ __volatile__( \
+ ".set\tpush\n\t" \
+ ".set\treorder\n\t" \
+ ".set\tmips64\n\t" \
+ "mfc0\t%0,"STR(source)","STR(sel)"\n\t" \
+ ".set\tmips0\n\t" \
+ ".set\tpop" \
+ : "=r" (__res)); \
+ __res;})
+#define write_32bit_cp0_registerx(register,sel,value) \
+ __asm__ __volatile__( \
+ ".set\tmips64\n\t" \
+ "mtc0\t%0,"STR(register)","STR(sel)"\n\t" \
+ ".set\tmips0\n\t" \
+ "nop" \
+ : : "r" (value));
+
+#undef DEBUG_CACHE
+
+/* Primary cache parameters. */
+int icache_size, dcache_size; /* Size in bytes */
+int ic_lsize, dc_lsize; /* LineSize in bytes */
+
+/* Secondary cache parameters. */
+unsigned int scache_size, sc_lsize; /* Again, in bytes */
+
+/* tertiary cache (if present) parameters. */
+unsigned int tcache_size, tc_lsize; /* Again, in bytes */
+
+#include <asm/cacheops.h>
+#include <asm/mips32_cache.h>
+
+// Unique the SR7100
+#define Index_Invalidate_T 0x2
+#define Hit_Invalidate_T 0x16
+static inline void blast_tcache(void)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = KSEG0 + tcache_size;
+
+ // Could use flash invalidate perhaps..
+ while(start < end)
+ {
+ cache_unroll(start,Index_Invalidate_T);
+ start += tc_lsize;
+ }
+}
+
+static inline void flush_tcache_line(unsigned long addr)
+{
+ __asm__ __volatile__
+ (
+ ".set noreorder\n\t"
+ ".set mips3\n\t"
+ "cache %1, (%0)\n\t"
+ ".set mips0\n\t"
+ ".set reorder"
+ :
+ : "r" (addr),
+ "i" (Hit_Invalidate_T));
+}
+
+/*
+ * Dummy cache handling routines for machines without boardcaches
+ */
+static void no_sc_noop(void) {}
+
+static struct bcache_ops no_sc_ops = {
+ (void *)no_sc_noop, (void *)no_sc_noop,
+ (void *)no_sc_noop, (void *)no_sc_noop
+};
+struct bcache_ops *bcops = &no_sc_ops;
+
+// Clean all virtually indexed caches
+static inline void sr7100_flush_cache_all_pc(void)
+{
+ unsigned long flags;
+
+ __save_and_cli(flags);
+ blast_dcache(); blast_icache();
+ __restore_flags(flags);
+}
+
+// This clears all caches. It is only used from a syscall..
+static inline void sr7100_nuke_caches(void)
+{
+ unsigned long flags;
+
+ __save_and_cli(flags);
+ blast_dcache(); blast_icache(); blast_scache();
+ if (tcache_size != 0)
+ blast_tcache();
+ __restore_flags(flags);
+}
+
+/* This is called to clean out a virtual mapping. We only need to flush the
+ I and D caches since the other two are physically tagged */
+static void sr7100_flush_cache_range_pc(struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ if(mm->context != 0) {
+ unsigned long flags;
+
+#ifdef DEBUG_CACHE
+ printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
+#endif
+ __save_and_cli(flags);
+ blast_dcache(); blast_icache();
+ __restore_flags(flags);
+ }
+}
+
+/*
+ * On architectures like the Sparc, we could get rid of lines in
+ * the cache created only by a certain context, but on the MIPS
+ * (and actually certain Sparc's) we cannot.
+ * Again, only clean the virtually tagged cache.
+ */
+static void sr7100_flush_cache_mm_pc(struct mm_struct *mm)
+{
+ if(mm->context != 0) {
+#ifdef DEBUG_CACHE
+ printk("cmm[%d]", (int)mm->context);
+#endif
+ sr7100_flush_cache_all_pc();
+ }
+}
+
+static void sr7100_flush_cache_page_pc(struct vm_area_struct *vma,
+ unsigned long page)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long flags;
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ /*
+ * If ownes no valid ASID yet, cannot possibly have gotten
+ * this page into the cache.
+ */
+ if (mm->context == 0)
+ return;
+
+#ifdef DEBUG_CACHE
+ printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+ __save_and_cli(flags);
+ page &= PAGE_MASK;
+ pgdp = pgd_offset(mm, page);
+ pmdp = pmd_offset(pgdp, page);
+ ptep = pte_offset(pmdp, page);
+
+ /*
+ * If the page isn't marked valid, the page cannot possibly be
+ * in the cache.
+ */
+ if (!(pte_val(*ptep) & _PAGE_VALID))
+ goto out;
+
+ /*
+ * Doing flushes for another ASID than the current one is
+ * too difficult since Mips32 caches do a TLB translation
+ * for every cache flush operation. So we do indexed flushes
+ * in that case, which doesn't overly flush the cache too much.
+ */
+ if (mm == current->active_mm) {
+ blast_dcache_page(page);
+ } else {
+ /* Do indexed flush, too much work to get the (possible)
+ * tlb refills to work correctly.
+ */
+ page = (KSEG0 + (page & (dcache_size - 1)));
+ blast_dcache_page_indexed(page);
+ }
+out:
+ __restore_flags(flags);
+}
+
+/* If the addresses passed to these routines are valid, they are
+ * either:
+ *
+ * 1) In KSEG0, so we can do a direct flush of the page.
+ * 2) In KSEG2, and since every process can translate those
+ * addresses all the time in kernel mode we can do a direct
+ * flush.
+ * 3) In KSEG1, no flush necessary.
+ */
+static void sr7100_flush_page_to_ram_pc(struct page *page)
+{
+ blast_dcache_page((unsigned long)page_address(page));
+}
+
+/* I-Cache and D-Cache are seperate and virtually tagged, these need to
+ flush them */
+static void sr7100_flush_icache_range(unsigned long start, unsigned long end)
+{
+ flush_cache_all(); // only does i and d, probably excessive
+}
+
+static void sr7100_flush_icache_page(struct vm_area_struct *vma,
+ struct page *page)
+{
+ int address;
+
+ if (!(vma->vm_flags & VM_EXEC))
+ return;
+
+ address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK &
(dcache_size - 1));
+ blast_icache_page_indexed(address);
+}
+
+/* Writeback and invalidate the primary cache dcache before DMA.
+ See asm-mips/io.h
+ */
+static void sr7100_dma_cache_wback_inv_sc(unsigned long addr,
+ unsigned long size)
+{
+ unsigned long end, a;
+
+ if (size >= scache_size) {
+ sr7100_nuke_caches();
+ return;
+ }
+
+ a = addr & ~(sc_lsize - 1);
+ end = (addr + size) & ~(sc_lsize - 1);
+ while (1) {
+ flush_dcache_line(a);
+ flush_scache_line(a); // Hit_Writeback_Inv_SD
+ if (a == end) break;
+ a += sc_lsize;
+ }
+}
+
+static void sr7100_dma_cache_wback_inv_tc(unsigned long addr,
+ unsigned long size)
+{
+ unsigned long end, a;
+
+ a = addr & ~(sc_lsize - 1);
+ end = (addr + size) & ~(sc_lsize - 1);
+ while (1) {
+ flush_dcache_line(a);
+ flush_scache_line(a); // Hit_Writeback_Inv_SD
+ flush_tcache_line(a); // Hit_Invalidate_T
+ if (a == end) break;
+ a += sc_lsize;
+ }
+}
+
+/* It is kind of silly to writeback for the inv case.. Oh well */
+static void sr7100_dma_cache_inv_sc(unsigned long addr, unsigned long size)
+{
+ unsigned long end, a;
+
+ if (size >= scache_size) {
+ sr7100_nuke_caches();
+ return;
+ }
+
+ a = addr & ~(sc_lsize - 1);
+ end = (addr + size) & ~(sc_lsize - 1);
+ while (1) {
+ flush_dcache_line(a);
+ flush_scache_line(a); // Hit_Writeback_Inv_SD
+ if (a == end) break;
+ a += sc_lsize;
+ }
+}
+
+static void sr7100_dma_cache_inv_tc(unsigned long addr, unsigned long size)
+{
+ unsigned long end, a;
+
+ a = addr & ~(sc_lsize - 1);
+ end = (addr + size) & ~(sc_lsize - 1);
+ while (1) {
+ flush_dcache_line(a);
+ flush_scache_line(a); // Hit_Writeback_Inv_SD
+ flush_tcache_line(a); // Hit_Invalidate_T
+ if (a == end) break;
+ a += sc_lsize;
+ }
+}
+
+static void sr7100_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+ panic("sr7100_dma_cache_wback called - should not happen.");
+}
+
+/*
+ * While we're protected against bad userland addresses we don't care
+ * very much about what happens in that case. Usually a segmentation
+ * fault will dump the process later on anyway ...
+ */
+static void sr7100_flush_cache_sigtramp(unsigned long addr)
+{
+ protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+ protected_flush_icache_line(addr & ~(ic_lsize - 1));
+}
+
+/* Detect and size the various caches. */
+static void __init probe_icache(unsigned long config,unsigned long config1)
+{
+ unsigned int lsize;
+
+ config1 = read_mips32_cp0_config1();
+
+ if ((lsize = ((config1 >> 19) & 7)))
+ mips_cpu.icache.linesz = 2 << lsize;
+ else
+ mips_cpu.icache.linesz = lsize;
+ mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7);
+ mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7);
+
+ ic_lsize = mips_cpu.icache.linesz;
+ icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways *
+ ic_lsize;
+ printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n",
+ icache_size >> 10, ic_lsize, mips_cpu.icache.ways);
+}
+
+static void __init probe_dcache(unsigned long config,unsigned long config1)
+{
+ unsigned int lsize;
+
+ if ((lsize = ((config1 >> 10) & 7)))
+ mips_cpu.dcache.linesz = 2 << lsize;
+ else
+ mips_cpu.dcache.linesz = lsize;
+ mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7);
+ mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7);
+
+ dc_lsize = mips_cpu.dcache.linesz;
+ dcache_size =
+ mips_cpu.dcache.sets * mips_cpu.dcache.ways
+ * dc_lsize;
+ printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n",
+ dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways);
+}
+
+static void __init probe_scache(unsigned long config,unsigned long config2)
+{
+ unsigned int lsize;
+
+ if ((lsize = ((config2 >> 4) & 7)))
+ mips_cpu.scache.linesz = 2 << lsize;
+ else
+ mips_cpu.scache.linesz = lsize;
+
+ mips_cpu.scache.sets = 64 << ((config2 >> 8) & 7);
+ mips_cpu.scache.ways = 1 + ((config2 >> 0) & 7);
+
+ sc_lsize = mips_cpu.scache.linesz;
+ scache_size = mips_cpu.scache.sets * mips_cpu.scache.ways * sc_lsize;
+
+ printk("Secondary cache %dK, linesize %d bytes (%d ways)\n",
+ scache_size >> 10, sc_lsize, mips_cpu.scache.ways);
+}
+
+static void __init probe_tcache(unsigned long config,unsigned long config2)
+{
+ unsigned int lsize;
+
+ /* Firmware or prom_init is required to configure the size of the
+ tertiary cache in config2 and set the TE bit in config2 to signal
+ the external SRAM chips are present. */
+ if ((config2 & (1<<28)) == 0)
+ return;
+
+ if ((lsize = ((config2 >> 20) & 7)))
+ mips_cpu.tcache.linesz = 2 << lsize;
+ else
+ mips_cpu.tcache.linesz = lsize;
+
+ mips_cpu.tcache.sets = 64 << ((config2 >> 24) & 7);
+ mips_cpu.tcache.ways = 1 + ((config2 >> 16) & 7);
+
+ tc_lsize = mips_cpu.tcache.linesz;
+ tcache_size = mips_cpu.tcache.sets * mips_cpu.tcache.ways * tc_lsize;
+
+ printk("Tertiary cache %dK, linesize %d bytes, blocksize %d "
+ "bytes (%d ways)\n",
+ tcache_size >> 10, sc_lsize, tc_lsize, mips_cpu.tcache.ways);
+}
+
+static void __init setup_scache_funcs(void)
+{
+ _flush_cache_all = sr7100_flush_cache_all_pc;
+ ___flush_cache_all = sr7100_nuke_caches;
+ _flush_cache_mm = sr7100_flush_cache_mm_pc;
+ _flush_cache_range = sr7100_flush_cache_range_pc;
+ _flush_cache_page = sr7100_flush_cache_page_pc;
+ _flush_page_to_ram = sr7100_flush_page_to_ram_pc;
+ _clear_page = (void *)mips32_clear_page_sc;
+ _copy_page = (void *)mips32_copy_page_sc;
+
+ _flush_icache_page = sr7100_flush_icache_page;
+
+ if (tcache_size == 0)
+ {
+ _dma_cache_wback_inv = sr7100_dma_cache_wback_inv_sc;
+ _dma_cache_inv = sr7100_dma_cache_inv_sc;
+ }
+ else
+ {
+ _dma_cache_wback_inv = sr7100_dma_cache_wback_inv_tc;
+ _dma_cache_inv = sr7100_dma_cache_inv_tc;
+ }
+
+ _dma_cache_wback = sr7100_dma_cache_wback;
+}
+
+/* This implements the cache intialization stuff from the SR7100 guide. After
+ this all the caches will be empty and ready to run. It must be run from
+ uncached space. */
+static void __init clear_enable_caches(unsigned long config)
+{
+ config = (config & (~CONF_CM_CMASK)) | CONF_CM_CACHABLE_NONCOHERENT;
+
+ /* Primary cache init (7.1.1)
+ SR71000 Primary Cache initialization of 4-way, 32 Kbyte line I/D
+ caches. */
+ __asm__ __volatile__
+ (
+ ".set push\n"
+ ".set noreorder\n"
+ ".set noat\n"
+ ".set mips64\n"
+
+ // Enable KSEG0 caching
+ " mtc0 %0, $16\n"
+
+ /* It is recommended that parity be disabled during cache
+ initialization. */
+ " mfc0 $1, $12\n" // Read CP0 Status Register.
+ " li $2, 0x00010000\n" // DE Bit.
+ " or $2, $1, $2\n"
+ " mtc0 $2, $12\n" // Disable Parity.
+
+ " ori $3, %1, 0x1FE0\n" // 256 sets.
+ " mtc0 $0, $28\n" // Set CP0 Tag_Lo Register
+ "1:\n"
+ " cache 8, 0x0000($3)\n" // Index_Store_Tag_I
+ " cache 8, 0x2000($3)\n" // Index_Store_Tag_I
+ " cache 8, 0x4000($3)\n" // Index_Store_Tag_I
+ " cache 8, 0x6000($3)\n" // Index_Store_Tag_I
+ " cache 9, 0x0000($3)\n" // Index_Store_Tag_D
+ " cache 9, 0x2000($3)\n" // Index_Store_Tag_D
+ " cache 9, 0x4000($3)\n" // Index_Store_Tag_D
+ " cache 9, 0x6000($3)\n" // Index_Store_Tag_D
+ " bne $3, %1, 1b\n"
+ " addiu $3, $3, -0x0020\n" // 32 byte cache line
+ " mtc0 $1, $12\n" // Put original back in Status Register.
+ ".set pop\n"
+ :
+ : "r"(config), "r"(KSEG0)
+ : "$1","$2","$3");
+ // Fixme: use settings from config register not hardwired
+
+ /* Secondary and tertiary flash invalidate (7.5.18)
+ This code fragment, invalidates (also disables), and
+ restores (re-enables) the secondary and tertiary caches.
+ Ensure system is operating in uncached space. */
+ __asm__ __volatile__
+ (
+ ".set push\n"
+ ".set noreorder\n"
+ ".set noat\n"
+ ".set mips64\n"
+ " sync\n" // flush core pipeline
+ " lw $2, 0(%0)\n" // flush pending accesses
+ " bne $2, $2, 1f\n" // prevent I-fetches
+ " nop\n"
+ "1: mfc0 $1, $16, 2\n" // save current Config2
+ " li $2, 0x20002000\n" // set flash invalidation bits
+ " or $2, $1, $2\n"
+ " mtc0 $2, $16, 2\n" // invalidate & disable caches
+ " mtc0 $1, $16, 2\n" // restore Config2
+ ".set pop\n"
+ :
+ : "r"(KSEG1)
+ : "$1","$2");
+}
+
+void __init ld_mmu_sr7100(void)
+{
+ unsigned long config = read_32bit_cp0_registerx(CP0_CONFIG,0);
+ unsigned long config1 = read_32bit_cp0_registerx(CP0_CONFIG,1);
+ unsigned long config2 = read_32bit_cp0_registerx(CP0_CONFIG,2);
+ void (*kseg1_cec)(unsigned long config) = (void
*)KSEG1ADDR(&clear_enable_caches);
+
+ // Should never happen
+ if (!(config & (1 << 31)) || !(config1 & (1 << 31)))
+ panic("sr7100 does not have necessary config registers");
+
+ /* We should be uncached for this.. If the firmware has enabled
+ the cache it may have dirty data and we really need to flush
+ it before doing a mass invalidate, on the other hand if the
+ cache has not been inited flushing it could corrupt ram.. */
+ if ((config & CONF_CM_CMASK) != CONF_CM_UNCACHED)
+ {
+ printk("Turning off cache.\n");
+ change_cp0_config(CONF_CM_CMASK,CONF_CM_UNCACHED);
+
+ // flush core pipeline
+ __asm__ __volatile__ (" sync\n");
+
+ sr7100_flush_cache_all_pc();
+
+ // Was the secondary cached turned on?
+ if ((config2 & (1<<12)) != 0)
+ blast_scache();
+
+ // Tertiary is write through so it is safe
+ }
+
+ probe_icache(config,config1);
+ probe_dcache(config,config1);
+ probe_scache(config,config2);
+ probe_tcache(config,config2);
+ setup_scache_funcs();
+
+ // Make sure the the secondary cache is turned on (always present)
+ write_32bit_cp0_registerx(CP0_CONFIG,2,config2 | (1<<12));
+
+#ifndef CONFIG_MIPS_UNCACHED
+ kseg1_cec(config);
+#endif
+
+ _flush_cache_sigtramp = sr7100_flush_cache_sigtramp;
+ _flush_icache_range = sr7100_flush_icache_range;
+}
diff --exclude CVS -bBrNu ./arch/mips/mm/loadmmu.c
../linux_2_4_branch/arch/mips/mm/loadmmu.c
--- ./arch/mips/mm/loadmmu.c Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/mm/loadmmu.c Sat Jan 12 15:56:36 2002
@@ -61,6 +61,7 @@
extern void ld_mmu_andes(void);
extern void ld_mmu_sb1(void);
extern void ld_mmu_mips32(void);
+extern void ld_mmu_sr7100(void);
extern void r3k_tlb_init(void);
extern void r4k_tlb_init(void);
extern void sb1_tlb_init(void);
@@ -89,6 +90,10 @@
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
ld_mmu_mips32();
+ r4k_tlb_init();
+#endif
+#if defined(CONFIG_CPU_SR7100)
+ ld_mmu_sr7100();
r4k_tlb_init();
#endif
} else switch(mips_cpu.cputype) {
diff --exclude CVS -bBrNu ./arch/mips/mm/tlb-r4k.c
../linux_2_4_branch/arch/mips/mm/tlb-r4k.c
--- ./arch/mips/mm/tlb-r4k.c Fri Jan 18 23:35:39 2002
+++ ../linux_2_4_branch/arch/mips/mm/tlb-r4k.c Sat Jan 12 16:09:30 2002
@@ -351,8 +351,6 @@
panic("No MMU present");
else
mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1;
-
- printk("Number of TLB entries %d.\n", mips_cpu.tlbsize);
}
void __init r4k_tlb_init(void)
diff --exclude CVS -bBrNu ./include/asm-mips/bootinfo.h
../linux_2_4_branch/include/asm-mips/bootinfo.h
--- ./include/asm-mips/bootinfo.h Fri Jan 18 23:35:38 2002
+++ ../linux_2_4_branch/include/asm-mips/bootinfo.h Fri Jan 18 23:45:25 2002
@@ -37,7 +37,7 @@
#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", "SNI", "ACN", \
"SGI", "Cobalt", "NEC DDB", "Baget", "Cosine", "Galileo", "Momentum", \
"ITE", "Philips", "Globepspan", "SiByte", "Toshiba", "Alchemy", \
- "NEC Vr41xx", "HP LaserJet" }
+ "NEC Vr41xx", "HP LaserJet"}
/*
* Valid machtype values for group unknown (low order halfword of
mips_machtype)
@@ -253,7 +253,8 @@
#define CPU_R5500 41
#define CPU_TX49XX 42
#define CPU_TX39XX 43
-#define CPU_LAST 43
+#define CPU_SR7100 44
+#define CPU_LAST 44
#define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \
"R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC", \
@@ -262,7 +263,7 @@
"R5000A", "R4640", "Nevada", "RM7000", "R5432", "MIPS 4Kc", \
"MIPS 5Kc", "R4310", "SiByte SB1", "TX3912", "TX3922", "TX3927", \
"Au1000", "MIPS 4KEc", "MIPS 4KSc", "NEC Vr41xx", "R5500", "TX49xx", \
- "TX39xx" }
+ "TX39xx", "SR7100" }
#define COMMAND_LINE_SIZE 256
diff --exclude CVS -bBrNu ./include/asm-mips/cpu.h
../linux_2_4_branch/include/asm-mips/cpu.h
--- ./include/asm-mips/cpu.h Fri Jan 18 23:35:38 2002
+++ ../linux_2_4_branch/include/asm-mips/cpu.h Thu Jan 10 20:21:53 2002
@@ -29,6 +29,7 @@
#define PRID_COMP_BROADCOM 0x020000
#define PRID_COMP_ALCHEMY 0x030000
#define PRID_COMP_SIBYTE 0x040000
+#define PRID_COMP_SANDCRAFT 0x050000
/*
* Assigned values for the product ID register. In order to detect a
@@ -73,6 +74,12 @@
*/
#define PRID_IMP_SB1 0x0100
+
+/*
+ * These are the PRID's for when 23:16 == PRID_COMP_SANDCRAFT
+ */
+
+#define PRID_IMP_SR7100 0x0400
/*
* Definitions for 7:0 on legacy processors
|