From: Olivier Martin Date: Thu, 24 Apr 2014 19:29:11 +0000 (+0000) Subject: EmbeddedPkg: Added Lan9118 Dxe driver X-Git-Tag: edk2-stable201903~11505 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=46f2c53b544438c735708abba5dc66f83fd2dc4f EmbeddedPkg: Added Lan9118 Dxe driver Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin Signed-off-by: Brendan Jackman git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15485 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c new file mode 100644 index 0000000000..fcaa351bf2 --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c @@ -0,0 +1,1356 @@ +/** @file +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "Lan9118Dxe.h" + + +typedef struct { + MAC_ADDR_DEVICE_PATH Lan9118; + EFI_DEVICE_PATH_PROTOCOL End; +} LAN9118_DEVICE_PATH; + +LAN9118_DEVICE_PATH Lan9118PathTemplate = { + { + { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, + { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) } + }, + { 0 }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } +}; + +/* +** Entry point for the LAN9118 driver +** +*/ +EFI_STATUS +Lan9118DxeEntry ( + IN EFI_HANDLE Handle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LAN9118_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + LAN9118_DEVICE_PATH *Lan9118Path; + EFI_HANDLE ControllerHandle; + + // The PcdLan9118DxeBaseAddress PCD must be defined + ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) != 0); + + // Allocate Resources + LanDriver = AllocateZeroPool (sizeof (LAN9118_DRIVER)); + if (LanDriver == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Lan9118Path = (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_DEVICE_PATH), &Lan9118PathTemplate); + if (Lan9118Path == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Initialize pointers + Snp = &(LanDriver->Snp); + SnpMode = &(LanDriver->SnpMode); + Snp->Mode = SnpMode; + + // Set the signature of the LAN Driver structure + LanDriver->Signature = LAN9118_SIGNATURE; + + // Assign fields and func pointers + Snp->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + Snp->WaitForPacket = NULL; + Snp->Initialize = SnpInitialize; + Snp->Start = SnpStart; + Snp->Stop = SnpStop; + Snp->Reset = SnpReset; + Snp->Shutdown = SnpShutdown; + Snp->ReceiveFilters = SnpReceiveFilters; + Snp->StationAddress = SnpStationAddress; + Snp->Statistics = SnpStatistics; + Snp->MCastIpToMac = SnpMcastIptoMac; + Snp->NvData = SnpNvData; + Snp->GetStatus = SnpGetStatus; + Snp->Transmit = SnpTransmit; + Snp->Receive = SnpReceive; + + // Start completing simple network mode structure + SnpMode->State = EfiSimpleNetworkStopped; + SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes + SnpMode->MediaHeaderSize = sizeof(ETHER_HEAD); // Not sure of this + SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes) + SnpMode->NvRamSize = 0; // No NVRAM with this device + SnpMode->NvRamAccessSize = 0; // No NVRAM with this device + + // Update network mode information + SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;/* | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;*/ + // Current allowed settings + SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses + SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; + SnpMode->MCastFilterCount = 0; + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS)); + + // Set the interface type (1: Ethernet or 6: IEEE 802 Networks) + SnpMode->IfType = NET_IFTYPE_ETHERNET; + + // Mac address is changeable as it is loaded from erasable memory + SnpMode->MacAddressChangeable = TRUE; + + // Can only transmit one packet at a time + SnpMode->MultipleTxSupported = FALSE; + + // MediaPresent checks for cable connection and partner link + SnpMode->MediaPresentSupported = TRUE; + SnpMode->MediaPresent = FALSE; + + // Set broadcast address + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + // Power up the device so we can find the MAC address + Status = Lan9118Initialize (Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Lan9118: Error initialising hardware\n")); + return EFI_DEVICE_ERROR; + } + + // Assign fields for device path + CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN); + Lan9118Path->Lan9118.IfType = Snp->Mode->IfType; + + // Initialise the protocol + ControllerHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, Snp, + &gEfiDevicePathProtocolGuid, Lan9118Path, + NULL + ); + // Say what the status of loading the protocol structure is + if (EFI_ERROR(Status)) { + FreePool (LanDriver); + } else { + LanDriver->ControllerHandle = ControllerHandle; + } + + return Status; +} + +/* + * UEFI Start() function + * + * Parameters: + * + * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + * + * Description: + * + * This function starts a network interface. If the network interface successfully starts, then + * EFI_SUCCESS will be returned. + */ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check state + if ((Snp->Mode->State == EfiSimpleNetworkStarted) || (Snp->Mode->State == EfiSimpleNetworkInitialized)) { + return EFI_ALREADY_STARTED; + } else if (Snp->Mode->State == EfiSimpleNetworkMaxState) { + return EFI_DEVICE_ERROR; + } + + // Change state + Snp->Mode->State = EfiSimpleNetworkStarted; + return EFI_SUCCESS; +} + +/* + * UEFI Stop() function + * + */ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check state of the driver + if ((Snp->Mode->State == EfiSimpleNetworkStopped) || (Snp->Mode->State == EfiSimpleNetworkMaxState)) { + return EFI_NOT_STARTED; + } + + // Stop the Tx and Rx + StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp); + StopRx (0, Snp); + + // Change the state + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + Snp->Mode->State = EfiSimpleNetworkStopped; + break; + default: + return EFI_DEVICE_ERROR; + } + + // Put the device into a power saving mode ? + return EFI_SUCCESS; +} + + +// Allocated receive and transmit buffers +STATIC UINT32 gTxBuffer = 0; + +/* + * UEFI Initialize() function + * + */ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + UINT32 PmConf; + INT32 AllocResult; + UINT32 RxStatusSize; + UINT32 TxStatusSize; + + // Initialize variables + // Global variables to hold tx and rx FIFO allocation + gTxBuffer = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkInitialized) { + DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n")); + return EFI_SUCCESS; + } else + if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethernet cable\n")); + return EFI_NOT_STARTED; + } + + // Initiate a software reset + Status = SoftReset (0, Snp); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Read the PM register + PmConf = MmioRead32 (LAN9118_PMT_CTRL); + + // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets + // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode + // MPTCTRL_PME_EN: Allow Power Management Events + PmConf = 0; + PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); + + // Write the current configuration to the register + MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + gBS->Stall (LAN9118_STALL); + gBS->Stall (LAN9118_STALL); + + // Configure GPIO and HW + Status = ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Assign the transmitter buffer size (default values) + TxStatusSize = LAN9118_TX_STATUS_SIZE; + RxStatusSize = LAN9118_RX_STATUS_SIZE; + + // Check that a buff size was specified + if (TxBufferSize > 0) { + if (RxBufferSize == 0) { + RxBufferSize = LAN9118_RX_DATA_SIZE; + } + + AllocResult = ChangeFifoAllocation ( + ALLOC_USE_FIFOS, + &TxBufferSize, + &RxBufferSize, + &TxStatusSize, + &RxStatusSize, + Snp + ); + + if (AllocResult < 0) { + return EFI_OUT_OF_RESOURCES; + } + } + + // Do auto-negotiation if supported + Status = AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_WARN, "Lan9118: Auto Negociation not supported.\n")); + } + + // Configure flow control depending on speed capabilities + Status = ConfigureFlow (0, 0, 0, 0, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Enable the receiver and transmitter + Status = StartRx (0, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = StartTx (START_TX_MAC | START_TX_CFG, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, ~0); + + // Declare the driver as initialized + Snp->Mode->State = EfiSimpleNetworkInitialized; + + return Status; +} + +/* + * UEFI Reset () function + * + */ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + UINT32 PmConf; + UINT32 HwConf; + UINT32 ResetFlags; + + PmConf = 0; + HwConf = 0; + ResetFlags = 0; + + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + if (PhySoftReset (PHY_RESET_PMT | PHY_RESET_CHECK_LINK, Snp) < 0) { + Snp->Mode->State = EfiSimpleNetworkStopped; + return EFI_NOT_STARTED; + } + + // Initiate a software reset + ResetFlags |= SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT; + + if (Verification) { + ResetFlags |= SOFT_RESET_SELF_TEST; + } + + if (SoftReset (ResetFlags, Snp) < 0) { + DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Read the PM register + PmConf = MmioRead32 (LAN9118_PMT_CTRL); + + // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic packets + // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumption mode + // MPTCTRL_PME_EN: Allow Power Management Events + PmConf |= (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); + + // Write the current configuration to the register + MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + gBS->Stall (LAN9118_STALL); + + // Check that a buffer size was specified in SnpInitialize + if (gTxBuffer != 0) { + HwConf = MmioRead32 (LAN9118_HW_CFG); // Read the HW register + HwConf &= ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits first + HwConf |= HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen in SnpInitialize + + MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf + gBS->Stall (LAN9118_STALL); + } + + // Enable the receiver and transmitter and clear their contents + StartRx (START_RX_CLEAR, Snp); + StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp); + + // Now acknowledge all interrupts + MmioWrite32 (LAN9118_INT_STS, ~0); + + return EFI_SUCCESS; +} + +/* + * UEFI Shutdown () function + * + */ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + // Check Snp Instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + PhySoftReset (PHY_RESET_PMT, Snp); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/* + * UEFI ReceiveFilters() function + * + */ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN Reset, + IN UINTN NumMfilter OPTIONAL, + IN EFI_MAC_ADDRESS *Mfilter OPTIONAL + ) +{ + UINT32 MacCSRValue; + UINT32 MultHashTableHigh; + UINT32 MultHashTableLow; + UINT32 Crc; + UINT8 BitToSelect; + UINT32 Count; + + MacCSRValue = 0; + MultHashTableHigh = 0; + MultHashTableLow = 0; + Crc = 0xFFFFFFFF; + BitToSelect = 0; + Count = 0; + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // If reset then clear the filter registers + if (Reset) { + Enable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, 0x00000000); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, 0x00000000); + } + + // Set the hash tables + if ((NumMfilter > 0) && (!Reset)) { + + // Read the Multicast High Hash Table + MultHashTableHigh = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); + + // Read the Multicast Low Hash Table + MultHashTableLow = IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + + // Go through each filter address and set appropriate bits on hash table + for (Count = 0; Count < NumMfilter; Count++) { + + // Generate a 32-bit CRC for Ethernet + Crc = GenEtherCrc32 (&Mfilter[Count],6); + //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't work as desired + + // Get the most significant 6 bits to index hash registers + BitToSelect = (Crc >> 26) & 0x3F; + + // Select hashlow register if MSB is not set + if ((BitToSelect & 0x20) == 0) { + MultHashTableLow |= (1 << BitToSelect); + } else { + MultHashTableHigh |= (1 << (BitToSelect & 0x1F)); + } + } + + // Write the desired hash + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + } + + // Read MAC controller + MacCSRValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + // Set the options for the MAC_CSR + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + StartRx (0, Snp); + DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + StopRx (0, Snp); + DEBUG ((DEBUG_NET, "Disabling Unicast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacCSRValue |= MACCR_HPFILT; + DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacCSRValue &= ~MACCR_HPFILT; + DEBUG ((DEBUG_NET, "Disabling Multicast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + MacCSRValue &= ~(MACCR_BCAST); + DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) { + MacCSRValue |= MACCR_BCAST; + DEBUG ((DEBUG_NET, "Disabling Broadcast Frame Reception\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacCSRValue |= MACCR_PRMS; + DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacCSRValue &= ~MACCR_PRMS; + DEBUG ((DEBUG_NET, "Disabling Promiscuous Mode\n")); + } + + if (Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacCSRValue |= (MACCR_HPFILT | MACCR_PRMS); + DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n")); + } + + if (Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacCSRValue &= ~(MACCR_HPFILT | MACCR_PRMS); + DEBUG ((DEBUG_NET, "Disabling Promiscuous Multicast Mode\n")); + } + + // Write the options to the MAC_CSR + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue); + gBS->Stall (LAN9118_STALL); + + return EFI_SUCCESS; +} + +/* + * UEFI StationAddress() function + * + */ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + DEBUG ((DEBUG_NET, "SnpStationAddress()\n")); + + UINT32 Count; + UINT8 PermAddr[6]; + UINT64 DefaultMacAddress; + + Count = 0; + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Get the Permanent MAC address if need reset + if (Reset) { + // Try using EEPROM first. Read the first byte of data from EEPROM at the address 0x0 + if ((IndirectEEPROMRead32 (0) & 0xFF) == EEPROM_EXTERNAL_SERIAL_EEPROM) { + for (Count = 1; Count < 7; Count++) { + PermAddr[Count - 1] = IndirectEEPROMRead32 (Count); + } + + // Write address + Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp); + } else { + DEBUG ((EFI_D_ERROR, "Lan9118: Warning: No valid MAC address in EEPROM, using fallback\n")); + DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress); + Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp); + } + } else { + // Otherwise use the specified new MAC address + if (NewMac == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Write address + Lan9118SetMacAddress (NewMac, Snp); + } + + return EFI_SUCCESS; +} + +/* + * UEFI Statistics() function + * + */ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + LAN9118_DRIVER *LanDriver; + + LanDriver = INSTANCE_FROM_SNP_THIS (Snp); + + DEBUG ((DEBUG_NET, "SnpStatistics()\n")); + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Check pointless condition + if ((!Reset) && (StatSize == NULL) && (Statistics == NULL)) { + return EFI_SUCCESS; + } + + // Check the parameters + if ((StatSize == NULL) && (Statistics != NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Do a reset if required + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // Check buffer size + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize = sizeof(EFI_NETWORK_STATISTICS); + return EFI_BUFFER_TOO_SMALL; + } + + // Fill in the statistics + CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + + return EFI_SUCCESS; +} + +/* + * UEFI MCastIPtoMAC() function + * + */ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n")); + + // Check Snp instance + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State == EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State == EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Check parameters + if ((McastMac == NULL) || (Ip == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure MAC address is empty + ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS)); + + // If we need ipv4 address + if (!IsIpv6) { + // Most significant 25 bits of a multicast HW address are set. + // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112) + McastMac->Addr[0] = 0x01; + McastMac->Addr[1] = 0x00; + McastMac->Addr[2] = 0x5E; + + // Lower 23 bits from ipv4 address + McastMac->Addr[3] = (Ip->v4.Addr[1] & 0x7F); // Clear the most significant bit (25th bit of MAC must be 0) + McastMac->Addr[4] = Ip->v4.Addr[2]; + McastMac->Addr[5] = Ip->v4.Addr[3]; + } else { + // Most significant 16 bits of multicast v6 HW address are set + // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464) + McastMac->Addr[0] = 0x33; + McastMac->Addr[1] = 0x33; + + // lower four octets are taken from ipv6 address + McastMac->Addr[2] = Ip->v6.Addr[8]; + McastMac->Addr[3] = Ip->v6.Addr[9]; + McastMac->Addr[4] = Ip->v6.Addr[10]; + McastMac->Addr[5] = Ip->v6.Addr[11]; + } + + return EFI_SUCCESS; +} + +/* + * UEFI NvData() function + * + */ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ) +{ + DEBUG ((DEBUG_NET, "SnpNvData()\n")); + + return EFI_UNSUPPORTED; +} + + +/* + * UEFI GetStatus () function + * + */ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + UINT32 FifoInt; + EFI_STATUS Status; + UINTN NumTxStatusEntries; + UINT32 TxStatus; + UINT16 PacketTag; + UINT32 Interrupts; + LAN9118_DRIVER *LanDriver; + + LanDriver = INSTANCE_FROM_SNP_THIS (Snp); + + // Check preliminaries + if (Snp == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + return EFI_NOT_STARTED; + } + + // Check and acknowledge TX Status interrupt (this will happen if the + // consumer of SNP does not call GetStatus.) + // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we + // should check for it and dump the TX Status FIFO. + FifoInt = MmioRead32 (LAN9118_FIFO_INT); + + // Clear the TX Status FIFO Overflow + if ((FifoInt & INSTS_TXSO) == 0) { + FifoInt |= INSTS_TXSO; + MmioWrite32 (LAN9118_FIFO_INT, FifoInt); + } + + // Read interrupt status if IrqStat is not NULL + if (IrqStat != NULL) { + + // Check for receive interrupt + if (MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved from rx FIFO + *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); + } else { + *IrqStat &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } + + // Check for transmit interrupt + if (MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) { + *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); + } else { + *IrqStat &= ~EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + + // Check for software interrupt + if (MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) { + *IrqStat |= EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); + } else { + *IrqStat &= ~EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + } + } + + // Check Status of transmitted packets + // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex) + + NumTxStatusEntries = MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOINF_TXSUSED_MASK; + if (NumTxStatusEntries > 0) { + TxStatus = MmioRead32 (LAN9118_TX_STATUS); + PacketTag = TxStatus >> 16; + TxStatus = TxStatus & 0xFFFF; + if ((TxStatus & TXSTATUS_ES) && TxStatus != (TXSTATUS_ES | TXSTATUS_NO_CA)) { + DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxStatus=0x%08x:", TxStatus)); + if (TxStatus & TXSTATUS_NO_CA) { + DEBUG ((EFI_D_ERROR, "- No carrier\n")); + } + if (TxStatus & TXSTATUS_DEF) { + DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n")); + } + if (TxStatus & TXSTATUS_EDEF) { + DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n")); + } + if (TxStatus & TXSTATUS_ECOLL) { + DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n")); + } + if (TxStatus & TXSTATUS_LCOLL) { + DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 bytes\n")); + } + if (TxStatus & TXSTATUS_LOST_CA) { + DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n")); + } + return EFI_DEVICE_ERROR; + } else { + LanDriver->Stats.TxTotalFrames += 1; + *TxBuff = LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES]; + } + } + + // Check for a TX Error interrupt + Interrupts = MmioRead32 (LAN9118_INT_STS); + if (Interrupts & INSTS_TXE) { + DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting...")); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Acknowledge the TXE + MmioWrite32 (LAN9118_INT_STS, INSTS_TXE); + gBS->Stall (LAN9118_STALL); + + // Restart the transmitter + StartTx (START_TX_MAC | START_TX_CFG, Snp); + } + + // Update the media status + Status = CheckLinkStatus (0, Snp); + if (EFI_ERROR(Status)) { + Snp->Mode->MediaPresent = FALSE; + } else { + Snp->Mode->MediaPresent = TRUE; + } + + return EFI_SUCCESS; +} + + +/* + * UEFI Transmit() function + * + */ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN HdrSize, + IN UINTN BuffSize, + IN VOID* Data, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 TxFreeSpace; + UINT32 TxStatusSpace; + INT32 Count; + UINT32 CommandA; + UINT32 CommandB; + UINT16 LocalProtocol; + UINT32 *LocalData; + UINT16 PacketTag; + +#if defined(EVAL_PERFORMANCE) + UINT64 Perf; + UINT64 StartClock; + UINT64 EndClock; + + Perf = GetPerformanceCounterProperties (NULL, NULL); + StartClock = GetPerformanceCounter (); +#endif + + LanDriver = INSTANCE_FROM_SNP_THIS (Snp); + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + return EFI_NOT_STARTED; + } + + // Ensure header is correct size if non-zero + if (HdrSize) { + if (HdrSize != Snp->Mode->MediaHeaderSize) { + return EFI_INVALID_PARAMETER; + } + + if ((DstAddr == NULL) || (Protocol == NULL)) { + return EFI_INVALID_PARAMETER; + } + } + + // Before transmitting check the link status + /*if (CheckLinkStatus (0, Snp) < 0) { + return EFI_NOT_READY; + }*/ + + // Get DATA FIFO free space in bytes + TxFreeSpace = TxDataFreeSpace (0, Snp); + if (TxFreeSpace < BuffSize) { + return EFI_NOT_READY; + } + + // Get STATUS FIFO used space in bytes + TxStatusSpace = TxStatusUsedSpace (0, Snp); + if (TxStatusSpace > 500) { + return EFI_NOT_READY; + } + + // If DstAddr is not provided, get it from Buffer (we trust that the caller + // has provided a well-formed frame). + if (DstAddr == NULL) { + DstAddr = (EFI_MAC_ADDRESS *) Data; + } + + // Check for the nature of the frame + if ((DstAddr->Addr[0] & 0x1) == 1) { + LanDriver->Stats.TxMulticastFrames += 1; + } else { + LanDriver->Stats.TxUnicastFrames += 1; + } + + // Check if broadcast + if (DstAddr->Addr[0] == 0xFF) { + LanDriver->Stats.TxBroadcastFrames += 1; + } + + PacketTag = LanDriver->NextPacketTag; + LanDriver->NextPacketTag++; + + if (HdrSize) { + + // Format pointer + LocalData = (UINT32*) Data; + LocalProtocol = *Protocol; + + // Create first buffer to pass to controller (for the header) + CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize); + CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the destination address + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[0]) | + (DstAddr->Addr[1] << 8) | + (DstAddr->Addr[2] << 16) | + (DstAddr->Addr[3] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[4]) | + (DstAddr->Addr[5] << 8) | + (SrcAddr->Addr[0] << 16) | // Write the Source Address + (SrcAddr->Addr[1] << 24) + ); + + MmioWrite32 (LAN9118_TX_DATA, + (SrcAddr->Addr[2]) | + (SrcAddr->Addr[3] << 8) | + (SrcAddr->Addr[4] << 16) | + (SrcAddr->Addr[5] << 24) + ); + + // Write the Protocol + MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol))); + + // Next buffer is the payload + CommandA = TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize - HdrSize) | TX_CMD_A_COMPLETION_INT | TX_CMD_A_DATA_START_OFFSET (2); // 2 bytes beginning offset + + // Write the commands + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the payload + for (Count = 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]); + } + } else { + // Format pointer + LocalData = (UINT32*) Data; + + // Create a buffer to pass to controller + CommandA = TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT; + CommandB = TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH (BuffSize); + + // Write the commands first + MmioWrite32 (LAN9118_TX_DATA, CommandA); + MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write all the data + for (Count = 0; Count < ((BuffSize + 3) >> 2); Count++) { + MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]); + } + } + + // Save the address of the submitted packet so we can notify the consumer that + // it has been sent in GetStatus. When the packet tag appears in the Tx Status + // Fifo, we will return Buffer in the TxBuff parameter of GetStatus. + LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] = Data; + +#if defined(EVAL_PERFORMANCE) + EndClock = GetPerformanceCounter (); + DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf)); +#endif + + LanDriver->Stats.TxGoodFrames += 1; + + return EFI_SUCCESS; +} + + +/* + * UEFI Receive() function + * + */ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BuffSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 RxFifoStatus; + UINT32 NumPackets; + UINT32 RxCfgValue; + UINT32 PLength; // Packet length + UINT32 ReadLimit; + UINT32 Count; + UINT32 Padding; + UINT32 *RawData; + EFI_MAC_ADDRESS Dst; + EFI_MAC_ADDRESS Src; + UINTN DroppedFrames; + + LanDriver = INSTANCE_FROM_SNP_THIS (Snp); + +#if defined(EVAL_PERFORMANCE) + UINT64 Perf = GetPerformanceCounterProperties (NULL, NULL); + UINT64 StartClock = GetPerformanceCounter (); +#endif + + // Check preliminaries + if ((Snp == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Snp->Mode->State != EfiSimpleNetworkInitialized) { + return EFI_NOT_STARTED; + } + + // Count dropped frames + DroppedFrames = MmioRead32 (LAN9118_RX_DROP); + LanDriver->Stats.RxDroppedFrames += DroppedFrames; + + NumPackets = RxStatusUsedSpace (0, Snp) / 4; + if (!NumPackets) { + return EFI_NOT_READY; + } + + // Read Rx Status (only if not empty) + RxFifoStatus = MmioRead32 (LAN9118_RX_STATUS); + LanDriver->Stats.RxTotalFrames += 1; + + // First check for errors + if ((RxFifoStatus & RXSTATUS_MII_ERROR) || + (RxFifoStatus & RXSTATUS_RXW_TO) || + (RxFifoStatus & RXSTATUS_FTL) || + (RxFifoStatus & RXSTATUS_LCOLL) || + (RxFifoStatus & RXSTATUS_LE) || + (RxFifoStatus & RXSTATUS_DB)) + { + DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n")); + return EFI_DEVICE_ERROR; + } + + // Check if we got a CRC error + if (RxFifoStatus & RXSTATUS_CRC_ERROR) { + DEBUG ((EFI_D_WARN, "Warning: Crc Error\n")); + LanDriver->Stats.RxCrcErrorFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + return EFI_DEVICE_ERROR; + } + + // Check if we got a runt frame + if (RxFifoStatus & RXSTATUS_RUNT) { + DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n")); + LanDriver->Stats.RxUndersizeFrames += 1; + LanDriver->Stats.RxDroppedFrames += 1; + return EFI_DEVICE_ERROR; + } + + // Check filtering status for this packet + if (RxFifoStatus & RXSTATUS_FILT_FAIL) { + DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n")); + // fast forward? + } + + // Check if we got a broadcast frame + if (RxFifoStatus & RXSTATUS_BCF) { + LanDriver->Stats.RxBroadcastFrames += 1; + } + + // Check if we got a multicast frame + if (RxFifoStatus & RXSTATUS_MCF) { + LanDriver->Stats.RxMulticastFrames += 1; + } + + // Check if we got a unicast frame + if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) == 0)) { + LanDriver->Stats.RxUnicastFrames += 1; + } + + // Get the received packet length + PLength = GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus); + LanDriver->Stats.RxTotalBytes += (PLength - 4); + + // Check buffer size + if (*BuffSize < PLength) { + *BuffSize = PLength; + return EFI_BUFFER_TOO_SMALL; + } + + // If padding is applied, read more DWORDs + if (PLength % 4) { + Padding = 4 - (PLength % 4); + ReadLimit = (PLength + Padding)/4; + } else { + ReadLimit = PLength/4; + Padding = 0; + } + + // Set the amount of data to be transfered out of FIFO for THIS packet + // This can be used to trigger an interrupt, and status can be checked + RxCfgValue = MmioRead32 (LAN9118_RX_CFG); + RxCfgValue &= ~(RXCFG_RX_DMA_CNT_MASK); + RxCfgValue |= RXCFG_RX_DMA_CNT (ReadLimit); + + // Set end alignment to 4-bytes + RxCfgValue &= ~(RXCFG_RX_END_ALIGN_MASK); + MmioWrite32 (LAN9118_RX_CFG, RxCfgValue); + + // Update buffer size + *BuffSize = PLength; // -4 bytes may be needed: Received in buffer as + // 4 bytes longer than packet actually is, unless + // packet is < 64 bytes + + if (HdrSize != NULL) + *HdrSize = Snp->Mode->MediaHeaderSize; + + // Format the pointer + RawData = (UINT32*)Data; + + // Read Rx Packet + for (Count = 0; Count < ReadLimit; Count++) { + RawData[Count] = MmioRead32 (LAN9118_RX_DATA); + } + + // Check for Rx errors (worst possible error) + if (MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) { + DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n")); + + // Initiate a software reset + if (SoftReset (0, Snp) < 0) { + DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n")); + return EFI_DEVICE_ERROR; + } + + // Acknowledge the RXE + MmioWrite32 (LAN9118_INT_STS, INSTS_RXE); + gBS->Stall (LAN9118_STALL); + + // Restart the rx (and do not clear FIFO) + StartRx (0, Snp); + + // Say that command could not be sent + return EFI_DEVICE_ERROR; + } + + // Get the destination address + if (DstAddr != NULL) { + Dst.Addr[0] = (RawData[0] & 0xFF); + Dst.Addr[1] = (RawData[0] & 0xFF00) >> 8; + Dst.Addr[2] = (RawData[0] & 0xFF0000) >> 16; + Dst.Addr[3] = (RawData[0] & 0xFF000000) >> 24; + Dst.Addr[4] = (RawData[1] & 0xFF); + Dst.Addr[5] = (RawData[1] & 0xFF00) >> 8; + CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN); + } + + // Get the source address + if (SrcAddr != NULL) { + Src.Addr[0] = (RawData[1] & 0xFF0000) >> 16; + Src.Addr[1] = (RawData[1] & 0xFF000000) >> 24; + Src.Addr[2] = (RawData[2] & 0xFF); + Src.Addr[3] = (RawData[2] & 0xFF00) >> 8; + Src.Addr[4] = (RawData[2] & 0xFF0000) >> 16; + Src.Addr[5] = (RawData[2] & 0xFF000000) >> 24; + CopyMem (SrcAddr,&Src, NET_ETHER_ADDR_LEN); + } + + // Get the protocol + if (Protocol != NULL) { + *Protocol = NTOHS (RawData[3] & 0xFFFF); + } + +#if defined(EVAL_PERFORMANCE) + UINT64 EndClock = GetPerformanceCounter (); + DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", StartClock - EndClock,Perf)); +#endif + + LanDriver->Stats.RxGoodFrames += 1; + + return EFI_SUCCESS; +} diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h new file mode 100644 index 0000000000..7d83b4f62e --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h @@ -0,0 +1,303 @@ +/** @file +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __LAN9118_DXE_H__ +#define __LAN9118_DXE_H__ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Lan9118DxeUtil.h" +#include "Lan9118DxeHw.h" + +#define LAN9118_STALL 2 + +#define LAN9118_DEFAULT_MAC_ADDRL 0x00F70200 +#define LAN9118_DEFAULT_MAC_ADDRH 0x00009040 + +#define LAN9118_TX_DATA_SIZE 4608 +#define LAN9118_TX_STATUS_SIZE 512 +#define LAN9118_RX_DATA_SIZE 10560 +#define LAN9118_RX_STATUS_SIZE 704 + +#define LAN9118_TX_RING_NUM_ENTRIES 32 + +/*------------------------------------------------------------------------------ + LAN9118 Information Structure +------------------------------------------------------------------------------*/ + +typedef struct { + // Driver signature + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + // EFI SNP protocol instances + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + // EFI Snp statistics instance + EFI_NETWORK_STATISTICS Stats; + + // Saved transmitted buffers so we can notify consumers when packets have been sent. + UINT16 NextPacketTag; + VOID *TxRing[LAN9118_TX_RING_NUM_ENTRIES]; +} LAN9118_DRIVER; + +#define LAN9118_SIGNATURE SIGNATURE_32('l', 'a', 'n', '9') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN9118_DRIVER, Snp, LAN9118_SIGNATURE) + + +/*--------------------------------------------------------------------------------------------------------------------- + + UEFI-Compliant functions for EFI_SIMPLE_NETWORK_PROTOCOL + + Refer to the Simple Network Protocol section (21.1) in the UEFI 2.3.1 Specification for related definitions + +---------------------------------------------------------------------------------------------------------------------*/ + + +/* + * UEFI Start() function + * + * Parameters: + * + * @param pobj: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + * + * Description: + * + * This function starts a network interface. If the network interface successfully starts, then + * EFI_SUCCESS will be returned. + */ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI Stop() function + * + */ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI Initialize() function + * + */ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN rx_buff_size, + IN UINTN tx_buff_size + ); + +/* + * UEFI Reset() function + * + */ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN ext_ver + ); + +/* + * UEFI Shutdown() function + * + */ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI ReceiveFilters() function + * + */ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINT32 enable, + IN UINT32 disable, + IN BOOLEAN reset_mfilter, + IN UINTN num_mfilter, + IN EFI_MAC_ADDRESS *mfilter + ); + +/* + * UEFI StationAddress() function + * + */ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN reset, + IN EFI_MAC_ADDRESS *new_maddr + ); + +/* + * UEFI Statistics() function + * + */ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN reset, + IN OUT UINTN *stat_size, + OUT EFI_NETWORK_STATISTICS *stat_table + ); + +/* + * UEFI MCastIPtoMAC() function + * + */ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN use_ipv6, + IN EFI_IP_ADDRESS *ip_addr, + OUT EFI_MAC_ADDRESS *mac_addr + ); + +/* + * UEFI NvData() function + * + */ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ); + +/* + * UEFI GetStatus() function + * + */ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINT32 *irq_stat OPTIONAL, + OUT VOID **tx_buff OPTIONAL + ); + +/* + * UEFI Transmit() function + * + */ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN hdr_size, + IN UINTN buff_size, + IN VOID *data, + IN EFI_MAC_ADDRESS *src_addr OPTIONAL, + IN EFI_MAC_ADDRESS *dest_addr OPTIONAL, + IN UINT16 *protocol OPTIONAL + ); + +/* + * UEFI Receive() function + * + */ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINTN *hdr_size OPTIONAL, + IN OUT UINTN *buff_size, + OUT VOID *data, + OUT EFI_MAC_ADDRESS *src_addr OPTIONAL, + OUT EFI_MAC_ADDRESS *dest_addr OPTIONAL, + OUT UINT16 *protocol OPTIONAL + ); + + +/*--------------------------------------------------------------------------------------------------------------------- + + UEFI-Compliant functions for EFI_COMPONENT_NAME2_PROTOCOL + + Refer to the Component Name Protocol section (10.5) in the UEFI 2.3.1 Specification for related definitions + +---------------------------------------------------------------------------------------------------------------------*/ + +/* + * UEFI GetDriverName() function + * + */ +EFI_STATUS +EFIAPI +SnpGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *Snp, + IN CHAR8 *Lang, + OUT CHAR16 **DriverName + ); + +/* + * UEFI GetControllerName() function + * + */ +EFI_STATUS +EFIAPI +SnpGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *Cnp, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Lang, + OUT CHAR16 **ControllerName + ); + +/*------------------------------------------------------------------------------ + Utility functions +------------------------------------------------------------------------------*/ + +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + VOID + ); + +#endif // __LAN9118_DXE_H__ diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf new file mode 100644 index 0000000000..392a7b537a --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf @@ -0,0 +1,57 @@ +#/** @file +# INF file for the LAN9118 Network Controller Driver. +# +# Copyright (c) 2012-2014, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = Lan9118Dxe + FILE_GUID = 4356b162-d0b2-11e1-8952-4437e6a60ea5 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = Lan9118DxeEntry + +[Sources.common] + Lan9118Dxe.c + Lan9118DxeUtil.c + Lan9118Dxe.h + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + NetworkPkg/NetworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiLib + NetLib + UefiDriverEntryPoint + BaseMemoryLib + ArmLib + IoLib + TimerLib + DevicePathLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress + gEmbeddedTokenSpaceGuid.PcdLan9118DefaultMacAddress + +[Depex] + TRUE diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h new file mode 100644 index 0000000000..9e89d27459 --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h @@ -0,0 +1,329 @@ +/** @file +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __LAN9118_DXE_HW_H__ +#define __LAN9118_DXE_HW_H__ + +/*------------------------------------------------------------------------------ + LAN9118 SMCS Registers +------------------------------------------------------------------------------*/ + +// Base address as on the VE board +#define LAN9118_BA ((UINT32) PcdGet32(PcdLan9118DxeBaseAddress)) + +/* ------------- Tx and Rx Data and Status Memory Locations ------------------*/ +#define LAN9118_RX_DATA (0x00000000 + LAN9118_BA) +#define LAN9118_RX_STATUS (0x00000040 + LAN9118_BA) +#define LAN9118_RX_STATUS_PEEK (0x00000044 + LAN9118_BA) +#define LAN9118_TX_DATA (0x00000020 + LAN9118_BA) +#define LAN9118_TX_STATUS (0x00000048 + LAN9118_BA) +#define LAN9118_TX_STATUS_PEEK (0x0000004C + LAN9118_BA) + +/* ------------- System Control and Status Registers -------------------------*/ +#define LAN9118_ID_REV (0x00000050 + LAN9118_BA) // Chip ID and Revision +#define LAN9118_IRQ_CFG (0x00000054 + LAN9118_BA) // Interrupt Configuration +#define LAN9118_INT_STS (0x00000058 + LAN9118_BA) // Interrupt Status +#define LAN9118_INT_EN (0x0000005C + LAN9118_BA) // Interrupt Enable +//#define LAN9118_RESERVED (0x00000060) +#define LAN9118_BYTE_TEST (0x00000064 + LAN9118_BA) // Byte Order Test +#define LAN9118_FIFO_INT (0x00000068 + LAN9118_BA) // FIFO Level Interrupts +#define LAN9118_RX_CFG (0x0000006C + LAN9118_BA) // Receive Configuration +#define LAN9118_TX_CFG (0x00000070 + LAN9118_BA) // Transmit Configuration +#define LAN9118_HW_CFG (0x00000074 + LAN9118_BA) // Hardware Configuration +#define LAN9118_RX_DP_CTL (0x00000078 + LAN9118_BA) // Receive Data-Path Configuration +#define LAN9118_RX_FIFO_INF (0x0000007C + LAN9118_BA) // Receive FIFO Information +#define LAN9118_TX_FIFO_INF (0x00000080 + LAN9118_BA) // Transmit FIFO Information +#define LAN9118_PMT_CTRL (0x00000084 + LAN9118_BA) // Power Management Control +#define LAN9118_GPIO_CFG (0x00000088 + LAN9118_BA) // General Purpose IO Configuration +#define LAN9118_GPT_CFG (0x0000008C + LAN9118_BA) // General Purpose Timer Configuration +#define LAN9118_GPT_CNT (0x00000090 + LAN9118_BA) // General Purpose Timer Current Count +#define LAN9118_WORD_SWAP (0x00000098 + LAN9118_BA) // Word Swap Control +#define LAN9118_FREE_RUN (0x0000009C + LAN9118_BA) // Free-Run 25MHz Counter +#define LAN9118_RX_DROP (0x000000A0 + LAN9118_BA) // Receiver Dropped Frames Counter +#define LAN9118_MAC_CSR_CMD (0x000000A4 + LAN9118_BA) // MAC CSR Synchronizer Command +#define LAN9118_MAC_CSR_DATA (0x000000A8 + LAN9118_BA) // MAC CSR Synchronizer Data +#define LAN9118_AFC_CFG (0x000000AC + LAN9118_BA) // Automatic Flow Control Configuration +#define LAN9118_E2P_CMD (0x000000B0 + LAN9118_BA) // EEPROM Command +#define LAN9118_E2P_DATA (0x000000B4 + LAN9118_BA) // EEPROM Data + + +// Receiver Status bits +#define RXSTATUS_CRC_ERROR BIT1 // Cyclic Redundancy Check Error +#define RXSTATUS_DB BIT2 // Dribbling bit: Frame had non-integer multiple of 8bits +#define RXSTATUS_MII_ERROR BIT3 // Receive error during interception +#define RXSTATUS_RXW_TO BIT4 // Incomming frame larger than 2kb +#define RXSTATUS_FT BIT5 // 1: Ether type / 0: 802.3 type frame +#define RXSTATUS_LCOLL BIT6 // Late collision detected +#define RXSTATUS_FTL BIT7 // Frame longer than Ether type +#define RXSTATUS_MCF BIT10 // Frame has Multicast Address +#define RXSTATUS_RUNT BIT11 // Bad frame +#define RXSTATUS_LE BIT12 // Actual length of frame different than it claims +#define RXSTATUS_BCF BIT13 // Frame has Broadcast Address +#define RXSTATUS_ES BIT15 // Reports any error from bits 1,6,7 and 11 +#define RXSTATUS_PL_MASK (0x3FFF0000) // Packet length bit mask +#define GET_RXSTATUS_PACKET_LENGTH(RxStatus) (((RxStatus) >> 16) & 0x3FFF) // Packet length bit mask +#define RXSTATUS_FILT_FAIL BIT30 // The frame failed filtering test + +// Transmitter Status bits +#define TXSTATUS_DEF BIT0 // Packet tx was deferred +#define TXSTATUS_EDEF BIT2 // Tx ended because of excessive deferral (> 24288 bit times) +#define TXSTATUS_CC_MASK (0x00000078) // Collision Count (before Tx) bit mask +#define TXSTATUS_ECOLL BIT8 // Tx ended because of Excessive Collisions (makes CC_MASK invalid after 16 collisions) +#define TXSTATUS_LCOLL BIT9 // Packet Tx aborted after coll window of 64 bytes +#define TXSTATUS_NO_CA BIT10 // Carrier signal not present during Tx (bad?) +#define TXSTATUS_LOST_CA BIT11 // Lost carrier during Tx +#define TXSTATUS_ES BIT15 // Reports any errors from bits 1,2,8,9,10 and 11 +#define TXSTATUS_PTAG_MASK (0xFFFF0000) // Mask for Unique ID of packets (So we know who the packets are for) + +// ID_REV register bits +#define IDREV_ID ((MmioRead32(LAN9118_ID_REV) & 0xFFFF0000) >> 16) +#define IDREV_REV (MmioRead32(LAN9118_ID_REV) & 0x0000FFFF) + +// Interrupt Config Register bits +#define IRQCFG_IRQ_TYPE BIT0 // IRQ Buffer type +#define IRQCFG_IRQ_POL BIT4 // IRQ Polarity +#define IRQCFG_IRQ_EN BIT8 // Enable external interrupt +#define IRQCFG_IRQ_INT BIT12 // State of internal interrupts line +#define IRQCFG_INT_DEAS_STS BIT13 // State of deassertion interval +#define IRQCFG_INT_DEAS_CLR BIT14 // Clear the deassertion counter +#define IRQCFG_INT_DEAS_MASK (0xFF000000) // Interrupt deassertion interval value mask + +// Interrupt Status Register bits +#define INSTS_GPIO_MASK (0x7) // GPIO interrupts mask +#define INSTS_RSFL (0x8) // Rx Status FIFO Level reached +#define INSTS_RSFF BIT4 // Rx Status FIFO full +#define INSTS_RXDF_INT BIT6 // Rx Frame dropped +#define INSTS_TSFL BIT7 // Tx Status FIFO Level reached +#define INSTS_TSFF BIT8 // Tx Status FIFO full +#define INSTS_TDFA BIT9 // Tx Data FIFO Level exceeded +#define INSTS_TDFO BIT10 // Tx Data FIFO full +#define INSTS_TXE BIT13 // Transmitter Error +#define INSTS_RXE BIT14 // Receiver Error +#define INSTS_RWT BIT15 // Packet > 2048 bytes received +#define INSTS_TXSO BIT16 // Tx Status FIFO Overflow +#define INSTS_PME_INT BIT17 // PME Signal detected +#define INSTS_PHY_INT BIT18 // Indicates PHY Interrupt +#define INSTS_GPT_INT BIT19 // GP Timer wrapped past 0xFFFF +#define INSTS_RXD_INT BIT20 // Indicates that amount of data written to RX_CFG was cleared +#define INSTS_TX_IOC BIT21 // Finished loading IOC flagged buffer to Tx FIFO +#define INSTS_RXDFH_INT BIT23 // Rx Dropped frames went past 0x7FFFFFFF +#define INSTS_RXSTOP_INT BIT24 // Rx was stopped +#define INSTS_TXSTOP_INT BIT25 // Tx was stopped +#define INSTS_SW_INT BIT31 // Software Interrupt occurred + +// Interrupt Enable Register bits + + +// Hardware Config Register bits +#define HWCFG_SRST BIT0 // Software Reset bit (SC) +#define HWCFG_SRST_TO BIT1 // Software Reset Timeout bit (RO) +#define HWCFG_BMODE BIT2 // 32/16 bit Mode bit (RO) +#define HWCFG_TX_FIFO_SIZE_MASK (~ (UINT32)0xF0000) // Mask to Clear FIFO Size +#define HWCFG_MBO BIT20 // Must Be One bit + +// Power Management Control Register +#define MPTCTRL_READY BIT0 // Device ready indicator +#define MPTCTRL_PME_EN BIT1 // Enable external PME signals +#define MPTCTRL_PME_POL BIT2 // Set polarity of PME signals +#define MPTCTRL_PME_IND BIT3 // Signal type of PME (refer to Spec) +#define MPTCTRL_WUPS_MASK (0x18) // Wake up status indicator mask +#define MPTCTRL_PME_TYPE BIT6 // PME Buffer type (Open Drain or Push-Pull) +#define MPTCTRL_ED_EN BIT8 // Energy-detect enable +#define MPTCTRL_WOL_EN BIT9 // Enable wake-on-lan +#define MPTCTRL_PHY_RST BIT10 // Reset the PHY +#define MPTCTRL_PM_MODE_MASK (BIT12 | BIT13) // Set the power mode + +// PHY control register bits +#define PHYCR_COLL_TEST BIT7 // Collision test enable +#define PHYCR_DUPLEX_MODE BIT8 // Set Duplex Mode +#define PHYCR_RST_AUTO BIT9 // Restart Auto-Negotiation of Link abilities +#define PHYCR_PD BIT11 // Power-Down switch +#define PHYCR_AUTO_EN BIT12 // Auto-Negotiation Enable +#define PHYCR_SPEED_SEL BIT13 // Link Speed Selection +#define PHYCR_LOOPBK BIT14 // Set loopback mode +#define PHYCR_RESET BIT15 // Do a PHY reset + +// PHY status register bits +#define PHYSTS_EXT_CAP BIT0 // Extended Capabilities Register capability +#define PHYSTS_JABBER BIT1 // Jabber condition detected +#define PHYSTS_LINK_STS BIT2 // Link Status +#define PHYSTS_AUTO_CAP BIT3 // Auto-Negotiation Capability +#define PHYSTS_REMOTE_FAULT BIT4 // Remote fault detected +#define PHYSTS_AUTO_COMP BIT5 // Auto-Negotiation Completed +#define PHYSTS_10BASET_HDPLX BIT11 // 10Mbps Half-Duplex ability +#define PHYSTS_10BASET_FDPLX BIT12 // 10Mbps Full-Duplex ability +#define PHYSTS_100BASETX_HDPLX BIT13 // 100Mbps Half-Duplex ability +#define PHYSTS_100BASETX_FDPLX BIT14 // 100Mbps Full-Duplex ability +#define PHYSTS_100BASE_T4 BIT15 // Base T4 ability + +// PHY Auto-Negotiation advertisement +#define PHYANA_SEL_MASK ((UINT32)0x1F) // Link type selector +#define PHYANA_10BASET BIT5 // Advertise 10BASET capability +#define PHYANA_10BASETFD BIT6 // Advertise 10BASET Full duplex capability +#define PHYANA_100BASETX BIT7 // Advertise 100BASETX capability +#define PHYANA_100BASETXFD BIT8 // Advertise 100 BASETX Full duplex capability +#define PHYANA_PAUSE_OP_MASK (3 << 10) // Advertise PAUSE frame capability +#define PHYANA_REMOTE_FAULT BIT13 // Remote fault detected + + +// PHY Auto-Negotiation Link Partner Ability + +// PHY Auto-Negotiation Expansion + +// PHY Mode control/status + +// PHY Special Modes + +// PHY Special control/status + +// PHY Interrupt Source Flags + +// PHY Interrupt Mask + +// PHY Super Special control/status +#define PHYSSCS_HCDSPEED_MASK (7 << 2) // Speed indication +#define PHYSSCS_AUTODONE BIT12 // Auto-Negotiation Done + + +// MAC control register bits +#define MACCR_RX_EN BIT2 // Enable Receiver bit +#define MACCR_TX_EN BIT3 // Enable Transmitter bit +#define MACCR_DFCHK BIT5 // Deferral Check bit +#define MACCR_PADSTR BIT8 // Automatic Pad Stripping bit +#define MACCR_BOLMT_MASK (0xC0) // Back-Off limit mask +#define MACCR_DISRTY BIT10 // Disable Transmit Retry bit +#define MACCR_BCAST BIT11 // Disable Broadcast Frames bit +#define MACCR_LCOLL BIT12 // Late Collision Control bit +#define MACCR_HPFILT BIT13 // Hash/Perfect Filtering Mode bit +#define MACCR_HO BIT15 // Hash Only Filtering Mode +#define MACCR_PASSBAD BIT16 // Receive all frames that passed filter bit +#define MACCR_INVFILT BIT17 // Enable Inverse Filtering bit +#define MACCR_PRMS BIT18 // Promiscuous Mode bit +#define MACCR_MCPAS BIT19 // Pass all Multicast packets bit +#define MACCR_FDPX BIT20 // Full Duplex Mode bit +#define MACCR_LOOPBK BIT21 // Loopback operation mode bit +#define MACCR_RCVOWN BIT23 // Disable Receive Own frames bit +#define MACCR_RX_ALL BIT31 // Receive all Packets and route to Filter + +// Wake-Up Control and Status Register +#define WUCSR_MPEN BIT1 // Magic Packet enable (allow wake from Magic P) +#define WUCSR_WUEN BIT2 // Allow remote wake up using Wake-Up Frames +#define WUCSR_MPR_MASK (0x10) // Received Magic Packet +#define WUCSR_WUFR_MASK (0x20) // Received Wake-Up Frame +#define WUCSR_GUE BIT9 // Enable wake on global unicast frames + +// RX Configuration Register bits +#define RXCFG_RXDOFF_MASK (0x1F00) // Rx Data Offset in Bytes +#define RXCFG_RX_DUMP BIT15 // Clear Rx data and status FIFOs +#define RXCFG_RX_DMA_CNT_MASK (0x0FFF0000) // Amount of data to be read from Rx FIFO +#define RXCFG_RX_DMA_CNT(cnt) (((cnt) & 0xFFF) << 16) // Amount of data to be read from Rx FIFO +#define RXCFG_RX_END_ALIGN_MASK (0xC0000000) // Alignment to preserve + +// TX Configuration Register bits +#define TXCFG_STOP_TX BIT0 // Stop the transmitter +#define TXCFG_TX_ON BIT1 // Start the transmitter +#define TXCFG_TXSAO BIT2 // Tx Status FIFO full +#define TXCFG_TXD_DUMP BIT14 // Clear Tx Data FIFO +#define TXCFG_TXS_DUMP BIT15 // Clear Tx Status FIFO + +// Rx FIFO Information Register bits +#define RXFIFOINF_RXDUSED_MASK (0xFFFF) // Rx Data FIFO Used Space +#define RXFIFOINF_RXSUSED_MASK (0xFF0000) // Rx Status FIFO Used Space + +// Tx FIFO Information Register bits +#define TXFIFOINF_TDFREE_MASK (0xFFFF) // Tx Data FIFO Free Space +#define TXFIFOINF_TXSUSED_MASK (0xFF0000) // Tx Status FIFO Used Space + +// E2P Register +#define E2P_EPC_BUSY BIT31 +#define E2P_EPC_CMD_READ (0) +#define E2P_EPC_TIMEOUT BIT9 +#define E2P_EPC_MAC_ADDRESS_LOADED BIT8 +#define E2P_EPC_ADDRESS(address) ((address) & 0xFFFF) + +// GPIO Configuration register +#define GPIO_GPIO0_PUSH_PULL BIT16 +#define GPIO_GPIO1_PUSH_PULL BIT17 +#define GPIO_GPIO2_PUSH_PULL BIT18 +#define GPIO_LED1_ENABLE BIT28 +#define GPIO_LED2_ENABLE BIT29 +#define GPIO_LED3_ENABLE BIT30 + +// MII_ACC bits +#define MII_ACC_MII_BUSY BIT0 +#define MII_ACC_MII_WRITE BIT1 +#define MII_ACC_MII_READ 0 + +#define MII_ACC_PHY_VALUE BIT11 +#define MII_ACC_MII_REG_INDEX(index) (((index) & 0x1F) << 6) + +// +// PHY Control Indexes +// +#define PHY_INDEX_BASIC_CTRL 0 +#define PHY_INDEX_BASIC_STATUS 1 +#define PHY_INDEX_ID1 2 +#define PHY_INDEX_ID2 3 +#define PHY_INDEX_AUTO_NEG_ADVERT 4 +#define PHY_INDEX_AUTO_NEG_LINK_ABILITY 5 +#define PHY_INDEX_AUTO_NEG_EXP 6 +#define PHY_INDEX_MODE 17 +#define PHY_INDEX_SPECIAL_MODES 18 +#define PHY_INDEX_SPECIAL_CTLR 27 +#define PHY_INDEX_INT_SRC 29 +#define PHY_INDEX_INT_MASK 30 +#define PHY_INDEX_SPECIAL_PHY_CTLR 31 + +// Indirect MAC Indexes +#define INDIRECT_MAC_INDEX_CR 1 +#define INDIRECT_MAC_INDEX_ADDRH 2 +#define INDIRECT_MAC_INDEX_ADDRL 3 +#define INDIRECT_MAC_INDEX_HASHH 4 +#define INDIRECT_MAC_INDEX_HASHL 5 +#define INDIRECT_MAC_INDEX_MII_ACC 6 +#define INDIRECT_MAC_INDEX_MII_DATA 7 + +// +// MAC CSR Synchronizer Command register +// +#define MAC_CSR_BUSY BIT31 +#define MAC_CSR_READ BIT30 +#define MAC_CSR_WRITE 0 +#define MAC_CSR_ADDR(Addr) ((Addr) & 0xFF) + +// +// TX Packet Format +// +#define TX_CMD_A_COMPLETION_INT BIT31 +#define TX_CMD_A_FIRST_SEGMENT BIT13 +#define TX_CMD_A_LAST_SEGMENT BIT12 +#define TX_CMD_A_BUFF_SIZE(size) ((size) & 0x000003FF) +#define TX_CMD_A_DATA_START_OFFSET(offset) (((offset) & 0x1F) << 16) +#define TX_CMD_B_PACKET_LENGTH(size) ((size) & 0x000003FF) +#define TX_CMD_B_PACKET_TAG(tag) (((tag) & 0x3FF) << 16) + +// Hardware Configuration Register +#define HW_CFG_TX_FIFO_SIZE_MASK (0xF << 16) +#define HW_CFG_TX_FIFO_SIZE(size) (((size) & 0xF) << 16) + +// EEPROM Definition +#define EEPROM_EXTERNAL_SERIAL_EEPROM 0xA5 + +// +// Conditional compilation flags +// +//#define EVAL_PERFORMANCE + + +#endif /* __LAN9118_DXE_HDR_H__ */ diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c new file mode 100644 index 0000000000..99c3ff0cec --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c @@ -0,0 +1,1021 @@ +/** @file +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "Lan9118Dxe.h" + +STATIC EFI_MAC_ADDRESS mZeroMac = { 0 }; + +/** + This internal function reverses bits for 32bit data. + + @param Value The data to be reversed. + + @return Data reversed. + +**/ +UINT32 +ReverseBits ( + UINT32 Value + ) +{ + UINTN Index; + UINT32 NewValue; + + NewValue = 0; + for (Index = 0; Index < 32; Index++) { + if ((Value & (1 << Index)) != 0) { + NewValue = NewValue | (1 << (31 - Index)); + } + } + + return NewValue; +} + +/* +** Create Ethernet CRC +** +** INFO USED: +** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check +** +** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html +** +** 3: http://en.wikipedia.org/wiki/Computation_of_CRC +*/ +UINT32 +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ) +{ + INT32 Iter; + UINT32 Remainder; + UINT8 *Ptr; + + Iter = 0; + Remainder = 0xFFFFFFFF; // 0xFFFFFFFF is standard seed for Ethernet + + // Convert Mac Address to array of bytes + Ptr = (UINT8*)Mac; + + // Generate the Crc bit-by-bit (LSB first) + while (AddrLen--) { + Remainder ^= *Ptr++; + for (Iter = 0;Iter < 8;Iter++) { + // Check if exponent is set + if (Remainder & 1) { + Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL; + } else { + Remainder = (Remainder >> 1) ^ 0; + } + } + } + + // Reverse the bits before returning (to Big Endian) + //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte reverse (in this case use SwapBytes32()) + return ReverseBits (Remainder); +} + +// Function to read from MAC indirect registers +UINT32 +IndirectMACRead32 ( + UINT32 Index + ) +{ + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <= 12); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are reading + // Set the index of CSR Address to access desired register + MacCSR = MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index); + + // Write to the register + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Now read from data register to get read value + return MmioRead32 (LAN9118_MAC_CSR_DATA); +} + +// Function to write to MAC indirect registers +UINT32 +IndirectMACWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <= 12); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are writing + // Set the index of CSR Address to access desired register + MacCSR = MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index); + + // Now write the value to the register before issuing the write command + ValueWritten = MmioWrite32 (LAN9118_MAC_CSR_DATA, Value); + + // Write the config to the register + MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY); + + return ValueWritten; +} + +// Function to read from MII register (PHY Access) +UINT32 +IndirectPHYRead32 ( + UINT32 Index + ) +{ + UINT32 ValueRead; + UINT32 MiiAcc; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc = MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY; + + // Now write this config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Now read the value of the register + ValueRead = (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF); // only lower 16 bits are valid for any PHY register + + return ValueRead; +} + + +// Function to write to the MII register (PHY Access) +UINT32 +IndirectPHYWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 MiiAcc; + UINT32 ValueWritten; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc = MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY; + + // Write the desired value to the register first + ValueWritten = IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value & 0xFFFF)); + + // Now write the config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for operation to terminate + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY); + + return ValueWritten; +} + + +/* ---------------- EEPROM Operations ------------------ */ + + +// Function to read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index + ) +{ + UINT32 EepromCmd; + + // Set the busy bit to ensure read will occur + EepromCmd = E2P_EPC_BUSY | E2P_EPC_CMD_READ; + + // Set the index to access desired EEPROM memory location + EepromCmd |= E2P_EPC_ADDRESS(Index); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on index %x\n",Index)); + return 0; + } + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Finally read the value + return MmioRead32 (LAN9118_E2P_DATA); +} + +// Function to write to EEPROM memory +UINT32 +IndirectEEPROMWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 EepromCmd; + + ValueWritten = 0; + + // Read the EEPROM Command register + EepromCmd = MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |= ((UINT32)1 << 31); + + // Set the EEPROM command to write(0b011) + EepromCmd &= ~(7 << 28); // Clear the command first + EepromCmd |= (3 << 28); // Write 011 + + // Set the index to access desired EEPROM memory location + EepromCmd |= (Index & 0xF); + + // Write the value to the data register first + ValueWritten = MmioWrite32 (LAN9118_E2P_DATA, Value); + + // Write to Eeprom command register + MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + gBS->Stall (LAN9118_STALL); + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index, Value)); + return 0; + } + + // Wait until operation has completed + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + return ValueWritten; +} + +/* ---------------- General Operations ----------------- */ + +VOID +Lan9118SetMacAddress ( + EFI_MAC_ADDRESS *Mac, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, + (Mac->Addr[0] & 0xFF) | + ((Mac->Addr[1] & 0xFF) << 8) | + ((Mac->Addr[2] & 0xFF) << 16) | + ((Mac->Addr[3] & 0xFF) << 24) + ); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, + (UINT32)(Mac->Addr[4] & 0xFF) | + ((Mac->Addr[5] & 0xFF) << 8) + ); + + CopyMem (&Snp->Mode->CurrentAddress, &Mac, NET_ETHER_ADDR_LEN); +} + +VOID +Lan9118ReadMacAddress ( + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT32 MacAddrHighValue; + UINT32 MacAddrLowValue; + + // Read the Mac Addr high register + MacAddrHighValue = (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xFFFF); + // Read the Mac Addr low register + MacAddrLowValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL); + + SetMem (MacAddress, sizeof(*MacAddress), 0); + MacAddress->Addr[0] = (MacAddrLowValue & 0xFF); + MacAddress->Addr[1] = (MacAddrLowValue & 0xFF00) >> 8; + MacAddress->Addr[2] = (MacAddrLowValue & 0xFF0000) >> 16; + MacAddress->Addr[3] = (MacAddrLowValue & 0xFF000000) >> 24; + MacAddress->Addr[4] = (MacAddrHighValue & 0xFF); + MacAddress->Addr[5] = (MacAddrHighValue & 0xFF00) >> 8; +} + +/* + * Power up the 9118 and find its MAC address. + * + * This operation can be carried out when the LAN9118 is in any power state + * + */ +EFI_STATUS +Lan9118Initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINTN Timeout; + UINT64 DefaultMacAddress; + + // Attempt to wake-up the device if it is in a lower power state + if (((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) { + DEBUG ((DEBUG_NET, "Waking from reduced power state.\n")); + MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF); + gBS->Stall (LAN9118_STALL); + } + + // Check that device is active + Timeout = 20; + while ((MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0 && --Timeout) { + gBS->Stall (LAN9118_STALL); + } + if (!Timeout) { + return EFI_TIMEOUT; + } + + // Check that EEPROM isn't active + Timeout = 20; + while ((MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY) && --Timeout){ + gBS->Stall (LAN9118_STALL); + } + if (!Timeout) { + return EFI_TIMEOUT; + } + + // Check if a MAC address was loaded from EEPROM, and if it was, set it as the + // current address. + if ((MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) == 0) { + DEBUG ((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or loading the MAC Address.\n")); + + // If we had an address before (set by StationAddess), continue to use it + if (CompareMem (&Snp->Mode->CurrentAddress, &mZeroMac, NET_ETHER_ADDR_LEN)) { + Lan9118SetMacAddress (&Snp->Mode->CurrentAddress, Snp); + } else { + // If there are no cached addresses, then fall back to a default + DEBUG ((EFI_D_WARN, "Warning: using driver-default MAC address\n")); + DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress); + Lan9118SetMacAddress((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp); + } + } else { + // Store the MAC address that was loaded from EEPROM + Lan9118ReadMacAddress (&Snp->Mode->CurrentAddress); + CopyMem (&Snp->Mode->PermanentAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN); + } + + // Clear and acknowledge interrupts + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Do self tests here? + + return EFI_SUCCESS; +} + + +// Perform software reset on the LAN9118 +// Return 0 on success, -1 on error +EFI_STATUS +SoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 ResetTime; + + // Initialize variable + ResetTime = 0; + + // Stop Rx and Tx + StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp); + StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO + + // Issue the reset + HwConf = MmioRead32 (LAN9118_HW_CFG); + HwConf |= 1; + + // Set the Must Be One (MBO) bit + if (((HwConf & HWCFG_MBO) >> 20) == 0) { + HwConf |= HWCFG_MBO; + } + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Write the configuration + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + // Wait for reset to complete + while (MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) { + + gBS->Stall (LAN9118_STALL); + ResetTime += 1; + + // If time taken exceeds 100us, then there was an error condition + if (ResetTime > 1000) { + Snp->Mode->State = EfiSimpleNetworkStopped; + return EFI_TIMEOUT; + } + } + + // Check that EEPROM isn't active + while (MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // TODO we probably need to re-set the mac address here. + + // Clear and acknowledge all interrupts + if (Flags & SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + // Do self tests here? + if (Flags & SOFT_RESET_SELF_TEST) { + + } + + return EFI_SUCCESS; +} + + +// Perform PHY software reset +INT32 +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PmtCtrl = 0; + UINT32 LinkTo = 0; + + // PMT PHY reset takes precedence over BCR + if (Flags & PHY_RESET_PMT) { + PmtCtrl = MmioRead32 (LAN9118_PMT_CTRL); + PmtCtrl |= MPTCTRL_PHY_RST; + MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl); + + // Wait for completion + while (MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) { + gBS->Stall (LAN9118_STALL); + } + // PHY Basic Control Register reset + } else if (Flags & PHY_RESET_PMT) { + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // Wait for completion + while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + gBS->Stall (LAN9118_STALL); + } + } + + // Check the link status + if (Flags & PHY_RESET_CHECK_LINK) { + LinkTo = 100000; // 2 second (could be 50% more) + while (EFI_ERROR (CheckLinkStatus (0, Snp)) && (LinkTo > 0)) { + gBS->Stall (LAN9118_STALL); + LinkTo--; + } + + // Timed out + if (LinkTo <= 0) { + return -1; + } + } + + // Clear and acknowledge all interrupts + if (Flags & PHY_SOFT_RESET_CLEAR_INT) { + MmioWrite32 (LAN9118_INT_EN, 0); + MmioWrite32 (LAN9118_IRQ_CFG, 0); + MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + return 0; +} + + +// Configure hardware for LAN9118 +EFI_STATUS +ConfigureHardware ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 GpioConf; + + // Check if we want to use LEDs on GPIO + if (Flags & HW_CONF_USE_LEDS) { + GpioConf = MmioRead32 (LAN9118_GPIO_CFG); + + // Enable GPIO as LEDs and Config as Push-Pull driver + GpioConf |= GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2_PUSH_PULL | + GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE; + + // Write the configuration + MmioWrite32 (LAN9118_GPIO_CFG, GpioConf); + gBS->Stall (LAN9118_STALL); + } + + return EFI_SUCCESS; +} + +// Configure flow control +EFI_STATUS +ConfigureFlow ( + UINT32 Flags, + UINT32 HighTrig, + UINT32 LowTrig, + UINT32 BPDuration, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + return EFI_SUCCESS; +} + +// Do auto-negotiation +EFI_STATUS +AutoNegotiate ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PhyControl; + UINT32 PhyStatus; + UINT32 Features; + UINT32 TimeOut; + + // First check that auto-negotiation is supported + PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) { + DEBUG ((EFI_D_ERROR, "Auto-negotiation not supported.\n")); + return EFI_DEVICE_ERROR; + } + + // Check that link is up first + if ((PhyStatus & PHYSTS_LINK_STS) == 0) { + // Wait until it is up or until Time Out + TimeOut = 2000; + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_LINK_STS) == 0) { + gBS->Stall (LAN9118_STALL); + TimeOut--; + if (!TimeOut) { + DEBUG ((EFI_D_ERROR, "Link timeout in auto-negotiation.\n")); + return EFI_TIMEOUT; + } + } + } + + // Configure features to advertise + Features = IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT); + + if ((Flags & AUTO_NEGOTIATE_ADVERTISE_ALL) > 0) { + // Link speed capabilities + Features |= (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | PHYANA_100BASETXFD); + + // Pause frame capabilities + Features &= ~(PHYANA_PAUSE_OP_MASK); + Features |= 3 << 10; + } + + // Write the features + IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, Features); + + // Read control register + PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL); + + // Enable Auto-Negotiation + if ((PhyControl & PHYCR_AUTO_EN) == 0) { + PhyControl |= PHYCR_AUTO_EN; + } + + // Restart auto-negotiation + PhyControl |= PHYCR_RST_AUTO; + + // Enable collision test if required to do so + if (Flags & AUTO_NEGOTIATE_COLLISION_TEST) { + PhyControl |= PHYCR_COLL_TEST; + } else { + PhyControl &= ~ PHYCR_COLL_TEST; + } + + // Write this configuration + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait until process has completed + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0); + + return EFI_SUCCESS; +} + +// Check the Link Status and take appropriate action +EFI_STATUS +CheckLinkStatus ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + // Get the PHY Status + UINT32 PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + + if (PhyBStatus & PHYSTS_LINK_STS) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } +} + +// Stop the transmitter +EFI_STATUS +StopTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 TxCfg; + + MacCsr = 0; + TxCfg = 0; + + // Check if we want to clear tx + if (Flags & STOP_TX_CLEAR) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // Check if already stopped + if (Flags & STOP_TX_MAC) { + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_TX_EN) { + MacCsr &= ~MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + } + + if (Flags & STOP_TX_CFG) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + + if (TxCfg & TXCFG_TX_ON) { + TxCfg |= TXCFG_STOP_TX; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + + // Wait for Tx to finish transmitting + while (MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX); + } + } + + return EFI_SUCCESS; +} + +// Stop the receiver +EFI_STATUS +StopRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg = 0; + + // Check if already stopped + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_RX_EN) { + MacCsr &= ~ MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + + // Check if we want to clear receiver FIFOs + if (Flags & STOP_RX_CLEAR) { + RxCfg = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + return EFI_SUCCESS; +} + +// Start the transmitter +EFI_STATUS +StartTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 TxCfg; + + MacCsr = 0; + TxCfg = 0; + + // Check if we want to clear tx + if (Flags & START_TX_CLEAR) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + + // Check if tx was started from MAC and enable if not + if (Flags & START_TX_MAC) { + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + gBS->Stall (LAN9118_STALL); + if ((MacCsr & MACCR_TX_EN) == 0) { + MacCsr |= MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + } + + // Check if tx was started from TX_CFG and enable if not + if (Flags & START_TX_CFG) { + TxCfg = MmioRead32 (LAN9118_TX_CFG); + gBS->Stall (LAN9118_STALL); + if ((TxCfg & TXCFG_TX_ON) == 0) { + TxCfg |= TXCFG_TX_ON; + MmioWrite32 (LAN9118_TX_CFG, TxCfg); + gBS->Stall (LAN9118_STALL); + } + } + + // Set the tx data trigger level + + return EFI_SUCCESS; +} + +// Start the receiver +EFI_STATUS +StartRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg = 0; + + // Check if already started + MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if ((MacCsr & MACCR_RX_EN) == 0) { + // Check if we want to clear receiver FIFOs before starting + if (Flags & START_RX_CLEAR) { + RxCfg = MmioRead32 (LAN9118_RX_CFG); + RxCfg |= RXCFG_RX_DUMP; + MmioWrite32 (LAN9118_RX_CFG, RxCfg); + gBS->Stall (LAN9118_STALL); + + while (MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + MacCsr |= MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + gBS->Stall (LAN9118_STALL); + } + + return EFI_SUCCESS; +} + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 FreeSpace; + + // Get the amount of free space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK); + + return FreeSpace; // Value in bytes +} + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + TxInf = MmioRead32 (LAN9118_TX_FIFO_INF); + UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16; + + return UsedSpace << 2; // Value in bytes +} + +// Check Rx Data used space +UINT32 +RxDataUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf = MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace = (RxInf & RXFIFOINF_RXDUSED_MASK); + + return UsedSpace; // Value in bytes (rounded up to nearest DWORD) +} + +// Check Rx Status used space +UINT32 +RxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf = MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace = (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16; + + return UsedSpace << 2; // Value in bytes +} + + +// Change the allocation of FIFOs +EFI_STATUS +ChangeFifoAllocation ( + IN UINT32 Flags, + IN OUT UINTN *TxDataSize OPTIONAL, + IN OUT UINTN *RxDataSize OPTIONAL, + IN OUT UINT32 *TxStatusSize OPTIONAL, + IN OUT UINT32 *RxStatusSize OPTIONAL, + IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 TxFifoOption; + + // Check that desired sizes don't exceed limits + if (*TxDataSize > TX_FIFO_MAX_SIZE) + return EFI_INVALID_PARAMETER; + +#if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE) + if (*RxDataSize > RX_FIFO_MAX_SIZE) { + return EFI_INVALID_PARAMETER; + } +#endif + + if (Flags & ALLOC_USE_DEFAULT) { + return EFI_SUCCESS; + } + + // If we use the FIFOs (always use this first) + if (Flags & ALLOC_USE_FIFOS) { + // Read the current value of allocation + HwConf = MmioRead32 (LAN9118_HW_CFG); + TxFifoOption = (HwConf >> 16) & 0xF; + + // Choose the correct size (always use larger than requested if possible) + if (*TxDataSize < TX_FIFO_MIN_SIZE) { + *TxDataSize = TX_FIFO_MIN_SIZE; + *RxDataSize = 13440; + *RxStatusSize = 896; + TxFifoOption = 2; + } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <= 2560)) { + *TxDataSize = 2560; + *RxDataSize = 12480; + *RxStatusSize = 832; + TxFifoOption = 3; + } else if ((*TxDataSize > 2560) && (*TxDataSize <= 3584)) { + *TxDataSize = 3584; + *RxDataSize = 11520; + *RxStatusSize = 768; + TxFifoOption = 4; + } else if ((*TxDataSize > 3584) && (*TxDataSize <= 4608)) { // default option + *TxDataSize = 4608; + *RxDataSize = 10560; + *RxStatusSize = 704; + TxFifoOption = 5; + } else if ((*TxDataSize > 4608) && (*TxDataSize <= 5632)) { + *TxDataSize = 5632; + *RxDataSize = 9600; + *RxStatusSize = 640; + TxFifoOption = 6; + } else if ((*TxDataSize > 5632) && (*TxDataSize <= 6656)) { + *TxDataSize = 6656; + *RxDataSize = 8640; + *RxStatusSize = 576; + TxFifoOption = 7; + } else if ((*TxDataSize > 6656) && (*TxDataSize <= 7680)) { + *TxDataSize = 7680; + *RxDataSize = 7680; + *RxStatusSize = 512; + TxFifoOption = 8; + } else if ((*TxDataSize > 7680) && (*TxDataSize <= 8704)) { + *TxDataSize = 8704; + *RxDataSize = 6720; + *RxStatusSize = 448; + TxFifoOption = 9; + } else if ((*TxDataSize > 8704) && (*TxDataSize <= 9728)) { + *TxDataSize = 9728; + *RxDataSize = 5760; + *RxStatusSize = 384; + TxFifoOption = 10; + } else if ((*TxDataSize > 9728) && (*TxDataSize <= 10752)) { + *TxDataSize = 10752; + *RxDataSize = 4800; + *RxStatusSize = 320; + TxFifoOption = 11; + } else if ((*TxDataSize > 10752) && (*TxDataSize <= 11776)) { + *TxDataSize = 11776; + *RxDataSize = 3840; + *RxStatusSize = 256; + TxFifoOption = 12; + } else if ((*TxDataSize > 11776) && (*TxDataSize <= 12800)) { + *TxDataSize = 12800; + *RxDataSize = 2880; + *RxStatusSize = 192; + TxFifoOption = 13; + } else if ((*TxDataSize > 12800) && (*TxDataSize <= 13824)) { + *TxDataSize = 13824; + *RxDataSize = 1920; + *RxStatusSize = 128; + TxFifoOption = 14; + } + } else { + ASSERT(0); // Untested code path + HwConf = 0; + TxFifoOption = 0; + } + + // Do we need DMA? + if (Flags & ALLOC_USE_DMA) { + return EFI_UNSUPPORTED; // Unsupported as of now + } + // Clear and assign the new size option + HwConf &= ~(0xF0000); + HwConf |= ((TxFifoOption & 0xF) << 16); + MmioWrite32 (LAN9118_HW_CFG, HwConf); + gBS->Stall (LAN9118_STALL); + + return EFI_SUCCESS; +} diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h new file mode 100644 index 0000000000..e75bbad3c0 --- /dev/null +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h @@ -0,0 +1,266 @@ +/** @file +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __LAN9118_DXE_UTIL_H__ +#define __LAN9118_DXE_UTIL_H__ + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + +/** + This internal function reverses bits for 32bit data. + + @param Value The data to be reversed. + + @return Data reversed. + +**/ +UINT32 +ReverseBits ( + UINT32 Value + ); + +// Create an Ethernet CRC +UINT32 +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ); + +/* ------------------ MAC CSR Access ------------------- */ + +// Read from MAC indirect registers +UINT32 +IndirectMACRead32 ( + UINT32 Index + ); + + +// Write to indirect registers +UINT32 +IndirectMACWrite32 ( + UINT32 Index, + UINT32 Value + ); + + +/* --------------- PHY Registers Access ---------------- */ + +// Read from MII register (PHY Access) +UINT32 +IndirectPHYRead32( + UINT32 Index + ); + + +// Write to the MII register (PHY Access) +UINT32 +IndirectPHYWrite32( + UINT32 Index, + UINT32 Value + ); + +/* ---------------- EEPROM Operations ------------------ */ + +// Read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index + ); + +// Write to EEPROM memory +UINT32 +IndirectEEPROMWrite32 ( + UINT32 Index, + UINT32 Value + ); + +/* ---------------- General Operations ----------------- */ + +VOID +Lan9118SetMacAddress ( + EFI_MAC_ADDRESS *Mac, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Initialise the LAN9118 +EFI_STATUS +Lan9118Initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for software reset +#define SOFT_RESET_CHECK_MAC_ADDR_LOAD BIT0 +#define SOFT_RESET_CLEAR_INT BIT1 +#define SOFT_RESET_SELF_TEST BIT2 + +// Perform software reset on the LAN9118 +EFI_STATUS +SoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for PHY reset +#define PHY_RESET_PMT BIT0 +#define PHY_RESET_BCR BIT1 +#define PHY_RESET_CHECK_LINK BIT2 +#define PHY_SOFT_RESET_CLEAR_INT BIT3 + +// Perform PHY software reset +INT32 +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for Hardware configuration +#define HW_CONF_USE_LEDS BIT0 + +// Configure hardware for LAN9118 +EFI_STATUS +ConfigureHardware ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Configure flow control +EFI_STATUS +ConfigureFlow ( + UINT32 Flags, + UINT32 HighTrig, + UINT32 LowTrig, + UINT32 BPDuration, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for auto negotiation +#define AUTO_NEGOTIATE_COLLISION_TEST BIT0 +#define AUTO_NEGOTIATE_ADVERTISE_ALL BIT1 + +// Do auto-negotiation +EFI_STATUS +AutoNegotiate ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check the Link Status and take appropriate action +EFI_STATUS +CheckLinkStatus ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop transmitter flags +#define STOP_TX_MAC BIT0 +#define STOP_TX_CFG BIT1 +#define STOP_TX_CLEAR BIT2 + +// Stop the transmitter +EFI_STATUS +StopTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop receiver flags +#define STOP_RX_CLEAR BIT0 + +// Stop the receiver +EFI_STATUS +StopRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Start transmitter flags +#define START_TX_MAC BIT0 +#define START_TX_CFG BIT1 +#define START_TX_CLEAR BIT2 + +// Start the transmitter +EFI_STATUS +StartTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop receiver flags +#define START_RX_CLEAR BIT0 + +// Start the receiver +EFI_STATUS +StartRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Rx Data used space +UINT32 +RxDataUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Rx Status used space +UINT32 +RxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + + +// Flags for FIFO allocation +#define ALLOC_USE_DEFAULT BIT0 +#define ALLOC_USE_FIFOS BIT1 +#define ALLOC_USE_DMA BIT2 + +// FIFO min and max sizes +#define TX_FIFO_MIN_SIZE 0x00000600 +#define TX_FIFO_MAX_SIZE 0x00003600 +//#define RX_FIFO_MIN_SIZE +//#define RX_FIFO_MAX_SIZE + +// Change the allocation of FIFOs +EFI_STATUS +ChangeFifoAllocation ( + IN UINT32 Flags, + IN OUT UINTN *TxDataSize OPTIONAL, + IN OUT UINTN *RxDataSize OPTIONAL, + IN OUT UINT32 *TxStatusSize OPTIONAL, + IN OUT UINT32 *RxStatusSize OPTIONAL, + IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +VOID +Lan9118ReadMacAddress ( + OUT EFI_MAC_ADDRESS *Mac + ); + +#endif // __LAN9118_DXE_UTIL_H__ diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index 84fbeb376d..ee3ff31ddd 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -129,6 +129,10 @@ gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount|10000000|UINT32|0x0000004c gEmbeddedTokenSpaceGuid.PcdGdbTimerPeriodMilliseconds|250|UINT32|0x0000004d + # LAN9118 Ethernet Driver PCDs + gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x00000025 + gEmbeddedTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x0|UINT64|0x00000026 + # # Android FastBoot # diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index 41c0c43002..c5d4ae6d1a 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -100,6 +100,11 @@ FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf + # Networking Requirements + NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + [LibraryClasses.common.DXE_DRIVER] PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf @@ -260,6 +265,7 @@ # Drivers EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf + EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf [Components.IA32, Components.X64, Components.IPF, Components.ARM] EmbeddedPkg/GdbStub/GdbStub.inf