summaryrefslogtreecommitdiff
path: root/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c')
-rw-r--r--SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c
new file mode 100644
index 000000000..51a8c1617
--- /dev/null
+++ b/SamsungPlatformPkg/ExynosPkg/Exynos5250/Drivers/EthDxe/EthDxe.c
@@ -0,0 +1,788 @@
+/** @file
+ Template for Timer Architecture Protocol driver of the ARM flavor
+
+ Copyright (c) 2012, Samsung Electronics Co. All rights reserved.<BR>
+
+ 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 <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/NetLib.h>
+#include <Library/TimerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/ExynosGpio.h>
+#include <Platform/ArmPlatform.h>
+#include "EthDxe.h"
+
+
+ETH_DXE_PRIVATE_DATA gEthDxePrivateTemplate = {
+ ETH_DXE_PRIVATE_DATA_SIGNATURE,
+ {
+ EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
+ EthStart,
+ EthStop,
+ EthInitialize,
+ EthReset,
+ EthShutdown,
+ EthReceiveFilters,
+ EthStationAddress,
+ EthStatistics,
+ EthMCastIpToMac,
+ EthNvData,
+ EthGetStatus,
+ EthTransmit,
+ EthReceive,
+ NULL,
+ NULL
+ },
+ {
+ EfiSimpleNetworkStopped, // State
+ NET_ETHER_ADDR_LEN, // HwAddressSize
+ NET_ETHER_HEADER_SIZE, // MediaHeaderSize
+ 1500, // MaxPacketSize
+ 0, // NvRamSize
+ 0, // NvRamAccessSize
+ 0, // ReceiveFilterMask
+ 0, // ReceiveFilterSetting
+ MAX_MCAST_FILTER_CNT, // MaxMCastFilterCount
+ 0, // MCastFilterCount
+ {
+ 0
+ }, // MCastFilter
+ {
+ 0
+ }, // CurrentAddress
+ {
+ 0
+ }, // BroadcastAddress
+ {
+ 0
+ }, // PermanentAddress
+ NET_IFTYPE_ETHERNET, // IfType
+ FALSE, // MacAddressChangeable
+ FALSE, // MultipleTxSupported
+ FALSE, // MediaPresentSupported
+ TRUE // MediaPresent
+ },
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
+ EFI_SIMPLE_NETWORK_PROTOCOL_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+ }
+};
+
+
+UINT32 smc911x_reg_read(UINT32 offset)
+{
+ UINT32 regBase = PcdGet32(PcdSMC911XBase);
+ UINT32 val;
+
+ val = (MmioRead16(regBase + offset) & 0xFFFF) | ((MmioRead16(regBase + offset + 2) & 0xFFFF) << 16);
+
+ return val;
+}
+
+VOID smc911x_reg_write(UINT32 offset, UINT32 val)
+{
+ UINT32 regBase = PcdGet32(PcdSMC911XBase);
+
+ MmioWrite16(regBase + offset, ((UINT16)(val & 0xFFFF)));
+ MmioWrite16(regBase + offset + 2, ((UINT16)((val & 0xFFFF0000)>>16)));
+}
+
+UINT32 smc911x_get_mac_csr(UINT8 reg)
+{
+ while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(MAC_CSR_CMD, (MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg));
+ while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ return smc911x_reg_read(MAC_CSR_DATA);
+}
+
+VOID smc911x_set_mac_csr(UINT8 reg, UINT32 data)
+{
+ while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(MAC_CSR_DATA, data);
+ smc911x_reg_write(MAC_CSR_CMD, (MAC_CSR_CMD_CSR_BUSY | reg));
+ while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+}
+
+VOID smc911x_reset(VOID)
+{
+ INT32 timeout;
+
+ /* Take out of PM setting first */
+ if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) {
+ /* Write to the bytetest will take out of powerdown */
+ smc911x_reg_write(BYTE_TEST, 0x0);
+
+ timeout = 10;
+
+ while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY))
+ MicroSecondDelay(10);
+ if (!timeout) {
+ DEBUG((EFI_D_ERROR, "smc911x_reset: timeout waiting for PM restore\n"));
+ return;
+ }
+ }
+
+ /* Disable interrupts */
+ smc911x_reg_write(INT_EN, 0);
+
+ smc911x_reg_write(HW_CFG, HW_CFG_SRST);
+
+ timeout = 1000;
+ while (timeout-- && (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY))
+ MicroSecondDelay(10);
+
+ if (!timeout) {
+ DEBUG((EFI_D_ERROR, "smc911x_reset: reset timeout\n"));
+ return;
+ }
+
+ /* Reset the FIFO level and flow control settings */
+ smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN);
+ smc911x_reg_write(AFC_CFG, 0x0050287F);
+
+ /* Set to LED outputs */
+ smc911x_reg_write(GPIO_CFG, 0x70070000);
+}
+
+VOID smc911x_phy_reset(VOID)
+{
+ UINT32 reg;
+
+ reg = smc911x_reg_read(PMT_CTRL);
+ reg &= ~0xfffff030;
+ reg |= PMT_CTRL_PHY_RST;
+ smc911x_reg_write(PMT_CTRL, reg);
+
+ MicroSecondDelay(100000);
+}
+
+VOID smc911x_miiphy_read(UINT8 phy, UINT8 reg, UINT16 *val)
+{
+ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ smc911x_set_mac_csr(MII_ACC, (phy << 11 | reg << 6 | MII_ACC_MII_BUSY));
+
+ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ *val = smc911x_get_mac_csr(MII_DATA);
+}
+
+VOID smc911x_miiphy_write(UINT8 phy, UINT8 reg, UINT16 val)
+{
+ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+
+ smc911x_set_mac_csr(MII_DATA, val);
+ smc911x_set_mac_csr(MII_ACC, (phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE));
+
+ while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
+ ;
+}
+
+VOID smc911x_phy_configure(VOID)
+{
+ INT32 timeout;
+ UINT16 status;
+
+ smc911x_phy_reset();
+
+ smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET);
+ MicroSecondDelay(1000);
+ smc911x_miiphy_write(1, PHY_ANAR, 0x01e1);
+ smc911x_miiphy_write(1, PHY_BMCR, (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG));
+
+ timeout = 5000;
+ do {
+ MicroSecondDelay(1000);
+ if ((timeout--) == 0)
+ goto err_out;
+
+ smc911x_miiphy_read(1, PHY_BMSR, &status);
+ } while (!(status & PHY_BMSR_LS));
+
+ DEBUG((EFI_D_ERROR, "smc911x_phy_configure: PHY initialized\n"));
+
+ return;
+
+err_out:
+ DEBUG((EFI_D_ERROR, "smc911x_phy_configure: autonegotiation timed out\n"));
+}
+
+VOID smc911x_handle_mac_address(ETH_DXE_PRIVATE_DATA *Private)
+{
+ UINT32 addrh, addrl;
+
+ addrl = Private->Mode.CurrentAddress.Addr[0] | \
+ (Private->Mode.CurrentAddress.Addr[1] << 8) | \
+ (Private->Mode.CurrentAddress.Addr[2] << 16) | \
+ (Private->Mode.CurrentAddress.Addr[3] << 24);
+ addrh = Private->Mode.CurrentAddress.Addr[4] | \
+ (Private->Mode.CurrentAddress.Addr[5] << 8);
+
+ smc911x_set_mac_csr(ADDRL, addrl);
+ smc911x_set_mac_csr(ADDRH, addrh);
+}
+
+VOID smc911x_enable(VOID)
+{
+ /* Enable TX */
+ smc911x_reg_write(HW_CFG, (8 << 16 | HW_CFG_SF));
+
+ smc911x_reg_write(GPT_CFG, (GPT_CFG_TIMER_EN | 10000));
+
+ smc911x_reg_write(TX_CFG, TX_CFG_TX_ON);
+
+ /* no padding to start of packets */
+ smc911x_reg_write(RX_CFG, 0);
+
+ smc911x_set_mac_csr(MAC_CR, (MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS /*| MAC_CR_PADSTR*/));
+}
+
+EFI_STATUS
+EFIAPI
+EthStart(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This
+)
+{
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This);
+
+ switch ( Private->Snp.Mode->State )
+ {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ return( EFI_ALREADY_STARTED );
+ break;
+
+ default:
+ return( EFI_DEVICE_ERROR );
+ break;
+ }
+
+ /* gpio configuration */
+ MmioAndThenOr32(0x11000000 + 0x120, ~((0xFF<<16)|(0xFF<<4)), ((0x22<<16)|(0x52<<4)));
+
+ /* 16 Bit bus width */
+ MmioWrite32(0x11000000 + 0x1C0, 0x22222222);
+ MmioWrite32(0x11000000 + 0x1E0, 0x22222222);
+
+ /* SROM BANK1 */
+ MmioAndThenOr32(0x12570000, ~(0xF<<4), (((1<<0)|(0<<2)|(1<<3))<<4));
+
+ /* set timing for nCS1 suitable for ethernet chip */
+ MmioWrite32(0x12570008, ((0x1 << 0) | (0x9 << 4) | (0xC << 8) | (0x1 << 12) | \
+ (0x6 << 16) | (0x1 << 24) | (0x1 << 28)));
+
+ Private->Snp.Mode->State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthStop(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This
+)
+{
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This);
+
+ switch ( Private->Snp.Mode->State )
+ {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return( EFI_NOT_STARTED );
+ break;
+
+ default:
+ return( EFI_DEVICE_ERROR );
+ break;
+ }
+
+ Private->Snp.Mode->State = EfiSimpleNetworkStopped;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthInitialize(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ UINTN ExtraRxBufferSize,
+ UINTN ExtraTxBufferSize
+)
+{
+ UINT32 val, i, addrh, addrl;
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This);
+
+ switch ( Private->Snp.Mode->State )
+ {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return( EFI_NOT_STARTED );
+ break;
+
+ default:
+ return( EFI_DEVICE_ERROR );
+ break;
+ }
+
+ val = smc911x_reg_read(BYTE_TEST);
+
+ if(val == 0xFFFFFFFF) {
+ return EFI_NO_MEDIA;
+ }
+ else if(val != 0x87654321) {
+ DEBUG((EFI_D_ERROR,"EthInitialize: Invalid chip endian 0x%x\n", val));
+ return EFI_NO_MEDIA;
+ }
+
+ val = smc911x_reg_read(ID_REV) >> 16;
+ for(i=0;chip_ids[i].id != 0;i++) {
+ if(chip_ids[i].id == val)
+ break;
+ }
+
+ if(!chip_ids[i].id) {
+ DEBUG((EFI_D_ERROR,"EthInitialize: Unknown chip id 0x%x\n", val));
+ return EFI_NO_MEDIA;
+ }
+ else {
+ DEBUG((EFI_D_ERROR,"EthInitialize: Chip id 0x%x\n", val));
+ }
+
+ addrh = smc911x_get_mac_csr(ADDRH);
+ addrl = smc911x_get_mac_csr(ADDRL);
+
+ if (addrl == 0xffffffff && addrh == 0x0000ffff) {
+ addrh = 0x00000040;
+ addrl = 0x5c260a5b;
+ }
+
+ Private->Mode.CurrentAddress.Addr[0] = (addrl & 0xFF);
+ Private->Mode.CurrentAddress.Addr[1] = (addrl & 0xFF00)>>8;
+ Private->Mode.CurrentAddress.Addr[2] = (addrl & 0xFF0000)>>16;
+ Private->Mode.CurrentAddress.Addr[3] = (addrl & 0xFF000000)>>24;
+ Private->Mode.CurrentAddress.Addr[4] = (addrh & 0xFF);
+ Private->Mode.CurrentAddress.Addr[5] = (addrh & 0xFF00)>>8;
+ gBS->CopyMem((VOID *)&Private->Mode.PermanentAddress, \
+ (VOID *)&Private->Mode.CurrentAddress, \
+ sizeof(EFI_MAC_ADDRESS));
+
+ DEBUG((EFI_D_ERROR,"EthInitialize: MAC address is "));
+
+ for(i=6;i>0;i--) {
+ DEBUG((EFI_D_ERROR,"%02x", Private->Mode.CurrentAddress.Addr[i - 1]));
+ if(i > 1)
+ DEBUG((EFI_D_ERROR,":"));
+ else
+ DEBUG((EFI_D_ERROR,"\n"));
+ }
+
+ smc911x_reset();
+
+ /* Configure the PHY, initialize the link state */
+ smc911x_phy_configure();
+
+ smc911x_handle_mac_address(Private);
+
+ /* Turn on Tx + Rx */
+ smc911x_enable();
+
+ Private->Snp.Mode->State = EfiSimpleNetworkInitialized;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthReset(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ BOOLEAN ExtendedVerification
+)
+{
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This);
+
+ switch ( Private->Snp.Mode->State )
+ {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return( EFI_NOT_STARTED );
+ break;
+
+ default:
+ return( EFI_DEVICE_ERROR );
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthShutdown(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This
+)
+{
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ Private = ETH_DXE_PRIVATE_DATA_FROM_SNP_THIS(This);
+
+ switch ( Private->Snp.Mode->State )
+ {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return( EFI_NOT_STARTED );
+ break;
+
+ default:
+ return( EFI_DEVICE_ERROR );
+ break;
+ }
+
+ Private->Snp.Mode->State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthReceiveFilters(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ UINT32 Enable,
+ UINT32 Disable,
+ BOOLEAN ResetMCastFilter,
+ UINTN MCastFilterCnt,
+ EFI_MAC_ADDRESS *MCastFilter
+)
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthStationAddress(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ BOOLEAN Reset,
+ EFI_MAC_ADDRESS *New
+)
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+EthStatistics(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ BOOLEAN Reset,
+ UINTN *StatisticsSize,
+ EFI_NETWORK_STATISTICS *StatisticsTable
+)
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+EthMCastIpToMac(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ BOOLEAN IPv6,
+ EFI_IP_ADDRESS *IP,
+ EFI_MAC_ADDRESS *MAC
+)
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+EthNvData(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ BOOLEAN ReadWrite,
+ UINTN Offset,
+ UINTN BufferSize,
+ VOID *Buffer
+)
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+EthGetStatus(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ UINT32 *InterruptStatus,
+ VOID **TxBuf
+)
+{
+ if ( TxBuf != NULL ) {
+ *( ( UINT8 ** ) TxBuf ) = ( UINT8 * ) 1;
+ }
+
+ if ( InterruptStatus != NULL ) {
+ *InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+EthTransmit(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ UINTN HeaderSize,
+ UINTN BufferSize,
+ VOID *Buffer,
+ EFI_MAC_ADDRESS *SrcAddr,
+ EFI_MAC_ADDRESS *DestAddr,
+ UINT16 *Protocol
+)
+{
+ UINT32 *data = (UINT32 *)Buffer;
+ UINT32 tmpSize;
+ UINT32 status;
+ EthernetHeader *EnetHeader;
+
+ if ( This->Mode->State < EfiSimpleNetworkStarted ) {
+ return( EFI_NOT_STARTED );
+ }
+
+ if ( HeaderSize != 0 ) {
+ if ( ( DestAddr == NULL ) || ( Protocol == NULL ) || \
+ ( HeaderSize != This->Mode->MediaHeaderSize ) ) {
+ return( EFI_INVALID_PARAMETER );
+ }
+
+ if ( SrcAddr == NULL ) {
+ SrcAddr = &This->Mode->CurrentAddress;
+ }
+
+ EnetHeader = (EthernetHeader *)Buffer;
+
+ CopyMem( EnetHeader->DstAddr, DestAddr, NET_ETHER_ADDR_LEN );
+ CopyMem( EnetHeader->SrcAddr, SrcAddr, NET_ETHER_ADDR_LEN );
+
+ EnetHeader->Type = HTONS( *Protocol );
+ }
+
+ smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | BufferSize);
+ smc911x_reg_write(TX_DATA_FIFO, BufferSize);
+
+ tmpSize = (BufferSize + 3) / 4;
+
+ while (tmpSize--)
+ smc911x_reg_write(TX_DATA_FIFO, *data++);
+
+ /* wait for transmission */
+ while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16))
+ ;
+
+ /* get status. Ignore 'no carrier' error, it has no meaning for
+ * full duplex operation
+ */
+ status = smc911x_reg_read(TX_STATUS_FIFO) & \
+ (TX_STS_LOC | TX_STS_LATE_COLL | \
+ TX_STS_MANY_COLL | TX_STS_MANY_DEFER | \
+ TX_STS_UNDERRUN);
+
+ if (!status)
+ return EFI_SUCCESS;
+
+ DEBUG((EFI_D_ERROR, "EthTransmit: Failed to send packet: %s%s%s%s%s\n",
+ status & TX_STS_LOC ? "TX_STS_LOC " : "",
+ status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
+ status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
+ status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
+ status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : ""));
+
+ return EFI_DEVICE_ERROR;
+}
+
+EFI_STATUS
+EFIAPI
+EthReceive(
+ EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ UINTN *HeaderSize,
+ UINTN *BufferSize,
+ VOID *Buffer,
+ EFI_MAC_ADDRESS *SrcAddr,
+ EFI_MAC_ADDRESS *DestAddr,
+ UINT16 *Protocol
+)
+{
+ UINT32 *data = (UINT32 *)Buffer;
+ UINT32 pktSize, tmpSize;
+ UINT32 status, i;
+ EthernetHeader *EnetHeader;
+
+ /* workaround: delay for rx packet should be added here.
+ * because NetLoop does not guarantee the RX packet delay.
+ */
+ for (i=0; i<0x100000; i++) {
+ if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16)
+ break;
+ }
+
+ if (i == 0x100000) {
+ DEBUG((EFI_D_ERROR, "EthReceive: timeout in RX\n"));
+ return EFI_TIMEOUT;
+ }
+
+ if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
+ status = smc911x_reg_read(RX_STATUS_FIFO);
+ pktSize = (status & RX_STS_PKT_LEN) >> 16;
+
+ smc911x_reg_write(RX_CFG, 0);
+
+ tmpSize = (pktSize + 3) / 4;
+ i = 0;
+ while (tmpSize--)
+ *data++ = smc911x_reg_read(RX_DATA_FIFO);
+
+ if (status & RX_STS_ES) {
+ DEBUG((EFI_D_ERROR, "EthReceive: dropped bad packet. Status: 0x%x\n", status));
+ }
+
+ *BufferSize = pktSize -4; //discard 4 bytes of FCS
+
+ }
+
+#if 0
+ {
+ UINT8 *tmpBuffer = (UINT8 *)Buffer;
+
+ for(i=0;i<*BufferSize;i++) {
+ DEBUG((EFI_D_ERROR, "%02x", *tmpBuffer++));
+ if((i%16) < 15)
+ DEBUG((EFI_D_ERROR, " "));
+ else
+ DEBUG((EFI_D_ERROR, "\n"));
+ }
+
+ DEBUG((EFI_D_ERROR, "\n"));
+ }
+#endif
+
+ if(HeaderSize != NULL) {
+ *HeaderSize = sizeof(EthernetHeader);
+ }
+
+ EnetHeader = (EthernetHeader *)Buffer;
+
+ if(SrcAddr != NULL) {
+ ZeroMem(SrcAddr, sizeof(EFI_MAC_ADDRESS));
+ CopyMem(SrcAddr, EnetHeader->SrcAddr, NET_ETHER_ADDR_LEN);
+ }
+
+ if(DestAddr != NULL) {
+ ZeroMem(DestAddr, sizeof(EFI_MAC_ADDRESS));
+ CopyMem(DestAddr, EnetHeader->DstAddr, NET_ETHER_ADDR_LEN);
+ }
+
+ if (Protocol != NULL) {
+ *Protocol = NTOHS(EnetHeader->Type);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize the state information for the Display Dxe
+
+ @param ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Protocol registered
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Hardware problems
+
+**/
+EFI_STATUS
+EFIAPI
+EthDxeInitialize (
+ EFI_HANDLE ImageHandle,
+ EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_GUID SimpleNetworkProtocolGuid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
+ EFI_GUID DevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID;
+ ETH_DXE_PRIVATE_DATA *Private;
+
+ /* Allocate the private data */
+ Private = (ETH_DXE_PRIVATE_DATA *)AllocateCopyPool(sizeof(ETH_DXE_PRIVATE_DATA), &gEthDxePrivateTemplate );
+ if ( Private == NULL ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ Private->Snp.Mode = &Private->Mode;
+
+ /* Set the broadcast address */
+ SetMem( &Private->Mode.BroadcastAddress, sizeof( EFI_MAC_ADDRESS ), 0xFF );
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &DevicePathProtocolGuid,
+ &Private->DevicePath,
+ &SimpleNetworkProtocolGuid,
+ &Private->Snp,
+ NULL);
+
+ return Status;
+}