|
@@ -0,0 +1,275 @@
|
|
|
+/** @file
|
|
|
+
|
|
|
+ Copyright 2017, 2020 NXP
|
|
|
+
|
|
|
+ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+
|
|
|
+**/
|
|
|
+
|
|
|
+#include <Library/BaseLib.h>
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/IoLib.h>
|
|
|
+#include <Library/NonDiscoverableDeviceRegistrationLib.h>
|
|
|
+#include <Library/UefiBootServicesTableLib.h>
|
|
|
+
|
|
|
+#include "UsbHcd.h"
|
|
|
+
|
|
|
+STATIC
|
|
|
+VOID
|
|
|
+XhciSetBeatBurstLength (
|
|
|
+ IN UINTN UsbReg
|
|
|
+ )
|
|
|
+{
|
|
|
+ DWC3 *Dwc3Reg;
|
|
|
+
|
|
|
+ Dwc3Reg = (VOID *)(UsbReg + DWC3_REG_OFFSET);
|
|
|
+
|
|
|
+ MmioAndThenOr32 ((UINTN)&Dwc3Reg->GSBusCfg0, ~USB3_ENABLE_BEAT_BURST_MASK,
|
|
|
+ USB3_ENABLE_BEAT_BURST);
|
|
|
+
|
|
|
+ MmioOr32 ((UINTN)&Dwc3Reg->GSBusCfg1, USB3_SET_BEAT_BURST_LIMIT);
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+VOID
|
|
|
+Dwc3SetFladj (
|
|
|
+ IN DWC3 *Dwc3Reg,
|
|
|
+ IN UINT32 Val
|
|
|
+ )
|
|
|
+{
|
|
|
+ MmioOr32 ((UINTN)&Dwc3Reg->GFLAdj, GFLADJ_30MHZ_REG_SEL |
|
|
|
+ GFLADJ_30MHZ (Val));
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+VOID
|
|
|
+Dwc3SetMode (
|
|
|
+ IN DWC3 *Dwc3Reg,
|
|
|
+ IN UINT32 Mode
|
|
|
+ )
|
|
|
+{
|
|
|
+ MmioAndThenOr32 ((UINTN)&Dwc3Reg->GCtl,
|
|
|
+ ~(DWC3_GCTL_PRTCAPDIR (DWC3_GCTL_PRTCAP_OTG)),
|
|
|
+ DWC3_GCTL_PRTCAPDIR (Mode));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This function issues phy reset and core soft reset
|
|
|
+
|
|
|
+ @param Dwc3Reg Pointer to DWC3 register.
|
|
|
+
|
|
|
+**/
|
|
|
+STATIC
|
|
|
+VOID
|
|
|
+Dwc3CoreSoftReset (
|
|
|
+ IN DWC3 *Dwc3Reg
|
|
|
+ )
|
|
|
+{
|
|
|
+ //
|
|
|
+ // Put core in reset before resetting PHY
|
|
|
+ //
|
|
|
+ MmioOr32 ((UINTN)&Dwc3Reg->GCtl, DWC3_GCTL_CORESOFTRESET);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Assert USB2 PHY reset
|
|
|
+ //
|
|
|
+ MmioOr32 ((UINTN)&Dwc3Reg->GUsb3PipeCtl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Assert USB3 PHY reset
|
|
|
+ //
|
|
|
+ MmioOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg, DWC3_GUSB2PHYCFG_PHYSOFTRST);
|
|
|
+
|
|
|
+ MemoryFence ();
|
|
|
+
|
|
|
+ //
|
|
|
+ // Clear USB3 PHY reset
|
|
|
+ //
|
|
|
+ MmioAnd32 ((UINTN)&Dwc3Reg->GUsb3PipeCtl[0], ~DWC3_GUSB3PIPECTL_PHYSOFTRST);
|
|
|
+
|
|
|
+ //
|
|
|
+ // Clear USB2 PHY reset
|
|
|
+ //
|
|
|
+ MmioAnd32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg, ~DWC3_GUSB2PHYCFG_PHYSOFTRST);
|
|
|
+
|
|
|
+ MemoryFence ();
|
|
|
+
|
|
|
+ //
|
|
|
+ // Take core out of reset, PHYs are stable now
|
|
|
+ //
|
|
|
+ MmioAnd32 ((UINTN)&Dwc3Reg->GCtl, ~DWC3_GCTL_CORESOFTRESET);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This function performs low-level initialization of DWC3 Core
|
|
|
+
|
|
|
+ @param Dwc3Reg Pointer to DWC3 register.
|
|
|
+
|
|
|
+**/
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+Dwc3CoreInit (
|
|
|
+ IN DWC3 *Dwc3Reg
|
|
|
+ )
|
|
|
+{
|
|
|
+ UINT32 Revision;
|
|
|
+ UINT32 Reg;
|
|
|
+ UINTN Dwc3Hwparams1;
|
|
|
+
|
|
|
+ Revision = MmioRead32 ((UINTN)&Dwc3Reg->GSnpsId);
|
|
|
+ //
|
|
|
+ // This should read as 0x5533, ascii of U3(DWC_usb3) followed by revision num
|
|
|
+ //
|
|
|
+ if ((Revision & DWC3_GSNPSID_MASK) != DWC3_SYNOPSYS_ID) {
|
|
|
+ DEBUG ((DEBUG_ERROR,"This is not a DesignWare USB3 DRD Core.\n"));
|
|
|
+ return EFI_NOT_FOUND;
|
|
|
+ }
|
|
|
+
|
|
|
+ Dwc3CoreSoftReset (Dwc3Reg);
|
|
|
+
|
|
|
+ Reg = MmioRead32 ((UINTN)&Dwc3Reg->GCtl);
|
|
|
+ Reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
|
|
+ Reg &= ~DWC3_GCTL_DISSCRAMBLE;
|
|
|
+
|
|
|
+ Dwc3Hwparams1 = MmioRead32 ((UINTN)&Dwc3Reg->GHwParams1);
|
|
|
+
|
|
|
+ if (DWC3_GHWPARAMS1_EN_PWROPT (Dwc3Hwparams1) ==
|
|
|
+ DWC3_GHWPARAMS1_EN_PWROPT_CLK) {
|
|
|
+ Reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
|
|
+ } else {
|
|
|
+ DEBUG ((DEBUG_WARN,"No power optimization available.\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((Revision & DWC3_RELEASE_MASK) < DWC3_RELEASE_190a) {
|
|
|
+ Reg |= DWC3_GCTL_U2RSTECN;
|
|
|
+ }
|
|
|
+
|
|
|
+ MmioWrite32 ((UINTN)&Dwc3Reg->GCtl, Reg);
|
|
|
+
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+XhciCoreInit (
|
|
|
+ IN UINTN UsbReg
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ DWC3 *Dwc3Reg;
|
|
|
+
|
|
|
+ Dwc3Reg = (VOID *)(UsbReg + DWC3_REG_OFFSET);
|
|
|
+
|
|
|
+ Status = Dwc3CoreInit (Dwc3Reg);
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((DEBUG_ERROR, "Dwc3CoreInit Failed for controller 0x%x (0x%r) \n",
|
|
|
+ UsbReg, Status));
|
|
|
+
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ Dwc3SetMode (Dwc3Reg, DWC3_GCTL_PRTCAP_HOST);
|
|
|
+
|
|
|
+ Dwc3SetFladj (Dwc3Reg, GFLADJ_30MHZ_DEFAULT);
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|
|
|
+
|
|
|
+NON_DISCOVERABLE_DEVICE_INIT
|
|
|
+EFIAPI
|
|
|
+InitializeUsbController (
|
|
|
+ IN UINTN UsbReg
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+
|
|
|
+ Status = XhciCoreInit (UsbReg);
|
|
|
+
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((DEBUG_ERROR, "USB Controller init Failed for %d (0x%r)\n",
|
|
|
+ UsbReg, Status));
|
|
|
+ return (VOID *)EFI_DEVICE_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Change beat burst and outstanding pipelined transfers requests
|
|
|
+ //
|
|
|
+ XhciSetBeatBurstLength (UsbReg);
|
|
|
+
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ This function gets registered as a callback to perform USB controller intialization
|
|
|
+
|
|
|
+ @param Event Event whose notification function is being invoked.
|
|
|
+ @param Context Pointer to the notification function's context.
|
|
|
+
|
|
|
+**/
|
|
|
+VOID
|
|
|
+EFIAPI
|
|
|
+UsbEndOfDxeCallback (
|
|
|
+ IN EFI_EVENT Event,
|
|
|
+ IN VOID *Context
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ UINT32 NumUsbController;
|
|
|
+ UINT32 ControllerAddr;
|
|
|
+ UINT32 Index;
|
|
|
+
|
|
|
+ gBS->CloseEvent (Event);
|
|
|
+
|
|
|
+ NumUsbController = PcdGet32 (PcdNumUsbController);
|
|
|
+
|
|
|
+ for (Index = 0; Index < NumUsbController; Index++) {
|
|
|
+ ControllerAddr = PcdGet64 (PcdUsbBaseAddr) +
|
|
|
+ (Index * PcdGet32 (PcdUsbSize));
|
|
|
+
|
|
|
+ Status = RegisterNonDiscoverableMmioDevice (
|
|
|
+ NonDiscoverableDeviceTypeXhci,
|
|
|
+ NonDiscoverableDeviceDmaTypeNonCoherent,
|
|
|
+ InitializeUsbController (ControllerAddr),
|
|
|
+ NULL,
|
|
|
+ 1,
|
|
|
+ ControllerAddr, PcdGet32 (PcdUsbSize)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((DEBUG_ERROR, "Failed to register USB device 0x%x, error 0x%r \n",
|
|
|
+ ControllerAddr, Status));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ The Entry Point of module. It follows the standard UEFI driver model.
|
|
|
+
|
|
|
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
|
+ @param[in] SystemTable A pointer to the EFI System Table.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The entry point is executed successfully.
|
|
|
+ @retval other Some error occurs when executing this entry point.
|
|
|
+
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+InitializeUsbHcd (
|
|
|
+ IN EFI_HANDLE ImageHandle,
|
|
|
+ IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ EFI_EVENT EndOfDxeEvent;
|
|
|
+
|
|
|
+ Status = gBS->CreateEventEx (
|
|
|
+ EVT_NOTIFY_SIGNAL,
|
|
|
+ TPL_CALLBACK,
|
|
|
+ UsbEndOfDxeCallback,
|
|
|
+ NULL,
|
|
|
+ &gEfiEndOfDxeEventGroupGuid,
|
|
|
+ &EndOfDxeEvent
|
|
|
+ );
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|