00001
00002
00003
00004
00005
00006
00007
00008 #include <linux/init.h>
00009 #include <linux/kernel.h>
00010 #include <linux/sched.h>
00011 #include <linux/mm.h>
00012
00013 #include <asm/bcache.h>
00014 #include <asm/sgi.h>
00015 #include <asm/sgimc.h>
00016 #include <asm/page.h>
00017 #include <asm/pgtable.h>
00018 #include <asm/system.h>
00019 #include <asm/bootinfo.h>
00020 #include <asm/sgialib.h>
00021 #include <asm/mmu_context.h>
00022
00023
00024 static unsigned long scache_size;
00025
00026 #undef DEBUG_CACHE
00027
00028 #define SC_SIZE 0x00080000
00029 #define SC_LINE 32
00030 #define CI_MASK (SC_SIZE - SC_LINE)
00031 #define SC_ROUND(n) ((n) + SC_LINE - 1)
00032 #define SC_INDEX(n) ((n) & CI_MASK)
00033
00034 static inline void indy_sc_wipe(unsigned long first, unsigned long last)
00035 {
00036 __asm__ __volatile__("
00037 .set noreorder
00038 .set mips3
00039 .set noat
00040 mfc0 $2, $12
00041 li $1, 0x80 # Go 64 bit
00042 mtc0 $1, $12
00043
00044 dli $1, 0x9000000080000000
00045 or %0, $1 # first line to flush
00046 or %1, $1 # last line to flush
00047 .set at
00048
00049 1: sw $0, 0(%0)
00050 bne %0, %1, 1b
00051 daddu %0, 32
00052
00053 mtc0 $2, $12 # Back to 32 bit
00054 nop; nop; nop; nop;
00055 .set mips0
00056 .set reorder"
00057 :
00058 : "r" (first), "r" (last)
00059 : "$1");
00060 }
00061
00062 static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size)
00063 {
00064 unsigned long first_line, last_line;
00065 unsigned int flags;
00066
00067 #ifdef DEBUG_CACHE
00068 printk("indy_sc_wback_invalidate[%08lx,%08lx]", addr, size);
00069 #endif
00070
00071 first_line = SC_INDEX(addr);
00072 if (size <= SC_LINE)
00073 last_line = SC_INDEX(addr);
00074 else
00075 last_line = SC_INDEX(addr + size - 1);
00076
00077 __save_and_cli(flags);
00078 if (first_line <= last_line) {
00079 indy_sc_wipe(first_line, last_line);
00080 goto out;
00081 }
00082
00083
00084
00085
00086 indy_sc_wipe(first_line, SC_SIZE - SC_LINE);
00087 indy_sc_wipe(0, last_line);
00088 out:
00089 __restore_flags(flags);
00090 }
00091
00092 static void indy_sc_enable(void)
00093 {
00094 unsigned long addr, tmp1, tmp2;
00095
00096
00097 #ifdef DEBUG_CACHE
00098 printk("Enabling R4600 SCACHE\n");
00099 #endif
00100 __asm__ __volatile__("
00101 .set noreorder
00102 .set mips3
00103 mfc0 %2, $12
00104 nop; nop; nop; nop;
00105 li %1, 0x80
00106 mtc0 %1, $12
00107 nop; nop; nop; nop;
00108 li %0, 0x1
00109 dsll %0, 31
00110 lui %1, 0x9000
00111 dsll32 %1, 0
00112 or %0, %1, %0
00113 sb $0, 0(%0)
00114 mtc0 $0, $12
00115 nop; nop; nop; nop;
00116 mtc0 %2, $12
00117 nop; nop; nop; nop;
00118 .set mips0
00119 .set reorder"
00120 : "=r" (tmp1), "=r" (tmp2), "=r" (addr));
00121 }
00122
00123 static void indy_sc_disable(void)
00124 {
00125 unsigned long tmp1, tmp2, tmp3;
00126
00127 #ifdef DEBUG_CACHE
00128 printk("Disabling R4600 SCACHE\n");
00129 #endif
00130 __asm__ __volatile__("
00131 .set noreorder
00132 .set mips3
00133 li %0, 0x1
00134 dsll %0, 31
00135 lui %1, 0x9000
00136 dsll32 %1, 0
00137 or %0, %1, %0
00138 mfc0 %2, $12
00139 nop; nop; nop; nop;
00140 li %1, 0x80
00141 mtc0 %1, $12
00142 nop; nop; nop; nop;
00143 sh $0, 0(%0)
00144 mtc0 $0, $12
00145 nop; nop; nop; nop;
00146 mtc0 %2, $12
00147 nop; nop; nop; nop;
00148 .set mips2
00149 .set reorder
00150 " : "=r" (tmp1), "=r" (tmp2), "=r" (tmp3));
00151 }
00152
00153 __initfunc(static inline int indy_sc_probe(void))
00154 {
00155 volatile unsigned int *cpu_control;
00156 unsigned short cmd = 0xc220;
00157 unsigned long data = 0;
00158 int i, n;
00159
00160 #ifdef __MIPSEB__
00161 cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00034);
00162 #else
00163 cpu_control = (volatile unsigned int *) KSEG1ADDR(0x1fa00030);
00164 #endif
00165 #define DEASSERT(bit) (*(cpu_control) &= (~(bit)))
00166 #define ASSERT(bit) (*(cpu_control) |= (bit))
00167 #define DELAY for(n = 0; n < 100000; n++) __asm__ __volatile__("")
00168 DEASSERT(SGIMC_EEPROM_PRE);
00169 DEASSERT(SGIMC_EEPROM_SDATAO);
00170 DEASSERT(SGIMC_EEPROM_SECLOCK);
00171 DEASSERT(SGIMC_EEPROM_PRE);
00172 DELAY;
00173 ASSERT(SGIMC_EEPROM_CSEL); ASSERT(SGIMC_EEPROM_SECLOCK);
00174 for(i = 0; i < 11; i++) {
00175 if(cmd & (1<<15))
00176 ASSERT(SGIMC_EEPROM_SDATAO);
00177 else
00178 DEASSERT(SGIMC_EEPROM_SDATAO);
00179 DEASSERT(SGIMC_EEPROM_SECLOCK);
00180 ASSERT(SGIMC_EEPROM_SECLOCK);
00181 cmd <<= 1;
00182 }
00183 DEASSERT(SGIMC_EEPROM_SDATAO);
00184 for(i = 0; i < (sizeof(unsigned short) * 8); i++) {
00185 unsigned int tmp;
00186
00187 DEASSERT(SGIMC_EEPROM_SECLOCK);
00188 DELAY;
00189 ASSERT(SGIMC_EEPROM_SECLOCK);
00190 DELAY;
00191 data <<= 1;
00192 tmp = *cpu_control;
00193 if(tmp & SGIMC_EEPROM_SDATAI)
00194 data |= 1;
00195 }
00196 DEASSERT(SGIMC_EEPROM_SECLOCK);
00197 DEASSERT(SGIMC_EEPROM_CSEL);
00198 ASSERT(SGIMC_EEPROM_PRE);
00199 ASSERT(SGIMC_EEPROM_SECLOCK);
00200
00201 data <<= PAGE_SHIFT;
00202 if (data == 0)
00203 return 0;
00204
00205 scache_size = data;
00206
00207 printk("R4600/R5000 SCACHE size %ldK, linesize 32 bytes.\n",
00208 scache_size >> 10);
00209
00210 return 1;
00211 }
00212
00213
00214
00215 struct bcache_ops indy_sc_ops = {
00216 indy_sc_enable,
00217 indy_sc_disable,
00218 indy_sc_wback_invalidate,
00219 indy_sc_wback_invalidate
00220 };
00221
00222 __initfunc(void indy_sc_init(void))
00223 {
00224 if (indy_sc_probe()) {
00225 indy_sc_enable();
00226 bcops = &indy_sc_ops;
00227 }
00228 }