]> git.proxmox.com Git - mirror_edk2.git/blame - BeagleBoardPkg/PciEmulation/PciEmulation.c
Missed a fix in the Cpu Driver. Added some more debug for Execption handling and...
[mirror_edk2.git] / BeagleBoardPkg / PciEmulation / PciEmulation.c
CommitLineData
2ef2b01e
A
1/** @file
2
3 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
4
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. 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
15#include "PciEmulation.h"
16#include <Omap3530/Omap3530.h>
17
18EFI_CPU_ARCH_PROTOCOL *gCpu;
19EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
20
21#define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44
22
23typedef struct {
24 ACPI_HID_DEVICE_PATH AcpiDevicePath;
25 PCI_DEVICE_PATH PciDevicePath;
26 EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
27} EFI_PCI_IO_DEVICE_PATH;
28
29typedef struct {
30 UINT32 Signature;
31 EFI_PCI_IO_DEVICE_PATH DevicePath;
32 EFI_PCI_IO_PROTOCOL PciIoProtocol;
33 PCI_TYPE00 *ConfigSpace;
34 PCI_ROOT_BRIDGE RootBridge;
35 UINTN Segment;
36} EFI_PCI_IO_PRIVATE_DATA;
37
38#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o')
39#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
40
41EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate =
42{
43 {
44 { ACPI_DEVICE_PATH, ACPI_DP, sizeof (ACPI_HID_DEVICE_PATH), 0},
45 EISA_PNP_ID(0x0A03), // HID
46 0 // UID
47 },
48 {
49 { HARDWARE_DEVICE_PATH, HW_PCI_DP, sizeof (PCI_DEVICE_PATH), 0},
50 0,
51 0
52 },
53 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
54};
55
56STATIC
57VOID
58ConfigureUSBHost (
59 VOID
60 )
61{
62 EFI_STATUS Status;
63 UINT8 Data = 0;
64
65 // Take USB host out of force-standby mode
66 MmioWrite32(UHH_SYSCONFIG, UHH_SYSCONFIG_MIDLEMODE_NO_STANDBY
67 | UHH_SYSCONFIG_CLOCKACTIVITY_ON
68 | UHH_SYSCONFIG_SIDLEMODE_NO_STANDBY
69 | UHH_SYSCONFIG_ENAWAKEUP_ENABLE
70 | UHH_SYSCONFIG_AUTOIDLE_ALWAYS_RUN);
71 MmioWrite32(UHH_HOSTCONFIG, UHH_HOSTCONFIG_P3_CONNECT_STATUS_DISCONNECT
72 | UHH_HOSTCONFIG_P2_CONNECT_STATUS_DISCONNECT
73 | UHH_HOSTCONFIG_P1_CONNECT_STATUS_DISCONNECT
74 | UHH_HOSTCONFIG_ENA_INCR_ALIGN_DISABLE
75 | UHH_HOSTCONFIG_ENA_INCR16_ENABLE
76 | UHH_HOSTCONFIG_ENA_INCR8_ENABLE
77 | UHH_HOSTCONFIG_ENA_INCR4_ENABLE
78 | UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN_ON
79 | UHH_HOSTCONFIG_P1_ULPI_BYPASS_ULPI_MODE);
80
81 // USB reset (GPIO 147 - Port 5 pin 19) output high
82 MmioAnd32(GPIO5_BASE + GPIO_OE, ~BIT19);
83 MmioWrite32(GPIO5_BASE + GPIO_SETDATAOUT, BIT19);
84
85 // Get the Power IC protocol.
86 Status = gBS->LocateProtocol(&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
87 ASSERT_EFI_ERROR(Status);
88
89 //Enable power to the USB host.
90 Status = gTPS65950->Read(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
91 ASSERT_EFI_ERROR(Status);
92
93 //LEDAON & LEDAPWM control the power to the USB host so enable those bits.
94 Data |= (LEDAON | LEDAPWM);
95
96 Status = gTPS65950->Write(gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID3, LEDEN), 1, &Data);
97 ASSERT_EFI_ERROR(Status);
98}
99
100EFI_STATUS
101PciIoPollMem (
102 IN EFI_PCI_IO_PROTOCOL *This,
103 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
104 IN UINT8 BarIndex,
105 IN UINT64 Offset,
106 IN UINT64 Mask,
107 IN UINT64 Value,
108 IN UINT64 Delay,
109 OUT UINT64 *Result
110 )
111{
112 ASSERT (FALSE);
113 return EFI_UNSUPPORTED;
114}
115
116EFI_STATUS
117PciIoPollIo (
118 IN EFI_PCI_IO_PROTOCOL *This,
119 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
120 IN UINT8 BarIndex,
121 IN UINT64 Offset,
122 IN UINT64 Mask,
123 IN UINT64 Value,
124 IN UINT64 Delay,
125 OUT UINT64 *Result
126 )
127{
128 ASSERT (FALSE);
129 return EFI_UNSUPPORTED;
130}
131
132EFI_STATUS
133PciIoMemRead (
134 IN EFI_PCI_IO_PROTOCOL *This,
135 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
136 IN UINT8 BarIndex,
137 IN UINT64 Offset,
138 IN UINTN Count,
139 IN OUT VOID *Buffer
140 )
141{
142 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
143
144 return PciRootBridgeIoMemRead (&Private->RootBridge.Io,
145 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
146 Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
147 Count,
148 Buffer
149 );
150}
151
152EFI_STATUS
153PciIoMemWrite (
154 IN EFI_PCI_IO_PROTOCOL *This,
155 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
156 IN UINT8 BarIndex,
157 IN UINT64 Offset,
158 IN UINTN Count,
159 IN OUT VOID *Buffer
160 )
161{
162 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
163
164 return PciRootBridgeIoMemWrite (&Private->RootBridge.Io,
165 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
166 Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
167 Count,
168 Buffer
169 );
170}
171
172EFI_STATUS
173PciIoIoRead (
174 IN EFI_PCI_IO_PROTOCOL *This,
175 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
176 IN UINT8 BarIndex,
177 IN UINT64 Offset,
178 IN UINTN Count,
179 IN OUT VOID *Buffer
180 )
181{
182 ASSERT (FALSE);
183 return EFI_UNSUPPORTED;
184}
185
186EFI_STATUS
187PciIoIoWrite (
188 IN EFI_PCI_IO_PROTOCOL *This,
189 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
190 IN UINT8 BarIndex,
191 IN UINT64 Offset,
192 IN UINTN Count,
193 IN OUT VOID *Buffer
194 )
195{
196 ASSERT (FALSE);
197 return EFI_UNSUPPORTED;
198}
199
200EFI_STATUS
201PciIoPciRead (
202 IN EFI_PCI_IO_PROTOCOL *This,
203 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
204 IN UINT32 Offset,
205 IN UINTN Count,
206 IN OUT VOID *Buffer
207 )
208{
209 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
210
211 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
212 Count,
213 TRUE,
214 (PTR)(UINTN)Buffer,
215 TRUE,
216 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
217 );
218}
219
220EFI_STATUS
221PciIoPciWrite (
222 IN EFI_PCI_IO_PROTOCOL *This,
223 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
224 IN UINT32 Offset,
225 IN UINTN Count,
226 IN OUT VOID *Buffer
227 )
228{
229 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
230
231 return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
232 Count,
233 TRUE,
234 (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
235 TRUE,
236 (PTR)(UINTN)Buffer
237 );
238}
239
240EFI_STATUS
241PciIoCopyMem (
242 IN EFI_PCI_IO_PROTOCOL *This,
243 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
244 IN UINT8 DestBarIndex,
245 IN UINT64 DestOffset,
246 IN UINT8 SrcBarIndex,
247 IN UINT64 SrcOffset,
248 IN UINTN Count
249 )
250{
251 ASSERT (FALSE);
252 return EFI_UNSUPPORTED;
253}
254
255EFI_STATUS
256PciIoMap (
257 IN EFI_PCI_IO_PROTOCOL *This,
258 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
259 IN VOID *HostAddress,
260 IN OUT UINTN *NumberOfBytes,
261 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
262 OUT VOID **Mapping
263 )
264{
265 MAP_INFO_INSTANCE *Map;
266 EFI_STATUS Status;
267
268 if ( HostAddress == NULL || NumberOfBytes == NULL ||
269 DeviceAddress == NULL || Mapping == NULL ) {
270
271 return EFI_INVALID_PARAMETER;
272 }
273
274
275 if (Operation >= EfiPciOperationMaximum) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 *DeviceAddress = ConvertToPhysicalAddress (HostAddress);
280
281 // Data cache flush (HostAddress, NumberOfBytes);
282
283 // Remember range so we can flush on the other side
284 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (PCI_DMA_MAP), (VOID **) &Map);
285 if (EFI_ERROR(Status)) {
286 return EFI_OUT_OF_RESOURCES;
287 }
288
289 *Mapping = Map;
290
291 Map->HostAddress = (UINTN)HostAddress;
292 Map->DeviceAddress = *DeviceAddress;
293 Map->NumberOfBytes = *NumberOfBytes;
294 Map->Operation = Operation;
295
296 // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate
297 gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);
298
299 return EFI_SUCCESS;
300}
301
302EFI_STATUS
303PciIoUnmap (
304 IN EFI_PCI_IO_PROTOCOL *This,
305 IN VOID *Mapping
306 )
307{
308 PCI_DMA_MAP *Map;
309
310 if (Mapping == NULL) {
311 ASSERT (FALSE);
312 return EFI_INVALID_PARAMETER;
313 }
314
315 Map = (PCI_DMA_MAP *)Mapping;
316 if (Map->Operation == EfiPciOperationBusMasterWrite) {
317 //
318 // Make sure we read buffer from uncached memory and not the cache
319 //
320 gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
d4f167a9 321 }
2ef2b01e
A
322
323 FreePool (Map);
324
325 return EFI_SUCCESS;
326}
327
328EFI_STATUS
329PciIoAllocateBuffer (
330 IN EFI_PCI_IO_PROTOCOL *This,
331 IN EFI_ALLOCATE_TYPE Type,
332 IN EFI_MEMORY_TYPE MemoryType,
333 IN UINTN Pages,
334 OUT VOID **HostAddress,
335 IN UINT64 Attributes
336 )
337{
338 if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
339 return EFI_UNSUPPORTED;
340 }
341
342 if (HostAddress == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 //
347 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
348 //
349 // We used uncached memory to keep coherency
350 //
351 if (MemoryType == EfiBootServicesData) {
352 *HostAddress = UncachedAllocatePages (Pages);
353 } else if (MemoryType != EfiRuntimeServicesData) {
354 *HostAddress = UncachedAllocateRuntimePages (Pages);
355 } else {
356 return EFI_INVALID_PARAMETER;
357 }
358
359 return EFI_SUCCESS;
360}
361
362EFI_STATUS
363PciIoFreeBuffer (
364 IN EFI_PCI_IO_PROTOCOL *This,
365 IN UINTN Pages,
366 IN VOID *HostAddress
367 )
368{
369 if (HostAddress == NULL) {
370 return EFI_INVALID_PARAMETER;
371 }
372
373 UncachedFreePages (HostAddress, Pages);
374 return EFI_SUCCESS;
375}
376
377
378EFI_STATUS
379PciIoFlush (
380 IN EFI_PCI_IO_PROTOCOL *This
381 )
382{
383 return EFI_SUCCESS;
384}
385
386EFI_STATUS
387PciIoGetLocation (
388 IN EFI_PCI_IO_PROTOCOL *This,
389 OUT UINTN *SegmentNumber,
390 OUT UINTN *BusNumber,
391 OUT UINTN *DeviceNumber,
392 OUT UINTN *FunctionNumber
393 )
394{
395 EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
396
397 if (SegmentNumber != NULL) {
398 *SegmentNumber = Private->Segment;
399 }
400
401 if (BusNumber != NULL) {
402 *BusNumber = 0xff;
403 }
404
405 if (DeviceNumber != NULL) {
406 *DeviceNumber = 0;
407 }
408
409 if (FunctionNumber != NULL) {
410 *FunctionNumber = 0;
411 }
412
413 return EFI_SUCCESS;
414}
415
416EFI_STATUS
417PciIoAttributes (
418 IN EFI_PCI_IO_PROTOCOL *This,
419 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
420 IN UINT64 Attributes,
421 OUT UINT64 *Result OPTIONAL
422 )
423{
424 switch (Operation) {
425 case EfiPciIoAttributeOperationGet:
426 case EfiPciIoAttributeOperationSupported:
427 if (Result == NULL) {
428 return EFI_INVALID_PARAMETER;
429 }
430 // We are not a real PCI device so just say things we kind of do
431 *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE;
432 break;
433
434 case EfiPciIoAttributeOperationSet:
435 case EfiPciIoAttributeOperationEnable:
436 case EfiPciIoAttributeOperationDisable:
437 // Since we are not a real PCI device no enable/set or disable operations exist.
438 return EFI_SUCCESS;
439 break;
440
441 default:
442 ASSERT (FALSE);
443 return EFI_INVALID_PARAMETER;
444 };
445 return EFI_SUCCESS;
446}
447
448EFI_STATUS
449PciIoGetBarAttributes (
450 IN EFI_PCI_IO_PROTOCOL *This,
451 IN UINT8 BarIndex,
452 OUT UINT64 *Supports, OPTIONAL
453 OUT VOID **Resources OPTIONAL
454 )
455{
456 ASSERT (FALSE);
457 return EFI_UNSUPPORTED;
458}
459
460EFI_STATUS
461PciIoSetBarAttributes (
462 IN EFI_PCI_IO_PROTOCOL *This,
463 IN UINT64 Attributes,
464 IN UINT8 BarIndex,
465 IN OUT UINT64 *Offset,
466 IN OUT UINT64 *Length
467 )
468{
469 ASSERT (FALSE);
470 return EFI_UNSUPPORTED;
471}
472
473EFI_PCI_IO_PROTOCOL PciIoTemplate =
474{
475 PciIoPollMem,
476 PciIoPollIo,
477 PciIoMemRead,
478 PciIoMemWrite,
479 PciIoIoRead,
480 PciIoIoWrite,
481 PciIoPciRead,
482 PciIoPciWrite,
483 PciIoCopyMem,
484 PciIoMap,
485 PciIoUnmap,
486 PciIoAllocateBuffer,
487 PciIoFreeBuffer,
488 PciIoFlush,
489 PciIoGetLocation,
490 PciIoAttributes,
491 PciIoGetBarAttributes,
492 PciIoSetBarAttributes,
493 0,
494 0
495};
496
497EFI_STATUS
498EFIAPI
499PciEmulationEntryPoint (
500 IN EFI_HANDLE ImageHandle,
501 IN EFI_SYSTEM_TABLE *SystemTable
502 )
503{
504 EFI_STATUS Status;
505 EFI_HANDLE Handle;
506 EFI_PCI_IO_PRIVATE_DATA *Private;
507 UINT8 CapabilityLength;
508 UINT8 PhysicalPorts;
509 UINTN Count;
510
511 // Get the Cpu protocol for later use
512 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
513 ASSERT_EFI_ERROR(Status);
514
515 //Configure USB host for OMAP3530.
516 ConfigureUSBHost();
517
518 // Create a private structure
519 Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
520 if (Private == NULL) {
521 Status = EFI_OUT_OF_RESOURCES;
522 return Status;
523 }
524
525 Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature
526 Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too
527 Private->RootBridge.MemoryStart = USB_EHCI_HCCAPBASE; // Get the USB capability register base
528 Private->Segment = 0; // Default to segment zero
529
530 // Find out the capability register length and number of physical ports.
531 CapabilityLength = MmioRead8(Private->RootBridge.MemoryStart);
532 PhysicalPorts = (MmioRead32(Private->RootBridge.MemoryStart + 0x4)) & 0x0000000F;
533
534 // Calculate the total size of the USB registers.
535 Private->RootBridge.MemorySize = CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1));
536
537 // Enable Port Power bit in Port status and control registers in EHCI register space.
538 // Port Power Control (PPC) bit in the HCSPARAMS register is already set which indicates
539 // host controller implementation includes port power control.
540 for (Count = 0; Count < PhysicalPorts; Count++) {
541 MmioOr32((Private->RootBridge.MemoryStart + CapabilityLength + HOST_CONTROLLER_OPERATION_REG_SIZE + 4*Count), 0x00001000);
542 }
543
544 // Create fake PCI config space.
545 Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
546 if (Private->ConfigSpace == NULL) {
547 Status = EFI_OUT_OF_RESOURCES;
548 FreePool(Private);
549 return Status;
550 }
551
552 // Configure PCI config space
553 Private->ConfigSpace->Hdr.VendorId = 0x3530;
554 Private->ConfigSpace->Hdr.DeviceId = 0x3530;
555 Private->ConfigSpace->Hdr.ClassCode[0] = 0x20;
556 Private->ConfigSpace->Hdr.ClassCode[1] = 0x03;
557 Private->ConfigSpace->Hdr.ClassCode[2] = 0x0C;
558 Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
559
560 Handle = NULL;
561
562 // Unique device path.
563 CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
564 Private->DevicePath.AcpiDevicePath.UID = 0;
565
566 // Copy protocol structure
567 CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
568
569 Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
570 &gEfiPciIoProtocolGuid, &Private->PciIoProtocol,
571 &gEfiDevicePathProtocolGuid, &Private->DevicePath,
572 NULL);
573 if (EFI_ERROR(Status)) {
574 DEBUG((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces() failed.\n"));
575 }
576
577 return Status;
578}
579