1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * sc-ip22.c: Indy cache management functions. 4 * 5 * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org), 6 * derived from r4xx0.c by David S. Miller (davem@davemloft.net). 7 */ 8 #include <linux/init.h> 9 #include <linux/kernel.h> 10 #include <linux/sched.h> 11 #include <linux/mm.h> 12 13 #include <asm/bcache.h> 14 #include <asm/page.h> 15 #include <asm/bootinfo.h> 16 #include <asm/sgi/ip22.h> 17 #include <asm/sgi/mc.h> 18 19 /* Secondary cache size in bytes, if present. */ 20 static unsigned long scache_size; 21 22 #undef DEBUG_CACHE 23 24 #define SC_SIZE 0x00080000 25 #define SC_LINE 32 26 #define CI_MASK (SC_SIZE - SC_LINE) 27 #define SC_INDEX(n) ((n) & CI_MASK) 28 29 static inline void indy_sc_wipe(unsigned long first, unsigned long last) 30 { 31 unsigned long tmp; 32 33 __asm__ __volatile__( 34 " .set push # indy_sc_wipe \n" 35 " .set noreorder \n" 36 " .set mips3 \n" 37 " .set noat \n" 38 " mfc0 %2, $12 \n" 39 " li $1, 0x80 # Go 64 bit \n" 40 " mtc0 $1, $12 \n" 41 " \n" 42 " # \n" 43 " # Open code a dli $1, 0x9000000080000000 \n" 44 " # \n" 45 " # Required because binutils 2.25 will happily accept \n" 46 " # 64 bit instructions in .set mips3 mode but puke on \n" 47 " # 64 bit constants when generating 32 bit ELF \n" 48 " # \n" 49 " lui $1,0x9000 \n" 50 " dsll $1,$1,0x10 \n" 51 " ori $1,$1,0x8000 \n" 52 " dsll $1,$1,0x10 \n" 53 " \n" 54 " or %0, $1 # first line to flush \n" 55 " or %1, $1 # last line to flush \n" 56 " .set at \n" 57 " \n" 58 "1: sw $0, 0(%0) \n" 59 " bne %0, %1, 1b \n" 60 " daddu %0, 32 \n" 61 " \n" 62 " mtc0 %2, $12 # Back to 32 bit \n" 63 " nop # pipeline hazard \n" 64 " nop \n" 65 " nop \n" 66 " nop \n" 67 " .set pop \n" 68 : "=r" (first), "=r" (last), "=&r" (tmp) 69 : "0" (first), "1" (last)); 70 } 71 72 static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) 73 { 74 unsigned long first_line, last_line; 75 unsigned long flags; 76 77 #ifdef DEBUG_CACHE 78 printk("indy_sc_wback_invalidate[%08lx,%08lx]", addr, size); 79 #endif 80 81 /* Catch bad driver code */ 82 BUG_ON(size == 0); 83 84 /* Which lines to flush? */ 85 first_line = SC_INDEX(addr); 86 last_line = SC_INDEX(addr + size - 1); 87 88 local_irq_save(flags); 89 if (first_line <= last_line) { 90 indy_sc_wipe(first_line, last_line); 91 goto out; 92 } 93 94 indy_sc_wipe(first_line, SC_SIZE - SC_LINE); 95 indy_sc_wipe(0, last_line); 96 out: 97 local_irq_restore(flags); 98 } 99 100 static void indy_sc_enable(void) 101 { 102 unsigned long addr, tmp1, tmp2; 103 104 /* This is really cool... */ 105 #ifdef DEBUG_CACHE 106 printk("Enabling R4600 SCACHE\n"); 107 #endif 108 __asm__ __volatile__( 109 ".set\tpush\n\t" 110 ".set\tnoreorder\n\t" 111 ".set\tmips3\n\t" 112 "mfc0\t%2, $12\n\t" 113 "nop; nop; nop; nop;\n\t" 114 "li\t%1, 0x80\n\t" 115 "mtc0\t%1, $12\n\t" 116 "nop; nop; nop; nop;\n\t" 117 "li\t%0, 0x1\n\t" 118 "dsll\t%0, 31\n\t" 119 "lui\t%1, 0x9000\n\t" 120 "dsll32\t%1, 0\n\t" 121 "or\t%0, %1, %0\n\t" 122 "sb\t$0, 0(%0)\n\t" 123 "mtc0\t$0, $12\n\t" 124 "nop; nop; nop; nop;\n\t" 125 "mtc0\t%2, $12\n\t" 126 "nop; nop; nop; nop;\n\t" 127 ".set\tpop" 128 : "=r" (tmp1), "=r" (tmp2), "=r" (addr)); 129 } 130 131 static void indy_sc_disable(void) 132 { 133 unsigned long tmp1, tmp2, tmp3; 134 135 #ifdef DEBUG_CACHE 136 printk("Disabling R4600 SCACHE\n"); 137 #endif 138 __asm__ __volatile__( 139 ".set\tpush\n\t" 140 ".set\tnoreorder\n\t" 141 ".set\tmips3\n\t" 142 "li\t%0, 0x1\n\t" 143 "dsll\t%0, 31\n\t" 144 "lui\t%1, 0x9000\n\t" 145 "dsll32\t%1, 0\n\t" 146 "or\t%0, %1, %0\n\t" 147 "mfc0\t%2, $12\n\t" 148 "nop; nop; nop; nop\n\t" 149 "li\t%1, 0x80\n\t" 150 "mtc0\t%1, $12\n\t" 151 "nop; nop; nop; nop\n\t" 152 "sh\t$0, 0(%0)\n\t" 153 "mtc0\t$0, $12\n\t" 154 "nop; nop; nop; nop\n\t" 155 "mtc0\t%2, $12\n\t" 156 "nop; nop; nop; nop\n\t" 157 ".set\tpop" 158 : "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)); 159 } 160 161 static inline int __init indy_sc_probe(void) 162 { 163 unsigned int size = ip22_eeprom_read(&sgimc->eeprom, 17); 164 if (size == 0) 165 return 0; 166 167 size <<= PAGE_SHIFT; 168 printk(KERN_INFO "R4600/R5000 SCACHE size %dK, linesize 32 bytes.\n", 169 size >> 10); 170 scache_size = size; 171 172 return 1; 173 } 174 175 /* XXX Check with wje if the Indy caches can differentiate between 176 writeback + invalidate and just invalidate. */ 177 static struct bcache_ops indy_sc_ops = { 178 .bc_enable = indy_sc_enable, 179 .bc_disable = indy_sc_disable, 180 .bc_wback_inv = indy_sc_wback_invalidate, 181 .bc_inv = indy_sc_wback_invalidate 182 }; 183 184 void indy_sc_init(void) 185 { 186 if (indy_sc_probe()) { 187 indy_sc_enable(); 188 bcops = &indy_sc_ops; 189 } 190 } 191