/******************************************************************************** Copyright (C) 2016 Marvell International Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent *******************************************************************************/ #include "UtmiPhyLib.h" typedef struct { EFI_PHYSICAL_ADDRESS UtmiPllAddr; EFI_PHYSICAL_ADDRESS UtmiBaseAddr; EFI_PHYSICAL_ADDRESS UsbCfgAddr; EFI_PHYSICAL_ADDRESS UtmiCfgAddr; UINT32 UtmiPhyPort; UINT32 PhyId; } UTMI_PHY_DATA; STATIC VOID RegSetSilent ( IN EFI_PHYSICAL_ADDRESS Addr, IN UINT32 Data, IN UINT32 Mask ) { UINT32 RegData; RegData = MmioRead32 (Addr); RegData &= ~Mask; RegData |= Data; MmioWrite32 (Addr, RegData); } STATIC VOID RegSet ( IN EFI_PHYSICAL_ADDRESS Addr, IN UINT32 Data, IN UINT32 Mask ) { DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)-\n", Addr, Data, Mask)); DEBUG((DEBUG_INFO, "old value = %10x ==>\n", MmioRead32 (Addr))); RegSetSilent (Addr, Data, Mask); DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr))); } STATIC VOID UtmiPhyPowerDown ( IN UINT32 UtmiIndex, IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, IN UINT32 UtmiPhyPort ) { UINT32 Mask, Data; DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power down transceiver(power down Phy)\n", UtmiIndex)); DEBUG((DEBUG_INFO, "UtmiPhy: stage: Power down PLL, and SuspendDM\n")); /* Power down UTMI PHY */ RegSet (UtmiCfgAddr, 0x0 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK); /* Config USB3 Device UTMI enable */ Mask = UTMI_USB_CFG_DEVICE_EN_MASK; /* * Prior to PHY init, configure mux for Device * (Device can be connected to UTMI0 or to UTMI1) */ if (UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) { Data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET; /* Config USB3 Device UTMI MUX */ Mask |= UTMI_USB_CFG_DEVICE_MUX_MASK; Data |= UtmiIndex << UTMI_USB_CFG_DEVICE_MUX_OFFSET; } else { Data = 0x0 << UTMI_USB_CFG_DEVICE_EN_OFFSET; } RegSet (UsbCfgAddr, Data, Mask); /* Set Test suspendm mode */ Mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK; Data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET; /* Enable Test UTMI select */ Mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK; Data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET; RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, Data, Mask); /* Wait for UTMI power down */ MicroSecondDelay (1000); } STATIC VOID UtmiPhyConfig ( IN UINT32 UtmiIndex, IN EFI_PHYSICAL_ADDRESS UtmiPllAddr, IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, IN UINT32 UtmiPhyPort ) { UINT32 Mask, Data; DEBUG((DEBUG_INFO, "UtmiPhy: stage: Configure UTMI PHY %d registers\n", UtmiIndex)); /* Reference Clock Divider Select */ Mask = UTMI_PLL_CTRL_REFDIV_MASK; Data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET; /* Feedback Clock Divider Select - 90 for 25Mhz */ Mask |= UTMI_PLL_CTRL_FBDIV_MASK; Data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET; /* Select LPFR - 0x0 for 25Mhz/5=5Mhz */ Mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK; Data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET; RegSet (UtmiPllAddr + UTMI_PLL_CTRL_REG, Data, Mask); /* Impedance Calibration Threshold Setting */ RegSet (UtmiPllAddr + UTMI_CALIB_CTRL_REG, 0x7 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET, UTMI_CALIB_CTRL_IMPCAL_VTH_MASK); /* Start Impedance and PLL Calibration */ Mask = UTMI_CALIB_CTRL_PLLCAL_START_MASK; Data = (0x1 << UTMI_CALIB_CTRL_PLLCAL_START_OFFSET); Mask |= UTMI_CALIB_CTRL_IMPCAL_START_MASK; Data |= (0x1 << UTMI_CALIB_CTRL_IMPCAL_START_OFFSET); RegSet (UtmiPllAddr + UTMI_CALIB_CTRL_REG, Data, Mask); /* Set LS TX driver strength coarse control */ Mask = UTMI_TX_CH_CTRL_DRV_EN_LS_MASK; Data = 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET; Mask |= UTMI_TX_CH_CTRL_AMP_MASK; Data |= 0x4 << UTMI_TX_CH_CTRL_AMP_OFFSET; Mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK; Data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET; RegSet (UtmiBaseAddr + UTMI_TX_CH_CTRL_REG, Data, Mask); /* Enable SQ */ Mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK; Data = 0x1 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET; /* Enable analog squelch detect */ Mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK; Data |= 0x0 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET; Mask |= UTMI_RX_CH_CTRL0_DISCON_THRESH_MASK; Data |= 0x0 << UTMI_RX_CH_CTRL0_DISCON_THRESH_OFFSET; RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL0_REG, Data, Mask); /* Set External squelch calibration number */ Mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK; Data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET; /* Enable the External squelch calibration */ Mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK; Data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET; RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL1_REG, Data, Mask); /* Set Control VDAT Reference Voltage - 0.325V */ Mask = UTMI_CHGDTC_CTRL_VDAT_MASK; Data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET; /* Set Control VSRC Reference Voltage - 0.6V */ Mask |= UTMI_CHGDTC_CTRL_VSRC_MASK; Data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET; RegSet (UtmiBaseAddr + UTMI_CHGDTC_CTRL_REG, Data, Mask); } STATIC UINTN UtmiPhyPowerUp ( IN UINT32 UtmiIndex, IN EFI_PHYSICAL_ADDRESS UtmiPllAddr, IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr, IN EFI_PHYSICAL_ADDRESS UsbCfgAddr, IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr, IN UINT32 UtmiPhyPort ) { EFI_STATUS Status; UINT32 Data; DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power up transceiver(Power up Phy)\n", UtmiIndex)); DEBUG((DEBUG_INFO, "UtmiPhy: stage: exit SuspendDM\n")); /* Power up UTMI PHY */ RegSet (UtmiCfgAddr, 0x1 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK); /* Disable Test UTMI select */ RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET, UTMI_CTRL_STATUS0_TEST_SEL_MASK); DEBUG((DEBUG_INFO, "UtmiPhy: stage: Wait for PLL and impedance calibration done, and PLL ready\n")); /* Delay 10ms */ MicroSecondDelay (10000); Data = MmioRead32 (UtmiPllAddr + UTMI_CALIB_CTRL_REG); if ((Data & UTMI_CALIB_CTRL_IMPCAL_DONE_MASK) == 0) { DEBUG((DEBUG_ERROR, "UtmiPhy: Impedance calibration is not done\n")); Status = EFI_D_ERROR; } if ((Data & UTMI_CALIB_CTRL_PLLCAL_DONE_MASK) == 0) { DEBUG((DEBUG_ERROR, "UtmiPhy: PLL calibration is not done\n")); Status = EFI_D_ERROR; } Data = MmioRead32 (UtmiPllAddr + UTMI_PLL_CTRL_REG); if ((Data & UTMI_PLL_CTRL_PLL_RDY_MASK) == 0) { DEBUG((DEBUG_ERROR, "UtmiPhy: PLL is not ready\n")); Status = EFI_D_ERROR; } return Status; } /* * Cp110UtmiPhyInit initializes the UTMI PHY * the init split in 3 parts: * 1. Power down transceiver and PLL * 2. UTMI PHY configure * 3. Power up transceiver and PLL */ STATIC VOID Cp110UtmiPhyInit ( IN UTMI_PHY_DATA *UtmiData ) { EFI_STATUS Status; UtmiPhyPowerDown (UtmiData->PhyId, UtmiData->UtmiBaseAddr, UtmiData->UsbCfgAddr, UtmiData->UtmiCfgAddr, UtmiData->UtmiPhyPort); /* Power down PLL */ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power down PLL\n")); MmioAnd32 (UtmiData->UsbCfgAddr, ~UTMI_USB_CFG_PLL_MASK); UtmiPhyConfig (UtmiData->PhyId, UtmiData->UtmiPllAddr, UtmiData->UtmiBaseAddr, UtmiData->UsbCfgAddr, UtmiData->UtmiCfgAddr, UtmiData->UtmiPhyPort); Status = UtmiPhyPowerUp (UtmiData->PhyId, UtmiData->UtmiPllAddr, UtmiData->UtmiBaseAddr, UtmiData->UsbCfgAddr, UtmiData->UtmiCfgAddr, UtmiData->UtmiPhyPort); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "UtmiPhy: Failed to initialize UTMI PHY %d\n", UtmiData->PhyId)); return; } DEBUG ((DEBUG_ERROR, "UTMI PHY %d initialized to ", UtmiData->PhyId)); if (UtmiData->UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) { DEBUG ((DEBUG_ERROR, "USB Device\n")); } else { DEBUG ((DEBUG_ERROR, "USB Host%d\n", UtmiData->UtmiPhyPort)); } /* Power up PLL */ DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power up PLL\n")); MmioOr32 (UtmiData->UsbCfgAddr, UTMI_USB_CFG_PLL_MASK); } EFI_STATUS UtmiPhyInit ( VOID ) { MARVELL_BOARD_DESC_PROTOCOL *BoardDescProtocol; MV_BOARD_UTMI_DESC *BoardDesc; UTMI_PHY_DATA UtmiData; EFI_STATUS Status; UINTN Index; /* Obtain board description */ Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid, NULL, (VOID **)&BoardDescProtocol); if (EFI_ERROR (Status)) { return Status; } Status = BoardDescProtocol->BoardDescUtmiGet (BoardDescProtocol, &BoardDesc); if (EFI_ERROR (Status)) { return Status; } /* Initialize enabled chips */ for (Index = 0; Index < BoardDesc->UtmiDevCount; Index++) { /* Get base address of UTMI phy */ UtmiData.UtmiBaseAddr = BoardDesc[Index].SoC->UtmiBaseAddress; /* Get base address of PLL registers */ UtmiData.UtmiPllAddr = BoardDesc[Index].SoC->UtmiPllAddress; /* Get usb config address */ UtmiData.UsbCfgAddr = BoardDesc[Index].SoC->UsbConfigAddress; /* Get UTMI config address */ UtmiData.UtmiCfgAddr = BoardDesc[Index].SoC->UtmiConfigAddress; /* Get UTMI PHY ID */ UtmiData.PhyId = BoardDesc[Index].SoC->UtmiPhyId; /* Get the usb port type */ UtmiData.UtmiPhyPort = BoardDesc[Index].UtmiPortType; /* Currently only Cp110 is supported */ Cp110UtmiPhyInit (&UtmiData); } BoardDescProtocol->BoardDescFree (BoardDesc); return EFI_SUCCESS; }