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