Commit | Line | Data |
---|---|---|
0f81b11d MG |
1 | /* |
2 | * Marvell hostbridge routines | |
3 | * | |
4 | * Author: Mark A. Greer <source@mvista.com> | |
5 | * | |
6 | * 2004, 2005, 2007 (c) MontaVista Software, Inc. This file is licensed under | |
7 | * the terms of the GNU General Public License version 2. This program | |
8 | * is licensed "as is" without any warranty of any kind, whether express | |
9 | * or implied. | |
10 | */ | |
11 | ||
12 | #include <stdarg.h> | |
13 | #include <stddef.h> | |
14 | #include "types.h" | |
15 | #include "elf.h" | |
16 | #include "page.h" | |
17 | #include "string.h" | |
18 | #include "stdio.h" | |
19 | #include "io.h" | |
20 | #include "ops.h" | |
21 | #include "mv64x60.h" | |
22 | ||
23 | #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) | |
24 | ||
25 | #define MV64x60_CPU2MEM_WINDOWS 4 | |
26 | #define MV64x60_CPU2MEM_0_BASE 0x0008 | |
27 | #define MV64x60_CPU2MEM_0_SIZE 0x0010 | |
28 | #define MV64x60_CPU2MEM_1_BASE 0x0208 | |
29 | #define MV64x60_CPU2MEM_1_SIZE 0x0210 | |
30 | #define MV64x60_CPU2MEM_2_BASE 0x0018 | |
31 | #define MV64x60_CPU2MEM_2_SIZE 0x0020 | |
32 | #define MV64x60_CPU2MEM_3_BASE 0x0218 | |
33 | #define MV64x60_CPU2MEM_3_SIZE 0x0220 | |
34 | ||
35 | #define MV64x60_ENET2MEM_BAR_ENABLE 0x2290 | |
36 | #define MV64x60_ENET2MEM_0_BASE 0x2200 | |
37 | #define MV64x60_ENET2MEM_0_SIZE 0x2204 | |
38 | #define MV64x60_ENET2MEM_1_BASE 0x2208 | |
39 | #define MV64x60_ENET2MEM_1_SIZE 0x220c | |
40 | #define MV64x60_ENET2MEM_2_BASE 0x2210 | |
41 | #define MV64x60_ENET2MEM_2_SIZE 0x2214 | |
42 | #define MV64x60_ENET2MEM_3_BASE 0x2218 | |
43 | #define MV64x60_ENET2MEM_3_SIZE 0x221c | |
44 | #define MV64x60_ENET2MEM_4_BASE 0x2220 | |
45 | #define MV64x60_ENET2MEM_4_SIZE 0x2224 | |
46 | #define MV64x60_ENET2MEM_5_BASE 0x2228 | |
47 | #define MV64x60_ENET2MEM_5_SIZE 0x222c | |
48 | #define MV64x60_ENET2MEM_ACC_PROT_0 0x2294 | |
49 | #define MV64x60_ENET2MEM_ACC_PROT_1 0x2298 | |
50 | #define MV64x60_ENET2MEM_ACC_PROT_2 0x229c | |
51 | ||
52 | #define MV64x60_MPSC2MEM_BAR_ENABLE 0xf250 | |
53 | #define MV64x60_MPSC2MEM_0_BASE 0xf200 | |
54 | #define MV64x60_MPSC2MEM_0_SIZE 0xf204 | |
55 | #define MV64x60_MPSC2MEM_1_BASE 0xf208 | |
56 | #define MV64x60_MPSC2MEM_1_SIZE 0xf20c | |
57 | #define MV64x60_MPSC2MEM_2_BASE 0xf210 | |
58 | #define MV64x60_MPSC2MEM_2_SIZE 0xf214 | |
59 | #define MV64x60_MPSC2MEM_3_BASE 0xf218 | |
60 | #define MV64x60_MPSC2MEM_3_SIZE 0xf21c | |
61 | #define MV64x60_MPSC_0_REMAP 0xf240 | |
62 | #define MV64x60_MPSC_1_REMAP 0xf244 | |
63 | #define MV64x60_MPSC2MEM_ACC_PROT_0 0xf254 | |
64 | #define MV64x60_MPSC2MEM_ACC_PROT_1 0xf258 | |
65 | #define MV64x60_MPSC2REGS_BASE 0xf25c | |
66 | ||
67 | #define MV64x60_IDMA2MEM_BAR_ENABLE 0x0a80 | |
68 | #define MV64x60_IDMA2MEM_0_BASE 0x0a00 | |
69 | #define MV64x60_IDMA2MEM_0_SIZE 0x0a04 | |
70 | #define MV64x60_IDMA2MEM_1_BASE 0x0a08 | |
71 | #define MV64x60_IDMA2MEM_1_SIZE 0x0a0c | |
72 | #define MV64x60_IDMA2MEM_2_BASE 0x0a10 | |
73 | #define MV64x60_IDMA2MEM_2_SIZE 0x0a14 | |
74 | #define MV64x60_IDMA2MEM_3_BASE 0x0a18 | |
75 | #define MV64x60_IDMA2MEM_3_SIZE 0x0a1c | |
76 | #define MV64x60_IDMA2MEM_4_BASE 0x0a20 | |
77 | #define MV64x60_IDMA2MEM_4_SIZE 0x0a24 | |
78 | #define MV64x60_IDMA2MEM_5_BASE 0x0a28 | |
79 | #define MV64x60_IDMA2MEM_5_SIZE 0x0a2c | |
80 | #define MV64x60_IDMA2MEM_6_BASE 0x0a30 | |
81 | #define MV64x60_IDMA2MEM_6_SIZE 0x0a34 | |
82 | #define MV64x60_IDMA2MEM_7_BASE 0x0a38 | |
83 | #define MV64x60_IDMA2MEM_7_SIZE 0x0a3c | |
84 | #define MV64x60_IDMA2MEM_ACC_PROT_0 0x0a70 | |
85 | #define MV64x60_IDMA2MEM_ACC_PROT_1 0x0a74 | |
86 | #define MV64x60_IDMA2MEM_ACC_PROT_2 0x0a78 | |
87 | #define MV64x60_IDMA2MEM_ACC_PROT_3 0x0a7c | |
88 | ||
89 | #define MV64x60_PCI_ACC_CNTL_WINDOWS 6 | |
90 | #define MV64x60_PCI0_PCI_DECODE_CNTL 0x0d3c | |
91 | #define MV64x60_PCI1_PCI_DECODE_CNTL 0x0dbc | |
92 | ||
93 | #define MV64x60_PCI0_BAR_ENABLE 0x0c3c | |
94 | #define MV64x60_PCI02MEM_0_SIZE 0x0c08 | |
95 | #define MV64x60_PCI0_ACC_CNTL_0_BASE_LO 0x1e00 | |
96 | #define MV64x60_PCI0_ACC_CNTL_0_BASE_HI 0x1e04 | |
97 | #define MV64x60_PCI0_ACC_CNTL_0_SIZE 0x1e08 | |
98 | #define MV64x60_PCI0_ACC_CNTL_1_BASE_LO 0x1e10 | |
99 | #define MV64x60_PCI0_ACC_CNTL_1_BASE_HI 0x1e14 | |
100 | #define MV64x60_PCI0_ACC_CNTL_1_SIZE 0x1e18 | |
101 | #define MV64x60_PCI0_ACC_CNTL_2_BASE_LO 0x1e20 | |
102 | #define MV64x60_PCI0_ACC_CNTL_2_BASE_HI 0x1e24 | |
103 | #define MV64x60_PCI0_ACC_CNTL_2_SIZE 0x1e28 | |
104 | #define MV64x60_PCI0_ACC_CNTL_3_BASE_LO 0x1e30 | |
105 | #define MV64x60_PCI0_ACC_CNTL_3_BASE_HI 0x1e34 | |
106 | #define MV64x60_PCI0_ACC_CNTL_3_SIZE 0x1e38 | |
107 | #define MV64x60_PCI0_ACC_CNTL_4_BASE_LO 0x1e40 | |
108 | #define MV64x60_PCI0_ACC_CNTL_4_BASE_HI 0x1e44 | |
109 | #define MV64x60_PCI0_ACC_CNTL_4_SIZE 0x1e48 | |
110 | #define MV64x60_PCI0_ACC_CNTL_5_BASE_LO 0x1e50 | |
111 | #define MV64x60_PCI0_ACC_CNTL_5_BASE_HI 0x1e54 | |
112 | #define MV64x60_PCI0_ACC_CNTL_5_SIZE 0x1e58 | |
113 | ||
114 | #define MV64x60_PCI1_BAR_ENABLE 0x0cbc | |
115 | #define MV64x60_PCI12MEM_0_SIZE 0x0c88 | |
116 | #define MV64x60_PCI1_ACC_CNTL_0_BASE_LO 0x1e80 | |
117 | #define MV64x60_PCI1_ACC_CNTL_0_BASE_HI 0x1e84 | |
118 | #define MV64x60_PCI1_ACC_CNTL_0_SIZE 0x1e88 | |
119 | #define MV64x60_PCI1_ACC_CNTL_1_BASE_LO 0x1e90 | |
120 | #define MV64x60_PCI1_ACC_CNTL_1_BASE_HI 0x1e94 | |
121 | #define MV64x60_PCI1_ACC_CNTL_1_SIZE 0x1e98 | |
122 | #define MV64x60_PCI1_ACC_CNTL_2_BASE_LO 0x1ea0 | |
123 | #define MV64x60_PCI1_ACC_CNTL_2_BASE_HI 0x1ea4 | |
124 | #define MV64x60_PCI1_ACC_CNTL_2_SIZE 0x1ea8 | |
125 | #define MV64x60_PCI1_ACC_CNTL_3_BASE_LO 0x1eb0 | |
126 | #define MV64x60_PCI1_ACC_CNTL_3_BASE_HI 0x1eb4 | |
127 | #define MV64x60_PCI1_ACC_CNTL_3_SIZE 0x1eb8 | |
128 | #define MV64x60_PCI1_ACC_CNTL_4_BASE_LO 0x1ec0 | |
129 | #define MV64x60_PCI1_ACC_CNTL_4_BASE_HI 0x1ec4 | |
130 | #define MV64x60_PCI1_ACC_CNTL_4_SIZE 0x1ec8 | |
131 | #define MV64x60_PCI1_ACC_CNTL_5_BASE_LO 0x1ed0 | |
132 | #define MV64x60_PCI1_ACC_CNTL_5_BASE_HI 0x1ed4 | |
133 | #define MV64x60_PCI1_ACC_CNTL_5_SIZE 0x1ed8 | |
134 | ||
135 | #define MV64x60_CPU2PCI_SWAP_NONE 0x01000000 | |
136 | ||
137 | #define MV64x60_CPU2PCI0_IO_BASE 0x0048 | |
138 | #define MV64x60_CPU2PCI0_IO_SIZE 0x0050 | |
139 | #define MV64x60_CPU2PCI0_IO_REMAP 0x00f0 | |
140 | #define MV64x60_CPU2PCI0_MEM_0_BASE 0x0058 | |
141 | #define MV64x60_CPU2PCI0_MEM_0_SIZE 0x0060 | |
142 | #define MV64x60_CPU2PCI0_MEM_0_REMAP_LO 0x00f8 | |
143 | #define MV64x60_CPU2PCI0_MEM_0_REMAP_HI 0x0320 | |
144 | ||
145 | #define MV64x60_CPU2PCI1_IO_BASE 0x0090 | |
146 | #define MV64x60_CPU2PCI1_IO_SIZE 0x0098 | |
147 | #define MV64x60_CPU2PCI1_IO_REMAP 0x0108 | |
148 | #define MV64x60_CPU2PCI1_MEM_0_BASE 0x00a0 | |
149 | #define MV64x60_CPU2PCI1_MEM_0_SIZE 0x00a8 | |
150 | #define MV64x60_CPU2PCI1_MEM_0_REMAP_LO 0x0110 | |
151 | #define MV64x60_CPU2PCI1_MEM_0_REMAP_HI 0x0340 | |
152 | ||
153 | struct mv64x60_mem_win { | |
154 | u32 hi; | |
155 | u32 lo; | |
156 | u32 size; | |
157 | }; | |
158 | ||
159 | struct mv64x60_pci_win { | |
160 | u32 fcn; | |
161 | u32 hi; | |
162 | u32 lo; | |
163 | u32 size; | |
164 | }; | |
165 | ||
166 | /* PCI config access routines */ | |
167 | struct { | |
168 | u32 addr; | |
169 | u32 data; | |
170 | } static mv64x60_pci_cfgio[2] = { | |
171 | { /* hose 0 */ | |
172 | .addr = 0xcf8, | |
173 | .data = 0xcfc, | |
174 | }, | |
175 | { /* hose 1 */ | |
176 | .addr = 0xc78, | |
177 | .data = 0xc7c, | |
178 | } | |
179 | }; | |
180 | ||
181 | u32 mv64x60_cfg_read(u8 *bridge_base, u8 hose, u8 bus, u8 devfn, u8 offset) | |
182 | { | |
183 | out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].addr), | |
184 | (1 << 31) | (bus << 16) | (devfn << 8) | offset); | |
185 | return in_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].data)); | |
186 | } | |
187 | ||
188 | void mv64x60_cfg_write(u8 *bridge_base, u8 hose, u8 bus, u8 devfn, u8 offset, | |
189 | u32 val) | |
190 | { | |
191 | out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].addr), | |
192 | (1 << 31) | (bus << 16) | (devfn << 8) | offset); | |
193 | out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].data), val); | |
194 | } | |
195 | ||
196 | /* I/O ctlr -> system memory setup */ | |
197 | static struct mv64x60_mem_win mv64x60_cpu2mem[MV64x60_CPU2MEM_WINDOWS] = { | |
198 | { | |
199 | .lo = MV64x60_CPU2MEM_0_BASE, | |
200 | .size = MV64x60_CPU2MEM_0_SIZE, | |
201 | }, | |
202 | { | |
203 | .lo = MV64x60_CPU2MEM_1_BASE, | |
204 | .size = MV64x60_CPU2MEM_1_SIZE, | |
205 | }, | |
206 | { | |
207 | .lo = MV64x60_CPU2MEM_2_BASE, | |
208 | .size = MV64x60_CPU2MEM_2_SIZE, | |
209 | }, | |
210 | { | |
211 | .lo = MV64x60_CPU2MEM_3_BASE, | |
212 | .size = MV64x60_CPU2MEM_3_SIZE, | |
213 | }, | |
214 | }; | |
215 | ||
216 | static struct mv64x60_mem_win mv64x60_enet2mem[MV64x60_CPU2MEM_WINDOWS] = { | |
217 | { | |
218 | .lo = MV64x60_ENET2MEM_0_BASE, | |
219 | .size = MV64x60_ENET2MEM_0_SIZE, | |
220 | }, | |
221 | { | |
222 | .lo = MV64x60_ENET2MEM_1_BASE, | |
223 | .size = MV64x60_ENET2MEM_1_SIZE, | |
224 | }, | |
225 | { | |
226 | .lo = MV64x60_ENET2MEM_2_BASE, | |
227 | .size = MV64x60_ENET2MEM_2_SIZE, | |
228 | }, | |
229 | { | |
230 | .lo = MV64x60_ENET2MEM_3_BASE, | |
231 | .size = MV64x60_ENET2MEM_3_SIZE, | |
232 | }, | |
233 | }; | |
234 | ||
235 | static struct mv64x60_mem_win mv64x60_mpsc2mem[MV64x60_CPU2MEM_WINDOWS] = { | |
236 | { | |
237 | .lo = MV64x60_MPSC2MEM_0_BASE, | |
238 | .size = MV64x60_MPSC2MEM_0_SIZE, | |
239 | }, | |
240 | { | |
241 | .lo = MV64x60_MPSC2MEM_1_BASE, | |
242 | .size = MV64x60_MPSC2MEM_1_SIZE, | |
243 | }, | |
244 | { | |
245 | .lo = MV64x60_MPSC2MEM_2_BASE, | |
246 | .size = MV64x60_MPSC2MEM_2_SIZE, | |
247 | }, | |
248 | { | |
249 | .lo = MV64x60_MPSC2MEM_3_BASE, | |
250 | .size = MV64x60_MPSC2MEM_3_SIZE, | |
251 | }, | |
252 | }; | |
253 | ||
254 | static struct mv64x60_mem_win mv64x60_idma2mem[MV64x60_CPU2MEM_WINDOWS] = { | |
255 | { | |
256 | .lo = MV64x60_IDMA2MEM_0_BASE, | |
257 | .size = MV64x60_IDMA2MEM_0_SIZE, | |
258 | }, | |
259 | { | |
260 | .lo = MV64x60_IDMA2MEM_1_BASE, | |
261 | .size = MV64x60_IDMA2MEM_1_SIZE, | |
262 | }, | |
263 | { | |
264 | .lo = MV64x60_IDMA2MEM_2_BASE, | |
265 | .size = MV64x60_IDMA2MEM_2_SIZE, | |
266 | }, | |
267 | { | |
268 | .lo = MV64x60_IDMA2MEM_3_BASE, | |
269 | .size = MV64x60_IDMA2MEM_3_SIZE, | |
270 | }, | |
271 | }; | |
272 | ||
273 | static u32 mv64x60_dram_selects[MV64x60_CPU2MEM_WINDOWS] = {0xe,0xd,0xb,0x7}; | |
274 | ||
275 | /* | |
276 | * ENET, MPSC, and IDMA ctlrs on the MV64x60 have separate windows that | |
277 | * must be set up so that the respective ctlr can access system memory. | |
278 | * Configure them to be same as cpu->memory windows. | |
279 | */ | |
280 | void mv64x60_config_ctlr_windows(u8 *bridge_base, u8 *bridge_pbase, | |
281 | u8 is_coherent) | |
282 | { | |
283 | u32 i, base, size, enables, prot = 0, snoop_bits = 0; | |
284 | ||
285 | /* Disable ctlr->mem windows */ | |
286 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0x3f); | |
287 | out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), 0xf); | |
288 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0xff); | |
289 | ||
290 | if (is_coherent) | |
291 | snoop_bits = 0x2 << 12; /* Writeback */ | |
292 | ||
293 | enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf; | |
294 | ||
295 | for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) { | |
296 | if (enables & (1 << i)) /* Set means disabled */ | |
297 | continue; | |
298 | ||
299 | base = in_le32((u32 *)(bridge_base + mv64x60_cpu2mem[i].lo)) | |
300 | << 16; | |
301 | base |= snoop_bits | (mv64x60_dram_selects[i] << 8); | |
302 | size = in_le32((u32 *)(bridge_base + mv64x60_cpu2mem[i].size)) | |
303 | << 16; | |
304 | prot |= (0x3 << (i << 1)); /* RW access */ | |
305 | ||
306 | out_le32((u32 *)(bridge_base + mv64x60_enet2mem[i].lo), base); | |
307 | out_le32((u32 *)(bridge_base + mv64x60_enet2mem[i].size), size); | |
308 | out_le32((u32 *)(bridge_base + mv64x60_mpsc2mem[i].lo), base); | |
309 | out_le32((u32 *)(bridge_base + mv64x60_mpsc2mem[i].size), size); | |
310 | out_le32((u32 *)(bridge_base + mv64x60_idma2mem[i].lo), base); | |
311 | out_le32((u32 *)(bridge_base + mv64x60_idma2mem[i].size), size); | |
312 | } | |
313 | ||
314 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_0), prot); | |
315 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_1), prot); | |
316 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_2), prot); | |
317 | out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_0), prot); | |
318 | out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_1), prot); | |
319 | out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_0), prot); | |
320 | out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_1), prot); | |
321 | out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_2), prot); | |
322 | out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_3), prot); | |
323 | ||
324 | /* Set mpsc->bridge's reg window to the bridge's internal registers. */ | |
325 | out_le32((u32 *)(bridge_base + MV64x60_MPSC2REGS_BASE), | |
326 | (u32)bridge_pbase); | |
327 | ||
328 | out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), enables); | |
329 | out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), enables); | |
330 | out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_BAR_ENABLE), enables); | |
331 | } | |
332 | ||
333 | /* PCI MEM -> system memory, et. al. setup */ | |
334 | static struct mv64x60_pci_win mv64x60_pci2mem[2] = { | |
335 | { /* hose 0 */ | |
336 | .fcn = 0, | |
337 | .hi = 0x14, | |
338 | .lo = 0x10, | |
339 | .size = MV64x60_PCI02MEM_0_SIZE, | |
340 | }, | |
341 | { /* hose 1 */ | |
342 | .fcn = 0, | |
343 | .hi = 0x94, | |
344 | .lo = 0x90, | |
345 | .size = MV64x60_PCI12MEM_0_SIZE, | |
346 | }, | |
347 | }; | |
348 | ||
349 | static struct | |
350 | mv64x60_mem_win mv64x60_pci_acc[2][MV64x60_PCI_ACC_CNTL_WINDOWS] = { | |
351 | { /* hose 0 */ | |
352 | { | |
353 | .hi = MV64x60_PCI0_ACC_CNTL_0_BASE_HI, | |
354 | .lo = MV64x60_PCI0_ACC_CNTL_0_BASE_LO, | |
355 | .size = MV64x60_PCI0_ACC_CNTL_0_SIZE, | |
356 | }, | |
357 | { | |
358 | .hi = MV64x60_PCI0_ACC_CNTL_1_BASE_HI, | |
359 | .lo = MV64x60_PCI0_ACC_CNTL_1_BASE_LO, | |
360 | .size = MV64x60_PCI0_ACC_CNTL_1_SIZE, | |
361 | }, | |
362 | { | |
363 | .hi = MV64x60_PCI0_ACC_CNTL_2_BASE_HI, | |
364 | .lo = MV64x60_PCI0_ACC_CNTL_2_BASE_LO, | |
365 | .size = MV64x60_PCI0_ACC_CNTL_2_SIZE, | |
366 | }, | |
367 | { | |
368 | .hi = MV64x60_PCI0_ACC_CNTL_3_BASE_HI, | |
369 | .lo = MV64x60_PCI0_ACC_CNTL_3_BASE_LO, | |
370 | .size = MV64x60_PCI0_ACC_CNTL_3_SIZE, | |
371 | }, | |
372 | }, | |
373 | { /* hose 1 */ | |
374 | { | |
375 | .hi = MV64x60_PCI1_ACC_CNTL_0_BASE_HI, | |
376 | .lo = MV64x60_PCI1_ACC_CNTL_0_BASE_LO, | |
377 | .size = MV64x60_PCI1_ACC_CNTL_0_SIZE, | |
378 | }, | |
379 | { | |
380 | .hi = MV64x60_PCI1_ACC_CNTL_1_BASE_HI, | |
381 | .lo = MV64x60_PCI1_ACC_CNTL_1_BASE_LO, | |
382 | .size = MV64x60_PCI1_ACC_CNTL_1_SIZE, | |
383 | }, | |
384 | { | |
385 | .hi = MV64x60_PCI1_ACC_CNTL_2_BASE_HI, | |
386 | .lo = MV64x60_PCI1_ACC_CNTL_2_BASE_LO, | |
387 | .size = MV64x60_PCI1_ACC_CNTL_2_SIZE, | |
388 | }, | |
389 | { | |
390 | .hi = MV64x60_PCI1_ACC_CNTL_3_BASE_HI, | |
391 | .lo = MV64x60_PCI1_ACC_CNTL_3_BASE_LO, | |
392 | .size = MV64x60_PCI1_ACC_CNTL_3_SIZE, | |
393 | }, | |
394 | }, | |
395 | }; | |
396 | ||
397 | static struct mv64x60_mem_win mv64x60_pci2reg[2] = { | |
398 | { | |
399 | .hi = 0x24, | |
400 | .lo = 0x20, | |
401 | .size = 0, | |
402 | }, | |
403 | { | |
404 | .hi = 0xa4, | |
405 | .lo = 0xa0, | |
406 | .size = 0, | |
407 | }, | |
408 | }; | |
409 | ||
410 | /* Only need to use 1 window (per hose) to get access to all of system memory */ | |
411 | void mv64x60_config_pci_windows(u8 *bridge_base, u8 *bridge_pbase, u8 hose, | |
412 | u8 bus, u32 mem_size, u32 acc_bits) | |
413 | { | |
414 | u32 i, offset, bar_enable, enables; | |
415 | ||
416 | /* Disable all windows but PCI MEM -> Bridge's regs window */ | |
417 | enables = ~(1 << 9); | |
418 | bar_enable = hose ? MV64x60_PCI1_BAR_ENABLE : MV64x60_PCI0_BAR_ENABLE; | |
419 | out_le32((u32 *)(bridge_base + bar_enable), enables); | |
420 | ||
421 | for (i=0; i<MV64x60_PCI_ACC_CNTL_WINDOWS; i++) | |
422 | out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][i].lo), 0); | |
423 | ||
424 | /* If mem_size is 0, leave windows disabled */ | |
425 | if (mem_size == 0) | |
426 | return; | |
427 | ||
428 | /* Cause automatic updates of PCI remap regs */ | |
429 | offset = hose ? | |
430 | MV64x60_PCI1_PCI_DECODE_CNTL : MV64x60_PCI0_PCI_DECODE_CNTL; | |
431 | i = in_le32((u32 *)(bridge_base + offset)); | |
432 | out_le32((u32 *)(bridge_base + offset), i & ~0x1); | |
433 | ||
434 | mem_size = (mem_size - 1) & 0xfffff000; | |
435 | ||
436 | /* Map PCI MEM addr 0 -> System Mem addr 0 */ | |
437 | mv64x60_cfg_write(bridge_base, hose, bus, | |
438 | PCI_DEVFN(0, mv64x60_pci2mem[hose].fcn), | |
439 | mv64x60_pci2mem[hose].hi, 0); | |
440 | mv64x60_cfg_write(bridge_base, hose, bus, | |
441 | PCI_DEVFN(0, mv64x60_pci2mem[hose].fcn), | |
442 | mv64x60_pci2mem[hose].lo, 0); | |
443 | out_le32((u32 *)(bridge_base + mv64x60_pci2mem[hose].size),mem_size); | |
444 | ||
445 | acc_bits |= MV64x60_PCI_ACC_CNTL_ENABLE; | |
446 | out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].hi), 0); | |
447 | out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].lo), acc_bits); | |
448 | out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].size),mem_size); | |
449 | ||
450 | /* Set PCI MEM->bridge's reg window to where they are in CPU mem map */ | |
451 | i = (u32)bridge_base; | |
452 | i &= 0xffff0000; | |
453 | i |= (0x2 << 1); | |
454 | mv64x60_cfg_write(bridge_base, hose, bus, PCI_DEVFN(0,0), | |
455 | mv64x60_pci2reg[hose].hi, 0); | |
456 | mv64x60_cfg_write(bridge_base, hose, bus, PCI_DEVFN(0,0), | |
457 | mv64x60_pci2reg[hose].lo, i); | |
458 | ||
459 | enables &= ~0x1; /* Enable PCI MEM -> System Mem window 0 */ | |
460 | out_le32((u32 *)(bridge_base + bar_enable), enables); | |
461 | } | |
462 | ||
463 | /* CPU -> PCI I/O & MEM setup */ | |
464 | struct mv64x60_cpu2pci_win mv64x60_cpu2pci_io[2] = { | |
465 | { /* hose 0 */ | |
466 | .lo = MV64x60_CPU2PCI0_IO_BASE, | |
467 | .size = MV64x60_CPU2PCI0_IO_SIZE, | |
468 | .remap_hi = 0, | |
469 | .remap_lo = MV64x60_CPU2PCI0_IO_REMAP, | |
470 | }, | |
471 | { /* hose 1 */ | |
472 | .lo = MV64x60_CPU2PCI1_IO_BASE, | |
473 | .size = MV64x60_CPU2PCI1_IO_SIZE, | |
474 | .remap_hi = 0, | |
475 | .remap_lo = MV64x60_CPU2PCI1_IO_REMAP, | |
476 | }, | |
477 | }; | |
478 | ||
479 | struct mv64x60_cpu2pci_win mv64x60_cpu2pci_mem[2] = { | |
480 | { /* hose 0 */ | |
481 | .lo = MV64x60_CPU2PCI0_MEM_0_BASE, | |
482 | .size = MV64x60_CPU2PCI0_MEM_0_SIZE, | |
483 | .remap_hi = MV64x60_CPU2PCI0_MEM_0_REMAP_HI, | |
484 | .remap_lo = MV64x60_CPU2PCI0_MEM_0_REMAP_LO, | |
485 | }, | |
486 | { /* hose 1 */ | |
487 | .lo = MV64x60_CPU2PCI1_MEM_0_BASE, | |
488 | .size = MV64x60_CPU2PCI1_MEM_0_SIZE, | |
489 | .remap_hi = MV64x60_CPU2PCI1_MEM_0_REMAP_HI, | |
490 | .remap_lo = MV64x60_CPU2PCI1_MEM_0_REMAP_LO, | |
491 | }, | |
492 | }; | |
493 | ||
494 | /* Only need to set up 1 window to pci mem space */ | |
495 | void mv64x60_config_cpu2pci_window(u8 *bridge_base, u8 hose, u32 pci_base_hi, | |
496 | u32 pci_base_lo, u32 cpu_base, u32 size, | |
497 | struct mv64x60_cpu2pci_win *offset_tbl) | |
498 | { | |
499 | cpu_base >>= 16; | |
500 | cpu_base |= MV64x60_CPU2PCI_SWAP_NONE; | |
501 | out_le32((u32 *)(bridge_base + offset_tbl[hose].lo), cpu_base); | |
502 | ||
503 | if (offset_tbl[hose].remap_hi != 0) | |
504 | out_le32((u32 *)(bridge_base + offset_tbl[hose].remap_hi), | |
505 | pci_base_hi); | |
506 | out_le32((u32 *)(bridge_base + offset_tbl[hose].remap_lo), | |
507 | pci_base_lo >> 16); | |
508 | ||
509 | size = (size - 1) >> 16; | |
510 | out_le32((u32 *)(bridge_base + offset_tbl[hose].size), size); | |
511 | } | |
512 | ||
513 | /* Read mem ctlr to get the amount of mem in system */ | |
514 | u32 mv64x60_get_mem_size(u8 *bridge_base) | |
515 | { | |
516 | u32 enables, i, v; | |
517 | u32 mem = 0; | |
518 | ||
519 | enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf; | |
520 | ||
521 | for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) | |
522 | if (!(enables & (1<<i))) { | |
523 | v = in_le32((u32*)(bridge_base | |
524 | + mv64x60_cpu2mem[i].size)); | |
525 | v = ((v & 0xffff) + 1) << 16; | |
526 | mem += v; | |
527 | } | |
528 | ||
529 | return mem; | |
530 | } | |
531 | ||
532 | /* Get physical address of bridge's registers */ | |
533 | u8 *mv64x60_get_bridge_pbase(void) | |
534 | { | |
535 | u32 v[2]; | |
536 | void *devp; | |
537 | ||
a05ce88a | 538 | devp = find_node_by_compatible(NULL, "marvell,mv64360"); |
0f81b11d MG |
539 | if (devp == NULL) |
540 | goto err_out; | |
541 | if (getprop(devp, "reg", v, sizeof(v)) != sizeof(v)) | |
542 | goto err_out; | |
543 | ||
544 | return (u8 *)v[0]; | |
545 | ||
546 | err_out: | |
547 | return 0; | |
548 | } | |
549 | ||
550 | /* Get virtual address of bridge's registers */ | |
551 | u8 *mv64x60_get_bridge_base(void) | |
552 | { | |
553 | u32 v; | |
554 | void *devp; | |
555 | ||
a05ce88a | 556 | devp = find_node_by_compatible(NULL, "marvell,mv64360"); |
0f81b11d MG |
557 | if (devp == NULL) |
558 | goto err_out; | |
559 | if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) | |
560 | goto err_out; | |
561 | ||
562 | return (u8 *)v; | |
563 | ||
564 | err_out: | |
565 | return 0; | |
566 | } | |
567 | ||
568 | u8 mv64x60_is_coherent(void) | |
569 | { | |
570 | u32 v; | |
571 | void *devp; | |
572 | ||
573 | devp = finddevice("/"); | |
574 | if (devp == NULL) | |
575 | return 1; /* Assume coherency on */ | |
576 | ||
577 | if (getprop(devp, "coherency-off", &v, sizeof(v)) < 0) | |
578 | return 1; /* Coherency on */ | |
579 | else | |
580 | return 0; | |
581 | } |