]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/PlatformDxe/PciDevice.c
Upload BSD-licensed Vlv2TbltDevicePkg and Vlv2DeviceRefCodePkg to
[mirror_edk2.git] / Vlv2TbltDevicePkg / PlatformDxe / PciDevice.c
1 /** @file
2
3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
4
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14 Module Name:
15
16
17 PciDevice.c
18
19 Abstract:
20
21 Platform Initialization Driver.
22
23 Revision History
24
25 --*/
26
27 #include "PlatformDxe.h"
28 #include "Library/DxeServicesTableLib.h"
29 #include "PciBus.h"
30 #include "Guid/PciLanInfo.h"
31
32 extern VOID *mPciLanInfo;
33 extern UINTN mPciLanCount;
34
35 extern EFI_HANDLE mImageHandle;
36 extern SYSTEM_CONFIGURATION mSystemConfiguration;
37
38
39 VOID *mPciRegistration;
40 #define NCR_VENDOR_ID 0x1000
41 #define ATI_VENDOR_ID 0x1002
42 #define INTEL_VENDOR_ID 0x8086
43 #define ATI_RV423_ID 0x5548
44 #define ATI_RV423_ID2 0x5d57
45 #define ATI_RV380_ID 0x3e50
46 #define ATI_RV370_ID 0x5b60
47 #define SI_VENDOR_ID 0x1095
48 #define SI_SISATA_ID 0x3114
49 #define SI_SIRAID_PCIUNL 0x40
50 #define INTEL_82573E_IDER 0x108D
51
52 typedef struct {
53 UINT8 ClassCode;
54 UINT8 SubClassCode;
55 UINT16 VendorId;
56 UINT16 DeviceId;
57 } BAD_DEVICE_TABLE;
58
59 BAD_DEVICE_TABLE BadDeviceTable[] = {
60 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_SCSI,(UINT16)NCR_VENDOR_ID, (UINT16)0xffff}, // Any NCR cards
61 {(UINT8)PCI_CLASS_MASS_STORAGE,(UINT8)PCI_CLASS_MASS_STORAGE_IDE,(UINT16)INTEL_VENDOR_ID, (UINT16)INTEL_82573E_IDER}, // Intel i82573E Tekoa GBit Lan IDE-R
62 {(UINT8)0xff,(UINT8)0xff,(UINT16)0xffff,(UINT16)0xffff}
63 };
64
65 EFI_STATUS
66 PciBusDriverHook (
67 )
68 {
69 EFI_STATUS Status;
70 EFI_EVENT FilterEvent;
71
72 //
73 // Register for callback to PCI I/O protocol
74 //
75 Status = gBS->CreateEvent (
76 EVT_NOTIFY_SIGNAL,
77 TPL_CALLBACK,
78 PciBusEvent,
79 NULL,
80 &FilterEvent
81 );
82 ASSERT_EFI_ERROR(Status);
83
84 //
85 // Register for protocol notifications on this event
86 //
87 Status = gBS->RegisterProtocolNotify (
88 &gEfiPciIoProtocolGuid,
89 FilterEvent,
90 &mPciRegistration
91 );
92 ASSERT_EFI_ERROR (Status);
93
94 return EFI_SUCCESS;
95 }
96
97 VOID
98 InitBadBars(
99 IN EFI_PCI_IO_PROTOCOL *PciIo,
100 IN UINT16 VendorId,
101 IN UINT16 DeviceId
102 )
103 {
104
105 EFI_STATUS Status;
106 PCI_IO_DEVICE *PciIoDevice;
107 UINT64 BaseAddress = 0;
108 UINT64 TempBaseAddress = 0;
109 UINT8 RevId = 0;
110 UINT32 Bar;
111 UINT64 IoSize;
112 UINT64 MemSize;
113 UINTN MemSizeBits;
114
115
116 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
117 switch ( VendorId) {
118 case ATI_VENDOR_ID:
119 //
120 // ATI fix-ups. At this time all ATI cards in BadDeviceTable
121 // have same problem in that OPROM BAR needs to be increased.
122 //
123 Bar = 0x30 ;
124 //
125 // Get original BAR address
126 //
127 Status = PciIo->Pci.Read (
128 PciIo,
129 EfiPciIoWidthUint32,
130 Bar,
131 1,
132 (VOID *) &BaseAddress
133 );
134 //
135 // Find BAR size
136 //
137 TempBaseAddress = 0xffffffff;
138 Status = PciIo->Pci.Write (
139 PciIo,
140 EfiPciIoWidthUint32,
141 Bar,
142 1,
143 (VOID *) &TempBaseAddress
144 );
145 Status = PciIo->Pci.Read (
146 PciIo,
147 EfiPciIoWidthUint32,
148 Bar,
149 1,
150 (VOID *) &TempBaseAddress
151 );
152 TempBaseAddress &= 0xfffffffe;
153 MemSize = 1;
154 while ((TempBaseAddress & 0x01) == 0) {
155 TempBaseAddress = TempBaseAddress >> 1;
156 MemSize = MemSize << 1;
157 }
158
159 //
160 // Free up allocated memory memory and re-allocate with increased size.
161 //
162 Status = gDS->FreeMemorySpace (
163 BaseAddress,
164 MemSize
165 );
166 //
167 // Force new alignment
168 //
169 MemSize = 0x8000000;
170 MemSizeBits = 28;
171
172 Status = gDS->AllocateMemorySpace (
173 EfiGcdAllocateAnySearchBottomUp,
174 EfiGcdMemoryTypeMemoryMappedIo,
175 MemSizeBits, // Alignment
176 MemSize,
177 &BaseAddress,
178 mImageHandle,
179 NULL
180 );
181 Status = PciIo->Pci.Write (
182 PciIo,
183 EfiPciIoWidthUint32,
184 Bar,
185 1,
186 (VOID *) &BaseAddress
187 );
188
189 break;
190 case NCR_VENDOR_ID:
191 #define MIN_NCR_IO_SIZE 0x800
192 #define NCR_GRAN 11 // 2**11 = 0x800
193 //
194 // NCR SCSI cards like 8250S lie about IO needed. Assign as least 0x80.
195 //
196 for (Bar = 0x10; Bar < 0x28; Bar+= 4) {
197
198 Status = PciIo->Pci.Read (
199 PciIo,
200 EfiPciIoWidthUint32,
201 Bar,
202 1,
203 (VOID *) &BaseAddress
204 );
205 if (BaseAddress && 0x01) {
206 TempBaseAddress = 0xffffffff;
207 Status = PciIo->Pci.Write (
208 PciIo,
209 EfiPciIoWidthUint32,
210 Bar,
211 1,
212 (VOID *) &TempBaseAddress
213 );
214 TempBaseAddress &= 0xfffffffc;
215 IoSize = 1;
216 while ((TempBaseAddress & 0x01) == 0) {
217 TempBaseAddress = TempBaseAddress >> 1;
218 IoSize = IoSize << 1;
219 }
220 if (IoSize < MIN_NCR_IO_SIZE) {
221 Status = gDS->FreeIoSpace (
222 BaseAddress,
223 IoSize
224 );
225
226 Status = gDS->AllocateIoSpace (
227 EfiGcdAllocateAnySearchTopDown,
228 EfiGcdIoTypeIo,
229 NCR_GRAN, // Alignment
230 MIN_NCR_IO_SIZE,
231 &BaseAddress,
232 mImageHandle,
233 NULL
234 );
235 TempBaseAddress = BaseAddress + 1;
236 Status = PciIo->Pci.Write (
237 PciIo,
238 EfiPciIoWidthUint32,
239 Bar,
240 1,
241 (VOID *) &TempBaseAddress
242 );
243 }
244 }
245 }
246
247 break;
248
249 case INTEL_VENDOR_ID:
250 if (DeviceId == INTEL_82573E_IDER) {
251 //
252 // Tekoa i82573E IDE-R fix-ups. At this time A2 step and earlier parts do not
253 // support any BARs except BAR0. Other BARS will actualy map to BAR0 so disable
254 // them all for Control Blocks and Bus mastering ops as well as Secondary IDE
255 // Controller.
256 // All Tekoa A2 or earlier step chips for now.
257 //
258 Status = PciIo->Pci.Read (
259 PciIo,
260 EfiPciIoWidthUint8,
261 PCI_REVISION_ID_OFFSET,
262 1,
263 &RevId
264 );
265 if (RevId <= 0x02) {
266 for (Bar = 0x14; Bar < 0x24; Bar+= 4) {
267 //
268 // Maybe want to clean this up a bit later but for now just clear out the secondary
269 // Bars don't worry aboyut freeing up thge allocs.
270 //
271 TempBaseAddress = 0x0;
272 Status = PciIo->Pci.Write (
273 PciIo,
274 EfiPciIoWidthUint32,
275 Bar,
276 1,
277 (VOID *) &TempBaseAddress
278 );
279 } // end for
280 }
281 else
282 {
283 //
284 //Tekoa A3 or above:
285 //Clear bus master base address (PCI register 0x20)
286 //since Tekoa does not fully support IDE Bus Mastering
287 //
288 TempBaseAddress = 0x0;
289 Status = PciIo->Pci.Write (
290 PciIo,
291 EfiPciIoWidthUint32,
292 0x20,
293 1,
294 (VOID *) &TempBaseAddress
295 );
296 }
297 }
298 break;
299
300 default:
301 break;
302 }
303 return;
304 }
305
306 VOID
307 ProgramPciLatency(
308 IN EFI_PCI_IO_PROTOCOL *PciIo
309 )
310 {
311 EFI_STATUS Status;
312
313 //
314 // Program Master Latency Timer
315 //
316 if (mSystemConfiguration.PciLatency != 0) {
317 Status = PciIo->Pci.Write (
318 PciIo,
319 EfiPciIoWidthUint8,
320 PCI_LATENCY_TIMER_OFFSET,
321 1,
322 &mSystemConfiguration.PciLatency
323 );
324 }
325 return;
326 }
327
328 /**
329 During S5 shutdown, we need to program PME in all LAN devices.
330 Here we identify LAN devices and save their bus/dev/func.
331
332 **/
333 VOID
334 SavePciLanAddress(
335 IN EFI_PCI_IO_PROTOCOL *PciIo
336 )
337 {
338 EFI_STATUS Status;
339 UINTN PciSegment,
340 PciBus,
341 PciDevice,
342 PciFunction;
343 VOID *NewBuffer;
344 PCI_LAN_INFO *x;
345
346 Status = PciIo->GetLocation (
347 PciIo,
348 &PciSegment,
349 &PciBus,
350 &PciDevice,
351 &PciFunction
352 );
353 if (EFI_ERROR (Status)) {
354 return;
355 }
356
357 mPciLanCount ++;
358 Status = gBS->AllocatePool (
359 EfiBootServicesData,
360 mPciLanCount * sizeof(PCI_LAN_INFO),
361 &NewBuffer
362 );
363 if (EFI_ERROR (Status)) {
364 return;
365 }
366
367 if (mPciLanCount > 1) {
368 //
369 // copy old data into new, larger buffer
370 //
371 gBS->CopyMem (
372 NewBuffer,
373 mPciLanInfo,
374 (mPciLanCount - 1) * sizeof(PCI_LAN_INFO)
375 );
376
377 //
378 // free the old memory buffer
379 //
380 gBS->FreePool (mPciLanInfo);
381
382 }
383
384 //
385 // init the new entry
386 //
387 x = (PCI_LAN_INFO *)NewBuffer + (mPciLanCount - 1);
388 x->PciBus = (UINT8)PciBus;
389 x->PciDevice = (UINT8)PciDevice;
390 x->PciFunction = (UINT8)PciFunction;
391
392 mPciLanInfo = NewBuffer;
393
394 return;
395 }
396
397 /**
398 @param Event the event that is signaled.
399 @param Context not used here.
400
401
402 **/
403 VOID
404 EFIAPI
405 PciBusEvent (
406 IN EFI_EVENT Event,
407 IN VOID* Context
408 )
409 {
410
411 EFI_STATUS Status;
412 UINTN BufferSize;
413 EFI_HANDLE Handle;
414 EFI_PCI_IO_PROTOCOL *PciIo;
415 PCI_IO_DEVICE *PciIoDevice;
416 UINT64 Supports;
417 UINTN Index;
418 UINT8 mCacheLineSize = 0x10;
419
420 while (TRUE) {
421 BufferSize = sizeof (EFI_HANDLE);
422 Status = gBS->LocateHandle (
423 ByRegisterNotify,
424 NULL,
425 mPciRegistration,
426 &BufferSize,
427 &Handle
428 );
429 if (EFI_ERROR (Status)) {
430 //
431 // If no more notification events exist
432 //
433 return;
434 }
435
436 Status = gBS->HandleProtocol (
437 Handle,
438 &gEfiPciIoProtocolGuid,
439 (void **)&PciIo
440 );
441
442 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
443
444 //
445 // Enable I/O for bridge so port 0x80 codes will come out
446 //
447 if (PciIoDevice->Pci.Hdr.VendorId == V_PCH_INTEL_VENDOR_ID)
448 {
449 Status = PciIo->Attributes(
450 PciIo,
451 EfiPciIoAttributeOperationSupported,
452 0,
453 &Supports
454 );
455 Supports &= EFI_PCI_DEVICE_ENABLE;
456 Status = PciIo->Attributes (
457 PciIo,
458 EfiPciIoAttributeOperationEnable,
459 Supports,
460 NULL
461 );
462 break;
463 }
464
465 //
466 // Program PCI Latency Timer
467 //
468 ProgramPciLatency(PciIo);
469
470 //
471 // Program Cache Line Size to 64 bytes (0x10 DWORDs)
472 //
473 Status = PciIo->Pci.Write (
474 PciIo,
475 EfiPciIoWidthUint8,
476 PCI_CACHELINE_SIZE_OFFSET,
477 1,
478 &mCacheLineSize
479 );
480
481 //
482 // If PCI LAN device, save bus/dev/func info
483 // so we can program PME during S5 shutdown
484 //
485 if (PciIoDevice->Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {
486 SavePciLanAddress(PciIo);
487 break;
488 }
489
490 //
491 // Workaround for cards with bad BARs
492 //
493 Index = 0;
494 while (BadDeviceTable[Index].ClassCode != 0xff) {
495 if (BadDeviceTable[Index].DeviceId == 0xffff) {
496 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) &&
497 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) &&
498 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId)) {
499 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId);
500 }
501 } else {
502 if ((PciIoDevice->Pci.Hdr.ClassCode[2] == BadDeviceTable[Index].ClassCode) &&
503 (PciIoDevice->Pci.Hdr.ClassCode[1] == BadDeviceTable[Index].SubClassCode) &&
504 (PciIoDevice->Pci.Hdr.VendorId == BadDeviceTable[Index].VendorId) &&
505 (PciIoDevice->Pci.Hdr.DeviceId == BadDeviceTable[Index].DeviceId)) {
506
507 InitBadBars(PciIo,BadDeviceTable[Index].VendorId,BadDeviceTable[Index].DeviceId);
508 }
509 }
510 ++Index;
511 }
512 break;
513 }
514
515 return;
516 }
517