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