GNU Linux-libre 6.9.1-gnu
[releases.git] / arch / mips / kernel / spram.c
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 }