Merge tag 'iio-for-5.11a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23...
[linux-2.6-microblaze.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
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 }