xref: /linux/arch/mips/kernel/spram.c (revision 249ebf3f65f8530beb2cbfb91bff1d83ba88d23c)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * MIPS SPRAM support
4  *
5  * Copyright (C) 2007, 2008 MIPS Technologies, Inc.
6  */
7 #include <linux/kernel.h>
8 #include <linux/ptrace.h>
9 #include <linux/stddef.h>
10 
11 #include <asm/fpu.h>
12 #include <asm/mipsregs.h>
13 #include <asm/r4kcache.h>
14 #include <asm/hazards.h>
15 #include <asm/spram.h>
16 
17 /*
18  * These definitions are correct for the 24K/34K/74K SPRAM sample
19  * implementation. The 4KS interpreted the tags differently...
20  */
21 #define SPRAM_TAG0_ENABLE	0x00000080
22 #define SPRAM_TAG0_PA_MASK	0xfffff000
23 #define SPRAM_TAG1_SIZE_MASK	0xfffff000
24 
25 #define SPRAM_TAG_STRIDE	8
26 
27 #define ERRCTL_SPRAM		(1 << 28)
28 
29 /* errctl access */
30 #define read_c0_errctl(x) read_c0_ecc(x)
31 #define write_c0_errctl(x) write_c0_ecc(x)
32 
33 /*
34  * Different semantics to the set_c0_* function built by __BUILD_SET_C0
35  */
36 static unsigned int bis_c0_errctl(unsigned int set)
37 {
38 	unsigned int res;
39 	res = read_c0_errctl();
40 	write_c0_errctl(res | set);
41 	return res;
42 }
43 
44 static void ispram_store_tag(unsigned int offset, unsigned int data)
45 {
46 	unsigned int errctl;
47 
48 	/* enable SPRAM tag access */
49 	errctl = bis_c0_errctl(ERRCTL_SPRAM);
50 	ehb();
51 
52 	write_c0_taglo(data);
53 	ehb();
54 
55 	cache_op(Index_Store_Tag_I, CKSEG0|offset);
56 	ehb();
57 
58 	write_c0_errctl(errctl);
59 	ehb();
60 }
61 
62 
63 static unsigned int ispram_load_tag(unsigned int offset)
64 {
65 	unsigned int data;
66 	unsigned int errctl;
67 
68 	/* enable SPRAM tag access */
69 	errctl = bis_c0_errctl(ERRCTL_SPRAM);
70 	ehb();
71 	cache_op(Index_Load_Tag_I, CKSEG0 | offset);
72 	ehb();
73 	data = read_c0_taglo();
74 	ehb();
75 	write_c0_errctl(errctl);
76 	ehb();
77 
78 	return data;
79 }
80 
81 static void dspram_store_tag(unsigned int offset, unsigned int data)
82 {
83 	unsigned int errctl;
84 
85 	/* enable SPRAM tag access */
86 	errctl = bis_c0_errctl(ERRCTL_SPRAM);
87 	ehb();
88 	write_c0_dtaglo(data);
89 	ehb();
90 	cache_op(Index_Store_Tag_D, CKSEG0 | offset);
91 	ehb();
92 	write_c0_errctl(errctl);
93 	ehb();
94 }
95 
96 
97 static unsigned int dspram_load_tag(unsigned int offset)
98 {
99 	unsigned int data;
100 	unsigned int errctl;
101 
102 	errctl = bis_c0_errctl(ERRCTL_SPRAM);
103 	ehb();
104 	cache_op(Index_Load_Tag_D, CKSEG0 | offset);
105 	ehb();
106 	data = read_c0_dtaglo();
107 	ehb();
108 	write_c0_errctl(errctl);
109 	ehb();
110 
111 	return data;
112 }
113 
114 static void probe_spram(char *type,
115 	    unsigned int base,
116 	    unsigned int (*read)(unsigned int),
117 	    void (*write)(unsigned int, unsigned int))
118 {
119 	unsigned int firstsize = 0, lastsize = 0;
120 	unsigned int firstpa = 0, lastpa = 0, pa = 0;
121 	unsigned int offset = 0;
122 	unsigned int size, tag0, tag1;
123 	unsigned int enabled;
124 	int i;
125 
126 	/*
127 	 * The limit is arbitrary but avoids the loop running away if
128 	 * the SPRAM tags are implemented differently
129 	 */
130 
131 	for (i = 0; i < 8; i++) {
132 		tag0 = read(offset);
133 		tag1 = read(offset+SPRAM_TAG_STRIDE);
134 		pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n",
135 			 type, i, tag0, tag1);
136 
137 		size = tag1 & SPRAM_TAG1_SIZE_MASK;
138 
139 		if (size == 0)
140 			break;
141 
142 		if (i != 0) {
143 			/* tags may repeat... */
144 			if ((pa == firstpa && size == firstsize) ||
145 			    (pa == lastpa && size == lastsize))
146 				break;
147 		}
148 
149 		/* Align base with size */
150 		base = (base + size - 1) & ~(size-1);
151 
152 		/* reprogram the base address base address and enable */
153 		tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE;
154 		write(offset, tag0);
155 
156 		base += size;
157 
158 		/* reread the tag */
159 		tag0 = read(offset);
160 		pa = tag0 & SPRAM_TAG0_PA_MASK;
161 		enabled = tag0 & SPRAM_TAG0_ENABLE;
162 
163 		if (i == 0) {
164 			firstpa = pa;
165 			firstsize = size;
166 		}
167 
168 		lastpa = pa;
169 		lastsize = size;
170 
171 		if (strcmp(type, "DSPRAM") == 0) {
172 			unsigned int *vp = (unsigned int *)(CKSEG1 | pa);
173 			unsigned int v;
174 #define TDAT	0x5a5aa5a5
175 			vp[0] = TDAT;
176 			vp[1] = ~TDAT;
177 
178 			mb();
179 
180 			v = vp[0];
181 			if (v != TDAT)
182 				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
183 				       vp, TDAT, v);
184 			v = vp[1];
185 			if (v != ~TDAT)
186 				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",
187 				       vp+1, ~TDAT, v);
188 		}
189 
190 		pr_info("%s%d: PA=%08x,Size=%08x%s\n",
191 			type, i, pa, size, enabled ? ",enabled" : "");
192 		offset += 2 * SPRAM_TAG_STRIDE;
193 	}
194 }
195 void spram_config(void)
196 {
197 	unsigned int config0;
198 
199 	switch (current_cpu_type()) {
200 	case CPU_24K:
201 	case CPU_34K:
202 	case CPU_74K:
203 	case CPU_1004K:
204 	case CPU_1074K:
205 	case CPU_INTERAPTIV:
206 	case CPU_PROAPTIV:
207 	case CPU_P5600:
208 	case CPU_QEMU_GENERIC:
209 	case CPU_I6400:
210 	case CPU_P6600:
211 		config0 = read_c0_config();
212 		/* FIXME: addresses are Malta specific */
213 		if (config0 & MIPS_CONF_ISP) {
214 			probe_spram("ISPRAM", 0x1c000000,
215 				    &ispram_load_tag, &ispram_store_tag);
216 		}
217 		if (config0 & MIPS_CONF_DSP)
218 			probe_spram("DSPRAM", 0x1c100000,
219 				    &dspram_load_tag, &dspram_store_tag);
220 	}
221 }
222