1 /** @file
2 Implementation of Usb Controller PPI.
3 
4 Copyright (c) 2013-2015 Intel Corporation.
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include <PiPei.h>
17 #include <Ppi/UsbController.h>
18 #include <Library/DebugLib.h>
19 #include <Library/PeimEntryPoint.h>
20 #include <Library/PeiServicesLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/PciLib.h>
24 #include <Library/IoLib.h>
25 
26 #include "UsbPei.h"
27 
28 //
29 // Globals
30 //
31 //
32 
33 EFI_PEI_PPI_DESCRIPTOR mPpiList = {
34   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
35   &gPeiUsbControllerPpiGuid,
36   NULL
37 };
38 
39 UINTN mIohOhciPciReg[IOH_MAX_OHCI_USB_CONTROLLERS] = {
40   PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, 0)
41 };
42 
43 UINTN mIohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = {
44   PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0),
45 };
46 
47 /**
48   When EHCI get started in DXE, OHCI couldn't get the ownership
49   of roothub after warm reset because CF@EHCI hasn't been cleared.
50   We should clear that reg before UpdateBootMode. But Reg@EHCI is
51   memory-mapped, so need assume a range of space without conflict
52   in PCI memory space.
53 
54   @param[in]  PeiServices     The pointer of EFI_PEI_SERVICES
55 
56 **/
57 
58 VOID
SwitchConfigFlag(IN EFI_PEI_SERVICES ** PeiServices)59 SwitchConfigFlag (
60   IN EFI_PEI_SERVICES          **PeiServices
61   )
62 {
63   UINT32             SavBaseAddr;
64   UINT32             UsbBaseAddr;
65   UINT16             SaveCmdData;
66   UINT8              EhciCapLen;
67   UINT8              Index;
68   UsbBaseAddr = 0;
69 
70   for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++) {
71     UsbBaseAddr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress);
72     //
73     // Manage EHCI on IOH, set UsbBaseAddr
74     //
75     SavBaseAddr = PciRead32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR);
76     PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, UsbBaseAddr);
77     //
78     // Save Cmd register
79     //
80     SaveCmdData = PciRead16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND);
81     //
82     // Enable EHCI on IOH
83     //
84     PciOr16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, B_IOH_USB_COMMAND_BME | B_IOH_USB_COMMAND_MSE );
85     //
86     // Clear CF register on EHCI
87     //
88     EhciCapLen = MmioRead8 (UsbBaseAddr + R_IOH_EHCI_CAPLENGTH);
89     MmioWrite32 (UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS, 0);
90 
91     DEBUG ((EFI_D_INFO, "CF@EHCI = %x \n", UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS));
92     //
93     // Restore EHCI UsbBaseAddr in PCI space
94     //
95     PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, SavBaseAddr);
96     //
97     // Restore EHCI Command register in PCI space
98     //
99     PciWrite16(mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, SaveCmdData);
100   }
101 }
102 /**
103   Retrieved specified the USB controller information.
104 
105   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
106   @param  This                  This PEI_USB_CONTROLLER_PPI instance.
107   @param  UsbControllerId       Indicate which usb controller information will be retrieved.
108   @param  ControllerType        Indicate the controller is Ehci, Ohci, OHCI
109   @param  BaseAddress           Indicate the memory bar of the controller
110 
111   @retval EFI_SUCCESS           The reset operation succeeded.
112   @retval EFI_INVALID_PARAMETER Attributes is not valid.
113 
114 **/
115 
116 EFI_STATUS
GetOhciController(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_CONTROLLER_PPI * This,IN UINT8 UsbControllerId,IN UINTN * ControllerType,IN UINTN * BaseAddress)117 GetOhciController (
118   IN EFI_PEI_SERVICES               **PeiServices,
119   IN PEI_USB_CONTROLLER_PPI         *This,
120   IN UINT8                          UsbControllerId,
121   IN UINTN                          *ControllerType,
122   IN UINTN                          *BaseAddress
123   )
124 {
125   IOH_OHCI_DEVICE         *PeiIohOhciDev;
126 
127   PeiIohOhciDev = IOH_OHCI_DEVICE_FROM_THIS (This);
128 
129   if (UsbControllerId >= IOH_MAX_OHCI_USB_CONTROLLERS) {
130     return EFI_INVALID_PARAMETER;
131   }
132   *ControllerType = PEI_OHCI_CONTROLLER;
133   *BaseAddress = PeiIohOhciDev->MmioBase[UsbControllerId];
134 
135   return EFI_SUCCESS;
136 }
137 /**
138   Retrieved specified the USB controller information.
139 
140   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
141   @param  This                  This PEI_USB_CONTROLLER_PPI instance.
142   @param  UsbControllerId       Indicate which usb controller information will be retrieved.
143   @param  ControllerType        Indicate the controller is Ehci, Ohci, OHCI
144   @param  BaseAddress           Indicate the memory bar of the controller
145 
146   @retval EFI_SUCCESS           The reset operation succeeded.
147   @retval EFI_INVALID_PARAMETER Attributes is not valid.
148 
149 **/
150 
151 EFI_STATUS
GetEhciController(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_CONTROLLER_PPI * This,IN UINT8 UsbControllerId,IN UINTN * ControllerType,IN UINTN * BaseAddress)152 GetEhciController (
153   IN EFI_PEI_SERVICES               **PeiServices,
154   IN PEI_USB_CONTROLLER_PPI         *This,
155   IN UINT8                          UsbControllerId,
156   IN UINTN                          *ControllerType,
157   IN UINTN                          *BaseAddress
158   )
159 {
160   IOH_EHCI_DEVICE         *PeiIohEhciDev;
161 
162   PeiIohEhciDev = IOH_EHCI_DEVICE_FROM_THIS (This);
163 
164   if (UsbControllerId >= IOH_MAX_EHCI_USB_CONTROLLERS) {
165     return EFI_INVALID_PARAMETER;
166   }
167   *ControllerType = PEI_EHCI_CONTROLLER;
168   *BaseAddress = PeiIohEhciDev->MmioBase[UsbControllerId];
169 
170   return EFI_SUCCESS;
171 }
172 
173 /**
174   Retrieved specified the USB controller information.
175 
176   @param  IohOhciPciReg         Ohci device address list.
177   @param  OhciCount             The count of the OHCI
178   @param  IohEhciPciReg         Ehci device address list.
179   @param  EhciCount             The count of the EHCI
180 
181 **/
182 
183 VOID
EnableBusMaster(IN UINTN IohOhciPciReg[],IN UINT8 OhciCount,IN UINTN IohEhciPciReg[],IN UINT8 EhciCount)184 EnableBusMaster (
185   IN UINTN IohOhciPciReg[],
186   IN UINT8 OhciCount,
187   IN UINTN IohEhciPciReg[],
188   IN UINT8 EhciCount
189   )
190 {
191   UINT8  Index;
192   UINT16 CmdReg;
193   for (Index = 0; Index < OhciCount; Index ++) {
194     CmdReg = PciRead16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND);
195     CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
196     PciWrite16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
197   }
198   for (Index = 0; Index < EhciCount; Index ++) {
199     CmdReg = PciRead16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND);
200     CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );
201     PciWrite16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);
202   }
203 }
204 
205 PEI_USB_CONTROLLER_PPI mUsbControllerPpi[2] = { {GetOhciController}, {GetEhciController}};
206 
207 /**
208   @param  FileHandle  Handle of the file being invoked.
209   @param  PeiServices Describes the list of possible PEI Services.
210 
211   @retval EFI_SUCCESS            PPI successfully installed
212 
213 **/
214 EFI_STATUS
PeimInitializeIchUsb(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)215 PeimInitializeIchUsb (
216   IN       EFI_PEI_FILE_HANDLE  FileHandle,
217   IN CONST EFI_PEI_SERVICES     **PeiServices
218   )
219 {
220   EFI_STATUS              Status;
221   UINTN                   i;
222   EFI_PHYSICAL_ADDRESS    AllocateAddress;
223   IOH_OHCI_DEVICE         *PeiIohOhciDev;
224   IOH_EHCI_DEVICE         *PeiIohEhciDev;
225   UINT16                  CmdReg;
226 
227   Status = PeiServicesAllocatePages (
228              EfiBootServicesCode,
229              1,
230              &AllocateAddress
231              );
232   ASSERT_EFI_ERROR (Status);
233 
234   EnableBusMaster (
235     mIohOhciPciReg,
236     IOH_MAX_OHCI_USB_CONTROLLERS,
237     mIohEhciPciReg,
238     IOH_MAX_EHCI_USB_CONTROLLERS
239     );
240 
241   if (FeaturePcdGet (PcdEhciRecoveryEnabled)) {
242     DEBUG ((EFI_D_INFO, "UsbPei:EHCI is used for recovery\n"));
243     //
244     // EHCI recovery is enabled
245     //
246     PeiIohEhciDev = (IOH_EHCI_DEVICE *)((UINTN)AllocateAddress);
247     ZeroMem (PeiIohEhciDev, sizeof(IOH_EHCI_DEVICE));
248 
249     PeiIohEhciDev->Signature            = PEI_IOH_EHCI_SIGNATURE;
250     CopyMem(&(PeiIohEhciDev->UsbControllerPpi), &mUsbControllerPpi[1], sizeof(PEI_USB_CONTROLLER_PPI));
251     CopyMem(&(PeiIohEhciDev->PpiList), &mPpiList, sizeof(mPpiList));
252     PeiIohEhciDev->PpiList.Ppi          = &PeiIohEhciDev->UsbControllerPpi;
253 
254     //
255     // Assign resources and enable Ehci controllers
256     //
257     for (i = 0; i < IOH_MAX_EHCI_USB_CONTROLLERS; i++) {
258       DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth EHCI controller for recovery\n", i));
259       PeiIohEhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
260       //
261       // Assign base address register, Enable Bus Master and Memory Io
262       //
263       PciWrite32 (mIohEhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohEhciDev->MmioBase[i]);
264       CmdReg = PciRead16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND);
265       CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
266       PciWrite16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
267     }
268     //
269     // Install USB Controller PPI
270     //
271     Status = (**PeiServices).InstallPpi (
272                                PeiServices,
273                                &PeiIohEhciDev->PpiList
274                                );
275 
276     ASSERT_EFI_ERROR (Status);
277   } else {
278     DEBUG ((EFI_D_INFO, "UsbPei:OHCI is used for recovery\n"));
279     //
280     // OHCI recovery is enabled
281     //
282     SwitchConfigFlag ((EFI_PEI_SERVICES**)PeiServices);
283     PeiIohOhciDev = (IOH_OHCI_DEVICE *)((UINTN)AllocateAddress);
284     ZeroMem (PeiIohOhciDev, sizeof(IOH_OHCI_DEVICE));
285 
286     PeiIohOhciDev->Signature            = PEI_IOH_OHCI_SIGNATURE;
287     CopyMem(&(PeiIohOhciDev->UsbControllerPpi), &mUsbControllerPpi[0], sizeof(PEI_USB_CONTROLLER_PPI));
288     CopyMem(&(PeiIohOhciDev->PpiList), &mPpiList, sizeof(mPpiList));
289     PeiIohOhciDev->PpiList.Ppi          = &PeiIohOhciDev->UsbControllerPpi;
290     //
291     // Assign resources and enable OHCI controllers
292     //
293     for (i = 0; i < IOH_MAX_OHCI_USB_CONTROLLERS; i++) {
294       DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth OHCI controller for recovery\n", i));
295       PeiIohOhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;
296       //
297       // Assign base address register, Enable Bus Master and Memory Io
298       //
299       PciWrite32 (mIohOhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohOhciDev->MmioBase[i]);
300 
301       Status = PeiServicesAllocatePages (
302                  EfiBootServicesCode,
303                  1,
304                  &AllocateAddress
305                  );
306       ASSERT_EFI_ERROR (Status);
307       MmioWrite32(PeiIohOhciDev->MmioBase[i] + R_IOH_USB_OHCI_HCCABAR, (UINT32)AllocateAddress);
308 
309       CmdReg = PciRead16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND);
310       CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );
311       PciWrite16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);
312     }
313     //
314     // Install USB Controller PPI
315     //
316     Status = (**PeiServices).InstallPpi (
317                                PeiServices,
318                                &PeiIohOhciDev->PpiList
319                                );
320 
321     ASSERT_EFI_ERROR (Status);
322   }
323 
324   return Status;
325 }
326 
327