Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

indy_sc.c

Go to the documentation of this file.
00001 /* $Id: indy_sc.c,v 1.9 1999/05/12 21:57:49 ulfc Exp $
00002  *
00003  * indy_sc.c: Indy cache managment functions.
00004  *
00005  * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org),
00006  * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
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 /* Secondary cache size in bytes, if present.  */
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                 : /* no output */
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         /* Which lines to flush?  */
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         /* Cache index wrap around.  Due to the way the buddy system works
00084            this case should not happen.  We're prepared to handle it,
00085            though. */
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         /* This is really cool... */
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 /* XXX Check with wje if the Indy caches can differenciate between
00214    writeback + invalidate and just invalidate.  */
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 }