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