diff options
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c | 1356 | ||||
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h | 303 | ||||
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf | 57 | ||||
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h | 329 | ||||
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c | 1021 | ||||
-rw-r--r-- | EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h | 266 | ||||
-rw-r--r-- | EmbeddedPkg/EmbeddedPkg.dec | 4 | ||||
-rw-r--r-- | EmbeddedPkg/EmbeddedPkg.dsc | 6 |
8 files changed, 3342 insertions, 0 deletions
diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c new file mode 100644 index 0000000..fcaa351 --- /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 0000000..7d83b4f --- /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 <Uefi.h>
+#include <Uefi/UefiSpec.h>
+#include <Base.h>
+
+// Protocols used by this driver
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/PxeBaseCode.h>
+#include <Protocol/DevicePath.h>
+
+// Libraries used by this driver
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/NetLib.h>
+#include <Library/DevicePathLib.h>
+
+#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 0000000..392a7b5 --- /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 0000000..9e89d27 --- /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 0000000..99c3ff0 --- /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 0000000..e75bbad --- /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 84fbeb3..ee3ff31 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 41c0c43..c5d4ae6 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
|