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