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