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