]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
5e23b8b4 SG |
2 | /* |
3 | * PCI autoconfiguration library | |
4 | * | |
5 | * Author: Matt Porter <mporter@mvista.com> | |
6 | * | |
7 | * Copyright 2000 MontaVista Software Inc. | |
5e23b8b4 SG |
8 | */ |
9 | ||
10 | #include <common.h> | |
4439bc35 | 11 | #include <dm.h> |
5e23b8b4 SG |
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; | |
6796704b | 32 | struct pci_region *bar_res = NULL; |
5e23b8b4 SG |
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, | |
d71975ae TT |
101 | &bar_value, |
102 | found_mem64) == 0) { | |
5e23b8b4 SG |
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, | |
d71975ae TT |
144 | &bar_value, |
145 | false) == 0) { | |
5e23b8b4 SG |
146 | dm_pci_write_config32(dev, rom_addr, |
147 | bar_value); | |
148 | } | |
149 | cmdstat |= PCI_COMMAND_MEMORY; | |
150 | debug("\n"); | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | /* PCI_COMMAND_IO must be set for VGA device */ | |
156 | dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class); | |
157 | if (class == PCI_CLASS_DISPLAY_VGA) | |
158 | cmdstat |= PCI_COMMAND_IO; | |
159 | ||
160 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat); | |
161 | dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE, | |
162 | CONFIG_SYS_PCI_CACHE_LINE_SIZE); | |
163 | dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80); | |
164 | } | |
165 | ||
166 | void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) | |
167 | { | |
168 | struct pci_region *pci_mem; | |
169 | struct pci_region *pci_prefetch; | |
170 | struct pci_region *pci_io; | |
171 | u16 cmdstat, prefechable_64; | |
4439bc35 SG |
172 | struct udevice *ctlr = pci_get_controller(dev); |
173 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
174 | |
175 | pci_mem = ctlr_hose->pci_mem; | |
176 | pci_prefetch = ctlr_hose->pci_prefetch; | |
177 | pci_io = ctlr_hose->pci_io; | |
178 | ||
179 | dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); | |
180 | dm_pci_read_config16(dev, PCI_PREF_MEMORY_BASE, &prefechable_64); | |
181 | prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK; | |
182 | ||
183 | /* Configure bus number registers */ | |
184 | dm_pci_write_config8(dev, PCI_PRIMARY_BUS, | |
3977dcd5 ML |
185 | PCI_BUS(dm_pci_get_bdf(dev)) - ctlr->seq); |
186 | dm_pci_write_config8(dev, PCI_SECONDARY_BUS, sub_bus - ctlr->seq); | |
5e23b8b4 SG |
187 | dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, 0xff); |
188 | ||
189 | if (pci_mem) { | |
190 | /* Round memory allocator to 1MB boundary */ | |
191 | pciauto_region_align(pci_mem, 0x100000); | |
192 | ||
193 | /* | |
194 | * Set up memory and I/O filter limits, assume 32-bit | |
195 | * I/O space | |
196 | */ | |
197 | dm_pci_write_config16(dev, PCI_MEMORY_BASE, | |
198 | (pci_mem->bus_lower & 0xfff00000) >> 16); | |
199 | ||
200 | cmdstat |= PCI_COMMAND_MEMORY; | |
201 | } | |
202 | ||
203 | if (pci_prefetch) { | |
204 | /* Round memory allocator to 1MB boundary */ | |
205 | pciauto_region_align(pci_prefetch, 0x100000); | |
206 | ||
207 | /* | |
208 | * Set up memory and I/O filter limits, assume 32-bit | |
209 | * I/O space | |
210 | */ | |
211 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, | |
212 | (pci_prefetch->bus_lower & 0xfff00000) >> 16); | |
213 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) | |
214 | #ifdef CONFIG_SYS_PCI_64BIT | |
215 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, | |
216 | pci_prefetch->bus_lower >> 32); | |
217 | #else | |
218 | dm_pci_write_config32(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
219 | #endif | |
220 | ||
221 | cmdstat |= PCI_COMMAND_MEMORY; | |
222 | } else { | |
223 | /* We don't support prefetchable memory for now, so disable */ | |
224 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_BASE, 0x1000); | |
225 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, 0x0); | |
226 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) { | |
227 | dm_pci_write_config16(dev, PCI_PREF_BASE_UPPER32, 0x0); | |
228 | dm_pci_write_config16(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | |
229 | } | |
230 | } | |
231 | ||
232 | if (pci_io) { | |
233 | /* Round I/O allocator to 4KB boundary */ | |
234 | pciauto_region_align(pci_io, 0x1000); | |
235 | ||
236 | dm_pci_write_config8(dev, PCI_IO_BASE, | |
237 | (pci_io->bus_lower & 0x0000f000) >> 8); | |
238 | dm_pci_write_config16(dev, PCI_IO_BASE_UPPER16, | |
239 | (pci_io->bus_lower & 0xffff0000) >> 16); | |
240 | ||
241 | cmdstat |= PCI_COMMAND_IO; | |
242 | } | |
243 | ||
244 | /* Enable memory and I/O accesses, enable bus master */ | |
245 | dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); | |
246 | } | |
247 | ||
248 | void dm_pciauto_postscan_setup_bridge(struct udevice *dev, int sub_bus) | |
249 | { | |
250 | struct pci_region *pci_mem; | |
251 | struct pci_region *pci_prefetch; | |
252 | struct pci_region *pci_io; | |
4439bc35 SG |
253 | struct udevice *ctlr = pci_get_controller(dev); |
254 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
255 | |
256 | pci_mem = ctlr_hose->pci_mem; | |
257 | pci_prefetch = ctlr_hose->pci_prefetch; | |
258 | pci_io = ctlr_hose->pci_io; | |
259 | ||
260 | /* Configure bus number registers */ | |
3977dcd5 | 261 | dm_pci_write_config8(dev, PCI_SUBORDINATE_BUS, sub_bus - ctlr->seq); |
5e23b8b4 SG |
262 | |
263 | if (pci_mem) { | |
264 | /* Round memory allocator to 1MB boundary */ | |
265 | pciauto_region_align(pci_mem, 0x100000); | |
266 | ||
267 | dm_pci_write_config16(dev, PCI_MEMORY_LIMIT, | |
268 | (pci_mem->bus_lower - 1) >> 16); | |
269 | } | |
270 | ||
271 | if (pci_prefetch) { | |
272 | u16 prefechable_64; | |
273 | ||
274 | dm_pci_read_config16(dev, PCI_PREF_MEMORY_LIMIT, | |
275 | &prefechable_64); | |
276 | prefechable_64 &= PCI_PREF_RANGE_TYPE_MASK; | |
277 | ||
278 | /* Round memory allocator to 1MB boundary */ | |
279 | pciauto_region_align(pci_prefetch, 0x100000); | |
280 | ||
281 | dm_pci_write_config16(dev, PCI_PREF_MEMORY_LIMIT, | |
282 | (pci_prefetch->bus_lower - 1) >> 16); | |
283 | if (prefechable_64 == PCI_PREF_RANGE_TYPE_64) | |
284 | #ifdef CONFIG_SYS_PCI_64BIT | |
285 | dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, | |
286 | (pci_prefetch->bus_lower - 1) >> 32); | |
287 | #else | |
288 | dm_pci_write_config32(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | |
289 | #endif | |
290 | } | |
291 | ||
292 | if (pci_io) { | |
293 | /* Round I/O allocator to 4KB boundary */ | |
294 | pciauto_region_align(pci_io, 0x1000); | |
295 | ||
296 | dm_pci_write_config8(dev, PCI_IO_LIMIT, | |
297 | ((pci_io->bus_lower - 1) & 0x0000f000) >> 8); | |
298 | dm_pci_write_config16(dev, PCI_IO_LIMIT_UPPER16, | |
299 | ((pci_io->bus_lower - 1) & 0xffff0000) >> 16); | |
300 | } | |
301 | } | |
302 | ||
303 | /* | |
304 | * HJF: Changed this to return int. I think this is required | |
305 | * to get the correct result when scanning bridges | |
306 | */ | |
307 | int dm_pciauto_config_device(struct udevice *dev) | |
308 | { | |
309 | struct pci_region *pci_mem; | |
310 | struct pci_region *pci_prefetch; | |
311 | struct pci_region *pci_io; | |
312 | unsigned int sub_bus = PCI_BUS(dm_pci_get_bdf(dev)); | |
313 | unsigned short class; | |
314 | bool enum_only = false; | |
4439bc35 SG |
315 | struct udevice *ctlr = pci_get_controller(dev); |
316 | struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr); | |
5e23b8b4 SG |
317 | int n; |
318 | ||
319 | #ifdef CONFIG_PCI_ENUM_ONLY | |
320 | enum_only = true; | |
321 | #endif | |
5e23b8b4 SG |
322 | |
323 | pci_mem = ctlr_hose->pci_mem; | |
324 | pci_prefetch = ctlr_hose->pci_prefetch; | |
325 | pci_io = ctlr_hose->pci_io; | |
326 | ||
327 | dm_pci_read_config16(dev, PCI_CLASS_DEVICE, &class); | |
328 | ||
329 | switch (class) { | |
330 | case PCI_CLASS_BRIDGE_PCI: | |
331 | debug("PCI Autoconfig: Found P2P bridge, device %d\n", | |
332 | PCI_DEV(dm_pci_get_bdf(dev))); | |
333 | ||
334 | dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io, | |
335 | enum_only); | |
336 | ||
337 | n = dm_pci_hose_probe_bus(dev); | |
338 | if (n < 0) | |
339 | return n; | |
340 | sub_bus = (unsigned int)n; | |
341 | break; | |
342 | ||
343 | case PCI_CLASS_BRIDGE_CARDBUS: | |
344 | /* | |
345 | * just do a minimal setup of the bridge, | |
346 | * let the OS take care of the rest | |
347 | */ | |
348 | dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io, | |
349 | enum_only); | |
350 | ||
351 | debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n", | |
352 | PCI_DEV(dm_pci_get_bdf(dev))); | |
353 | ||
354 | break; | |
355 | ||
356 | #if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE) | |
357 | case PCI_CLASS_BRIDGE_OTHER: | |
358 | debug("PCI Autoconfig: Skipping bridge device %d\n", | |
359 | PCI_DEV(dm_pci_get_bdf(dev))); | |
360 | break; | |
361 | #endif | |
362 | #if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349) | |
363 | case PCI_CLASS_BRIDGE_OTHER: | |
364 | /* | |
365 | * The host/PCI bridge 1 seems broken in 8349 - it presents | |
366 | * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_ | |
367 | * device claiming resources io/mem/irq.. we only allow for | |
368 | * the PIMMR window to be allocated (BAR0 - 1MB size) | |
369 | */ | |
370 | debug("PCI Autoconfig: Broken bridge found, only minimal config\n"); | |
371 | dm_pciauto_setup_device(dev, 0, hose->pci_mem, | |
372 | hose->pci_prefetch, hose->pci_io, | |
373 | enum_only); | |
374 | break; | |
375 | #endif | |
376 | ||
377 | case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ | |
378 | debug("PCI AutoConfig: Found PowerPC device\n"); | |
f19345b5 | 379 | /* fall through */ |
5e23b8b4 SG |
380 | |
381 | default: | |
382 | dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io, | |
383 | enum_only); | |
384 | break; | |
385 | } | |
386 | ||
387 | return sub_bus; | |
388 | } |