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