]>
Commit | Line | Data |
---|---|---|
5e23b8b4 SG |
1 | /* |
2 | * PCI autoconfiguration library | |
3 | * | |
4 | * Author: Matt Porter <[email protected]> | |
5 | * | |
6 | * Copyright 2000 MontaVista Software Inc. | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <errno.h> | |
13 | #include <pci.h> | |
14 | ||
15 | /* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */ | |
16 | #ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE | |
17 | #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8 | |
18 | #endif | |
19 | ||
20 | void dm_pciauto_setup_device(struct udevice *dev, int bars_num, | |
21 | struct pci_region *mem, | |
22 | struct pci_region *prefetch, struct pci_region *io, | |
23 | bool enum_only) | |
24 | { | |
25 | u32 bar_response; | |
26 | pci_size_t bar_size; | |
27 | u16 cmdstat = 0; | |
28 | int bar, bar_nr = 0; | |
29 | u8 header_type; | |
30 | int rom_addr; | |
31 | pci_addr_t bar_value; | |
32 | struct pci_region *bar_res; | |
33 | int found_mem64 = 0; | |
34 | u16 class; | |
35 | ||
36 | dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); | |
37 | cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | | |
38 | PCI_COMMAND_MASTER; | |
39 | ||
40 | for (bar = PCI_BASE_ADDRESS_0; | |
41 | bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) { | |
42 | /* Tickle the BAR and get the response */ | |
43 | if (!enum_only) | |
44 | dm_pci_write_config32(dev, bar, 0xffffffff); | |
45 | dm_pci_read_config32(dev, bar, &bar_response); | |
46 | ||
47 | /* If BAR is not implemented go to the next BAR */ | |
48 | if (!bar_response) | |
49 | continue; | |
50 | ||
51 | found_mem64 = 0; | |
52 | ||
53 | /* Check the BAR type and set our address mask */ | |
54 | if (bar_response & PCI_BASE_ADDRESS_SPACE) { | |
55 | bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK)) | |
56 | & 0xffff) + 1; | |
57 | if (!enum_only) | |
58 | bar_res = io; | |
59 | ||
60 | debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", | |
61 | bar_nr, (unsigned long long)bar_size); | |
62 | } else { | |
63 | if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == | |
64 | PCI_BASE_ADDRESS_MEM_TYPE_64) { | |
65 | u32 bar_response_upper; | |
66 | u64 bar64; | |
67 | ||
68 | if (!enum_only) { | |
69 | dm_pci_write_config32(dev, bar + 4, | |
70 | 0xffffffff); | |
71 | } | |
72 | dm_pci_read_config32(dev, bar + 4, | |
73 | &bar_response_upper); | |
74 | ||
75 | bar64 = ((u64)bar_response_upper << 32) | | |
76 | bar_response; | |
77 | ||
78 | bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) | |
79 | + 1; | |
80 | if (!enum_only) | |
81 | found_mem64 = 1; | |
82 | } else { | |
83 | bar_size = (u32)(~(bar_response & | |
84 | PCI_BASE_ADDRESS_MEM_MASK) + 1); | |
85 | } | |
86 | if (!enum_only) { | |
87 | if (prefetch && (bar_response & | |
88 | PCI_BASE_ADDRESS_MEM_PREFETCH)) { | |
89 | bar_res = prefetch; | |
90 | } else { | |
91 | bar_res = mem; | |
92 | } | |
93 | } | |
94 | ||
95 | debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ", | |
96 | bar_nr, bar_res == prefetch ? "Prf" : "Mem", | |
97 | (unsigned long long)bar_size); | |
98 | } | |
99 | ||
100 | if (!enum_only && pciauto_region_allocate(bar_res, bar_size, | |
101 | &bar_value) == 0) { | |
102 | /* Write it out and update our limit */ | |
103 | dm_pci_write_config32(dev, bar, (u32)bar_value); | |
104 | ||
105 | if (found_mem64) { | |
106 | bar += 4; | |
107 | #ifdef CONFIG_SYS_PCI_64BIT | |
108 | dm_pci_write_config32(dev, bar, | |
109 | (u32)(bar_value >> 32)); | |
110 | #else | |
111 | /* | |
112 | * If we are a 64-bit decoder then increment to | |
113 | * the upper 32 bits of the bar and force it to | |
114 | * locate in the lower 4GB of memory. | |
115 | */ | |
116 | dm_pci_write_config32(dev, bar, 0x00000000); | |
117 | #endif | |
118 | } | |
119 | } | |
120 | ||
121 | cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ? | |
122 | PCI_COMMAND_IO : PCI_COMMAND_MEMORY; | |
123 | ||
124 | debug("\n"); | |
125 | ||
126 | bar_nr++; | |
127 | } | |
128 | ||
129 | if (!enum_only) { | |
130 | /* Configure the expansion ROM address */ | |
131 | dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); | |
132 | header_type &= 0x7f; | |
133 | if (header_type != PCI_HEADER_TYPE_CARDBUS) { | |
134 | rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ? | |
135 | PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1; | |
136 | dm_pci_write_config32(dev, rom_addr, 0xfffffffe); | |
137 | dm_pci_read_config32(dev, rom_addr, &bar_response); | |
138 | if (bar_response) { | |
139 | bar_size = -(bar_response & ~1); | |
140 | debug("PCI Autoconfig: ROM, size=%#x, ", | |
141 | (unsigned int)bar_size); | |
142 | if (pciauto_region_allocate(mem, bar_size, | |
143 | &bar_value) == 0) { | |
144 | dm_pci_write_config32(dev, rom_addr, | |
145 | bar_value); | |
146 | } | |
147 | cmdstat |= PCI_COMMAND_MEMORY; | |
148 | debug("\n"); | |
149 | } | |
150 | } | |
151 | } | |
152 | ||
153 | /* PCI_COMMAND_IO must be set for VGA device */ | |
154 | dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class); | |
155 | if (class == PCI_CLASS_DISPLAY_VGA) | |
156 | cmdstat |= PCI_COMMAND_IO; | |
157 | ||
158 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat); | |
159 | dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE, | |
160 | CONFIG_SYS_PCI_CACHE_LINE_SIZE); | |
161 | dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80); | |
162 | } | |
163 | ||
164 | void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) | |
165 | { | |
166 | struct pci_region *pci_mem; | |
167 | struct pci_region *pci_prefetch; | |
168 | struct pci_region *pci_io; | |
169 | u16 cmdstat, prefechable_64; | |
170 | /* The root controller has the region information */ | |
171 | struct pci_controller *ctlr_hose = pci_bus_to_hose(0); | |
172 | ||
173 | pci_mem = ctlr_hose->pci_mem; | |
174 | pci_prefetch = ctlr_hose->pci_prefetch; | |
175 | pci_io = ctlr_hose->pci_io; | |
176 | ||
177 | dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); | |
178 | dm_pci_read_config16(dev, PCI_PREF_MEMORY_BASE, &prefechable_64); | |
179 | prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK; | |
180 | ||
181 | /* Configure bus number registers */ | |
182 | dm_pci_write_config8(dev, PCI_PRIMARY_BUS, | |
183 | PCI_BUS(dm_pci_get_bdf(dev))); | |
184 | dm_pci_write_config8(dev, PCI_SECONDARY_BUS, sub_bus); | |
185 | dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, 0xff); | |
186 | ||
187 | if (pci_mem) { | |
188 | /* Round memory allocator to 1MB boundary */ | |
189 | pciauto_region_align(pci_mem, 0x100000); | |
190 | ||
191 | /* | |
192 | * Set up memory and I/O filter limits, assume 32-bit | |
193 | * I/O space | |
194 | */ | |
195 | dm_pci_write_config16(dev, PCI_MEMORY_BASE, | |
196 | (pci_mem->bus_lower & 0xfff00000) >> 16); | |
197 | ||
198 | cmdstat |= PCI_COMMAND_MEMORY; | |
199 | } | |
200 | ||
201 | if (pci_prefetch) { | |
202 | /* Round memory allocator to 1MB boundary */ | |
203 | pciauto_region_align(pci_prefetch, 0x100000); | |
204 | ||
205 | /* | |
206 | * Set up memory and I/O filter limits, assume 32-bit | |
207 | * I/O space | |
208 | */ | |
209 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, | |
210 | (pci_prefetch->bus_lower & 0xfff00000) >> 16); | |
211 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) | |
212 | #ifdef CONFIG_SYS_PCI_64BIT | |
213 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, | |
214 | pci_prefetch->bus_lower >> 32); | |
215 | #else | |
216 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
217 | #endif | |
218 | ||
219 | cmdstat |= PCI_COMMAND_MEMORY; | |
220 | } else { | |
221 | /* We don't support prefetchable memory for now, so disable */ | |
222 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, 0x1000); | |
223 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, 0x0); | |
224 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) { | |
225 | dm_pci_write_config16(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
226 | dm_pci_write_config16(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | |
227 | } | |
228 | } | |
229 | ||
230 | if (pci_io) { | |
231 | /* Round I/O allocator to 4KB boundary */ | |
232 | pciauto_region_align(pci_io, 0x1000); | |
233 | ||
234 | dm_pci_write_config8(dev, PCI_IO_BASE, | |
235 | (pci_io->bus_lower & 0x0000f000) >> 8); | |
236 | dm_pci_write_config16(dev, PCI_IO_BASE_UPPER16, | |
237 | (pci_io->bus_lower & 0xffff0000) >> 16); | |
238 | ||
239 | cmdstat |= PCI_COMMAND_IO; | |
240 | } | |
241 | ||
242 | /* Enable memory and I/O accesses, enable bus master */ | |
243 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); | |
244 | } | |
245 | ||
246 | void dm_pciauto_postscan_setup_bridge(struct udevice *dev, int sub_bus) | |
247 | { | |
248 | struct pci_region *pci_mem; | |
249 | struct pci_region *pci_prefetch; | |
250 | struct pci_region *pci_io; | |
251 | ||
252 | /* The root controller has the region information */ | |
253 | struct pci_controller *ctlr_hose = pci_bus_to_hose(0); | |
254 | ||
255 | pci_mem = ctlr_hose->pci_mem; | |
256 | pci_prefetch = ctlr_hose->pci_prefetch; | |
257 | pci_io = ctlr_hose->pci_io; | |
258 | ||
259 | /* Configure bus number registers */ | |
260 | dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, sub_bus); | |
261 | ||
262 | if (pci_mem) { | |
263 | /* Round memory allocator to 1MB boundary */ | |
264 | pciauto_region_align(pci_mem, 0x100000); | |
265 | ||
266 | dm_pci_write_config16(dev, PCI_MEMORY_LIMIT, | |
267 | (pci_mem->bus_lower - 1) >> 16); | |
268 | } | |
269 | ||
270 | if (pci_prefetch) { | |
271 | u16 prefechable_64; | |
272 | ||
273 | dm_pci_read_config16(dev, PCI_PREF_MEMORY_LIMIT, | |
274 | &prefechable_64); | |
275 | prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK; | |
276 | ||
277 | /* Round memory allocator to 1MB boundary */ | |
278 | pciauto_region_align(pci_prefetch, 0x100000); | |
279 | ||
280 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, | |
281 | (pci_prefetch->bus_lower - 1) >> 16); | |
282 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) | |
283 | #ifdef CONFIG_SYS_PCI_64BIT | |
284 | dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, | |
285 | (pci_prefetch->bus_lower - 1) >> 32); | |
286 | #else | |
287 | dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | |
288 | #endif | |
289 | } | |
290 | ||
291 | if (pci_io) { | |
292 | /* Round I/O allocator to 4KB boundary */ | |
293 | pciauto_region_align(pci_io, 0x1000); | |
294 | ||
295 | dm_pci_write_config8(dev, PCI_IO_LIMIT, | |
296 | ((pci_io->bus_lower - 1) & 0x0000f000) >> 8); | |
297 | dm_pci_write_config16(dev, PCI_IO_LIMIT_UPPER16, | |
298 | ((pci_io->bus_lower - 1) & 0xffff0000) >> 16); | |
299 | } | |
300 | } | |
301 | ||
302 | /* | |
303 | * HJF: Changed this to return int. I think this is required | |
304 | * to get the correct result when scanning bridges | |
305 | */ | |
306 | int dm_pciauto_config_device(struct udevice *dev) | |
307 | { | |
308 | struct pci_region *pci_mem; | |
309 | struct pci_region *pci_prefetch; | |
310 | struct pci_region *pci_io; | |
311 | unsigned int sub_bus = PCI_BUS(dm_pci_get_bdf(dev)); | |
312 | unsigned short class; | |
313 | bool enum_only = false; | |
314 | int n; | |
315 | ||
316 | #ifdef CONFIG_PCI_ENUM_ONLY | |
317 | enum_only = true; | |
318 | #endif | |
319 | /* The root controller has the region information */ | |
320 | struct pci_controller *ctlr_hose = pci_bus_to_hose(0); | |
321 | ||
322 | pci_mem = ctlr_hose->pci_mem; | |
323 | pci_prefetch = ctlr_hose->pci_prefetch; | |
324 | pci_io = ctlr_hose->pci_io; | |
325 | ||
326 | dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class); | |
327 | ||
328 | switch (class) { | |
329 | case PCI_CLASS_BRIDGE_PCI: | |
330 | debug("PCI Autoconfig: Found P2P bridge, device %d\n", | |
331 | PCI_DEV(dm_pci_get_bdf(dev))); | |
332 | ||
333 | dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io, | |
334 | enum_only); | |
335 | ||
336 | n = dm_pci_hose_probe_bus(dev); | |
337 | if (n < 0) | |
338 | return n; | |
339 | sub_bus = (unsigned int)n; | |
340 | break; | |
341 | ||
342 | case PCI_CLASS_BRIDGE_CARDBUS: | |
343 | /* | |
344 | * just do a minimal setup of the bridge, | |
345 | * let the OS take care of the rest | |
346 | */ | |
347 | dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io, | |
348 | enum_only); | |
349 | ||
350 | debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n", | |
351 | PCI_DEV(dm_pci_get_bdf(dev))); | |
352 | ||
353 | break; | |
354 | ||
355 | #if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE) | |
356 | case PCI_CLASS_BRIDGE_OTHER: | |
357 | debug("PCI Autoconfig: Skipping bridge device %d\n", | |
358 | PCI_DEV(dm_pci_get_bdf(dev))); | |
359 | break; | |
360 | #endif | |
361 | #if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349) | |
362 | case PCI_CLASS_BRIDGE_OTHER: | |
363 | /* | |
364 | * The host/PCI bridge 1 seems broken in 8349 - it presents | |
365 | * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_ | |
366 | * device claiming resources io/mem/irq.. we only allow for | |
367 | * the PIMMR window to be allocated (BAR0 - 1MB size) | |
368 | */ | |
369 | debug("PCI Autoconfig: Broken bridge found, only minimal config\n"); | |
370 | dm_pciauto_setup_device(dev, 0, hose->pci_mem, | |
371 | hose->pci_prefetch, hose->pci_io, | |
372 | enum_only); | |
373 | break; | |
374 | #endif | |
375 | ||
376 | case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ | |
377 | debug("PCI AutoConfig: Found PowerPC device\n"); | |
378 | ||
379 | default: | |
380 | dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io, | |
381 | enum_only); | |
382 | break; | |
383 | } | |
384 | ||
385 | return sub_bus; | |
386 | } |