]>
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> | |
4439bc35 | 12 | #include <dm.h> |
5e23b8b4 SG |
13 | #include <errno.h> |
14 | #include <pci.h> | |
15 | ||
16 | /* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */ | |
17 | #ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE | |
18 | #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8 | |
19 | #endif | |
20 | ||
21 | void dm_pciauto_setup_device(struct udevice *dev, int bars_num, | |
22 | struct pci_region *mem, | |
23 | struct pci_region *prefetch, struct pci_region *io, | |
24 | bool enum_only) | |
25 | { | |
26 | u32 bar_response; | |
27 | pci_size_t bar_size; | |
28 | u16 cmdstat = 0; | |
29 | int bar, bar_nr = 0; | |
30 | u8 header_type; | |
31 | int rom_addr; | |
32 | pci_addr_t bar_value; | |
6796704b | 33 | struct pci_region *bar_res = NULL; |
5e23b8b4 SG |
34 | int found_mem64 = 0; |
35 | u16 class; | |
36 | ||
37 | dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); | |
38 | cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | | |
39 | PCI_COMMAND_MASTER; | |
40 | ||
41 | for (bar = PCI_BASE_ADDRESS_0; | |
42 | bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) { | |
43 | /* Tickle the BAR and get the response */ | |
44 | if (!enum_only) | |
45 | dm_pci_write_config32(dev, bar, 0xffffffff); | |
46 | dm_pci_read_config32(dev, bar, &bar_response); | |
47 | ||
48 | /* If BAR is not implemented go to the next BAR */ | |
49 | if (!bar_response) | |
50 | continue; | |
51 | ||
52 | found_mem64 = 0; | |
53 | ||
54 | /* Check the BAR type and set our address mask */ | |
55 | if (bar_response & PCI_BASE_ADDRESS_SPACE) { | |
56 | bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK)) | |
57 | & 0xffff) + 1; | |
58 | if (!enum_only) | |
59 | bar_res = io; | |
60 | ||
61 | debug("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", | |
62 | bar_nr, (unsigned long long)bar_size); | |
63 | } else { | |
64 | if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == | |
65 | PCI_BASE_ADDRESS_MEM_TYPE_64) { | |
66 | u32 bar_response_upper; | |
67 | u64 bar64; | |
68 | ||
69 | if (!enum_only) { | |
70 | dm_pci_write_config32(dev, bar + 4, | |
71 | 0xffffffff); | |
72 | } | |
73 | dm_pci_read_config32(dev, bar + 4, | |
74 | &bar_response_upper); | |
75 | ||
76 | bar64 = ((u64)bar_response_upper << 32) | | |
77 | bar_response; | |
78 | ||
79 | bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) | |
80 | + 1; | |
81 | if (!enum_only) | |
82 | found_mem64 = 1; | |
83 | } else { | |
84 | bar_size = (u32)(~(bar_response & | |
85 | PCI_BASE_ADDRESS_MEM_MASK) + 1); | |
86 | } | |
87 | if (!enum_only) { | |
88 | if (prefetch && (bar_response & | |
89 | PCI_BASE_ADDRESS_MEM_PREFETCH)) { | |
90 | bar_res = prefetch; | |
91 | } else { | |
92 | bar_res = mem; | |
93 | } | |
94 | } | |
95 | ||
96 | debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ", | |
97 | bar_nr, bar_res == prefetch ? "Prf" : "Mem", | |
98 | (unsigned long long)bar_size); | |
99 | } | |
100 | ||
101 | if (!enum_only && pciauto_region_allocate(bar_res, bar_size, | |
102 | &bar_value) == 0) { | |
103 | /* Write it out and update our limit */ | |
104 | dm_pci_write_config32(dev, bar, (u32)bar_value); | |
105 | ||
106 | if (found_mem64) { | |
107 | bar += 4; | |
108 | #ifdef CONFIG_SYS_PCI_64BIT | |
109 | dm_pci_write_config32(dev, bar, | |
110 | (u32)(bar_value >> 32)); | |
111 | #else | |
112 | /* | |
113 | * If we are a 64-bit decoder then increment to | |
114 | * the upper 32 bits of the bar and force it to | |
115 | * locate in the lower 4GB of memory. | |
116 | */ | |
117 | dm_pci_write_config32(dev, bar, 0x00000000); | |
118 | #endif | |
119 | } | |
120 | } | |
121 | ||
122 | cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ? | |
123 | PCI_COMMAND_IO : PCI_COMMAND_MEMORY; | |
124 | ||
125 | debug("\n"); | |
126 | ||
127 | bar_nr++; | |
128 | } | |
129 | ||
130 | if (!enum_only) { | |
131 | /* Configure the expansion ROM address */ | |
132 | dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); | |
133 | header_type &= 0x7f; | |
134 | if (header_type != PCI_HEADER_TYPE_CARDBUS) { | |
135 | rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ? | |
136 | PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1; | |
137 | dm_pci_write_config32(dev, rom_addr, 0xfffffffe); | |
138 | dm_pci_read_config32(dev, rom_addr, &bar_response); | |
139 | if (bar_response) { | |
140 | bar_size = -(bar_response & ~1); | |
141 | debug("PCI Autoconfig: ROM, size=%#x, ", | |
142 | (unsigned int)bar_size); | |
143 | if (pciauto_region_allocate(mem, bar_size, | |
144 | &bar_value) == 0) { | |
145 | dm_pci_write_config32(dev, rom_addr, | |
146 | bar_value); | |
147 | } | |
148 | cmdstat |= PCI_COMMAND_MEMORY; | |
149 | debug("\n"); | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | /* PCI_COMMAND_IO must be set for VGA device */ | |
155 | dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class); | |
156 | if (class == PCI_CLASS_DISPLAY_VGA) | |
157 | cmdstat |= PCI_COMMAND_IO; | |
158 | ||
159 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat); | |
160 | dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE, | |
161 | CONFIG_SYS_PCI_CACHE_LINE_SIZE); | |
162 | dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80); | |
163 | } | |
164 | ||
165 | void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) | |
166 | { | |
167 | struct pci_region *pci_mem; | |
168 | struct pci_region *pci_prefetch; | |
169 | struct pci_region *pci_io; | |
170 | u16 cmdstat, prefechable_64; | |
4439bc35 SG |
171 | struct udevice *ctlr = pci_get_controller(dev); |
172 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
173 | |
174 | pci_mem = ctlr_hose->pci_mem; | |
175 | pci_prefetch = ctlr_hose->pci_prefetch; | |
176 | pci_io = ctlr_hose->pci_io; | |
177 | ||
178 | dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); | |
179 | dm_pci_read_config16(dev, PCI_PREF_MEMORY_BASE, &prefechable_64); | |
180 | prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK; | |
181 | ||
182 | /* Configure bus number registers */ | |
183 | dm_pci_write_config8(dev, PCI_PRIMARY_BUS, | |
184 | PCI_BUS(dm_pci_get_bdf(dev))); | |
185 | dm_pci_write_config8(dev, PCI_SECONDARY_BUS, sub_bus); | |
186 | dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, 0xff); | |
187 | ||
188 | if (pci_mem) { | |
189 | /* Round memory allocator to 1MB boundary */ | |
190 | pciauto_region_align(pci_mem, 0x100000); | |
191 | ||
192 | /* | |
193 | * Set up memory and I/O filter limits, assume 32-bit | |
194 | * I/O space | |
195 | */ | |
196 | dm_pci_write_config16(dev, PCI_MEMORY_BASE, | |
197 | (pci_mem->bus_lower & 0xfff00000) >> 16); | |
198 | ||
199 | cmdstat |= PCI_COMMAND_MEMORY; | |
200 | } | |
201 | ||
202 | if (pci_prefetch) { | |
203 | /* Round memory allocator to 1MB boundary */ | |
204 | pciauto_region_align(pci_prefetch, 0x100000); | |
205 | ||
206 | /* | |
207 | * Set up memory and I/O filter limits, assume 32-bit | |
208 | * I/O space | |
209 | */ | |
210 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, | |
211 | (pci_prefetch->bus_lower & 0xfff00000) >> 16); | |
212 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) | |
213 | #ifdef CONFIG_SYS_PCI_64BIT | |
214 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, | |
215 | pci_prefetch->bus_lower >> 32); | |
216 | #else | |
217 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
218 | #endif | |
219 | ||
220 | cmdstat |= PCI_COMMAND_MEMORY; | |
221 | } else { | |
222 | /* We don't support prefetchable memory for now, so disable */ | |
223 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, 0x1000); | |
224 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, 0x0); | |
225 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) { | |
226 | dm_pci_write_config16(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
227 | dm_pci_write_config16(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | |
228 | } | |
229 | } | |
230 | ||
231 | if (pci_io) { | |
232 | /* Round I/O allocator to 4KB boundary */ | |
233 | pciauto_region_align(pci_io, 0x1000); | |
234 | ||
235 | dm_pci_write_config8(dev, PCI_IO_BASE, | |
236 | (pci_io->bus_lower & 0x0000f000) >> 8); | |
237 | dm_pci_write_config16(dev, PCI_IO_BASE_UPPER16, | |
238 | (pci_io->bus_lower & 0xffff0000) >> 16); | |
239 | ||
240 | cmdstat |= PCI_COMMAND_IO; | |
241 | } | |
242 | ||
243 | /* Enable memory and I/O accesses, enable bus master */ | |
244 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); | |
245 | } | |
246 | ||
247 | void dm_pciauto_postscan_setup_bridge(struct udevice *dev, int sub_bus) | |
248 | { | |
249 | struct pci_region *pci_mem; | |
250 | struct pci_region *pci_prefetch; | |
251 | struct pci_region *pci_io; | |
4439bc35 SG |
252 | struct udevice *ctlr = pci_get_controller(dev); |
253 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
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; | |
4439bc35 SG |
314 | struct udevice *ctlr = pci_get_controller(dev); |
315 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
316 | int n; |
317 | ||
318 | #ifdef CONFIG_PCI_ENUM_ONLY | |
319 | enum_only = true; | |
320 | #endif | |
5e23b8b4 SG |
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"); | |
f19345b5 | 378 | /* fall through */ |
5e23b8b4 SG |
379 | |
380 | default: | |
381 | dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io, | |
382 | enum_only); | |
383 | break; | |
384 | } | |
385 | ||
386 | return sub_bus; | |
387 | } |