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