diff options
Diffstat (limited to 'arch/mips/mm/sc-ip22.c')
-rw-r--r-- | arch/mips/mm/sc-ip22.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c new file mode 100644 index 000000000..d7238687d --- /dev/null +++ b/arch/mips/mm/sc-ip22.c | |||
@@ -0,0 +1,190 @@ | |||
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 | } | ||