diff --git a/Platform/Sophgo/SG2044Pkg/SG2044.dsc b/Platform/Sophgo/SG2044Pkg/SG2044.dsc index 51eee3679a..aa7e40e30c 100644 --- a/Platform/Sophgo/SG2044Pkg/SG2044.dsc +++ b/Platform/Sophgo/SG2044Pkg/SG2044.dsc @@ -43,6 +43,7 @@ DEFINE NETWORK_ISCSI_ENABLE = FALSE DEFINE FLASH_ENABLE = TRUE + DEFINE ETH_ENABLE = FALSE # # x64 Emulator @@ -276,6 +277,7 @@ RngLib|Silicon/Sophgo/Library/RngLib/RngLib.inf ResetSystemLib|OvmfPkg/RiscVVirt/Library/ResetSystemLib/BaseResetSystemLib.inf + DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf [LibraryClasses.common.SEC] ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf ExtractGuidedSectionLib|MdePkg/Library/BaseExtractGuidedSectionLib/BaseExtractGuidedSectionLib.inf @@ -469,8 +471,11 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|50000000 +!if $(ETH_ENABLE) == TRUE gSophgoTokenSpaceGuid.PcdPhyResetGpio|TRUE gSophgoTokenSpaceGuid.PcdPhyResetGpioPin|28 + gSophgoTokenSpaceGuid.PcdDwMac4DefaultMacAddress|0x12345678ABCD +!endif [PcdsFixedAtBuild.common] gSophgoTokenSpaceGuid.PcdSDIOSourceClockFrequency|400000000 gSophgoTokenSpaceGuid.PcdSDIOTransmissionClockFrequency|25000000 @@ -585,8 +590,11 @@ Silicon/Sophgo/Drivers/SdHostDxe/SdHostDxe.inf Silicon/Sophgo/Drivers/DwSpiDxe/DwSpiDxe.inf Silicon/Sophgo/Drivers/DwGpioDxe/DwGpioDxe.inf +!if $(ETH_ENABLE) == TRUE Silicon/Sophgo/Drivers/Net/StmmacMdioDxe/StmmacMdioDxe.inf Silicon/Sophgo/Drivers/Net/MotorcommPhyDxe/Motorcomm8531PhyDxe.inf + Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.inf +!endif # # RISC-V Core module diff --git a/Platform/Sophgo/SG2044Pkg/SG2044.fdf b/Platform/Sophgo/SG2044Pkg/SG2044.fdf index f094b57d29..5a5e5e586b 100644 --- a/Platform/Sophgo/SG2044Pkg/SG2044.fdf +++ b/Platform/Sophgo/SG2044Pkg/SG2044.fdf @@ -124,8 +124,11 @@ INF Platform/Sophgo/SG2044Pkg/Drivers/SmbiosPlatformDxe/SmbiosPlatformDxe.inf # Network modules # !include NetworkPkg/Network.fdf.inc +!if $(ETH_ENABLE) == TRUE INF Silicon/Sophgo/Drivers/Net/StmmacMdioDxe/StmmacMdioDxe.inf INF Silicon/Sophgo/Drivers/Net/MotorcommPhyDxe/Motorcomm8531PhyDxe.inf +INF Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.inf +!endif # # Random Number Generator Support diff --git a/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.c b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.c new file mode 100755 index 0000000000..3259ab8e19 --- /dev/null +++ b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.c @@ -0,0 +1,1902 @@ +/** @file + + Copyright (c) 2024, SOPHGO Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include + +#include +#include "DwMac4DxeUtil.h" +#include +//STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; + + +struct StmmacRxRouting { + UINT32 RegMask; + UINT32 RegShift; +}; + +UINT32 RxChannelsCount = 1; +UINT32 TxChannelsCount = 1; +UINT32 RxQueuesToUse = 1; +UINT32 TxQueuesToUse = 1; + +STATIC +UINT32 +DwMac4MmioRead ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Offset + ) +{ + ASSERT ((Offset & 3) == 0); + + return MmioRead32 ((UINTN)(DwMac4Driver->RegBase + Offset)); +} + +STATIC +VOID +DwMac4MmioWrite ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT ((Offset & 3) == 0); + + MemoryFence (); + MmioWrite32 ((UINTN)(DwMac4Driver->RegBase + Offset), Data); +} + +/* + * linux/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c + */ +VOID +EFIAPI +StmmacSetUmacAddr ( + IN EFI_MAC_ADDRESS *MacAddress, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN RegN + ) +{ + // + // Note: This MAC_ADDR0 registers programming sequence cannot be swap: + // Must program HIGH Offset first before LOW Offset + // because synchronization is triggered when MAC Address0 Low Register are written. + // + DwMac4MmioWrite (DwMac4Driver, GMAC_ADDR_HIGH(RegN), + (UINT32)(MacAddress->Addr[4] & 0xFF) | + ((MacAddress->Addr[5] & 0xFF) << 8) | + GMAC_HI_REG_AE + ); + // + // MacAddress->Addr[0,1,2] is the 3 bytes OUI + // + DwMac4MmioWrite (DwMac4Driver, GMAC_ADDR_LOW(RegN), + (MacAddress->Addr[0] & 0xFF) | + ((MacAddress->Addr[1] & 0xFF) << 8) | + ((MacAddress->Addr[2] & 0xFF) << 16) | + ((MacAddress->Addr[3] & 0xFF) << 24) + ); + + DEBUG (( + DEBUG_VERBOSE, + "%a(): GMAC_ADDR_LOW(%d) = 0x%08X \r\n", + __func__, + RegN, + DwMac4MmioRead (DwMac4Driver, GMAC_ADDR_LOW(RegN)) + )); + DEBUG (( + DEBUG_VERBOSE, + "%a(): GMAC_ADDR_HIGH(%d) = 0x%08X \r\n", + __func__, + RegN, + DwMac4MmioRead (DwMac4Driver, GMAC_ADDR_HIGH(RegN)) + )); +} + +VOID +EFIAPI +StmmacGetMacAddr ( + OUT EFI_MAC_ADDRESS *MacAddress, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN RegN + ) +{ + UINT32 MacAddrHighValue; + UINT32 MacAddrLowValue; + + // + // Read the Mac Addr high register + // + MacAddrHighValue = DwMac4MmioRead (DwMac4Driver, GMAC_ADDR_HIGH(RegN)) & 0xFFFF; + + // + // Read the Mac Addr low register + // + MacAddrLowValue = DwMac4MmioRead (DwMac4Driver, GMAC_ADDR_LOW(RegN)); + + SetMem (MacAddress, sizeof(*MacAddress), 0); + MacAddress->Addr[0] = MacAddrLowValue & 0xFF; + MacAddress->Addr[1] = (MacAddrLowValue >> 8) & 0xFF; + MacAddress->Addr[2] = (MacAddrLowValue >> 16) & 0xFF; + MacAddress->Addr[3] = (MacAddrLowValue >> 24) & 0xFF; + MacAddress->Addr[4] = MacAddrHighValue & 0xFF; + MacAddress->Addr[5] = (MacAddrHighValue >> 8) & 0xFF; + + DEBUG (( + DEBUG_INFO, + "%a(): MAC Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", + __func__, + MacAddress->Addr[0], + MacAddress->Addr[1], + MacAddress->Addr[2], + MacAddress->Addr[3], + MacAddress->Addr[4], + MacAddress->Addr[5] + )); +} + +VOID +DwMac4DmaAxi ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Value; + UINT32 AxiWrOsrLmt; + UINT32 AxiRdOsrLmt; + + AxiWrOsrLmt = 1; + AxiRdOsrLmt = 1; + Value = DwMac4MmioRead (DwMac4Driver, DMA_SYS_BUS_MODE); + + DEBUG (( + DEBUG_VERBOSE, + "%a(): Master AXI performs %s burst length\n", + __func__, + (Value & DMA_SYS_BUS_FB) ? L"fixed" : L"any" + )); + + Value &= ~DMA_AXI_WR_OSR_LMT; + Value |= (AxiWrOsrLmt & DMA_AXI_OSR_MAX) << DMA_AXI_WR_OSR_LMT_SHIFT; + + Value &= ~DMA_AXI_RD_OSR_LMT; + Value |= (AxiRdOsrLmt & DMA_AXI_OSR_MAX) << DMA_AXI_RD_OSR_LMT_SHIFT; + + Value |= DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | DMA_AXI_BLEN4; + + // + // ? + // + Value |= DMA_AXI_1KBBE; + + DwMac4MmioWrite (DwMac4Driver, DMA_SYS_BUS_MODE, Value); +} + +VOID +StmmacSetRxTailPtr ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN TailPtr, + IN UINT32 Channel + ) +{ + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_END_ADDR(Channel), TailPtr); +} + +VOID +StmmacSetTxTailPtr ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN TailPtr, + IN UINT32 Channel + ) +{ + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_END_ADDR(Channel), TailPtr); +} + +VOID +DwMac4DmaStartTx ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Channel + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel)); + Value |= DMA_CONTROL_ST; + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel), Value); + + Value = DwMac4MmioRead (DwMac4Driver, GMAC_CONFIG); + Value |= GMAC_CONFIG_TE; + + DwMac4MmioWrite (DwMac4Driver, GMAC_CONFIG, Value); +} + +VOID +DwMac4DmaStopTx ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Channel + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel)); + Value &= ~DMA_CONTROL_ST; + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel), Value); +} + +VOID +DwMac4DmaStartRx ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Channel + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel)); + Value |= DMA_CONTROL_SR; + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel), Value); + + Value = DwMac4MmioRead (DwMac4Driver, GMAC_CONFIG); + Value |= GMAC_CONFIG_RE; + + DwMac4MmioWrite (DwMac4Driver, GMAC_CONFIG, Value); +} + +VOID +DwMac4DmaStopRx ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Channel + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel)); + Value &= ~DMA_CONTROL_SR; + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel), Value); +} + +/* + * Start all RX and TX DMA channels + */ +VOID +EFIAPI +StmmacStartAllDma ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Channel; + + for (Channel = 0; Channel < RxChannelsCount; Channel++) { + DwMac4DmaStartRx (DwMac4Driver, Channel); + } + + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DwMac4DmaStartTx (DwMac4Driver, Channel); + } +} + +/* + * Stop all RX and TX DMA channels + */ +VOID +EFIAPI +StmmacStopAllDma ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Channel; + + for (Channel = 0; Channel < RxChannelsCount; Channel++) { + DwMac4DmaStopRx (DwMac4Driver, Channel); + } + + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DwMac4DmaStopTx (DwMac4Driver, Channel); + } +} + +EFI_STATUS +EFIAPI +DwMac4DmaReset ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Value; + UINT32 Timeout; + + Timeout = 1000000; + Value = DwMac4MmioRead (DwMac4Driver, DMA_BUS_MODE); + + // + // DMA SW reset + // + Value |= DMA_BUS_MODE_SFT_RESET; + DwMac4MmioWrite (DwMac4Driver, DMA_BUS_MODE, Value); + + // + // wait till the bus software reset + // + do { + Value = DwMac4MmioRead (DwMac4Driver, DMA_BUS_MODE); + if (Timeout-- == 10000) { + DEBUG (( + DEBUG_ERROR, + "%a(): Bus software reset timeout\n", + __func__ + )); + + return EFI_TIMEOUT; + } + } while (Value & DMA_BUS_MODE_SFT_RESET); + + return EFI_SUCCESS; +} + +VOID +DwMac4DmaInit ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_SYS_BUS_MODE); + + Value |= DMA_SYS_BUS_AAL; + Value |= DMA_SYS_BUS_EAME; + + DwMac4MmioWrite (DwMac4Driver, DMA_SYS_BUS_MODE, Value); + + Value = DwMac4MmioRead (DwMac4Driver, DMA_BUS_MODE); + + // + // Only DWMAC core version 5.20 onwards supports HW descriptor prefetch. + // + if (DwMac4MmioRead (DwMac4Driver, GMAC4_VERSION) >= 0x52) { + Value |= DMA_BUS_MODE_DCHE; + } + + DwMac4MmioWrite (DwMac4Driver, DMA_BUS_MODE, Value); +} + +VOID +DwMac4InitChannel ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel + ) +{ + UINT32 Value; + BOOLEAN Pblx8; + + Pblx8 = TRUE; + + // + // Common channel control register config + // + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CONTROL(Channel)); + + if (Pblx8) { + Value = Value | DMA_BUS_MODE_PBL; + } + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_CONTROL(Channel), Value); +#if 1 + // + // Mask interrupts by writing to CSR7 + // + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_INTR_ENA(Channel), DMA_CHAN_INTR_DEFAULT_MASK); +#endif +} + +VOID +DwMac4DmaInitRxChan ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel + ) +{ + UINT32 Value; + UINT32 RxPbl; + + RxPbl = 32; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel)); + Value = Value | (RxPbl << DMA_BUS_MODE_RPBL_SHIFT); + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel), Value); +} + +VOID +DwMac4DmaInitTxChan ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel + ) +{ + UINT32 Value; + UINT32 TxPbl; + + TxPbl = 32; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel)); + Value = Value | (TxPbl << DMA_BUS_MODE_PBL_SHIFT); + + // + // Enable OSP to get best performance + // + Value |= DMA_CONTROL_OSP; + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_CONTROL(Channel), Value); +} + +VOID +DwMac4SetupRxDescriptor ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Index; + DMA_DESCRIPTOR *RxDescriptor; + UINT32 Channel; + + Channel = 0; + + for (Index = 0; Index < RX_DESC_NUM; Index++) { + RxDescriptor = (VOID *)(UINTN)DwMac4Driver->MacDriver.RxDescRingMap[Index].PhysAddress; + + RxDescriptor->Des0 = LOWER_32_BITS(DwMac4Driver->MacDriver.RxBufNum[Index].PhysAddress); + RxDescriptor->Des1 = UPPER_32_BITS(DwMac4Driver->MacDriver.RxBufNum[Index].PhysAddress); + RxDescriptor->Des2 = 0; + RxDescriptor->Des3 = RDES3_OWN | RDES3_BUFFER1_VALID_ADDR; + + DEBUG (( + DEBUG_VERBOSE, + "%a[%d] RxDescriptor(0x%lx): Des0=0x%lx\tDesc1=0x%lx\n", + __func__, + __LINE__, + RxDescriptor, + RxDescriptor->Des0, + RxDescriptor->Des1 + )); +#if 0 + // + // Flush Rx Descriptor + // + mCpu->FlushDataCache ( + mCpu, + (UINTN)DwMac4Driver->MacDriver.RxDescRingMap[Index].PhysAddress, + EFI_PAGES_TO_SIZE (sizeof (DMA_DESCRIPTOR)), + EfiCpuFlushTypeWriteBackInvalidate + ); + DEBUG ((DEBUG_INFO, "=======%a[%d] flush rx buffer addr=0x%lx =====\n", __func__, __LINE__, + DwMac4Driver->MacDriver.RxBufNum[Index].PhysAddress)); + // + // Invalidate Rx Buffer + // + mCpu->FlushDataCache ( + mCpu, + DwMac4Driver->MacDriver.RxBufNum[Index].PhysAddress, + ETH_BUFFER_SIZE, + EfiCpuFlushTypeInvalidate + ); +#endif + } + + // + // Write the address of Rx descriptor list + // + DwMac4MmioWrite (DwMac4Driver, + DMA_CHAN_RX_BASE_ADDR_HI(Channel), + UPPER_32_BITS((UINTN)DwMac4Driver->MacDriver.RxDescRingMap[0].PhysAddress)); + + DwMac4MmioWrite (DwMac4Driver, + DMA_CHAN_RX_BASE_ADDR(Channel), + LOWER_32_BITS((UINTN)DwMac4Driver->MacDriver.RxDescRingMap[0].PhysAddress)); + + // + // Initialize the descriptor number + // + DwMac4Driver->MacDriver.RxCurrentDescriptorNum = 0; + DwMac4Driver->MacDriver.RxNextDescriptorNum = 0; +} + +VOID +DwMac4SetupTxDescriptor ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Index; + DMA_DESCRIPTOR *TxDescriptor; + UINT32 Channel; + + Channel = 0; + + for (Index = 0; Index < TX_DESC_NUM; Index++) { + TxDescriptor = (VOID *)(UINTN)DwMac4Driver->MacDriver.TxDescRingMap[Index].PhysAddress; + } + + // + // Write the address of tx descriptor list + // + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_BASE_ADDR_HI(Channel), + UPPER_32_BITS((UINTN)DwMac4Driver->MacDriver.TxDescRingMap[0].PhysAddress)); + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_BASE_ADDR(Channel), + LOWER_32_BITS((UINTN)DwMac4Driver->MacDriver.TxDescRingMap[0].PhysAddress)); + + // + // Initialize the descriptor number + // + DwMac4Driver->MacDriver.TxCurrentDescriptorNum = 0; + DwMac4Driver->MacDriver.TxNextDescriptorNum = 0; +} + +VOID +DwMac4DmaRxChanOpMode ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel, + IN UINT32 FifoSize, + IN UINT32 Mode, + IN UINT8 Qmode + ) +{ + UINT32 Rqs; + UINT32 MtlRxOp; + UINT32 Rfd; + UINT32 Rfa; + + Rqs = FifoSize / 256 - 1; + MtlRxOp = DwMac4MmioRead (DwMac4Driver, MTL_CHAN_RX_OP_MODE(Channel)); + + if (Mode == SF_DMA_MODE) { + DEBUG (( + DEBUG_VERBOSE, + "%a(): enable RX store and forward mode\n", + __func__ + )); + MtlRxOp |= MTL_OP_MODE_RSF; + } else { + DEBUG (( + DEBUG_VERBOSE, + "%a(): disable RX SF mode (threshold %d)\n", + __func__, + Mode + )); + + MtlRxOp &= ~MTL_OP_MODE_RSF; + MtlRxOp &= MTL_OP_MODE_RTC_MASK; + + if (Mode <= 32) { + MtlRxOp |= MTL_OP_MODE_RTC_32; + } else if (Mode <= 64) { + MtlRxOp |= MTL_OP_MODE_RTC_64; + } else if (Mode <= 96) { + MtlRxOp |= MTL_OP_MODE_RTC_96; + } else { + MtlRxOp |= MTL_OP_MODE_RTC_128; + } + } + + MtlRxOp &= ~MTL_OP_MODE_RQS_MASK; + MtlRxOp |= Rqs << MTL_OP_MODE_RQS_SHIFT; + + // + // Enable flow control only if each channel gets 4 KiB or more FIFO and + // only if channel is not an AVB channel. + // + if ((FifoSize >= 4096) && (Qmode != MTL_QUEUE_AVB)) { + MtlRxOp |= MTL_OP_MODE_EHFC; + + // + // Set Threshold for Activating Flow Control to min 2 frames, + // i.e. 1500 * 2 = 3000 bytes. + // + // Set Threshold for Deactivating Flow Control to min 1 frame, + // i.e. 1500 bytes. + // + switch (FifoSize) { + case 4096: + // + // This violates the above formula because of FIFO size + // limit therefore overflow may occur in spite of this. + // + Rfd = 0x03; /* Full-2.5K */ + Rfa = 0x01; /* Full-1.5K */ + break; + + default: + Rfd = 0x07; /* Full-4.5K */ + Rfa = 0x04; /* Full-3K */ + break; + } + + MtlRxOp &= ~MTL_OP_MODE_RFD_MASK; + MtlRxOp |= Rfd << MTL_OP_MODE_RFD_SHIFT; + + MtlRxOp &= ~MTL_OP_MODE_RFA_MASK; + MtlRxOp |= Rfa << MTL_OP_MODE_RFA_SHIFT; + } + + DwMac4MmioWrite (DwMac4Driver, MTL_CHAN_RX_OP_MODE(Channel), MtlRxOp); +} + +VOID +DwMac4DmaTxChanOpMode ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel, + IN UINT32 FifoSize, + IN UINT32 Mode, + IN UINT8 Qmode + ) +{ + UINT32 MtlTxOp; + UINT32 Tqs; + + MtlTxOp = DwMac4MmioRead (DwMac4Driver, MTL_CHAN_TX_OP_MODE(Channel)); + Tqs = FifoSize / 256 - 1; + + if (Mode == SF_DMA_MODE) { + DEBUG (( + DEBUG_VERBOSE, + "%a(): enable TX store and forward mode\n", + __func__ + )); + // + // Transmit COE type 2 cannot be done in cut-through mode. + // + MtlTxOp |= MTL_OP_MODE_TSF; + } else { + DEBUG (( + DEBUG_VERBOSE, + "%a(): disabling TX SF (threshold %d)\n", + __func__, + Mode + )); + MtlTxOp &= ~MTL_OP_MODE_TSF; + MtlTxOp &= MTL_OP_MODE_TTC_MASK; + + // + // Set the transmit threshold + // + if (Mode <= 32) { + MtlTxOp |= MTL_OP_MODE_TTC_32; + } else if (Mode <= 64) { + MtlTxOp |= MTL_OP_MODE_TTC_64; + } else if (Mode <= 96) { + MtlTxOp |= MTL_OP_MODE_TTC_96; + } else if (Mode <= 128) { + MtlTxOp |= MTL_OP_MODE_TTC_128; + } else if (Mode <= 192) { + MtlTxOp |= MTL_OP_MODE_TTC_192; + } else if (Mode <= 256) { + MtlTxOp |= MTL_OP_MODE_TTC_256; + } else if (Mode <= 384) { + MtlTxOp |= MTL_OP_MODE_TTC_384; + } else { + MtlTxOp |= MTL_OP_MODE_TTC_512; + } + } + + // + // For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO + // with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE. + // For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W + // with reset values: TXQEN off, TQS 256 bytes. + // + // TXQEN must be written for multi-channel operation and TQS must + // reflect the available fifo size per queue (total fifo size / number + // of enabled queues). + // + MtlTxOp &= ~MTL_OP_MODE_TXQEN_MASK; + if (Qmode != MTL_QUEUE_AVB) { + MtlTxOp |= MTL_OP_MODE_TXQEN; + } else { + MtlTxOp |= MTL_OP_MODE_TXQEN_AV; + } + + MtlTxOp &= ~MTL_OP_MODE_TQS_MASK; + MtlTxOp |= Tqs << MTL_OP_MODE_TQS_SHIFT; + + DwMac4MmioWrite(DwMac4Driver, MTL_CHAN_TX_OP_MODE(Channel), MtlTxOp); +} + +VOID +DwMac4ProgMtlRxAlgorithms ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 RxAlg + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, MTL_OPERATION_MODE); + Value &= ~MTL_OPERATION_RAA; + + switch (RxAlg) { + case MTL_RX_ALGORITHM_SP: + Value |= MTL_OPERATION_RAA_SP; + break; + case MTL_RX_ALGORITHM_WSP: + Value |= MTL_OPERATION_RAA_WSP; + break; + default: + break; + } + + DwMac4MmioWrite (DwMac4Driver, MTL_OPERATION_MODE, Value); +} + +VOID +DwMac4ProgMtlTxAlgorithms ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 TxAlg + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, MTL_OPERATION_MODE); + Value &= ~MTL_OPERATION_SCHALG_MASK; + + switch (TxAlg) { + case MTL_TX_ALGORITHM_WRR: + Value |= MTL_OPERATION_SCHALG_WRR; + break; + case MTL_TX_ALGORITHM_WFQ: + Value |= MTL_OPERATION_SCHALG_WFQ; + break; + case MTL_TX_ALGORITHM_DWRR: + Value |= MTL_OPERATION_SCHALG_DWRR; + break; + case MTL_TX_ALGORITHM_SP: + Value |= MTL_OPERATION_SCHALG_SP; + break; + default: + break; + } + + DwMac4MmioWrite (DwMac4Driver, MTL_OPERATION_MODE, Value); +} + +VOID +DwMac4SetTxRingLen ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Length, + IN UINT32 Channel + ) +{ + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_TX_RING_LEN(Channel), Length); +} + +VOID +DwMac4SetRxRingLen ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Length, + IN UINT32 Channel + ) +{ + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_RING_LEN(Channel), Length); +} + +VOID +EFIAPI +DwMac4CoreInit ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, GMAC_CONFIG); + Value |= GMAC_CORE_INIT; + + DwMac4MmioWrite (DwMac4Driver, GMAC_CONFIG, Value); +#if 1 + // + // Enable GMAC interrupts + // + Value = GMAC_INT_DEFAULT_ENABLE; + + // + // Enable FPE interrupt + // + if ((GMAC_HW_FEAT_FPESEL & DwMac4MmioRead (DwMac4Driver, GMAC_HW_FEATURE3)) >> 26) { + Value |= GMAC_INT_FPE_EN; + } + + DwMac4MmioWrite (DwMac4Driver, GMAC_INT_EN, Value); +#endif +} + +VOID +DwMac4EnableDmaInterrupt ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN Channel, + IN BOOLEAN Rx, + IN BOOLEAN Tx + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_INTR_ENA(Channel)); + + if (Rx) { + Value |= DMA_CHAN_INTR_DEFAULT_RX; + } + + if (Tx) { + Value |= DMA_CHAN_INTR_DEFAULT_TX; + } + + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_INTR_ENA(Channel), Value); +} + +/* + * DMA init. + * Description: + * It inits the DMA invoking the specific MAC/GMAC callback. + * Some DMA parameters can be passed from the platform; + * in case of these are not passed a default is kept for the MAC or GMAC. + */ +EFI_STATUS +EFIAPI +StmmacInitDmaEngine ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 DmaCsrCh; + UINT32 Channel; + EFI_STATUS Status; + UINT32 Value; + + DEBUG (( + DEBUG_INFO, + "%a(): MacBaseAddress=0x%lx\r\n", + __func__, + DwMac4Driver->RegBase + )); + + DmaCsrCh = MAX (RxChannelsCount, TxChannelsCount); + + // + // Step 1. Provide a software reset. This resets all of the MAC internal + // registers and logic (bit-0 of DMA_Mode). + // Step 2. Wait for the completion of the reset process (poll bit 0 of the + // DMA_Mode, which is only cleared after the reset operation is completed). + // + Status = DwMac4DmaReset (DwMac4Driver); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Reset the dma failed!\n", + __func__ + )); + return Status; + } + + // + // Step 3. Program the following fields to initialize the DMA_SysBus_Mode + // register: + // (1) AAL. + // (2) Fixed burst or undefined burst. + // (3) Burst mode values in case of AHB bus interface, OSR_LMT in case of + // AXI bus interface. + // (4) If fixed length value is enabled, select the maximum burst length + // possible on the AXI Bus (bits [7:1]). + // + DwMac4DmaInit (DwMac4Driver); + + DwMac4DmaAxi (DwMac4Driver); + + // + // Step 4. Create a descriptor list for transmit and receive. + // In addition, ensure that the descriptors are owned by DMA + // (set bit 31 of descriptor TDES3/RDES3). + // + // DMA CSR Channel configuration + // + DwMac4SetupTxDescriptor (DwMac4Driver); + DwMac4SetupRxDescriptor (DwMac4Driver); + + // + // Step 5. Program the Transmit and Receive Ring length registers + // (DMA_CH(#i)_TxDesc_Ring_Length (for i = 0; i <= DWC_EQOS_NUM_DMA_TX_CH-1) + // and DMA_CH(#i)_RxDesc_Ring_Length (for i = 0; i <= DWC_EQOS_NUM_DMA_RX_CH-1)). + // The ring length programmed must be at least 4. + // + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DwMac4SetTxRingLen (DwMac4Driver, TX_DESC_NUM - 1, Channel); + } + + for (Channel = 0; Channel < RxChannelsCount; Channel++) { + DwMac4SetRxRingLen (DwMac4Driver, RX_DESC_NUM - 1, Channel); + } + + // + // Step 6. Initialize receive and transmit descriptor list address with + // the base address of the transmit and receive descriptor + // (DMA_CH(#i)_TxDesc_List_Address (for i = 0; i <= DWC_EQOS_NUM_DMA_TX_CH-1), + // DMA_CH(#i)_RxDesc_List_Address (for i = 0; i <= DWC_EQOS_NUM_DMA_RX_CH-1)). + // Also, program transmit and receive tail pointer registers indicating to + // the DMA about the available descriptors + // (DMA_CH(#i)_TxDesc_Tail_Pointer (for i = 0; i <= DWC_EQOS_NUM_DMA_TX_CH-1) + // and DMA_CH(#i)_RxDesc_Tail_Pointer (for i = 0; i <= DWC_EQOS_NUM_DMA_RX_CH-1)). + // + // Step 7. Program the settings of the following registers for the parameters + // like maximum burst-length (PBL) initiated by DMA, descriptor skip lengths, + // OSP in case of Tx DMA, RBSZ in case of Rx DMA, and so on. + // + for (Channel = 0; Channel < DmaCsrCh; Channel++) { + DwMac4InitChannel (DwMac4Driver, Channel); + } + + for (Channel = 0; Channel < RxChannelsCount; Channel++) { + DwMac4DmaInitRxChan (DwMac4Driver, Channel); + // + // RX buffer size. Must be a multiple of bus width + // + Value = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel)); + Value &= ~DMA_RBSZ_MASK; + Value |= (RX_MAX_PACKET << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK; + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_RX_CONTROL(Channel), Value); + + } + + // + // DMA TX Channel Configuration + // + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DwMac4DmaInitTxChan (DwMac4Driver, Channel); + } + + // + // Step 8. Enable the interrupts by programming the + // DMA_CH(#i)_Interrupt_Enable (for i = 0; i <= DWC_EQOS_NUM_DMA_TX_CH-1) register. + // + DwMac4CoreInit (DwMac4Driver); +#if 1 + for (Channel = 0; Channel < DmaCsrCh; Channel++) { + DwMac4EnableDmaInterrupt (DwMac4Driver, Channel, TRUE, TRUE); + } +#endif + // + // Step 9. Start the Receive and Transmit DMAs by setting SR (bit 0) of the + // DMA_CH(#i)_RX_Control (for i = 0; i <= DWC_EQOS_NUM_DMA_RX_CH-1) and + // ST (bit 0) of the DMA_CH(#i)_TX_Control (for i = 0; i <= DWC_EQOS_NUM_DMA_TX_CH-1) register. + // + StmmacStartAllDma (DwMac4Driver); + + StmmacSetRxTailPtr (DwMac4Driver, + (UINTN)DwMac4Driver->MacDriver.RxDescRingMap[RX_DESC_NUM - 1].PhysAddress, + 0); + // + // Step 10. Repeat steps 4 to 9 for all the Tx DMA and Rx DMA channels + // selected in the hardware. + // + + return EFI_SUCCESS; +} + +VOID +DwMac4SetMtlTxQueueWeight ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Weight, + IN UINT32 Queue + ) +{ + UINT32 Value; + Value = DwMac4MmioRead (DwMac4Driver, MTL_TXQ_WEIGHT_BASE_ADDR + (Queue * MTL_TXQ_WEIGHT_BASE_OFFSET)); + + Value &= ~MTL_TXQ_WEIGHT_ISCQW_MASK; + Value |= Weight & MTL_TXQ_WEIGHT_ISCQW_MASK; + + DwMac4MmioWrite (DwMac4Driver, MTL_TXQ_WEIGHT_BASE_ADDR + (Queue * MTL_TXQ_WEIGHT_BASE_OFFSET), Value); +} + +VOID +DwMac4MapMtlDma ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Queue, + IN UINT32 Channel + ) +{ + UINT32 Value; + + if (Queue < 4) { + Value = DwMac4MmioRead (DwMac4Driver, MTL_RXQ_DMA_MAP0); + Value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(Queue); + Value |= MTL_RXQ_DMA_QXMDMACH(Channel, Queue); + DwMac4MmioWrite (DwMac4Driver, MTL_RXQ_DMA_MAP0, Value); + } else { + Value = DwMac4MmioRead (DwMac4Driver, MTL_RXQ_DMA_MAP1); + Value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(Queue - 4); + Value |= MTL_RXQ_DMA_QXMDMACH(Channel, Queue - 4); + DwMac4MmioWrite (DwMac4Driver, MTL_RXQ_DMA_MAP1, Value); + } +} + +VOID +DwMac4RxQueueEnable ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT8 Mode, + IN UINT32 Queue + ) +{ + UINT32 Value; + + Value = DwMac4MmioRead (DwMac4Driver, GMAC_RXQ_CTRL0); + + Value &= GMAC_RX_QUEUE_CLEAR(Queue); + if (Mode == MTL_QUEUE_AVB) { + Value |= GMAC_RX_AV_QUEUE_ENABLE(Queue); + } else if (Mode == MTL_QUEUE_DCB) { + Value |= GMAC_RX_DCB_QUEUE_ENABLE(Queue); + } + + DwMac4MmioWrite (DwMac4Driver, GMAC_RXQ_CTRL0, Value); +} + +/** + * stmmac_mtl_configuration - Configure MTL + * @priv: driver private structure + * Description: It is used for configurring MTL + */ +VOID +StmmacMtlConfiguration ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 HwCap; + UINT32 TxFifoSize; + UINT32 RxFifoSize; + UINT32 TxAlgorithm; + UINT32 RxAlgorithm; + UINT32 Queue; + UINT32 Weight; + UINT32 Channel; + UINT8 Mode; + UINT32 Value; + + TxAlgorithm = MTL_TX_ALGORITHM_SP; + RxAlgorithm = MTL_RX_ALGORITHM_WSP; + HwCap = DwMac4MmioRead (DwMac4Driver, GMAC_HW_FEATURE1); + + // + // RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by + // shifting and store the sizes in bytes. + // + TxFifoSize = 128 << ((HwCap & GMAC_HW_TXFIFOSIZE) >> 6); + RxFifoSize = 128 << ((HwCap & GMAC_HW_RXFIFOSIZE) >> 0); + + // + // Adjust for real per queue fifo size + // + TxFifoSize /= TxQueuesToUse; + RxFifoSize /= RxQueuesToUse; + + if (TxQueuesToUse > 1) { + for (Queue = 0; Queue < TxQueuesToUse; Queue++) { + Weight = 0x10 + Queue; + DwMac4SetMtlTxQueueWeight (DwMac4Driver, Weight, Queue); + } + } + + // + // Configure MTL RX algorithms + // + if (RxQueuesToUse > 1) { + DwMac4ProgMtlRxAlgorithms (DwMac4Driver, RxAlgorithm); + } + + // + // Configure MTL TX algorithms + // + if (TxQueuesToUse > 1) { + DwMac4ProgMtlTxAlgorithms (DwMac4Driver, TxAlgorithm); + } + + // + // Map RX MTL to DMA channels + // + for (Queue = 0; Queue < RxQueuesToUse; Queue++) { + Channel = Queue; + DwMac4MapMtlDma (DwMac4Driver, Queue, Channel); + } + + // + // Enable MAC RX Queues + // + for (Queue = 0; Queue < RxQueuesToUse; Queue++) { + Mode = MTL_QUEUE_DCB; + DwMac4RxQueueEnable (DwMac4Driver, Mode, Queue); + } + + // + // Step 3. Program the following fields to initialize the mode of operation + // in the MTL_TxQ0_Operation_Mode register. + // a. Transmit Store And Forward (TSF) or Transmit Threshold Control (TTC) in case of threshold mode + // b. Transmit Queue Enable (TXQEN) to value 2‘b10 to enable Transmit Queue0 + // c. Transmit Queue Size (TQS) + // + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DwMac4DmaTxChanOpMode (DwMac4Driver, Channel, TxFifoSize, SF_DMA_MODE, MTL_QUEUE_DCB); + } + + // + // Step 4. Program the following fields to initialize the mode of operation + // in the MTL_RxQ0_Operation_Mode register: + // a. Receive Store and Forward (RSF) or RTC in case of Threshold mode + // b. Flow Control Activation and De-activation thresholds for MTL Receive FIFO (RFA and RFD) + // c. Error Packet and undersized good Packet forwarding enable (FEP and FUP) + // d. Receive Queue Size (RQS) + // + for (Channel = 0; Channel < RxChannelsCount; Channel++) { + DwMac4DmaRxChanOpMode (DwMac4Driver, Channel, RxFifoSize, SF_DMA_MODE, MTL_QUEUE_DCB); + } + + // + // Set TX priorities + // + Value = DwMac4MmioRead (DwMac4Driver, GMAC_TXQ_PRTY_MAP0); + Value &= ~GMAC_TXQCTRL_PSTQX_MASK(0); + Value |= (0 << GMAC_TXQCTRL_PSTQX_SHIFT(0)) & GMAC_TXQCTRL_PSTQX_MASK(0); + DwMac4MmioWrite (DwMac4Driver, GMAC_TXQ_PRTY_MAP0, Value); + + // + // Set RX priorities + // + Value = DwMac4MmioRead (DwMac4Driver, GMAC_RXQ_CTRL2); + Value &= ~GMAC_RXQCTRL_PSRQX_MASK(0); + Value |= (0 << GMAC_RXQCTRL_PSRQX_SHIFT(0)) & GMAC_RXQCTRL_PSRQX_MASK(0); + DwMac4MmioWrite (DwMac4Driver, GMAC_RXQ_CTRL2, Value); + + // + // Set RX routing: Multicast and Broadcast Queue Enable + // + Value = DwMac4MmioRead (DwMac4Driver, GMAC_RXQ_CTRL1); + Value &= ~GMAC_RXQCTRL_MCBCQEN; + Value |= 0x1 << GMAC_RXQCTRL_MCBCQEN_SHIFT; + DwMac4MmioWrite (DwMac4Driver, GMAC_RXQ_CTRL1, Value); + + // + // Enable promiscuous mode + // + Value = DwMac4MmioRead (DwMac4Driver, GMAC_PACKET_FILTER); + Value |= GMAC_PACKET_FILTER_PR; + DwMac4MmioWrite (DwMac4Driver, GMAC_PACKET_FILTER, Value); +} + +VOID +StmmacMacFlowControl ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Duplex, + IN UINT32 FlowCtrl + ) +{ + UINT32 Flow; + UINT32 Queue; + UINT32 PauseTime; + + Flow = 0; + Queue = 0; + PauseTime = PAUSE_TIME; + + DEBUG ((DEBUG_VERBOSE, "GMAC Flow-Control:\n")); + if (FlowCtrl & FLOW_RX) { + DEBUG ((DEBUG_VERBOSE, "\tReceive Flow-Control ON\n")); + Flow |= GMAC_RX_FLOW_CTRL_RFE; + } else { + DEBUG ((DEBUG_VERBOSE, "\tReceive Flow-Control OFF\n")); + } + + DwMac4MmioWrite (DwMac4Driver, GMAC_RX_FLOW_CTRL, Flow); + + if (FlowCtrl & FLOW_TX) { + DEBUG ((DEBUG_VERBOSE, "\tTransmit Flow-Control ON\n")); + + if (Duplex) { + DEBUG ((DEBUG_VERBOSE, "\tduplex mode: PAUSE %d\n", PauseTime)); + } + + for (Queue = 0; Queue < TxQueuesToUse; Queue++) { + Flow = GMAC_TX_FLOW_CTRL_TFE; + + if (Duplex) { + Flow |= (PauseTime << GMAC_TX_FLOW_CTRL_PT_SHIFT); + } + + DwMac4MmioWrite (DwMac4Driver, GMAC_QX_TX_FLOW_CTRL(Queue), Flow); + } + } else { + for (Queue = 0; Queue < TxQueuesToUse; Queue++) { + DwMac4MmioWrite (DwMac4Driver, GMAC_QX_TX_FLOW_CTRL(Queue), 0); + } + } +} + +EFI_STATUS +EFIAPI +StmmacSetFilters ( + IN UINT32 ReceiveFilterSetting, + IN BOOLEAN Reset, + IN UINTN NumMfilter OPTIONAL, + IN EFI_MAC_ADDRESS *Mfilter OPTIONAL, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 MacFilter; + UINT32 Crc; + UINT32 Index; + UINT32 HashReg; + UINT32 HashBit; + UINT32 Register; + UINT32 Value; + + // + // If reset then clear the filter registers + // + if (Reset) { + for (Index = 0; Index < NumMfilter; Index++) { + DwMac4MmioWrite (DwMac4Driver, GMAC_HASH_TAB(Index), 0x0); + } + } + + // + // Set MacFilter to the reset value of the GMAC_PACKET_FILTER register. + // + MacFilter = DwMac4MmioRead (DwMac4Driver, GMAC_PACKET_FILTER); + MacFilter &= ~GMAC_PACKET_FILTER_HMC; + MacFilter &= ~GMAC_PACKET_FILTER_HPF; + MacFilter &= ~GMAC_PACKET_FILTER_PCF; + MacFilter &= ~GMAC_PACKET_FILTER_PM; + MacFilter &= ~GMAC_PACKET_FILTER_PR; + MacFilter &= ~GMAC_PACKET_FILTER_RA; + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacFilter |= GMAC_PACKET_FILTER_HMC; + + // + // Set the hash tables. + // + if ((NumMfilter > 0) && (!Reset)) { + // + // Go through each filter address and set appropriate bits on hash table. + // + for (Index = 0; Index < NumMfilter; Index++) { + // + // Generate a 32-bit CRC. + // + Crc = GenEtherCrc32 (&Mfilter[Index], NET_ETHER_ADDR_LEN); + // + // Reserve CRC + take upper 8 bit = take lower 8 bit and reverse it. + // + Value = BitReverse (Crc & 0xff); + // + // The most significant bits determines the register to be used (Hash Table Register X), + // and the least significant five bits determine the bit within the register. + // For example, a hash value of 8b'10111111 selects Bit 31 of the Hash Table Register 5. + // + HashReg = (Value >> 5); + HashBit = (Value & 0x1f); + + Register = DwMac4MmioRead (DwMac4Driver, GMAC_HASH_TAB(HashReg)); + // + // Set 1 to HashBit of HashReg. + // For example, set 1 to bit 31 to Reg 5 as in above example. + // + Register |= (1 << HashBit); + DwMac4MmioWrite (DwMac4Driver, GMAC_HASH_TAB(HashReg), Register); + } + } + } + + if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) == 0) { + MacFilter |= GMAC_PACKET_FILTER_DBF; + } + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacFilter |= GMAC_PACKET_FILTER_PR; + } + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + MacFilter |= GMAC_PACKET_FILTER_PM; + } + + // + // Set MacFilter to GMAC_PACKET_FILTER register. + // + DwMac4MmioWrite (DwMac4Driver, GMAC_PACKET_FILTER, MacFilter); + + return EFI_SUCCESS; +} + +/* + * Create Ethernet CRC + * INFO USED: + * 1. http://en.wikipedia.org/wiki/Cyclic_redundancy_check + * 2. http://en.wikipedia.org/wiki/Computation_of_CRC + */ +UINT32 +EFIAPI +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; + } + } + } + + return (~Remainder); +} + +STATIC CONST UINT8 NibbleTab[] = { + /* 0x0 0000 -> 0000 */ 0x0, + /* 0x1 0001 -> 1000 */ 0x8, + /* 0x2 0010 -> 0100 */ 0x4, + /* 0x3 0011 -> 1100 */ 0xc, + /* 0x4 0100 -> 0010 */ 0x2, + /* 0x5 0101 -> 1010 */ 0xa, + /* 0x6 0110 -> 0110 */ 0x6, + /* 0x7 0111 -> 1110 */ 0xe, + /* 0x8 1000 -> 0001 */ 0x1, + /* 0x9 1001 -> 1001 */ 0x9, + /* 0xa 1010 -> 0101 */ 0x5, + /* 0xb 1011 -> 1101 */ 0xd, + /* 0xc 1100 -> 0011 */ 0x3, + /* 0xd 1101 -> 1011 */ 0xb, + /* 0xe 1110 -> 0111 */ 0x7, + /* 0xf 1111 -> 1111 */ 0xf +}; + +UINT8 +EFIAPI +BitReverse ( + UINT8 Value + ) +{ + return (NibbleTab[Value & 0xf] << 4) | NibbleTab[Value >> 4]; +} + +/* + * Get DMA Interrupt Stauts. + * dwmac4_dma_interrupt + */ +VOID +EFIAPI +StmmacGetDmaStatus ( + OUT UINT32 *IrqStat OPTIONAL, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 DmaStatus; + UINT32 IntrEnable; + UINT32 ErrorBit; + UINT32 Mask; + UINT32 Channel; + + ErrorBit = 0; + Mask = 0; + + if (IrqStat != NULL) { + *IrqStat = 0; + } + + for (Channel = 0; Channel < TxChannelsCount; Channel++) { + DmaStatus = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_STATUS(Channel)); + IntrEnable = DwMac4MmioRead (DwMac4Driver, DMA_CHAN_INTR_ENA(Channel)); + + DEBUG ((DEBUG_INFO, "%a() DMA_CHAN_STATUS(0)=0x%x\n", __func__, DmaStatus)); + DEBUG ((DEBUG_INFO, "%a() DMA_CHAN_INTR_ENA(0)=0x%x\n", __func__, IntrEnable)); + + // + // TX/RX NORMAL interrupts. + // + if (DmaStatus & DMA_CHAN_STATUS_NIS) { + Mask |= DMA_CHAN_STATUS_NIS; + // + // Rx interrupt. + // + if (DmaStatus & DMA_CHAN_STATUS_RI) { + DEBUG (( + DEBUG_INFO, + "%a(): Rx interrupt enabled\n", + __func__ + )); + if (IrqStat != NULL) { + *IrqStat |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + Mask |= DMA_CHAN_STATUS_RI; + } + } + + // + // Tx interrupt. + // + if (DmaStatus & DMA_CHAN_STATUS_TI) { + DEBUG (( + DEBUG_INFO, + "%a(): Tx interrupt enabled\n", + __func__ + )); + if (IrqStat != NULL) { + *IrqStat |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + Mask |= DMA_CHAN_STATUS_TI; + } + } + + // + // Tx Buffer. + // + if (DmaStatus & DMA_CHAN_STATUS_TBU) { + Mask |= DMA_CHAN_STATUS_TBU; + } + // + // Early receive interrupt. + // + if (DmaStatus & DMA_CHAN_STATUS_ERI) { + Mask |= DMA_CHAN_STATUS_ERI; + } + } + + // + // ABNORMAL interrupts. + // + if (DmaStatus & DMA_CHAN_STATUS_AIS) { + Mask |= DMA_CHAN_STATUS_AIS; + // + // Transmit process stopped. + // + if (DmaStatus & DMA_CHAN_STATUS_TPS) { + DEBUG (( + DEBUG_INFO, + "%a(): Transmit process stopped\n", + __func__ + )); + Mask |= DMA_CHAN_STATUS_TPS; + } + + // + // Receive buffer unavailable. + // + if (DmaStatus & DMA_CHAN_STATUS_RBU) { + Mask |= DMA_CHAN_STATUS_RBU; + } + + // + // Receive process stopped. + // + if (DmaStatus & DMA_CHAN_STATUS_RPS) { + DEBUG (( + DEBUG_INFO, + "%a(): Receive process stop\n", + __func__ + )); + Mask |= DMA_CHAN_STATUS_RPS; + } + + // + // Receive watchdog timeout + // + if (DmaStatus & DMA_CHAN_STATUS_RWT) { + DEBUG (( + DEBUG_INFO, + "%a(): Receive watchdog timeout\n", + __func__ + )); + Mask |= DMA_CHAN_STATUS_RWT; + } + + // + // Early transmit interrupt. + // + if (DmaStatus & DMA_CHAN_STATUS_ETI) { + Mask |= DMA_CHAN_STATUS_ETI; + } + + // + // Fatal bus error. + // + if (DmaStatus & DMA_CHAN_STATUS_FBE) { + DEBUG (( + DEBUG_INFO, + "%a(): Fatal bus error:\n", + __func__ + )); + Mask |= DMA_CHAN_STATUS_FBE; + + ErrorBit = DmaStatus & DMA_CHAN_STATUS_TEB >> DMA_CHAN_STATUS_TEB_SHIFT; + switch (ErrorBit) { + case DMA_TX_WRITE_DATA_BUFFER_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Tx DMA write buffer error\n", + __func__ + )); + break; + case DMA_TX_WRITE_DESCRIPTOR_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Tx DMA write descriptor error\n", + __func__ + )); + break; + case DMA_TX_READ_DATA_BUFFER_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Tx DMA read buffer error\n", + __func__ + )); + break; + case DMA_TX_READ_DESCRIPTOR_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Tx DMA read descriptor error\n", + __func__ + )); + break; + default: + DEBUG (( + DEBUG_INFO, + "%a(): Undefined error\n", + __func__ + )); + break; + } + + ErrorBit = DmaStatus & DMA_CHAN_STATUS_REB >> DMA_CHAN_STATUS_REB_SHIFT; + switch (ErrorBit) { + case DMA_RX_WRITE_DATA_BUFFER_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Rx DMA write buffer error\n", + __func__ + )); + break; + case DMA_RX_WRITE_DESCRIPTOR_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Rx DMA write descriptor error\n", + __func__ + )); + break; + case DMA_RX_READ_DATA_BUFFER_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Rx DMA read buffer error\n", + __func__ + )); + break; + case DMA_RX_READ_DESCRIPTOR_ERROR: + DEBUG (( + DEBUG_INFO, + "%a(): Rx DMA read descriptor error\n", + __func__ + )); + break; + default: + DEBUG (( + DEBUG_INFO, + "%a(): Undefined error\n", + __func__ + )); + break; + } + } + } + DwMac4MmioWrite (DwMac4Driver, DMA_CHAN_STATUS(Channel), Mask & IntrEnable); + } +} + +/* + * MMC: MAC Management Counters + * drivers/net/ethernet/stmicro/stmmac/mmc_core.c + */ +VOID +EFIAPI +StmmacGetStatistic ( + OUT EFI_NETWORK_STATISTICS *Statistic, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + EFI_NETWORK_STATISTICS *Stats; + + DEBUG (( + DEBUG_INFO, + "%a()\r\n", + __func__ + )); + + // + // Allocate Resources + // + Stats = AllocateZeroPool (sizeof (EFI_NETWORK_STATISTICS)); + if (Stats == NULL) { + return; + } + + Stats->RxTotalFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_FRAMECOUNT_GB); + Stats->RxUndersizeFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_UNDERSIZE_G); + Stats->RxOversizeFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_OVERSIZE_G); + Stats->RxUnicastFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_UNICAST_G); + Stats->RxBroadcastFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_BROADCASTFRAME_G); + Stats->RxMulticastFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_MULTICASTFRAME_G); + Stats->RxCrcErrorFrames = DwMac4MmioRead (DwMac4Driver, MMC_RX_CRC_ERROR); + Stats->RxTotalBytes = DwMac4MmioRead (DwMac4Driver, MMC_RX_OCTETCOUNT_GB); + Stats->RxGoodFrames = Stats->RxUnicastFrames + + Stats->RxBroadcastFrames + + Stats->RxMulticastFrames; + + Stats->TxTotalFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_FRAMECOUNT_GB); + Stats->TxGoodFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_FRAMECOUNT_G); + Stats->TxOversizeFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_OVERSIZE_G); + Stats->TxUnicastFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_UNICAST_GB); + Stats->TxBroadcastFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_BROADCASTFRAME_G); + Stats->TxMulticastFrames = DwMac4MmioRead (DwMac4Driver, MMC_TX_MULTICASTFRAME_G); + Stats->TxTotalBytes = DwMac4MmioRead (DwMac4Driver, MMC_TX_OCTETCOUNT_GB); + Stats->Collisions = DwMac4MmioRead (DwMac4Driver, MMC_TX_LATECOL) + + DwMac4MmioRead (DwMac4Driver, MMC_TX_EXESSCOL); + + // + // Fill in the statistics + // + CopyMem (Statistic, Stats, sizeof (EFI_NETWORK_STATISTICS)); +} + +VOID +EFIAPI +StmmacMacLinkUp ( + IN UINT32 Speed, + IN UINT32 Duplex, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 OldValue; + UINT32 Value; + + OldValue = DwMac4MmioRead (DwMac4Driver, GMAC_CONFIG); + + Value = OldValue & ~(GMAC_CONFIG_FES | GMAC_CONFIG_PS); + + switch (Speed) { + case SPEED_10: + Value |= GMAC_CONFIG_PS; + break; + case SPEED_100: + Value |= GMAC_CONFIG_FES | GMAC_CONFIG_PS; + break; + case SPEED_1000: + Value |= 0; + break; + case SPEED_2500: + Value |= GMAC_CONFIG_FES; + break; + default: + break; + } + + if (Duplex == DUPLEX_FULL) { + Value |= GMAC_CONFIG_DM; +#if 0 + // + // Debug: config Loopback mode. + // + Value |= GMAC_CONFIG_LM; + DEBUG ((DEBUG_INFO, "\n\n%a[%d] Loopback mode config\n\n", __func__, __LINE__)); +#endif + } + + if (Value != OldValue) { + DwMac4MmioWrite (DwMac4Driver, GMAC_CONFIG, Value); + } +} + +EFI_STATUS +PhyLinkAdjustGmacConfig ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + EFI_STATUS Status; + + Status = DwMac4Driver->Phy->Status (DwMac4Driver->Phy, DwMac4Driver->PhyDev); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DwMac4Driver->PhyDev->LinkUp) { + DEBUG (( + DEBUG_VERBOSE, + "Link is up - Network Cable is Plugged\r\n" + )); + StmmacMacLinkUp (DwMac4Driver->PhyDev->Speed, DwMac4Driver->PhyDev->Duplex, DwMac4Driver); + Status = EFI_SUCCESS; + } else { + DEBUG (( + DEBUG_VERBOSE, + "Link is Down - Network Cable is Unplugged?\r\n" + )); + Status = EFI_NOT_READY; + } + + return Status; +} + +VOID +EFIAPI +StmmacDebug ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ) +{ + UINT32 Value; + UINT32 TfcStatus; + UINT32 Rps0; + UINT32 Tps0; + + // + // GMAC debug + // + Value = DwMac4MmioRead (DwMac4Driver, GMAC_DEBUG); + + if (Value & GMAC_DEBUG_TFCSTS_MASK) { + TfcStatus = (Value & GMAC_DEBUG_TFCSTS_MASK) >> GMAC_DEBUG_TFCSTS_SHIFT; + switch (TfcStatus) { + case GMAC_DEBUG_TFCSTS_XFER: + DEBUG ((DEBUG_INFO, "%a(): Transferring input packet for transmission.\n", __func__)); + break; + case GMAC_DEBUG_TFCSTS_GEN_PAUSE: + DEBUG ((DEBUG_INFO, "%a(): Generating and transmitting a Pause control packet (in full-duplex mode).\n", __func__)); + break; + case GMAC_DEBUG_TFCSTS_WAIT: + DEBUG ((DEBUG_INFO, "%a(): Waiting for one of the following: Status of the previous packet OR IPG or back off period to be over.\n", __func__)); + break; + case GMAC_DEBUG_TFCSTS_IDLE: + DEBUG ((DEBUG_INFO, "%a(): Idle State.\n", __func__)); + break; + default: + break; + } + } + + if (Value & GMAC_DEBUG_TPESTS) { + DEBUG ((DEBUG_INFO, "%a(): MAC GMII or MII Transmit Protocol Engine Status detected\n", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a(): MAC GMII or MII Transmit Protocol Engine Status NOT detected\n", __func__)); + } + + if (Value & GMAC_DEBUG_RFCFCSTS_MASK) { + DEBUG ((DEBUG_INFO, "%a(): MAC Receive Packet Controller FIFO Status=0x%x\n", __func__, + (Value & GMAC_DEBUG_RFCFCSTS_MASK) >> GMAC_DEBUG_RFCFCSTS_SHIFT)); + } + + if (Value & GMAC_DEBUG_RPESTS) { + DEBUG ((DEBUG_INFO, "%a(): MAC GMII or MII Receive Protocol Engine Status detected\n", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a(): MAC GMII or MII Receive Protocol Engine Status NOT detected\n", __func__)); + } + + // + // DMA debug + // + Value = DwMac4MmioRead (DwMac4Driver, DMA_STATUS); + if (Value & BIT0) { + DEBUG ((DEBUG_INFO, "%a(): DMA Channel 0 Interrupt Status detected\n", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a(): DMA Channel 0 Interrupt Status NOT detected\n", __func__)); + } + + // + // DMA debug + // + Value = DwMac4MmioRead (DwMac4Driver, DMA_DEBUG_STATUS_0); + + if (Value & DMA_DEBUG_STATUS_0_AXWHSTS) { + DEBUG ((DEBUG_INFO, "%a(): AXI Master Write Channel or AHB Master Status detected\n", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a(): AXI Master Write Channel or AHB Master Status NOT detected\n", __func__)); + } + + if (Value & DMA_DEBUG_STATUS_0_AXRHSTS) { + DEBUG ((DEBUG_INFO, "%a(): AXI Master Read Channel Status detected\n", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a(): AXI Master Read Channel Status NOT detected\n", __func__)); + } + + if (Value & DMA_DEBUG_STATUS_0_RPS0_MASK) { + Rps0 = (Value & DMA_DEBUG_STATUS_0_RPS0_MASK) >> DMA_DEBUG_STATUS_0_RPS0_SHIFT; + DEBUG ((DEBUG_INFO, "%a(): Channel0 Receive Process Status:\n", __func__)); + switch (Rps0) { + case DMA_DEBUG_RPS0_STOP: + DEBUG ((DEBUG_INFO, " Stopped (Reset or Stop Receive Command issued).\n")); + break; + case DMA_DEBUG_RPS0_RUN_FRTD: + DEBUG ((DEBUG_INFO, " Running (Fetching Rx Transfer Descriptor).\n")); + break; + case DMA_DEBUG_RPS0_RSVD: + DEBUG ((DEBUG_INFO, " Reserved for future use.\n")); + break; + case DMA_DEBUG_RPS0_RUN_WRP: + DEBUG ((DEBUG_INFO, " Running (Waiting for Rx packet).\n")); + break; + case DMA_DEBUG_RPS0_SUSPND: + DEBUG ((DEBUG_INFO, " Suspended (Rx Descriptor Unavailable).\n")); + break; + case DMA_DEBUG_RPS0_RUN_CRD: + DEBUG ((DEBUG_INFO, " Running (Closing the Rx Descriptor).\n")); + break; + case DMA_DEBUG_RPS0_TSTMP: + DEBUG ((DEBUG_INFO, " Timestamp write state.\n")); + break; + case DMA_DEBUG_RPS0_RUN_TRP: + DEBUG ((DEBUG_INFO, " Running (Transferring the received packet data from the Rx buffer to the system memory).\n")); + break; + default: + break; + } + } + + if (Value & DMA_DEBUG_STATUS_0_TPS0_MASK) { + Tps0 = (Value & DMA_DEBUG_STATUS_0_TPS0_MASK) >> DMA_DEBUG_STATUS_0_TPS0_SHIFT; + DEBUG ((DEBUG_INFO, "%a(): Channel0 Transmit Process Status:\n", __func__)); + switch (Tps0) { + case DMA_DEBUG_TPS0_STOP: + DEBUG ((DEBUG_INFO, " Stopped (Reset or Stop Transmit Command issued).\n")); + break; + case DMA_DEBUG_TPS0_RUN_FTTD: + DEBUG ((DEBUG_INFO, " Running (Fetching Tx Transfer Descriptor).\n")); + break; + case DMA_DEBUG_TPS0_RUN_WS: + DEBUG ((DEBUG_INFO, " Running (Waiting for status).\n")); + break; + case DMA_DEBUG_TPS0_RUN_RDS: + DEBUG ((DEBUG_INFO, " Running (Reading Data from system memory buffer and queuing it to the Tx buffer (Tx FIFO)).\n")); + break; + case DMA_DEBUG_TPS0_TSTMP_WS: + DEBUG ((DEBUG_INFO, " Timestamp write state.\n")); + break; + case DMA_DEBUG_TPS0_RSVD: + DEBUG ((DEBUG_INFO, " Reserved for future use.\n")); + break; + case DMA_DEBUG_TPS0_SUSPND: + DEBUG ((DEBUG_INFO, " Suspended (Tx Descriptor Unavailable or Tx Buffer Underflow).\n")); + break; + case DMA_DEBUG_TPS0_RUN_CTD: + DEBUG ((DEBUG_INFO, " Running (Closing Tx Descriptor).\n")); + break; + default: + break; + } + } + + DEBUG ((DEBUG_INFO, "Current Tx Buffer addr(H): 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_TX_BUF_ADDR_H(0)))); + DEBUG ((DEBUG_INFO, "Current Tx Buffer addr(L): 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_TX_BUF_ADDR(0)))); + DEBUG ((DEBUG_INFO, "Current Rx Buffer addr(H): 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_RX_BUF_ADDR_H(0)))); + DEBUG ((DEBUG_INFO, "Current Rx Buffer addr(L): 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_RX_BUF_ADDR(0)))); + DEBUG ((DEBUG_INFO, "Current Tx desc pointer: 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_RX_DESC(0)))); + DEBUG ((DEBUG_INFO, "Current Rx desc pointer: 0x%lx\n", DwMac4MmioRead (DwMac4Driver, DMA_CHAN_CUR_RX_DESC(0)))); +} diff --git a/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.h b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.h new file mode 100755 index 0000000000..47aa1aacd3 --- /dev/null +++ b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4DxeUtil.h @@ -0,0 +1,1254 @@ +/** @file + + Copyright (c) 2024, SOPHGO Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef STMMAC_DXE_UTIL_H__ +#define STMMAC_DXE_UTIL_H__ + +#include +#include +#include +#define BIT(nr) (1UL << (nr)) +#define GENMASK(end, start) (((1ULL << ((end) - (start) + 1)) - 1) << (start)) + +#define UPPER_32_BITS(n) ((UINT32)((n) >> 32)) +#define LOWER_32_BITS(n) ((UINT32)((n) & 0xffffffff)) + +#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */ + +// +// MAC registers +// +#define GMAC_CONFIG 0x00000000 +#define GMAC_EXT_CONFIG 0x00000004 +#define GMAC_PACKET_FILTER 0x00000008 +#define GMAC_HASH_TAB(x) (0x10 + (x) * 4) +#define GMAC_VLAN_TAG 0x00000050 +#define GMAC_VLAN_TAG_DATA 0x00000054 +#define GMAC_VLAN_HASH_TABLE 0x00000058 +#define GMAC_RX_FLOW_CTRL 0x00000090 +#define GMAC_VLAN_INCL 0x00000060 +#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) +#define GMAC_TXQ_PRTY_MAP0 0x98 +#define GMAC_TXQ_PRTY_MAP1 0x9C +#define GMAC_RXQ_CTRL0 0x000000a0 +#define GMAC_RXQ_CTRL1 0x000000a4 +#define GMAC_RXQ_CTRL2 0x000000a8 +#define GMAC_RXQ_CTRL3 0x000000ac +#define GMAC_INT_STATUS 0x000000b0 +#define GMAC_INT_EN 0x000000b4 +#define GMAC_1US_TIC_COUNTER 0x000000dc +#define GMAC_PCS_BASE 0x000000e0 +#define GMAC_PHYIF_CONTROL_STATUS 0x000000f8 +#define GMAC_PMT 0x000000c0 +#define GMAC_DEBUG 0x00000114 +#define GMAC_HW_FEATURE0 0x0000011c +#define GMAC_HW_FEATURE1 0x00000120 +#define GMAC_HW_FEATURE2 0x00000124 +#define GMAC_HW_FEATURE3 0x00000128 +#define GMAC_MDIO_ADDR 0x00000200 +#define GMAC_MDIO_DATA 0x00000204 +#define GMAC_GPIO_STATUS 0x0000020C +#define GMAC_ARP_ADDR 0x00000210 +#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) +#define GMAC_ADDR_LOW(reg) (0x304 + reg * 8) +#define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30) +#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30) +#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30) +#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30) +#define GMAC_TIMESTAMP_STATUS 0x00000b20 + +// +// RX Queues Routing +// +#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0) +#define GMAC_RXQCTRL_AVCPQ_SHIFT 0 +#define GMAC_RXQCTRL_PTPQ_MASK GENMASK(6, 4) +#define GMAC_RXQCTRL_PTPQ_SHIFT 4 +#define GMAC_RXQCTRL_DCBCPQ_MASK GENMASK(10, 8) +#define GMAC_RXQCTRL_DCBCPQ_SHIFT 8 +#define GMAC_RXQCTRL_UPQ_MASK GENMASK(14, 12) +#define GMAC_RXQCTRL_UPQ_SHIFT 12 +#define GMAC_RXQCTRL_MCBCQ_MASK GENMASK(18, 16) +#define GMAC_RXQCTRL_MCBCQ_SHIFT 16 +#define GMAC_RXQCTRL_MCBCQEN BIT20 +#define GMAC_RXQCTRL_MCBCQEN_SHIFT 20 +#define GMAC_RXQCTRL_TACPQE BIT21 +#define GMAC_RXQCTRL_TACPQE_SHIFT 21 +#define GMAC_RXQCTRL_FPRQ GENMASK(26, 24) +#define GMAC_RXQCTRL_FPRQ_SHIFT 24 + +// +// MAC Packet Filtering +// +#define GMAC_PACKET_FILTER_PR BIT0 +#define GMAC_PACKET_FILTER_HMC BIT2 +#define GMAC_PACKET_FILTER_PM BIT4 +#define GMAC_PACKET_FILTER_DBF BIT5 +#define GMAC_PACKET_FILTER_PCF BIT7 +#define GMAC_PACKET_FILTER_HPF BIT10 +#define GMAC_PACKET_FILTER_VTFE BIT16 +#define GMAC_PACKET_FILTER_IPFE BIT20 +#define GMAC_PACKET_FILTER_RA BIT31 + +#define GMAC_MAX_PERFECT_ADDRESSES 128 + +// +// MAC VLAN +// +#define GMAC_VLAN_EDVLP BIT26 +#define GMAC_VLAN_VTHM BIT25 +#define GMAC_VLAN_DOVLTC BIT20 +#define GMAC_VLAN_ESVL BIT18 +#define GMAC_VLAN_ETV BIT16 +#define GMAC_VLAN_VID GENMASK(15, 0) +#define GMAC_VLAN_VLTI BIT20 +#define GMAC_VLAN_CSVL BIT19 +#define GMAC_VLAN_VLC GENMASK(17, 16) +#define GMAC_VLAN_VLC_SHIFT 16 +#define GMAC_VLAN_VLHT GENMASK(15, 0) + +// +// MAC VLAN Tag +// +#define GMAC_VLAN_TAG_VID GENMASK(15, 0) +#define GMAC_VLAN_TAG_ETV BIT16 + +// +// MAC VLAN Tag Control +// +#define GMAC_VLAN_TAG_CTRL_OB BIT0 +#define GMAC_VLAN_TAG_CTRL_CT BIT1 +#define GMAC_VLAN_TAG_CTRL_OFS_MASK GENMASK(6, 2) +#define GMAC_VLAN_TAG_CTRL_OFS_SHIFT 2 +#define GMAC_VLAN_TAG_CTRL_EVLS_MASK GENMASK(22, 21) +#define GMAC_VLAN_TAG_CTRL_EVLS_SHIFT 21 +#define GMAC_VLAN_TAG_CTRL_EVLRXS BIT24 + +#define GMAC_VLAN_TAG_STRIP_NONE (0x0 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) +#define GMAC_VLAN_TAG_STRIP_PASS (0x1 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) +#define GMAC_VLAN_TAG_STRIP_FAIL (0x2 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) +#define GMAC_VLAN_TAG_STRIP_ALL (0x3 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) + +// +// MAC VLAN Tag Data/Filter +// +#define GMAC_VLAN_TAG_DATA_VID GENMASK(15, 0) +#define GMAC_VLAN_TAG_DATA_VEN BIT16 +#define GMAC_VLAN_TAG_DATA_ETV BIT17 + +// +// MAC RX Queue Enable +// +#define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2)) +#define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2) +#define GMAC_RX_DCB_QUEUE_ENABLE(queue) BIT(((queue) * 2) + 1) + +// +// MAC Flow Control RX +// +#define GMAC_RX_FLOW_CTRL_RFE BIT0 + +// +// RX Queues Priorities +// +#define GMAC_RXQCTRL_PSRQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8)) +#define GMAC_RXQCTRL_PSRQX_SHIFT(x) ((x) * 8) + +// +// TX Queues Priorities +// +#define GMAC_TXQCTRL_PSTQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8)) +#define GMAC_TXQCTRL_PSTQX_SHIFT(x) ((x) * 8) + +// +// MAC Flow Control TX +// +#define GMAC_TX_FLOW_CTRL_TFE BIT1 +#define GMAC_TX_FLOW_CTRL_PT_SHIFT 16 + +// +// MAC Interrupt bitmap +// +#define GMAC_INT_RGSMIIS BIT0 +#define GMAC_INT_PCS_LINK BIT1 +#define GMAC_INT_PCS_ANE BIT2 +#define GMAC_INT_PCS_PHYIS BIT3 +#define GMAC_INT_PMT_EN BIT4 +#define GMAC_INT_LPI_EN BIT5 +#define GMAC_INT_TSIE BIT12 +#define GMAC_INT_FPE_EN BIT17 + +#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \ + GMAC_INT_PCS_ANE) + +#define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \ + GMAC_INT_TSIE) + +/* Energy Efficient Ethernet (EEE) for GMAC4 + * + * LPI status, timer and control register offset + */ +#define GMAC4_LPI_CTRL_STATUS 0xd0 +#define GMAC4_LPI_TIMER_CTRL 0xd4 +#define GMAC4_LPI_ENTRY_TIMER 0xd8 +#define GMAC4_MAC_ONEUS_TIC_COUNTER 0xdc + +// +// LPI control and status defines +// +#define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT21 /* LPI Tx Clock Stop Enable */ +#define GMAC4_LPI_CTRL_STATUS_LPIATE BIT20 /* LPI Timer Enable */ +#define GMAC4_LPI_CTRL_STATUS_LPITXA BIT19 /* Enable LPI TX Automate */ +#define GMAC4_LPI_CTRL_STATUS_PLS BIT17 /* PHY Link Status */ +#define GMAC4_LPI_CTRL_STATUS_LPIEN BIT16 /* LPI Enable */ +#define GMAC4_LPI_CTRL_STATUS_RLPIEX BIT3 /* Receive LPI Exit */ +#define GMAC4_LPI_CTRL_STATUS_RLPIEN BIT2 /* Receive LPI Entry */ +#define GMAC4_LPI_CTRL_STATUS_TLPIEX BIT1 /* Transmit LPI Exit */ +#define GMAC4_LPI_CTRL_STATUS_TLPIEN BIT0 /* Transmit LPI Entry */ + +// +// MAC Debug bitmap +// +#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17) +#define GMAC_DEBUG_TFCSTS_SHIFT 17 +#define GMAC_DEBUG_TFCSTS_IDLE 0 +#define GMAC_DEBUG_TFCSTS_WAIT 1 +#define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2 +#define GMAC_DEBUG_TFCSTS_XFER 3 +#define GMAC_DEBUG_TPESTS BIT16 +#define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1) +#define GMAC_DEBUG_RFCFCSTS_SHIFT 1 +#define GMAC_DEBUG_RPESTS BIT0 + +// +// MAC config +// +#define GMAC_CONFIG_ARPEN BIT31 +#define GMAC_CONFIG_SARC GENMASK(30, 28) +#define GMAC_CONFIG_SARC_SHIFT 28 +#define GMAC_CONFIG_IPC BIT27 +#define GMAC_CONFIG_IPG GENMASK(26, 24) +#define GMAC_CONFIG_IPG_SHIFT 24 +#define GMAC_CONFIG_2K BIT22 +#define GMAC_CONFIG_ACS BIT20 +#define GMAC_CONFIG_BE BIT18 +#define GMAC_CONFIG_JD BIT17 +#define GMAC_CONFIG_JE BIT16 +#define GMAC_CONFIG_PS BIT15 +#define GMAC_CONFIG_FES BIT14 +#define GMAC_CONFIG_FES_SHIFT 14 +#define GMAC_CONFIG_DM BIT13 +#define GMAC_CONFIG_LM BIT12 +#define GMAC_CONFIG_DCRS BIT9 +#define GMAC_CONFIG_TE BIT1 +#define GMAC_CONFIG_RE BIT0 + +// +// MAC extended config +// +#define GMAC_CONFIG_EIPG GENMASK(29, 25) +#define GMAC_CONFIG_EIPG_SHIFT 25 +#define GMAC_CONFIG_EIPG_EN BIT24 +#define GMAC_CONFIG_HDSMS GENMASK(22, 20) +#define GMAC_CONFIG_HDSMS_SHIFT 20 +#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT) + +// +// MAC HW features0 bitmap +// +#define GMAC_HW_FEAT_SAVLANINS BIT27 +#define GMAC_HW_FEAT_ADDMAC BIT18 +#define GMAC_HW_FEAT_RXCOESEL BIT16 +#define GMAC_HW_FEAT_TXCOSEL BIT14 +#define GMAC_HW_FEAT_EEESEL BIT13 +#define GMAC_HW_FEAT_TSSEL BIT12 +#define GMAC_HW_FEAT_ARPOFFSEL BIT9 +#define GMAC_HW_FEAT_MMCSEL BIT8 +#define GMAC_HW_FEAT_MGKSEL BIT7 +#define GMAC_HW_FEAT_RWKSEL BIT6 +#define GMAC_HW_FEAT_SMASEL BIT5 +#define GMAC_HW_FEAT_VLHASH BIT4 +#define GMAC_HW_FEAT_PCSSEL BIT3 +#define GMAC_HW_FEAT_HDSEL BIT2 +#define GMAC_HW_FEAT_GMIISEL BIT1 +#define GMAC_HW_FEAT_MIISEL BIT0 + +// +// MAC HW features1 bitmap +// +#define GMAC_HW_FEAT_L3L4FNUM GENMASK(30, 27) +#define GMAC_HW_HASH_TB_SZ GENMASK(25, 24) +#define GMAC_HW_FEAT_AVSEL BIT20 +#define GMAC_HW_TSOEN BIT18 +#define GMAC_HW_FEAT_SPHEN BIT17 +#define GMAC_HW_ADDR64 GENMASK(15, 14) +#define GMAC_HW_TXFIFOSIZE GENMASK(10, 6) +#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0) + +// +// MAC HW features2 bitmap +// +#define GMAC_HW_FEAT_AUXSNAPNUM GENMASK(30, 28) +#define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24) +#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18) +#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12) +#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6) +#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0) + +// +// MAC HW features3 bitmap +// +#define GMAC_HW_FEAT_ASP GENMASK(29, 28) +#define GMAC_HW_FEAT_TBSSEL BIT27 +#define GMAC_HW_FEAT_FPESEL BIT26 +#define GMAC_HW_FEAT_ESTWID GENMASK(21, 20) +#define GMAC_HW_FEAT_ESTDEP GENMASK(19, 17) +#define GMAC_HW_FEAT_ESTSEL BIT16 +#define GMAC_HW_FEAT_FRPES GENMASK(14, 13) +#define GMAC_HW_FEAT_FRPBS GENMASK(12, 11) +#define GMAC_HW_FEAT_FRPSEL BIT10 +#define GMAC_HW_FEAT_DVLAN BIT5 +#define GMAC_HW_FEAT_NRVF GENMASK(2, 0) + +// +// GMAC GPIO Status reg +// +#define GMAC_GPO0 BIT16 +#define GMAC_GPO1 BIT17 +#define GMAC_GPO2 BIT18 +#define GMAC_GPO3 BIT19 + +// +// MAC HW ADDR regs +// +#define GMAC_HI_DCS GENMASK(18, 16) +#define GMAC_HI_DCS_SHIFT 16 +#define GMAC_HI_REG_AE BIT31 + +// +// L3/L4 Filters regs +// +#define GMAC_L4DPIM0 BIT21 +#define GMAC_L4DPM0 BIT20 +#define GMAC_L4SPIM0 BIT19 +#define GMAC_L4SPM0 BIT18 +#define GMAC_L4PEN0 BIT16 +#define GMAC_L3DAIM0 BIT5 +#define GMAC_L3DAM0 BIT4 +#define GMAC_L3SAIM0 BIT3 +#define GMAC_L3SAM0 BIT2 +#define GMAC_L3PEN0 BIT0 +#define GMAC_L4DP0 GENMASK(31, 16) +#define GMAC_L4DP0_SHIFT 16 +#define GMAC_L4SP0 GENMASK(15, 0) + +// +// MAC Timestamp Status +// +#define GMAC_TIMESTAMP_AUXTSTRIG BIT2 +#define GMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25) +#define GMAC_TIMESTAMP_ATSNS_SHIFT 25 + +// +// MTL registers +// +#define MTL_OPERATION_MODE 0x00000c00 +#define MTL_FRPE BIT15 +#define MTL_OPERATION_SCHALG_MASK GENMASK(6, 5) +#define MTL_OPERATION_SCHALG_WRR (0x0 << 5) +#define MTL_OPERATION_SCHALG_WFQ (0x1 << 5) +#define MTL_OPERATION_SCHALG_DWRR (0x2 << 5) +#define MTL_OPERATION_SCHALG_SP (0x3 << 5) +#define MTL_OPERATION_RAA BIT2 +#define MTL_OPERATION_RAA_SP (0x0 << 2) +#define MTL_OPERATION_RAA_WSP (0x1 << 2) + +#define MTL_INT_STATUS 0x00000c20 +#define MTL_INT_QX(x) BIT(x) + +#define MTL_RXQ_DMA_MAP0 0x00000c30 /* queue 0 to 3 */ +#define MTL_RXQ_DMA_MAP1 0x00000c34 /* queue 4 to 7 */ +#define MTL_RXQ_DMA_QXMDMACH_MASK(x) (0xf << 8 * (x)) +#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q))) + +#define MTL_CHAN_BASE_ADDR 0x00000d00 +#define MTL_CHAN_BASE_OFFSET 0x40 +#define MTL_CHANX_BASE_ADDR(x) (MTL_CHAN_BASE_ADDR + \ + (x * MTL_CHAN_BASE_OFFSET)) + +#define MTL_CHAN_TX_OP_MODE(x) MTL_CHANX_BASE_ADDR(x) +#define MTL_CHAN_TX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x8) +#define MTL_CHAN_INT_CTRL(x) (MTL_CHANX_BASE_ADDR(x) + 0x2c) +#define MTL_CHAN_RX_OP_MODE(x) (MTL_CHANX_BASE_ADDR(x) + 0x30) +#define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x38) + +#define MTL_OP_MODE_RSF BIT5 +#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2) +#define MTL_OP_MODE_TXQEN_AV BIT2 +#define MTL_OP_MODE_TXQEN BIT3 +#define MTL_OP_MODE_TSF BIT1 + +#define MTL_OP_MODE_TQS_MASK GENMASK(24, 16) +#define MTL_OP_MODE_TQS_SHIFT 16 + +#define MTL_OP_MODE_TTC_MASK 0x70 +#define MTL_OP_MODE_TTC_SHIFT 4 + +#define MTL_OP_MODE_TTC_32 0 +#define MTL_OP_MODE_TTC_64 (1 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_96 (2 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_128 (3 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_192 (4 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_256 (5 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_384 (6 << MTL_OP_MODE_TTC_SHIFT) +#define MTL_OP_MODE_TTC_512 (7 << MTL_OP_MODE_TTC_SHIFT) + +#define MTL_OP_MODE_RQS_MASK GENMASK(29, 20) +#define MTL_OP_MODE_RQS_SHIFT 20 + +#define MTL_OP_MODE_RFD_MASK GENMASK(19, 14) +#define MTL_OP_MODE_RFD_SHIFT 14 + +#define MTL_OP_MODE_RFA_MASK GENMASK(13, 8) +#define MTL_OP_MODE_RFA_SHIFT 8 + +#define MTL_OP_MODE_EHFC BIT7 + +#define MTL_OP_MODE_RTC_MASK 0x18 +#define MTL_OP_MODE_RTC_SHIFT 3 + +#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT) +#define MTL_OP_MODE_RTC_64 0 +#define MTL_OP_MODE_RTC_96 (2 << MTL_OP_MODE_RTC_SHIFT) +#define MTL_OP_MODE_RTC_128 (3 << MTL_OP_MODE_RTC_SHIFT) + +// +// MTL ETS Control register +// +#define MTL_ETS_CTRL_BASE_ADDR 0x00000d10 +#define MTL_ETS_CTRL_BASE_OFFSET 0x40 + +#define MTL_ETS_CTRL_CC BIT3 +#define MTL_ETS_CTRL_AVALG BIT2 + +// +// MTL Queue Quantum Weight +// +#define MTL_TXQ_WEIGHT_BASE_ADDR 0x00000d18 +#define MTL_TXQ_WEIGHT_BASE_OFFSET 0x40 + +#define MTL_TXQ_WEIGHT_ISCQW_MASK GENMASK(20, 0) + +// +// MTL sendSlopeCredit register +// +#define MTL_SEND_SLP_CRED_BASE_ADDR 0x00000d1c +#define MTL_SEND_SLP_CRED_OFFSET 0x40 + +#define MTL_SEND_SLP_CRED_SSC_MASK GENMASK(13, 0) + +// +// MTL hiCredit register +// +#define MTL_HIGH_CRED_BASE_ADDR 0x00000d20 +#define MTL_HIGH_CRED_OFFSET 0x40 + + +#define MTL_HIGH_CRED_HC_MASK GENMASK(28, 0) + +// +// MTL loCredit register +// +#define MTL_LOW_CRED_BASE_ADDR 0x00000d24 +#define MTL_LOW_CRED_OFFSET 0x40 + +#define MTL_HIGH_CRED_LC_MASK GENMASK(28, 0) + +// +// MTL debug +// +#define MTL_DEBUG_TXSTSFSTS BIT5 +#define MTL_DEBUG_TXFSTS BIT4 +#define MTL_DEBUG_TWCSTS BIT3 + +// +// MTL debug: Tx FIFO Read Controller Status +// +#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1) +#define MTL_DEBUG_TRCSTS_SHIFT 1 +#define MTL_DEBUG_TRCSTS_IDLE 0 +#define MTL_DEBUG_TRCSTS_READ 1 +#define MTL_DEBUG_TRCSTS_TXW 2 +#define MTL_DEBUG_TRCSTS_WRITE 3 +#define MTL_DEBUG_TXPAUSED BIT0 + +// +// MAC debug: GMII or MII Transmit Protocol Engine Status +// +#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4) +#define MTL_DEBUG_RXFSTS_SHIFT 4 +#define MTL_DEBUG_RXFSTS_EMPTY 0 +#define MTL_DEBUG_RXFSTS_BT 1 +#define MTL_DEBUG_RXFSTS_AT 2 +#define MTL_DEBUG_RXFSTS_FULL 3 +#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1) +#define MTL_DEBUG_RRCSTS_SHIFT 1 +#define MTL_DEBUG_RRCSTS_IDLE 0 +#define MTL_DEBUG_RRCSTS_RDATA 1 +#define MTL_DEBUG_RRCSTS_RSTAT 2 +#define MTL_DEBUG_RRCSTS_FLUSH 3 +#define MTL_DEBUG_RWCSTS BIT0 + +// +// MTL interrupt +// +#define MTL_RX_OVERFLOW_INT_EN BIT24 +#define MTL_RX_OVERFLOW_INT BIT16 + +// +// Default operating mode of the MAC +// +#define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \ + GMAC_CONFIG_BE | GMAC_CONFIG_DCRS | \ + GMAC_CONFIG_JE) + +// +// To dump the core regs excluding the Address Registers +// +#define GMAC_REG_NUM 132 + +// +// MTL debug +// +#define MTL_DEBUG_TXSTSFSTS BIT5 +#define MTL_DEBUG_TXFSTS BIT4 +#define MTL_DEBUG_TWCSTS BIT3 + +// +// MTL debug: Tx FIFO Read Controller Status +// +#define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1) +#define MTL_DEBUG_TRCSTS_SHIFT 1 +#define MTL_DEBUG_TRCSTS_IDLE 0 +#define MTL_DEBUG_TRCSTS_READ 1 +#define MTL_DEBUG_TRCSTS_TXW 2 +#define MTL_DEBUG_TRCSTS_WRITE 3 +#define MTL_DEBUG_TXPAUSED BIT0 + +// +// MAC debug: GMII or MII Transmit Protocol Engine Status +// +#define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4) +#define MTL_DEBUG_RXFSTS_SHIFT 4 +#define MTL_DEBUG_RXFSTS_EMPTY 0 +#define MTL_DEBUG_RXFSTS_BT 1 +#define MTL_DEBUG_RXFSTS_AT 2 +#define MTL_DEBUG_RXFSTS_FULL 3 +#define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1) +#define MTL_DEBUG_RRCSTS_SHIFT 1 +#define MTL_DEBUG_RRCSTS_IDLE 0 +#define MTL_DEBUG_RRCSTS_RDATA 1 +#define MTL_DEBUG_RRCSTS_RSTAT 2 +#define MTL_DEBUG_RRCSTS_FLUSH 3 +#define MTL_DEBUG_RWCSTS BIT0 + +// +// SGMII/RGMII status register +// +#define GMAC_PHYIF_CTRLSTATUS_TC BIT0 +#define GMAC_PHYIF_CTRLSTATUS_LUD BIT1 +#define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT4 +#define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT16 +#define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17) +#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17 +#define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT19 +#define GMAC_PHYIF_CTRLSTATUS_JABTO BIT20 +#define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT21 + +// +// Most common CRC32 Polynomial for little endian machines +// +#define CRC_POLYNOMIAL 0xEDB88320 + +// +// DMA CRS Control and Status Register Mapping +// +#define DMA_BUS_MODE 0x00001000 +#define DMA_SYS_BUS_MODE 0x00001004 +#define DMA_STATUS 0x00001008 +#define DMA_DEBUG_STATUS_0 0x0000100c +#define DMA_DEBUG_STATUS_1 0x00001010 +#define DMA_DEBUG_STATUS_2 0x00001014 +#define DMA_AXI_BUS_MODE 0x00001028 +#define DMA_TBS_CTRL 0x00001050 + +#define DMA_DEBUG_STATUS_0_AXWHSTS BIT0 +#define DMA_DEBUG_STATUS_0_AXRHSTS BIT1 +#define DMA_DEBUG_STATUS_0_RPS0_SHIFT 8 +#define DMA_DEBUG_STATUS_0_RPS0_MASK GENMASK(11, 8) +#define DMA_DEBUG_RPS0_STOP 0 +#define DMA_DEBUG_RPS0_RUN_FRTD 1 +#define DMA_DEBUG_RPS0_RSVD 2 +#define DMA_DEBUG_RPS0_RUN_WRP 3 +#define DMA_DEBUG_RPS0_SUSPND 4 +#define DMA_DEBUG_RPS0_RUN_CRD 5 +#define DMA_DEBUG_RPS0_TSTMP 6 +#define DMA_DEBUG_RPS0_RUN_TRP 7 +#define DMA_DEBUG_STATUS_0_TPS0_SHIFT 12 +#define DMA_DEBUG_STATUS_0_TPS0_MASK GENMASK(15, 12) +#define DMA_DEBUG_TPS0_STOP 0 +#define DMA_DEBUG_TPS0_RUN_FTTD 1 +#define DMA_DEBUG_TPS0_RUN_WS 2 +#define DMA_DEBUG_TPS0_RUN_RDS 3 +#define DMA_DEBUG_TPS0_TSTMP_WS 4 +#define DMA_DEBUG_TPS0_RSVD 5 +#define DMA_DEBUG_TPS0_SUSPND 6 +#define DMA_DEBUG_TPS0_RUN_CTD 7 + +// +// DMA Bus Mode bitmap +// +#define DMA_BUS_MODE_DCHE BIT19 +#define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16) +#define DMA_BUS_MODE_INTM_SHIFT 16 +#define DMA_BUS_MODE_INTM_MODE1 0x1 +#define DMA_BUS_MODE_SFT_RESET BIT0 + +// +// DMA SYS Bus Mode bitmap +// +#define DMA_BUS_MODE_SPH BIT24 +#define DMA_BUS_MODE_PBL BIT16 +#define DMA_BUS_MODE_PBL_SHIFT 16 +#define DMA_BUS_MODE_RPBL_SHIFT 16 +#define DMA_BUS_MODE_MB BIT14 +#define DMA_BUS_MODE_FB BIT0 + +// +// Rx watchdog register +// +#define DMA_RX_WATCHDOG 0x00001024 + +/* DMA debug status bitmap */ +#define DMA_DEBUG_STATUS_TS_MASK 0xf +#define DMA_DEBUG_STATUS_RS_MASK 0xf + +/* DMA AXI bitmap */ +#define DMA_AXI_EN_LPI BIT31 +#define DMA_AXI_LPI_XIT_FRM BIT30 +#define DMA_AXI_WR_OSR_LMT GENMASK(27, 24) +#define DMA_AXI_WR_OSR_LMT_SHIFT 24 +#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16) +#define DMA_AXI_RD_OSR_LMT_SHIFT 16 + +#define DMA_AXI_OSR_MAX 0xf +#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \ + (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT)) + +// +// AXI Master Bus Mode +// +#define DMA_AXI_BUS_MODE 0x00001028 + +#define DMA_AXI_EN_LPI BIT31 +#define DMA_AXI_LPI_XIT_FRM BIT30 +#define DMA_SYS_BUS_MB BIT14 +#define DMA_AXI_1KBBE BIT13 +#define DMA_SYS_BUS_AAL BIT12 +#define DMA_SYS_BUS_EAME BIT11 +#define DMA_AXI_BLEN256 BIT7 +#define DMA_AXI_BLEN128 BIT6 +#define DMA_AXI_BLEN64 BIT5 +#define DMA_AXI_BLEN32 BIT4 +#define DMA_AXI_BLEN16 BIT3 +#define DMA_AXI_BLEN8 BIT2 +#define DMA_AXI_BLEN4 BIT1 +#define DMA_SYS_BUS_FB BIT0 + +#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \ + DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \ + DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \ + DMA_AXI_BLEN4) + +#define DMA_AXI_BURST_LEN_MASK 0x000000FE + +/* DMA TBS Control */ +#define DMA_TBS_FTOS GENMASK(31, 8) +#define DMA_TBS_FTOV BIT0 +#define DMA_TBS_DEF_FTOS (DMA_TBS_FTOS | DMA_TBS_FTOV) + +/* Following DMA defines are channel-oriented */ +#define DMA_CHAN_BASE_ADDR 0x00001100 +#define DMA_CHAN_BASE_OFFSET 0x80 +// +// DMA: chanels oriented +// +#define DMA_CHAN_BASE_ADDR 0x00001100 +#define DMA_CHAN_BASE_OFFSET 0x80 +#define DMA_CHANX_BASE_ADDR(x) (DMA_CHAN_BASE_ADDR + \ + (x * DMA_CHAN_BASE_OFFSET)) +#define DMA_CHAN_REG_NUMBER 17 + +#define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x) +#define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4) +#define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8) +#define DMA_CHAN_TX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x10) +#define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14) +#define DMA_CHAN_RX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x18) +#define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c) +#define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20) +#define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28) +#define DMA_CHAN_TX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x2c) +#define DMA_CHAN_RX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x30) +#define DMA_CHAN_INTR_ENA(x) (DMA_CHANX_BASE_ADDR(x) + 0x34) +#define DMA_CHAN_RX_WATCHDOG(x) (DMA_CHANX_BASE_ADDR(x) + 0x38) +#define DMA_CHAN_SLOT_CTRL_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x3c) +#define DMA_CHAN_CUR_TX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x44) +#define DMA_CHAN_CUR_RX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x4c) +#define DMA_CHAN_CUR_TX_BUF_ADDR_H(x) (DMA_CHANX_BASE_ADDR(x) + 0x50) +#define DMA_CHAN_CUR_TX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x54) +#define DMA_CHAN_CUR_RX_BUF_ADDR_H(x) (DMA_CHANX_BASE_ADDR(x) + 0x58) +#define DMA_CHAN_CUR_RX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x5c) +#define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x60) + +// +// DMA Control X +// +#define DMA_CONTROL_SPH BIT24 +#define DMA_CONTROL_MSS_MASK GENMASK(13, 0) + +// +// DMA Tx Channel X Control register defines +// +#define DMA_CONTROL_EDSE BIT28 +#define DMA_CONTROL_TSE BIT12 +#define DMA_CONTROL_OSP BIT4 +#define DMA_CONTROL_ST BIT0 + +// +// DMA Rx Channel X Control register defines +// +#define DMA_CONTROL_SR BIT0 +#define DMA_RBSZ_MASK GENMASK(14, 1) +#define DMA_RBSZ_SHIFT 1 + +// +// Interrupt enable bits per channel +// +#define DMA_CHAN_INTR_ENA_NIE BIT16 +#define DMA_CHAN_INTR_ENA_AIE BIT15 +#define DMA_CHAN_INTR_ENA_NIE_4_10 BIT15 +#define DMA_CHAN_INTR_ENA_AIE_4_10 BIT14 +#define DMA_CHAN_INTR_ENA_CDE BIT13 +#define DMA_CHAN_INTR_ENA_FBE BIT12 +#define DMA_CHAN_INTR_ENA_ERE BIT11 +#define DMA_CHAN_INTR_ENA_ETE BIT10 +#define DMA_CHAN_INTR_ENA_RWE BIT9 +#define DMA_CHAN_INTR_ENA_RSE BIT8 +#define DMA_CHAN_INTR_ENA_RBUE BIT7 +#define DMA_CHAN_INTR_ENA_RIE BIT6 +#define DMA_CHAN_INTR_ENA_TBUE BIT2 +#define DMA_CHAN_INTR_ENA_TSE BIT1 +#define DMA_CHAN_INTR_ENA_TIE BIT0 + +#define DMA_CHAN_INTR_NORMAL (DMA_CHAN_INTR_ENA_NIE | \ + DMA_CHAN_INTR_ENA_RIE | \ + DMA_CHAN_INTR_ENA_TIE) + +#define DMA_CHAN_INTR_ABNORMAL (DMA_CHAN_INTR_ENA_AIE | \ + DMA_CHAN_INTR_ENA_FBE) + +// +// DMA default interrupt mask for 4.00 +// +#define DMA_CHAN_INTR_DEFAULT_MASK (DMA_CHAN_INTR_NORMAL | \ + DMA_CHAN_INTR_ABNORMAL) +#define DMA_CHAN_INTR_DEFAULT_RX (DMA_CHAN_INTR_ENA_RIE) +#define DMA_CHAN_INTR_DEFAULT_TX (DMA_CHAN_INTR_ENA_TIE) +#define DMA_CHAN_INTR_NORMAL_4_10 (DMA_CHAN_INTR_ENA_NIE_4_10 | \ + DMA_CHAN_INTR_ENA_RIE | \ + DMA_CHAN_INTR_ENA_TIE) + +#define DMA_CHAN_INTR_ABNORMAL_4_10 (DMA_CHAN_INTR_ENA_AIE_4_10 | \ + DMA_CHAN_INTR_ENA_FBE) +// +// Interrupt status per channel +// +#define DMA_CHAN_STATUS_REB GENMASK(21, 19) +#define DMA_CHAN_STATUS_REB_SHIFT 19 +#define DMA_CHAN_STATUS_TEB GENMASK(18, 16) +#define DMA_CHAN_STATUS_TEB_SHIFT 16 +#define DMA_CHAN_STATUS_NIS BIT15 +#define DMA_CHAN_STATUS_AIS BIT14 +#define DMA_CHAN_STATUS_CDE BIT13 +#define DMA_CHAN_STATUS_FBE BIT12 +#define DMA_CHAN_STATUS_ERI BIT11 +#define DMA_CHAN_STATUS_ETI BIT10 +#define DMA_CHAN_STATUS_RWT BIT9 +#define DMA_CHAN_STATUS_RPS BIT8 +#define DMA_CHAN_STATUS_RBU BIT7 +#define DMA_CHAN_STATUS_RI BIT6 +#define DMA_CHAN_STATUS_TBU BIT2 +#define DMA_CHAN_STATUS_TPS BIT1 +#define DMA_CHAN_STATUS_TI BIT0 + +#define DMA_CHAN_STATUS_MSK_COMMON (DMA_CHAN_STATUS_NIS | \ + DMA_CHAN_STATUS_AIS | \ + DMA_CHAN_STATUS_CDE | \ + DMA_CHAN_STATUS_FBE) + +#define DMA_CHAN_STATUS_MSK_RX (DMA_CHAN_STATUS_REB | \ + DMA_CHAN_STATUS_ERI | \ + DMA_CHAN_STATUS_RWT | \ + DMA_CHAN_STATUS_RPS | \ + DMA_CHAN_STATUS_RBU | \ + DMA_CHAN_STATUS_RI | \ + DMA_CHAN_STATUS_MSK_COMMON) + +#define DMA_CHAN_STATUS_MSK_TX (DMA_CHAN_STATUS_ETI | \ + DMA_CHAN_STATUS_TBU | \ + DMA_CHAN_STATUS_TPS | \ + DMA_CHAN_STATUS_TI | \ + DMA_CHAN_STATUS_MSK_COMMON) + +#define DMA_RX_NO_ERROR 0x0 +#define DMA_RX_WRITE_DATA_BUFFER_ERROR 0x1 +#define DMA_RX_WRITE_DESCRIPTOR_ERROR 0x3 +#define DMA_RX_READ_DATA_BUFFER_ERROR 0x5 +#define DMA_RX_READ_DESCRIPTOR_ERROR 0x7 +#define DMA_TX_NO_ERROR 0x0 +#define DMA_TX_WRITE_DATA_BUFFER_ERROR 0x1 +#define DMA_TX_WRITE_DESCRIPTOR_ERROR 0x3 +#define DMA_TX_READ_DATA_BUFFER_ERROR 0x5 +#define DMA_TX_READ_DESCRIPTOR_ERROR 0x7 + +// +// MMC (MAC Management Counters) +// +#define MMC_TX_FRAMECOUNT_GB 0x700 + 0x18 +#define MMC_TX_BROADCASTFRAME_G 0x700 + 0x1c +#define MMC_TX_MULTICASTFRAME_G 0x700 + 0x20 +#define MMC_TX_UNICAST_GB 0x700 + 0x3c +#define MMC_TX_LATECOL 0x700 + 0x58 +#define MMC_TX_EXESSCOL 0x700 + 0x5c +#define MMC_TX_OCTETCOUNT_GB 0x700 + 0x64 +#define MMC_TX_FRAMECOUNT_G 0x700 + 0x68 +#define MMC_TX_OVERSIZE_G 0x700 + 0x78 + +#define MMC_RX_FRAMECOUNT_GB 0x700 + 0x80 +#define MMC_RX_OCTETCOUNT_GB 0x700 + 0x84 +#define MMC_RX_BROADCASTFRAME_G 0x700 + 0x8c +#define MMC_RX_MULTICASTFRAME_G 0x700 + 0x90 +#define MMC_RX_CRC_ERROR 0x700 + 0x94 +#define MMC_RX_UNDERSIZE_G 0x700 + 0xa4 +#define MMC_RX_OVERSIZE_G 0x700 + 0xa8 +#define MMC_RX_UNICAST_G 0x700 + 0xc4 + +#define TX_DESC_NUM 4 +#define RX_DESC_NUM 4 +//#define ETH_BUFFER_SIZE 2048 // 2KiB +#define ETH_BUFFER_SIZE 1600 // 2KiB +#define TX_TOTAL_BUFFER_SIZE (TX_DESC_NUM * ETH_BUFFER_SIZE) +#define RX_TOTAL_BUFFER_SIZE (RX_DESC_NUM * ETH_BUFFER_SIZE) +#define RX_MAX_PACKET 1600 // ALIGN(1568, 64) + +/* Normal transmit descriptor defines (without split feature) */ + +/* TDES2 (read format) */ +#define TDES2_BUFFER1_SIZE_MASK GENMASK(13, 0) +#define TDES2_VLAN_TAG_MASK GENMASK(15, 14) +#define TDES2_VLAN_TAG_SHIFT 14 +#define TDES2_BUFFER2_SIZE_MASK GENMASK(29, 16) +#define TDES2_BUFFER2_SIZE_MASK_SHIFT 16 +#define TDES3_IVTIR_MASK GENMASK(19, 18) +#define TDES3_IVTIR_SHIFT 18 +#define TDES3_IVLTV BIT17 +#define TDES2_TIMESTAMP_ENABLE BIT30 +#define TDES2_IVT_MASK GENMASK(31, 16) +#define TDES2_IVT_SHIFT 16 +#define TDES2_INTERRUPT_ON_COMPLETION BIT31 + +/* TDES3 (read format) */ +#define TDES3_PACKET_SIZE_MASK GENMASK(14, 0) +#define TDES3_VLAN_TAG GENMASK(15, 0) +#define TDES3_VLTV BIT16 +#define TDES3_CHECKSUM_INSERTION_MASK GENMASK(17, 16) +#define TDES3_CHECKSUM_INSERTION_SHIFT 16 +#define TDES3_TCP_PKT_PAYLOAD_MASK GENMASK(17, 0) +#define TDES3_TCP_SEGMENTATION_ENABLE BIT18 +#define TDES3_HDR_LEN_SHIFT 19 +#define TDES3_SLOT_NUMBER_MASK GENMASK(22, 19) +#define TDES3_SA_INSERT_CTRL_MASK GENMASK(25, 23) +#define TDES3_SA_INSERT_CTRL_SHIFT 23 +#define TDES3_CRC_PAD_CTRL_MASK GENMASK(27, 26) + +/* TDES3 (write back format) */ +#define TDES3_IP_HDR_ERROR BIT0 +#define TDES3_DEFERRED BIT1 +#define TDES3_UNDERFLOW_ERROR BIT2 +#define TDES3_EXCESSIVE_DEFERRAL BIT3 +#define TDES3_COLLISION_COUNT_MASK GENMASK(7, 4) +#define TDES3_COLLISION_COUNT_SHIFT 4 +#define TDES3_EXCESSIVE_COLLISION BIT8 +#define TDES3_LATE_COLLISION BIT9 +#define TDES3_NO_CARRIER BIT10 +#define TDES3_LOSS_CARRIER BIT11 +#define TDES3_PAYLOAD_ERROR BIT12 +#define TDES3_PACKET_FLUSHED BIT13 +#define TDES3_JABBER_TIMEOUT BIT14 +#define TDES3_ERROR_SUMMARY BIT15 +#define TDES3_TIMESTAMP_STATUS BIT17 +#define TDES3_TIMESTAMP_STATUS_SHIFT 17 + +/* TDES3 context */ +#define TDES3_CTXT_TCMSSV BIT26 + +/* TDES3 Common */ +#define TDES3_RS1V BIT26 +#define TDES3_RS1V_SHIFT 26 +#define TDES3_LAST_DESCRIPTOR BIT28 +#define TDES3_LAST_DESCRIPTOR_SHIFT 28 +#define TDES3_FIRST_DESCRIPTOR BIT29 +#define TDES3_CONTEXT_TYPE BIT30 +#define TDES3_CONTEXT_TYPE_SHIFT 30 + +// +// TDS3 use for both format (read and write back) +// +#define TDES3_OWN BIT31 +#define TDES3_OWN_SHIFT 31 +/* Normal receive descriptor defines (without split feature) */ + +/* RDES0 (write back format) */ +#define RDES0_VLAN_TAG_MASK GENMASK(15, 0) + +/* RDES1 (write back format) */ +#define RDES1_IP_PAYLOAD_TYPE_MASK GENMASK(2, 0) +#define RDES1_IP_HDR_ERROR BIT3 +#define RDES1_IPV4_HEADER BIT4 +#define RDES1_IPV6_HEADER BIT5 +#define RDES1_IP_CSUM_BYPASSED BIT6 +#define RDES1_IP_CSUM_ERROR BIT7 +#define RDES1_PTP_MSG_TYPE_MASK GENMASK(11, 8) +#define RDES1_PTP_PACKET_TYPE BIT12 +#define RDES1_PTP_VER BIT13 +#define RDES1_TIMESTAMP_AVAILABLE BIT14 +#define RDES1_TIMESTAMP_AVAILABLE_SHIFT 14 +#define RDES1_TIMESTAMP_DROPPED BIT15 +#define RDES1_IP_TYPE1_CSUM_MASK GENMASK(31, 16) + +/* RDES2 (write back format) */ +#define RDES2_L3_L4_HEADER_SIZE_MASK GENMASK(9, 0) +#define RDES2_VLAN_FILTER_STATUS BIT15 +#define RDES2_SA_FILTER_FAIL BIT16 +#define RDES2_DA_FILTER_FAIL BIT17 +#define RDES2_HASH_FILTER_STATUS BIT18 +#define RDES2_MAC_ADDR_MATCH_MASK GENMASK(26, 19) +#define RDES2_HASH_VALUE_MATCH_MASK GENMASK(26, 19) +#define RDES2_L3_FILTER_MATCH BIT27 +#define RDES2_L4_FILTER_MATCH BIT28 +#define RDES2_L3_L4_FILT_NB_MATCH_MASK GENMASK(27, 26) +#define RDES2_L3_L4_FILT_NB_MATCH_SHIFT 26 +#define RDES2_HL GENMASK(9, 0) + +/* RDES3 (write back format) */ +#define RDES3_PACKET_SIZE_MASK GENMASK(14, 0) +#define RDES3_ERROR_SUMMARY BIT15 +#define RDES3_PACKET_LEN_TYPE_MASK GENMASK(18, 16) +#define RDES3_DRIBBLE_ERROR BIT19 +#define RDES3_RECEIVE_ERROR BIT20 +#define RDES3_OVERFLOW_ERROR BIT21 +#define RDES3_RECEIVE_WATCHDOG BIT22 +#define RDES3_GIANT_PACKET BIT23 +#define RDES3_CRC_ERROR BIT24 +#define RDES3_RDES0_VALID BIT25 +#define RDES3_RDES1_VALID BIT26 +#define RDES3_RDES2_VALID BIT27 +#define RDES3_LAST_DESCRIPTOR BIT28 +#define RDES3_FIRST_DESCRIPTOR BIT29 +#define RDES3_CONTEXT_DESCRIPTOR BIT30 +#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30 + +/* RDES3 (read format) */ +#define RDES3_BUFFER1_VALID_ADDR BIT24 +#define RDES3_BUFFER2_VALID_ADDR BIT25 +#define RDES3_INT_ON_COMPLETION_EN BIT30 + +/* TDS3 use for both format (read and write back) */ +#define RDES3_OWN BIT31 + +// +// MTL algorithms identifiers. +// +#define MTL_TX_ALGORITHM_WRR 0x0 +#define MTL_TX_ALGORITHM_WFQ 0x1 +#define MTL_TX_ALGORITHM_DWRR 0x2 +#define MTL_TX_ALGORITHM_SP 0x3 +#define MTL_RX_ALGORITHM_SP 0x4 +#define MTL_RX_ALGORITHM_WSP 0x5 + +// +// RX/TX Queue Mode. +// +#define MTL_QUEUE_AVB 0x0 +#define MTL_QUEUE_DCB 0x1 + +#define PAUSE_TIME 0xffff +// +// Flow Control defines +// +#define FLOW_OFF 0 +#define FLOW_RX 1 +#define FLOW_TX 2 +#define FLOW_AUTO (FLOW_TX | FLOW_RX) + + +#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ + +/* Basic descriptor structure for normal and alternate descriptors */ +typedef struct { + UINT32 Des0; + UINT32 Des1; + UINT32 Des2; + UINT32 Des3; +} DMA_DESCRIPTOR; + +typedef struct { + EFI_PHYSICAL_ADDRESS PhysAddress; + void *Mapping; +} MAP_INFO; + +typedef struct { + //DMA_DESCRIPTOR *TxDescRing[TX_DESC_NUM]; + //DMA_DESCRIPTOR *RxDescRing[RX_DESC_NUM]; + DMA_DESCRIPTOR *TxDescRing; + DMA_DESCRIPTOR *RxDescRing; + //EFI_PHYSICAL_ADDRESS RxBuffer; + UINT8 *TxBuffer; + UINT8 *RxBuffer; + + // CHAR8 TxBuffer[TX_TOTAL_BUFFER_SIZE]; + // CHAR8 RxBuffer[RX_TOTAL_BUFFER_SIZE]; + MAP_INFO TxDescRingMap[TX_DESC_NUM]; + MAP_INFO RxDescRingMap[RX_DESC_NUM]; + MAP_INFO TxBufNum[TX_DESC_NUM]; + MAP_INFO RxBufNum[RX_DESC_NUM]; + UINT32 TxCurrentDescriptorNum; + UINT32 TxNextDescriptorNum; + UINT32 RxCurrentDescriptorNum; + UINT32 RxNextDescriptorNum; +} STMMAC_DRIVER; + +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; + + STMMAC_DRIVER MacDriver; + PHY_DEVICE *PhyDev; + SOPHGO_PHY_PROTOCOL *Phy; + + EFI_LOCK Lock; + + UINTN RegBase; +#if 1 + // Array of the recycled transmit buffer address + //UINT64 *RecycledTxBuf; + UINT8 *RecycledTxBuf; + + // The maximum number of recycled buffer pointers in RecycledTxBuf + UINT32 MaxRecycledTxBuf; + + // Current number of recycled buffer pointers in RecycledTxBuf + UINT32 RecycledTxBufCount; + + // For TX buffer DmaUnmap + VOID *MappingTxbuf; +#endif +} SOPHGO_SIMPLE_NETWORK_DRIVER; + +#define SNP_DRIVER_SIGNATURE SIGNATURE_32('A', 'S', 'N', 'P') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, SOPHGO_SIMPLE_NETWORK_DRIVER, Snp, SNP_DRIVER_SIGNATURE) +#define SNP_TX_BUFFER_INCREASE 32 +#define SNP_MAX_TX_BUFFER_NUM 65536 + +VOID +EFIAPI +StmmacSetUmacAddr ( + IN EFI_MAC_ADDRESS *MacAddress, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN RegN + ); + +VOID +EFIAPI +StmmacGetMacAddr ( + OUT EFI_MAC_ADDRESS *MacAddress, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN RegN + ); + +VOID +EFIAPI +StmmacReadMacAddress ( + OUT EFI_MAC_ADDRESS *MacAddress, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacDxeInitialization ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacDmaInit ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacSetupTxdesc ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacSetupRxdesc ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacStartTransmission ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacSetFilters ( + IN UINT32 ReceiveFilterSetting, + IN BOOLEAN Reset, + IN UINTN NumMfilter OPTIONAL, + IN EFI_MAC_ADDRESS *Mfilter OPTIONAL, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +UINT32 +EFIAPI +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ); + +UINT8 +EFIAPI +BitReverse ( + UINT8 Value + ); + +VOID +EFIAPI +StmmacStopTxRx ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacDmaStart ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + + +VOID +EFIAPI +StmmacGetDmaStatus ( + OUT UINT32 *IrqStat OPTIONAL, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacGetStatistic ( + IN EFI_NETWORK_STATISTICS *Stats, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacStartAllDma ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacStopAllDma ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +EFI_STATUS +EFIAPI +StmmacInitDmaEngine ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacMacLinkUp ( + IN UINT32 Speed, + IN UINT32 Duplex, + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +EFIAPI +StmmacDebug ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +StmmacSetRxTailPtr ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN TailPtr, + IN UINT32 Channel + ); + +VOID +StmmacSetTxTailPtr ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINTN TailPtr, + IN UINT32 Channel + ); + +VOID +StmmacMtlConfiguration ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); + +VOID +StmmacMacFlowControl ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver, + IN UINT32 Duplex, + IN UINT32 FlowCtrl + ); + +EFI_STATUS +EFIAPI +PhyLinkAdjustGmacConfig ( + IN SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver + ); +#endif // STMMAC_DXE_UTIL_H__ diff --git a/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.c b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.c new file mode 100755 index 0000000000..f116456458 --- /dev/null +++ b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.c @@ -0,0 +1,2093 @@ +/** @file + DW Mac4 SNP driver. + + Copyright (c) 2024, SOPHGO Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + The original software modules are licensed as follows: + + Copyright (c) 2012 - 2020, Arm Limited. All rights reserved.
+ Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DwMac4SnpDxe.h" +#include "DwMac4DxeUtil.h" + +//STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; + +//STATIC EFI_MAC_ADDRESS mZeroMac = { { 0 } }; + +STATIC +SOPHGO_SIMPLE_NETWORK_DEVICE_PATH PathTemplate = { + { + { + 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 + } + } +}; + +/** + Change the state of a network interface from "stopped" to "started." + + This function starts a network interface. If the network interface successfully + starts, then EFI_SUCCESS will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + + @retval EFI_SUCCESS The network interface was started. + @retval EFI_ALREADY_STARTED The network interface is already in the started state. + @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStarted) { + return EFI_ALREADY_STARTED; + } else if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkStopped) { + return EFI_DEVICE_ERROR; + } + + // + // Change state + // + DwMac4Driver->SnpMode.State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +/** + Changes the state of a network interface from "started" to "stopped." + + This function stops a network interface. This call is only valid if the network + interface is in the started state. If the network interface was successfully + stopped, then EFI_SUCCESS will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL + instance. + + + @retval EFI_SUCCESS The network interface was stopped. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a + valid EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network + interface. + @retval EFI_UNSUPPORTED This function is not supported by the network + interface. + +**/ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* This + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } else if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkStarted) { + return EFI_DEVICE_ERROR; + } + + // + // Stop all RX and TX DMA channels + // + StmmacStopAllDma (DwMac4Driver); + + // + // Change the state + // + DwMac4Driver->SnpMode.State = EfiSimpleNetworkStopped; + + return EFI_SUCCESS; +} + +/** + Resets a network adapter and allocates the transmit and receive buffers + required by the network interface; optionally, also requests allocation of + additional transmit and receive buffers. + + This function allocates the transmit and receive buffers required by the network + interface. If this allocation fails, then EFI_OUT_OF_RESOURCES is returned. + If the allocation succeeds and the network interface is successfully initialized, + then EFI_SUCCESS will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + + @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the + extra buffer, and the caller will not know if it is + actually being used. + @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the + extra buffer, and the caller will not know if it is + actually being used. + + @retval EFI_SUCCESS The network interface was initialized. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and + receive buffers. + @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED The increased buffer size feature is not supported. + +**/ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } else if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkStarted) { + return EFI_DEVICE_ERROR; + } + + // + // Init PHY + // + Status = gBS->LocateProtocol ( + &gSophgoPhyProtocolGuid, + NULL, + (VOID **) &DwMac4Driver->Phy + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Locate SOPHGO_PHY_PROTOCOL failed (Status=%r)\n", + __func__, + Status + )); + return Status; + } +#if 1 + Status = DwMac4Driver->Phy->Init (DwMac4Driver->Phy, + PHY_INTERFACE_MODE_RGMII_ID, + &DwMac4Driver->PhyDev + ); + if (EFI_ERROR (Status) && Status != EFI_TIMEOUT) { + DEBUG (( + DEBUG_ERROR, + "%a(): PHY initialization failed (Status=%r)\n", + __func__, + Status + )); + return Status; + } + + gBS->Stall (1000000); + // + #if 0 + // Get Phy Status + // + Status = DwMac4Driver->Phy->Status (DwMac4Driver->Phy, DwMac4Driver->PhyDev); + if (EFI_ERROR (Status)) { + ReturnUnlock (EFI_DEVICE_ERROR); + } +#endif +#else + StmmacMacLinkUp (PHY_INTERFACE_MODE_RGMII_ID, DUPLEX_FULL, DwMac4Driver); +#endif + // + // DMA initialization and SW reset + // + Status = StmmacInitDmaEngine (DwMac4Driver); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): DMA initialization failed (Status=%r)\n", + __func__, + Status + )); + return Status; + } + + // + // Configure flow control + // + StmmacMacFlowControl (DwMac4Driver, DwMac4Driver->PhyDev->Duplex, FLOW_AUTO); + StmmacMtlConfiguration (DwMac4Driver); + + // + // Copy the MAC addr into the HW + // + StmmacSetUmacAddr (&DwMac4Driver->SnpMode.CurrentAddress, DwMac4Driver, 0); + StmmacGetMacAddr (&DwMac4Driver->SnpMode.CurrentAddress, DwMac4Driver, 0); + + // + // Declare the driver as initialized + // + DwMac4Driver->SnpMode.State = EfiSimpleNetworkInitialized; + + return EFI_SUCCESS; +} + +/** + Resets a network adapter and reinitializes it with the parameters that were + provided in the previous call to Initialize(). + + This function resets a network adapter and reinitializes it with the parameters + that were provided in the previous call to Initialize(). The transmit and + receive queues are emptied and all pending interrupts are cleared. + Receive filters, the station address, the statistics, and the multicast-IP-to-HW + MAC addresses are not reset by this call. If the network interface was + successfully reset, then EFI_SUCCESS will be returned. If the driver has not + been initialized, EFI_DEVICE_ERROR will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param ExtendedVerification Indicates that the driver may perform a more + exhaustive verification operation of the device + during reset. + + @retval EFI_SUCCESS The network interface was reset. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + //EFI_STATUS Status; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + DEBUG (( + DEBUG_INFO, + "%a()\r\n", + __func__ + )); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + +#if 0 + // + // Initiate a PHY reset + // + Status = PhySoftReset (&DwMac4Driver->PhyDev, Snp->RegBase); + if (EFI_ERROR (Status)) { + DwMac4Driver->SnpMode.State = EfiSimpleNetworkStopped; + return EFI_NOT_STARTED; + } +#endif + return EFI_SUCCESS; +} + +/** + Resets a network adapter and leaves it in a state that is safe for another + driver to initialize. + + This function releases the memory buffers assigned in the Initialize() call. + Pending transmits and receives are lost, and interrupts are cleared and disabled. + After this call, only the Initialize() and Stop() calls may be used. If the + network interface was successfully shutdown, then EFI_SUCCESS will be returned. + If the driver has not been initialized, EFI_DEVICE_ERROR will be returned. + + @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + + @retval EFI_SUCCESS The network interface was shutdown. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + +**/ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* This + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + DEBUG (( + DEBUG_INFO, + "%a ()\r\n", + __func__ + )); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + // + // Stop all RX and TX DMA channels + // + StmmacStopAllDma (DwMac4Driver); + + DwMac4Driver->SnpMode.State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +/** + Manages the multicast receive filters of a network interface. + + This function is used enable and disable the hardware and software receive + filters for the underlying network device. + The receive filter change is broken down into three steps: + * The filter mask bits that are set (ON) in the Enable parameter are added to + the current receive filter settings. + * The filter mask bits that are set (ON) in the Disable parameter are subtracted + from the updated receive filter settings. + * If the resulting receive filter setting is not supported by the hardware a + more liberal setting is selected. + If the same bits are set in the Enable and Disable parameters, then the bits + in the Disable parameter takes precedence. + If the ResetMCastFilter parameter is TRUE, then the multicast address list + filter is disabled (irregardless of what other multicast bits are set in the + Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set + to zero. The Snp->Mode->MCastFilter contents are undefined. + After enabling or disabling receive filter settings, software should verify + the new settings by checking the Snp->Mode->ReceiveFilterSettings, + Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields. + Note: Some network drivers and/or devices will automatically promote receive + filter settings if the requested setting can not be honored. For example, if + a request for four multicast addresses is made and the underlying hardware + only supports two multicast addresses the driver might set the promiscuous + or promiscuous multicast receive filters instead. The receiving software is + responsible for discarding any extra packets that get through the hardware + receive filters. + Note: Note: To disable all receive filter hardware, the network driver must + be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to + Snp->Mode->ReceiveFilterSettings will make it so no more packets are + returned by the Receive() function, but the receive hardware may still be + moving packets into system memory before inspecting and discarding them. + Unexpected system errors, reboots and hangs can occur if an OS is loaded + and the network devices are not Shutdown() and Stopped(). + If ResetMCastFilter is TRUE, then the multicast receive filter list on the + network interface will be reset to the default multicast receive filter list. + If ResetMCastFilter is FALSE, and this network interface allows the multicast + receive filter list to be modified, then the MCastFilterCnt and MCastFilter + are used to update the current multicast receive filter list. The modified + receive filter list settings can be found in the MCastFilter field of + EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast + receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned. + If the driver has not been initialized, EFI_DEVICE_ERROR will be returned. + If the receive filter mask and multicast receive filter list have been + successfully updated on the network interface, EFI_SUCCESS will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param Enable A bit mask of receive filters to enable on the network + interface. + @param Disable A bit mask of receive filters to disable on the network + interface. For backward compatibility with EFI 1.1 + platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit + must be set when the ResetMCastFilter parameter is TRUE. + @param ResetMCastFilter Set to TRUE to reset the contents of the multicast + receive filters on the network interface to their + default values. + @param MCastFilterCnt Number of multicast HW MAC addresses in the new MCastFilter + list. This value must be less than or equal to the + MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. + This field is optional if ResetMCastFilter is TRUE. + @param MCastFilter A pointer to a list of new multicast receive filter HW + MAC addresses. This list will replace any existing + multicast HW MAC address list. This field is optional + if ResetMCastFilter is TRUE. + + @retval EFI_SUCCESS The multicast receive filter list was updated. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + * This is NULL + * There are bits set in Enable that are not set + in Snp->Mode->ReceiveFilterMask + * There are bits set in Disable that are not set + in Snp->Mode->ReceiveFilterMask + * Multicast is being enabled (the + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is + set in Enable, it is not set in Disable, and + ResetMCastFilter is FALSE) and MCastFilterCount + is zero + * Multicast is being enabled and MCastFilterCount + is greater than Snp->Mode->MaxMCastFilterCount + * Multicast is being enabled and MCastFilter is NULL + * Multicast is being enabled and one or more of + the addresses in the MCastFilter list are not + valid multicast MAC addresses + @retval EFI_DEVICE_ERROR One or more of the following conditions is TRUE: + * The network interface has been started but has + not been initialized + * An unexpected error was returned by the + underlying network driver or device + @retval EFI_UNSUPPORTED This function is not supported by the network + interface. + +**/ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ) +{ + UINT32 ReceiveFilterSetting; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + // + // Check that bits set in Enable/Disable are set in ReceiveFilterMask + // + if ((Enable & (~DwMac4Driver->SnpMode.ReceiveFilterMask)) || + (Disable & (~DwMac4Driver->SnpMode.ReceiveFilterMask))) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the filter mask bits that are set in Enable parameter or Disable Parameter + // Same bits that are set in Enable/Disable parameters, then bits in the Disable parameter takes precedance + // + ReceiveFilterSetting = (DwMac4Driver->SnpMode.ReceiveFilterSetting | Enable) & (~Disable); + + StmmacSetFilters (ReceiveFilterSetting, ResetMCastFilter, MCastFilterCnt, MCastFilter, DwMac4Driver); + + return EFI_SUCCESS; +} + +/** + Modifies or resets the current station address, if supported. + + This function modifies or resets the current station address of a network + interface, if supported. If Reset is TRUE, then the current station address is + set to the network interface's permanent address. If Reset is FALSE, and the + network interface allows its station address to be modified, then the current + station address is changed to the address specified by New. If the network + interface does not allow its station address to be modified, then + EFI_INVALID_PARAMETER will be returned. If the station address is successfully + updated on the network interface, EFI_SUCCESS will be returned. If the driver + has not been initialized, EFI_DEVICE_ERROR will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param Reset Flag used to reset the station address to the network interface's + permanent address. + @param NewMac New station address to be used for the network interface. + + + @retval EFI_SUCCESS The network interface's station address was updated. + @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been + started by calling Start(). + @retval EFI_INVALID_PARAMETER The New station address was not accepted by the NIC. + @retval EFI_INVALID_PARAMETER Reset is FALSE and New is NULL. + @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not + been initialized by calling Initialize(). + @retval EFI_DEVICE_ERROR An error occurred attempting to set the new + station address. + @retval EFI_UNSUPPORTED The NIC does not support changing the network + interface's station address. + +**/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac + ) +{ + return EFI_UNSUPPORTED; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + //UINT32 Count; + //UINT8 PermAddr[NET_ETHER_ADDR_LEN]; + + + DEBUG (( + DEBUG_INFO, + "%a()\r\n", + __func__ + )); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + // + // Get the Permanent MAC address if need reset + // + if (Reset) { + // + // Try parse conf.ini first to get mac address + // + if (IsIniFileExist ()) { + MacAddrIniParser (); + NewMac = (EFI_MAC_ADDRESS *) (MacConfig.Mac0Addr); + } else { + DEBUG (( + DEBUG_WARN, + "%a() Warning: using driver-default MAC address\n", + __func__ + )); + NewMac = (EFI_MAC_ADDRESS *) (FixedPcdGet64 (PcdDwMac4DefaultMacAddress)); + } + } else { + // + // Otherwise use the specified new MAC address + // + if (NewMac == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // If it is a multicast address, it is not valid. + // + if (NewMac->Addr[0] & 0x01) { + return EFI_INVALID_PARAMETER; + } + } + + CopyMem (&DwMac4Driver->SnpMode.CurrentAddress, NewMac, NET_ETHER_ADDR_LEN); + StmmacSetUmacAddr (&DwMac4Driver->SnpMode.CurrentAddress, DwMac4Driver, 0); + + return EFI_SUCCESS; +} + +/** + Resets or collects the statistics on a network interface. + + This function resets or collects the statistics on a network interface. If the + size of the statistics table specified by StatisticsSize is not big enough for + all the statistics that are collected by the network interface, then a partial + buffer of statistics is returned in StatisticsTable, StatisticsSize is set to + the size required to collect all the available statistics, and + EFI_BUFFER_TOO_SMALL is returned. + If StatisticsSize is big enough for all the statistics, then StatisticsTable + will be filled, StatisticsSize will be set to the size of the returned + StatisticsTable structure, and EFI_SUCCESS is returned. + If the driver has not been initialized, EFI_DEVICE_ERROR will be returned. + If Reset is FALSE, and both StatisticsSize and StatisticsTable are NULL, then + no operations will be performed, and EFI_SUCCESS will be returned. + If Reset is TRUE, then all of the supported statistics counters on this network + interface will be reset to zero. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param Reset Set to TRUE to reset the statistics for the network interface. + @param StatSize On input the size, in bytes, of StatisticsTable. On output + the size, in bytes, of the resulting table of statistics. + @param Statistics A pointer to the EFI_NETWORK_STATISTICS structure that + contains the statistics. Type EFI_NETWORK_STATISTICS is + defined in "Related Definitions" below. + + @retval EFI_SUCCESS The requested operation succeeded. + @retval EFI_NOT_STARTED The Simple Network Protocol interface has not been + started by calling Start(). + @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is + NULL. The current buffer size that is needed to + hold all the statistics is returned in StatisticsSize. + @retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is + not NULL. The current buffer size that is needed + to hold all the statistics is returned in + StatisticsSize. A partial set of statistics is + returned in StatisticsTable. + @retval EFI_INVALID_PARAMETER StatisticsSize is NULL and StatisticsTable is not + NULL. + @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not + been initialized by calling Initialize(). + @retval EFI_DEVICE_ERROR An error was encountered collecting statistics + from the NIC. + @retval EFI_UNSUPPORTED The NIC does not support collecting statistics + from the network interface. + +**/ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + DEBUG (( + DEBUG_INFO, + "%a()\r\n", + __func__ + )); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + // + // Check the parameters + // + if ((StatSize == NULL) && (Statistics != NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Do a reset if required + // + if (Reset) { + ZeroMem (&DwMac4Driver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // + // Check buffer size + // + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize = sizeof(EFI_NETWORK_STATISTICS); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Read statistic counters + // + StmmacGetStatistic (&DwMac4Driver->Stats, DwMac4Driver); + + // + // Fill in the statistics + // + CopyMem (&Statistics, &DwMac4Driver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + + return EFI_SUCCESS; +} + +/** + Converts a multicast IP address to a multicast HW MAC address. + + This function converts a multicast IP address to a multicast HW MAC address + for all packet transactions. If the mapping is accepted, then EFI_SUCCESS will + be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param IsIpv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. + Set to FALSE if the multicast IP address is IPv4 [RFC 791]. + @param Ip The multicast IP address that is to be converted to a multicast + HW MAC address. + @param McastMac The multicast HW MAC address that is to be generated from IP. + + @retval EFI_SUCCESS The multicast IP address was mapped to the + multicast HW MAC address. + @retval EFI_NOT_STARTED The Simple Network Protocol interface has not + been started by calling Start(). + @retval EFI_INVALID_PARAMETER IP is NULL. + @retval EFI_INVALID_PARAMETER MAC is NULL. + @retval EFI_INVALID_PARAMETER IP does not point to a valid IPv4 or IPv6 + multicast address. + @retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not + been initialized by calling Initialize(). + @retval EFI_UNSUPPORTED IPv6 is TRUE and the implementation does not + support IPv6 multicast to MAC address conversion. + +**/ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + DEBUG (( + DEBUG_INFO, + "%a()\r\n", + __func__ + )); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStarted) { + return EFI_DEVICE_ERROR; + } else if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + 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; +} + +/** + Performs read and write operations on the NVRAM device attached to a network + interface. + + This function performs read and write operations on the NVRAM device attached + to a network interface. If ReadWrite is TRUE, a read operation is performed. + If ReadWrite is FALSE, a write operation is performed. Offset specifies the + byte offset at which to start either operation. Offset must be a multiple of + NvRamAccessSize , and it must have a value between zero and NvRamSize. + BufferSize specifies the length of the read or write operation. BufferSize must + also be a multiple of NvRamAccessSize, and Offset + BufferSize must not exceed + NvRamSize. + If any of the above conditions is not met, then EFI_INVALID_PARAMETER will be + returned. + If all the conditions are met and the operation is "read," the NVRAM device + attached to the network interface will be read into Buffer and EFI_SUCCESS + will be returned. If this is a write operation, the contents of Buffer will be + used to update the contents of the NVRAM device attached to the network + interface and EFI_SUCCESS will be returned. + + It does the basic checking on the input parameters and retrieves snp structure + and then calls the read_nvdata() call which does the actual reading + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param ReadWrite TRUE for read operations, FALSE for write operations. + @param Offset Byte offset in the NVRAM device at which to start the read or + write operation. This must be a multiple of NvRamAccessSize + and less than NvRamSize. (See EFI_SIMPLE_NETWORK_MODE) + @param BufferSize The number of bytes to read or write from the NVRAM device. + This must also be a multiple of NvramAccessSize. + @param Buffer A pointer to the data buffer. + + @retval EFI_SUCCESS The NVRAM access was performed. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + * The This parameter is NULL + * The This parameter does not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure + * The Offset parameter is not a multiple of + EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize + * The Offset parameter is not less than + EFI_SIMPLE_NETWORK_MODE.NvRamSize + * The BufferSize parameter is not a multiple of + EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize + * The Buffer parameter is NULL + @retval EFI_DEVICE_ERROR The command could not be sent to the network + interface. + @retval EFI_UNSUPPORTED This function is not supported by the network + interface. + +**/ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Reads the current interrupt status and recycled transmit buffer status from a + network interface. + + This function gets the current interrupt and recycled transmit buffer status + from the network interface. The interrupt status is returned as a bit mask in + InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be + read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved. + If a recycled transmit buffer address is returned in TxBuf, then the buffer has + been successfully transmitted, and the status for that buffer is cleared. If + the status of the network interface is successfully collected, EFI_SUCCESS + will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will + be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param IrqStat A pointer to the bit mask of the currently active + interrupts (see "Related Definitions"). If this is NULL, + the interrupt status will not be read from the device. + If this is not NULL, the interrupt status will be read + from the device. When the interrupt status is read, it + will also be cleared. Clearing the transmit interrupt does + not empty the recycled transmit buffer array. + @param TxBuff Recycled transmit buffer address. The network interface + will not transmit if its internal recycled transmit + buffer array is full. Reading the transmit buffer does + not clear the transmit interrupt. If this is NULL, then + the transmit buffer status will not be read. If there + are no transmit buffers to recycle and TxBuf is not NULL, + TxBuf will be set to NULL. + + @retval EFI_SUCCESS The status of the network interface was retrieved. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The command could not be sent to the network + interface. + +**/ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + EFI_STATUS Status; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + // + // Update the media status + // +#if 0 + Status = DwMac4Driver->Phy->Status (DwMac4Driver->Phy, DwMac4Driver->PhyDev); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DwMac4Driver->PhyDev->LinkUp) { + DEBUG (( + DEBUG_VERBOSE, + "Link is up - Network Cable is Plugged\r\n" + )); + StmmacMacLinkUp (DwMac4Driver->PhyDev->Speed, DwMac4Driver->PhyDev->Duplex, DwMac4Driver); + DwMac4Driver->SnpMode.MediaPresent = TRUE; + } else { + DEBUG (( + DEBUG_VERBOSE, + "Link is Down - Network Cable is Unplugged?\r\n" + )); + DwMac4Driver->SnpMode.MediaPresent = FALSE; + } +#endif + Status = PhyLinkAdjustGmacConfig (DwMac4Driver); + if (EFI_ERROR (Status)) { + DwMac4Driver->SnpMode.MediaPresent = FALSE; + } else { + DwMac4Driver->SnpMode.MediaPresent = TRUE; + } +#if 1 + // + // TxBuff + // + if (TxBuff != NULL) { + // + // Get a recycled buf from DwMac4Driver->RecycledTxBuf + // + if (DwMac4Driver->RecycledTxBufCount == 0) { + *TxBuff = NULL; + } else { + DwMac4Driver->RecycledTxBufCount--; + *TxBuff = (VOID *)(UINTN) DwMac4Driver->RecycledTxBuf[DwMac4Driver->RecycledTxBufCount]; + } + } +#endif + // + // Check DMA Irq status + // + //StmmacGetDmaStatus (IrqStat, DwMac4Driver); + + return EFI_SUCCESS; +} + +/** + Places a packet in the transmit queue of a network interface. + + This function places the packet specified by Header and Buffer on the transmit + queue. If HeaderSize is nonzero and HeaderSize is not equal to + This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If + BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL + will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be + returned. If HeaderSize is nonzero and tAddr or Protocol is NULL, then + EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network + interface is busy, then EFI_NOT_READY will be returned. If this packet can be + accepted by the transmit engine of the network interface, the packet contents + specified by Buffer will be placed on the transmit queue of the network + interface, and EFI_SUCCESS will be returned. GetStatus() can be used to + determine when the packet has actually been transmitted. The contents of the + Buffer must not be modified until the packet has actually been transmitted. + The Transmit() function performs nonblocking I/O. A caller who wants to perform + blocking I/O, should call Transmit(), and then GetStatus() until the + transmitted buffer shows up in the recycled transmit buffer. + If the driver has not been initialized, EFI_DEVICE_ERROR will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param HeadSize The size, in bytes, of the media header to be filled in by the + Transmit() function. If HeaderSize is nonzero, then it must + be equal to This->Mode->MediaHeaderSize and the tAddr and + Protocol parameters must not be NULL. + @param The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param Data A pointer to the packet (media header followed by data) to be + transmitted. This parameter cannot be NULL. If HeaderSize is + zero, then the media header in Buffer must already be filled + in by the caller. If HeaderSize is nonzero, then the media + header will be filled in by the Transmit() function. + @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this + parameter is ignored. If HeaderSize is nonzero and SrcAddr + is NULL, then This->Mode->CurrentAddress is used for the + source HW MAC address. + @param DstAddr The tination HW MAC address. If HeaderSize is zero, then + this parameter is ignored. + @param Protocol The type of header to build. If HeaderSize is zero, then this + parameter is ignored. See RFC 1700, section "Ether Types," + for examples. + + @retval EFI_SUCCESS The packet was placed on the transmit queue. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY The network interface is too busy to accept this + transmit request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported + value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + @retval EFI_ACCESS_DENIED Error acquire global lock for operation. + +**/ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeadSize, + IN UINTN BufferSize, + IN VOID *Data, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + UINT32 TxDescIndex; + DMA_DESCRIPTOR *TxDescriptor; + DMA_DESCRIPTOR *TxDescriptorMap; + UINT8 *EthernetPacket; + //UINT64 *Tmp; + UINT8 *Tmp; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TxBufferPhysAddress; + UINT32 Index; + UINTN DmaNumberOfBytes; + UINT32 Retries; + + // + // Setup DMA descriptor + // + EthernetPacket = Data; + + if ((This == NULL) || (Data == NULL)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Invalid parameter (missing handle or buffer)\n", + __func__ + )); + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (!DwMac4Driver->SnpMode.MediaPresent) { + // + // We should only really get here if the link was up + // and is now down due to a stop/shutdown sequence, and + // the app (grub) doesn't bother to check link state + // because it was up a moment before. + // Lets wait a bit for the link to resume, rather than + // failing to send. In the case of grub it works either way + // but we can't be sure that is universally true, and + // hanging for a couple seconds is nicer than a screen of + // grub send failure messages. + // + Retries = 1000; + DEBUG ((DEBUG_INFO, "%a(): Waiting 5s for link\n", __func__)); + do { + gBS->Stall (5000); + Status = PhyLinkAdjustGmacConfig (DwMac4Driver); + } while ((EFI_ERROR (Status)) && Retries-- > 0); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): no link\n", __func__)); + return EFI_NOT_READY; + } else { + DwMac4Driver->SnpMode.MediaPresent = TRUE; + } + } + + // + // Ensure header is correct size if non-zero + // + if (HeadSize) { + if (HeadSize != DwMac4Driver->SnpMode.MediaHeaderSize) { + DEBUG (( + DEBUG_ERROR, + "%a(): Invalid parameter (header size mismatch; HeaderSize 0x%X, SnpMode.MediaHeaderSize 0x%X))\n", + __func__, + HeadSize, + DwMac4Driver->SnpMode.MediaHeaderSize + )); + return EFI_INVALID_PARAMETER; + } + + if ((DstAddr == NULL) || (Protocol == NULL)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Invalid parameter (dest addr or protocol missing)\n", + __func__ + )); + return EFI_INVALID_PARAMETER; + } + } + + // + // Check validity of BufferSize + // + if (BufferSize < DwMac4Driver->SnpMode.MediaHeaderSize) { + DEBUG (( + DEBUG_ERROR, + "%a(): Buffer too small\n", + __func__ + )); + return EFI_BUFFER_TOO_SMALL; + } + + if ((DwMac4Driver->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASE) >= SNP_MAX_TX_BUFFER_NUM) { + return EFI_NOT_READY; + } + + // + // Check preliminaries + // + Status = EfiAcquireLockOrFail (&DwMac4Driver->Lock); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Couldn't get lock: %r\n", + __func__, + Status + )); + return EFI_ACCESS_DENIED; + } + + DwMac4Driver->MacDriver.TxCurrentDescriptorNum = DwMac4Driver->MacDriver.TxNextDescriptorNum; + TxDescIndex = DwMac4Driver->MacDriver.TxCurrentDescriptorNum; + + TxDescriptor = DwMac4Driver->MacDriver.TxDescRing + TxDescIndex * sizeof (DMA_DESCRIPTOR); + TxDescriptorMap = (VOID *)(UINTN)DwMac4Driver->MacDriver.TxDescRingMap[TxDescIndex].PhysAddress; + + if (HeadSize) { + EthernetPacket[0] = DstAddr->Addr[0]; + EthernetPacket[1] = DstAddr->Addr[1]; + EthernetPacket[2] = DstAddr->Addr[2]; + EthernetPacket[3] = DstAddr->Addr[3]; + EthernetPacket[4] = DstAddr->Addr[4]; + EthernetPacket[5] = DstAddr->Addr[5]; + + EthernetPacket[6] = SrcAddr->Addr[0]; + EthernetPacket[7] = SrcAddr->Addr[1]; + EthernetPacket[8] = SrcAddr->Addr[2]; + EthernetPacket[9] = SrcAddr->Addr[3]; + EthernetPacket[10] = SrcAddr->Addr[4]; + EthernetPacket[11] = SrcAddr->Addr[5]; + + EthernetPacket[12] = (*Protocol & 0xFF00) >> 8; + EthernetPacket[13] = *Protocol & 0xFF; + } + + DmaNumberOfBytes = BufferSize; + DEBUG ((DEBUG_VERBOSE, "%a(): Packet=0x%p, Length=0x%x\n", __func__, EthernetPacket, BufferSize)); + Status = DmaMap ( + MapOperationBusMasterRead, + (VOID *)(UINTN)EthernetPacket, + &DmaNumberOfBytes, + &TxBufferPhysAddress, + &DwMac4Driver->MappingTxbuf + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Txbuffer: %r\n", + __func__, + Status + )); + + goto ReleaseLock; + } +#if 0 + // + // Flush Tx Buffer + // + mCpu->FlushDataCache ( + mCpu, + TxBufferPhysAddress, + DmaNumberOfBytes, + EfiCpuFlushTypeWriteBackInvalidate + ); +#endif + + TxDescriptor->Des0 = LOWER_32_BITS(TxBufferPhysAddress); + TxDescriptor->Des1 = UPPER_32_BITS(TxBufferPhysAddress); + TxDescriptor->Des2 = BufferSize; + MemoryFence(); + + // + // Make sure that if HW sees the _OWN write below, it will see all the + // writes to the rest of the Descriptor too. + // + TxDescriptor->Des3 = TDES3_OWN | + TDES3_FIRST_DESCRIPTOR | + TDES3_LAST_DESCRIPTOR | + BufferSize; + // + // Increase Descriptor number + // + TxDescIndex++; + TxDescIndex %= TX_DESC_NUM; + DwMac4Driver->MacDriver.TxNextDescriptorNum = TxDescIndex; + StmmacSetTxTailPtr (DwMac4Driver, + (UINTN)DwMac4Driver->MacDriver.TxDescRingMap[TxDescIndex].PhysAddress, + 0); + + if (DwMac4Driver->RecycledTxBufCount < DwMac4Driver->MaxRecycledTxBuf) { + DwMac4Driver->RecycledTxBuf[DwMac4Driver->RecycledTxBufCount] = (UINT64)(UINTN)Data; + DwMac4Driver->RecycledTxBufCount ++; + } else { + Tmp = AllocatePool (sizeof (UINT64) * (DwMac4Driver->MaxRecycledTxBuf + TX_DESC_NUM)); + if (Tmp == NULL) { + Status = EFI_DEVICE_ERROR; + goto ReleaseLock; + } + + CopyMem (Tmp, DwMac4Driver->RecycledTxBuf, sizeof (UINT64) * DwMac4Driver->RecycledTxBufCount); + FreePool (DwMac4Driver->RecycledTxBuf); + DwMac4Driver->RecycledTxBuf = Tmp; + DwMac4Driver->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASE; + } + + for (Index = 0; Index < 1000000; Index++) { + if (!(MmioRead32 ((UINTN)&TxDescriptor->Des3) & TDES3_OWN)) { + Status = EFI_SUCCESS; + goto ReleaseLock; + } + gBS->Stall(1); + } + + //StmmacGetDmaStatus (0, DwMac4Driver); + StmmacDebug (DwMac4Driver); + DEBUG (( + DEBUG_ERROR, + "%a(): TX timeout\n", + __func__ + )); + + Status = EFI_TIMEOUT; + + DmaUnmap (DwMac4Driver->MappingTxbuf); + +ReleaseLock: + EfiReleaseLock (&DwMac4Driver->Lock); +#if 0 + StmmacDebug (DwMac4Driver); +#endif + + return Status; +} + +/** + Receives a packet from a network interface. + + This function retrieves one packet from the receive queue of a network interface. + If there are no packets on the receive queue, then EFI_NOT_READY will be + returned. If there is a packet on the receive queue, and the size of the packet + is smaller than BufferSize, then the contents of the packet will be placed in + Buffer, and BufferSize will be updated with the actual size of the packet. + In addition, if SrcAddr, tAddr, and Protocol are not NULL, then these values + will be extracted from the media header and returned. EFI_SUCCESS will be + returned if a packet was successfully received. + If BufferSize is smaller than the received packet, then the size of the receive + packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned. + If the driver has not been initialized, EFI_DEVICE_ERROR will be returned. + + @param Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + @param HeadSize The size, in bytes, of the media header received on the network + interface. If this parameter is NULL, then the media header size + will not be returned. + @param On entry, the size, in bytes, of Buffer. On exit, the size, in + bytes, of the packet that was received on the network interface. + @param Data A pointer to the data buffer to receive both the media + header and the data. + @param SrcAddr The source HW MAC address. If this parameter is NULL, the HW + MAC source address will not be extracted from the media header. + @param DstAddr The tination HW MAC address. If this parameter is NULL, + the HW MAC tination address will not be extracted from + the media header. + @param Protocol The media header type. If this parameter is NULL, then the + protocol will not be extracted from the media header. See + RFC 1700 section "Ether Types" for examples. + + @retval EFI_SUCCESS The received data was stored in Buffer, and + BufferSize has been updated to the number of + bytes received. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY No packets have been received on the network interface. + @retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received packets. + BufferSize has been updated to the required size. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + * The This parameter is NULL + * The This parameter does not point to a valid + EFI_SIMPLE_NETWORK_PROTOCOL structure. + * The BufferSize parameter is NULL + * The Buffer parameter is NULL + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_ACCESS_DENIED Error acquire global lock for operation. + +**/ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeadSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + EFI_MAC_ADDRESS Dst; + EFI_MAC_ADDRESS Src; + UINT32 Length; + UINT32 RxDescriptorStatus; + UINT8 *RawData; + UINT32 RxDescIndex; + DMA_DESCRIPTOR *RxDescriptor; + DMA_DESCRIPTOR *RxDescriptorMap; + UINTN BufferSizeBuf; + UINTN *RxBufferAddr; + EFI_STATUS Status; + + BufferSizeBuf = ETH_BUFFER_SIZE; + + // + // Check preliminaries + // + if ((This == NULL) || (Data == NULL)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Invalid parameter (missing handle or buffer)\n", + __func__ + )); + return EFI_INVALID_PARAMETER; + } + + DwMac4Driver = INSTANCE_FROM_SNP_THIS (This); + if (DwMac4Driver->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if (DwMac4Driver->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + Status = EfiAcquireLockOrFail (&DwMac4Driver->Lock); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): Couldn't get lock: %r\n", + __func__, + Status + )); + return EFI_ACCESS_DENIED; + } + + // + // Get Rx descriptor + // + DwMac4Driver->MacDriver.RxCurrentDescriptorNum = DwMac4Driver->MacDriver.RxNextDescriptorNum; + RxDescIndex = DwMac4Driver->MacDriver.RxCurrentDescriptorNum; + RxDescriptor = DwMac4Driver->MacDriver.RxDescRing + RxDescIndex * sizeof (DMA_DESCRIPTOR); + + RxBufferAddr = (UINTN *)(DwMac4Driver->MacDriver.RxBuffer + RxDescIndex * BufferSizeBuf); + RxDescriptorMap = (VOID *)(UINTN)DwMac4Driver->MacDriver.RxDescRingMap[RxDescIndex].PhysAddress; + + RawData = (UINT8 *) Data; + + // + // Write-Back: Get Rx Status + // +#if 0 + StmmacDebug (DwMac4Driver); +#endif + RxDescriptorStatus = RxDescriptor->Des3; + if (RxDescriptorStatus & RDES3_OWN) { + DEBUG (( + DEBUG_VERBOSE, + "%a(): RX packet not available!\n", + __func__ + )); + Status = EFI_NOT_READY; + goto ReleaseLock; + } + + if (RxDescriptorStatus & RDES3_ERROR_SUMMARY) { + // + // Check for errors + // + if (RxDescriptorStatus & RDES3_CRC_ERROR) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: CRC Error\n", + __func__ + )); + } + + if (RxDescriptorStatus & RDES3_DRIBBLE_ERROR) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: Dribble Bit Error\n", + __func__ + )); + } + + if (RxDescriptorStatus & RDES3_RECEIVE_ERROR) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: Receive Error\n", + __func__ + )); + } + + if (RxDescriptorStatus & RDES3_RECEIVE_WATCHDOG) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: Watchdog Timeout\n", + __func__ + )); + } + + if (RxDescriptorStatus & RDES3_OVERFLOW_ERROR) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: Overflow Error\n", + __func__ + )); + } + + if (RxDescriptorStatus & RDES3_GIANT_PACKET) { + DEBUG (( + DEBUG_WARN, + "%a(): Rx decritpor Status Error: Giant Packet\n", + __func__ + )); + } + + Status = EFI_DEVICE_ERROR; + goto ReleaseLock; + } + + Length = RxDescriptorStatus & RDES3_PACKET_SIZE_MASK; + DEBUG (( + DEBUG_VERBOSE, + "%a(): RxBufferAddr=0x%lx, Length = %d\n", + __func__, + RxBufferAddr, + Length + )); + if (!Length) { + DEBUG (( + DEBUG_WARN, + "%a(): Error: Invalid Frame Packet length \r\n", + __func__ + )); + Status = EFI_NOT_READY; + goto ReleaseLock; + } + + // + // Check buffer size + // + if (*BufferSize < Length) { + DEBUG (( + DEBUG_WARN, + "%a(): Error: Buffer size is too small\n", + __func__ + )); + Status = EFI_BUFFER_TOO_SMALL; + goto ReleaseLock; + } + + *BufferSize = Length; + + if (HeadSize != NULL) { + *HeadSize = DwMac4Driver->SnpMode.MediaHeaderSize; + } +#if 1 + // + // Given an RX buffer descriptor index, undo the DmaMap operation on the buffer. + // + DmaUnmap (DwMac4Driver->MacDriver.RxBufNum[RxDescIndex].Mapping); + DwMac4Driver->MacDriver.RxBufNum[RxDescIndex].Mapping = NULL; +#endif + CopyMem (RawData, (VOID *)RxBufferAddr, *BufferSize); + + if (DstAddr != NULL) { + Dst.Addr[0] = RawData[0]; + Dst.Addr[1] = RawData[1]; + Dst.Addr[2] = RawData[2]; + Dst.Addr[3] = RawData[3]; + Dst.Addr[4] = RawData[4]; + Dst.Addr[5] = RawData[5]; + + CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN); + + DEBUG (( + DEBUG_INFO, + "%a(): Received from source address %x %x\r\n", + __func__, + DstAddr, + &Dst + )); + } + + // + // Get the source address + // + if (SrcAddr != NULL) { + Src.Addr[0] = RawData[6]; + Src.Addr[1] = RawData[7]; + Src.Addr[2] = RawData[8]; + Src.Addr[3] = RawData[9]; + Src.Addr[4] = RawData[10]; + Src.Addr[5] = RawData[11]; + + DEBUG (( + DEBUG_INFO, + "%a(): Received from source address %x %x\r\n", + __func__, + SrcAddr, + &Src + )); + + CopyMem (SrcAddr, &Src, NET_ETHER_ADDR_LEN); + } + + // + // Get the protocol + // + if (Protocol != NULL) { + *Protocol = NTOHS (RawData[12] | (RawData[13] >> 8) | + (RawData[14] >> 16) | (RawData[15] >> 24)); + } + + // + // DMA map for the current receive buffer + // + Status = DmaMap ( + MapOperationBusMasterWrite, + (VOID *)RxBufferAddr, + &BufferSizeBuf, + &DwMac4Driver->MacDriver.RxBufNum[RxDescIndex].PhysAddress, + &DwMac4Driver->MacDriver.RxBufNum[RxDescIndex].Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Rxbuffer: %r\n", + __func__, + Status + )); + + goto ReleaseLock; + } + + RxDescriptor->Des3 |= (UINT32)RDES3_OWN; + + // + // Increase descriptor number + // + RxDescIndex++; + RxDescIndex %= RX_DESC_NUM; + DwMac4Driver->MacDriver.RxNextDescriptorNum = RxDescIndex; + + Status = EFI_SUCCESS; + +ReleaseLock: + EfiReleaseLock (&DwMac4Driver->Lock); +#if 0 + StmmacDebug (DwMac4Driver); +#endif + + return Status; +} + +/* + * Entry point for DwMac4 driver. + */ +EFI_STATUS +EFIAPI +DwMac4SnpDxeEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SOPHGO_SIMPLE_NETWORK_DRIVER *DwMac4Driver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + SOPHGO_SIMPLE_NETWORK_DEVICE_PATH *DevicePath; + UINT64 DefaultMacAddress; + EFI_MAC_ADDRESS *SwapMacAddressPtr; + UINTN DescriptorSize; + UINTN BufferSize; + UINT32 Index; + EFI_HANDLE Handle; + EFI_CPU_ARCH_PROTOCOL *gCpu; + + Handle = NULL; + + // + // Allocate Resources + // + DwMac4Driver = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (SOPHGO_SIMPLE_NETWORK_DRIVER))); + if (DwMac4Driver == NULL) { + DEBUG (( + DEBUG_ERROR, + "%a() for Snp is NULL!\n", + __func__ + )); + return EFI_OUT_OF_RESOURCES; + } + + DevicePath = (SOPHGO_SIMPLE_NETWORK_DEVICE_PATH *)AllocateCopyPool (sizeof (SOPHGO_SIMPLE_NETWORK_DEVICE_PATH), &PathTemplate); + if (DevicePath == NULL) { + DEBUG (( + DEBUG_ERROR, + "%a() for DeivcePath is NULL!\n", + __func__ + )); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->LocateProtocol ( + &gEfiCpuArchProtocolGuid, + NULL, + (VOID **)&gCpu + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a(): LocateProtocol gEfiCpuArchProtocolGuid Status = %r !\n", + __func__, + Status + )); + } + + // + // Size for descriptor + // + DescriptorSize = sizeof (DMA_DESCRIPTOR); + + // + // Size for transmit and receive buffer + // + BufferSize = ETH_BUFFER_SIZE; + DEBUG (( + DEBUG_VERBOSE, + "%a[%d] DescriptorSize=0x%lx\tRxBufferSize=0x%lx\n", + __func__, + __LINE__, + DescriptorSize, + BufferSize + )); + + Status = DmaAllocateBuffer (EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize * TX_DESC_NUM), + (VOID *)&DwMac4Driver->MacDriver.TxBuffer + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Tx Buffer: %r\n", + __func__, + Status + )); + return Status; + } + + Status = DmaAllocateBuffer (EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize * RX_DESC_NUM), + (VOID *)&DwMac4Driver->MacDriver.RxBuffer + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Rx Buffer: %r\n", + __func__, + Status + )); + return Status; + } + + // + // DMA TxDescRing allocate buffer + // + Status = DmaAllocateBuffer (EfiBootServicesData, + EFI_SIZE_TO_PAGES (DescriptorSize * TX_DESC_NUM), + (VOID *)&DwMac4Driver->MacDriver.TxDescRing + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for TxDescRing: %r\n", + __func__, + Status + )); + return Status; + } + + ZeroMem (DwMac4Driver->MacDriver.TxDescRing, DescriptorSize * TX_DESC_NUM); + + // + // DMA RxDescRing allocte buffer + // + Status = DmaAllocateBuffer (EfiBootServicesData, + EFI_SIZE_TO_PAGES (DescriptorSize * RX_DESC_NUM), + (VOID *)&DwMac4Driver->MacDriver.RxDescRing + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for RxDescRing: %r\n", + __func__, + Status + )); + return Status; + } + + ZeroMem (DwMac4Driver->MacDriver.RxDescRing, DescriptorSize * RX_DESC_NUM); + + for (Index = 0; Index < TX_DESC_NUM; Index++) { + DEBUG (( + DEBUG_VERBOSE, + "%a[%d] TxDesc[%d] BaseAddr=0x%lx, Size=0x%lx\n\n", + __func__, + __LINE__, + Index, + (EFI_PHYSICAL_ADDRESS)(DwMac4Driver->MacDriver.TxDescRing + Index * DescriptorSize), + DescriptorSize + )); + + Status = DmaMap (MapOperationBusMasterCommonBuffer, + DwMac4Driver->MacDriver.TxDescRing + Index * DescriptorSize, + &DescriptorSize, + &DwMac4Driver->MacDriver.TxDescRingMap[Index].PhysAddress, + &DwMac4Driver->MacDriver.TxDescRingMap[Index].Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for TxDescRing: %r\n", + __func__, + Status + )); + return Status; + } + + DEBUG (( + DEBUG_VERBOSE, + "%a[%d] RxDesc[%d] BaseAddr=0x%lx, Size=0x%lx\n\n", + __func__, + __LINE__, + Index, + (EFI_PHYSICAL_ADDRESS)(DwMac4Driver->MacDriver.RxDescRing + Index * DescriptorSize), + DescriptorSize + )); + + Status = DmaMap (MapOperationBusMasterCommonBuffer, + DwMac4Driver->MacDriver.RxDescRing + Index * DescriptorSize, + &DescriptorSize, + &DwMac4Driver->MacDriver.RxDescRingMap[Index].PhysAddress, + &DwMac4Driver->MacDriver.RxDescRingMap[Index].Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for RxDescRing: %r\n", + __func__, + Status + )); + return Status; + } + + // + // DMA mapping for transmit buffer + // + Status = DmaMap (MapOperationBusMasterWrite, + DwMac4Driver->MacDriver.TxBuffer + Index * BufferSize, + &BufferSize, + &DwMac4Driver->MacDriver.TxBufNum[Index].PhysAddress, + &DwMac4Driver->MacDriver.TxBufNum[Index].Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Rxbuffer: %r\n", + __func__, + Status + )); + return Status; + } + + // + // DMA mapping for receive buffer + // + Status = DmaMap (MapOperationBusMasterWrite, + DwMac4Driver->MacDriver.RxBuffer + Index * BufferSize, + &BufferSize, + &DwMac4Driver->MacDriver.RxBufNum[Index].PhysAddress, + &DwMac4Driver->MacDriver.RxBufNum[Index].Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a() for Rxbuffer: %r\n", + __func__, + Status + )); + return Status; + } + } + + // + // Initialized signature (used by INSTANCE_FROM_SNP_THIS macro) + // + DwMac4Driver->Signature = SNP_DRIVER_SIGNATURE; + + EfiInitializeLock (&DwMac4Driver->Lock, TPL_CALLBACK); + + // + // Initialize pointers + // + Snp = &DwMac4Driver->Snp; + SnpMode = &DwMac4Driver->SnpMode; + Snp->Mode = SnpMode; + + // + // Get MAC controller base address + // + DwMac4Driver->RegBase = 0x7030006000; + + // + // 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; + + DwMac4Driver->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASE); + if (DwMac4Driver->RecycledTxBuf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + + DwMac4Driver->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASE; + DwMac4Driver->RecycledTxBufCount = 0; + + // + // 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); + 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_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + + // + // We do not intend to receive anything for the time being. + // + //SnpMode->ReceiveFilterSetting = 0; + SnpMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + // + // GMAC 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); + + // + // Set current address. + // Try parse conf.ini first to get mac address + // + if (IsIniFileExist ()) { + MacAddrIniParser (); + DefaultMacAddress = MacConfig.Mac0Addr; + } else { + DEBUG (( + DEBUG_WARN, + "%a() Warning: using driver-default MAC address\n", + __func__ + )); + DefaultMacAddress = FixedPcdGet64 (PcdDwMac4DefaultMacAddress); + } + + CopyMem (&Snp->Mode->CurrentAddress, &DefaultMacAddress, NET_ETHER_ADDR_LEN); + + // + // Swap PCD human readable form to correct endianess + // + SwapMacAddressPtr = (EFI_MAC_ADDRESS *) &DefaultMacAddress; + SnpMode->CurrentAddress.Addr[0] = SwapMacAddressPtr->Addr[5]; + SnpMode->CurrentAddress.Addr[1] = SwapMacAddressPtr->Addr[4]; + SnpMode->CurrentAddress.Addr[2] = SwapMacAddressPtr->Addr[3]; + SnpMode->CurrentAddress.Addr[3] = SwapMacAddressPtr->Addr[2]; + SnpMode->CurrentAddress.Addr[4] = SwapMacAddressPtr->Addr[1]; + SnpMode->CurrentAddress.Addr[5] = SwapMacAddressPtr->Addr[0]; + + // + // Assign fields for device path + // + CopyMem (&DevicePath->MacAddrDP.MacAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN); + DevicePath->MacAddrDP.IfType = Snp->Mode->IfType; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiSimpleNetworkProtocolGuid, + Snp, + &gEfiDevicePathProtocolGuid, + DevicePath, + NULL + ); + + if (EFI_ERROR(Status)) { + FreePages (DwMac4Driver, EFI_SIZE_TO_PAGES (sizeof (SOPHGO_SIMPLE_NETWORK_DRIVER))); + DEBUG (( + DEBUG_ERROR, + "%a(): Install SIMPLE_NETWORK_PROTOCOL failed!\n", + __func__ + )); + } + + return Status; +} diff --git a/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.h b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.h new file mode 100755 index 0000000000..855dc1e3d4 --- /dev/null +++ b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.h @@ -0,0 +1,158 @@ +/** @file + + Copyright (c) 2011 - 2019, Intel Corporaton. All rights reserved. + Copyright (c) 2024, SOPHGO Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + The original software modules are licensed as follows: + + Copyright (c) 2012-2014, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef DWMAC4_SNP_DXE_H__ +#define DWMAC4_SNP_DXE_H__ + +// +// Protocols used by this driver +// +#include +#include + +#include +#include "DwMac4DxeUtil.h" + +/*------------------------------------------------------------------------------ + Information Structure +------------------------------------------------------------------------------*/ + +typedef struct { + MAC_ADDR_DEVICE_PATH MacAddrDP; + EFI_DEVICE_PATH_PROTOCOL End; +} SOPHGO_SIMPLE_NETWORK_DEVICE_PATH; + +/*--------------------------------------------------------------------------------------------------------------------- + + UEFI-Compliant functions for EFI_SIMPLE_NETWORK_PROTOCOL + + Refer to the Simple Network Protocol section (24.1) in the UEFI 2.8 Specification for related definitions + +---------------------------------------------------------------------------------------------------------------------*/ + +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ); + +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN ExtendedVerification + ); + +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ); + +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +); + +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ); + +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ); + +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ); + +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN HdrSize, + IN UINTN BufferSize, + IN VOID *Data, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ); + +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ); + +#endif // DWMAC4_SNP_DXE_H__ diff --git a/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.inf b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.inf new file mode 100755 index 0000000000..b62657502d --- /dev/null +++ b/Silicon/Sophgo/Drivers/Net/DwMac4SnpDxe/DwMac4SnpDxe.inf @@ -0,0 +1,52 @@ +## @file +# +# DW Mac4 Simple Networking Protocol Driver (SNP) DXE Driver +# +# Copyright (c) 2024, SOPHGO Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DwMac4SnpDxe + FILE_GUID = A4F0DA4E-4371-4308-ACDA-9507CBCCC76E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwMac4SnpDxeEntry + +[Sources.common] + DwMac4SnpDxe.c + DwMac4DxeUtil.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + Silicon/Sophgo/Sophgo.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DmaLib + IoLib + NetLib + TimerLib + UefiDriverEntryPoint + UefiLib + IniParserLib + +[Protocols] + gEfiDevicePathProtocolGuid ## PRODUCES + gEfiSimpleNetworkProtocolGuid ## PRODUCES + gSophgoPhyProtocolGuid ## CONSUMES + gEfiCpuArchProtocolGuid ## CONSUMES + +[FixedPcd] + gSophgoTokenSpaceGuid.PcdDwMac4DefaultMacAddress ## CONSUMES + +[Depex] + gSophgoPhyProtocolGuid diff --git a/Silicon/Sophgo/Sophgo.dec b/Silicon/Sophgo/Sophgo.dec index b2518dbf7b..fd32fcace6 100644 --- a/Silicon/Sophgo/Sophgo.dec +++ b/Silicon/Sophgo/Sophgo.dec @@ -43,6 +43,7 @@ gSophgoTokenSpaceGuid.PcdRtcI2cBusNum|0x0|UINT32|0x00001012 gSophgoTokenSpaceGuid.PcdPhyResetGpio|FALSE|BOOLEAN|0x00001013 gSophgoTokenSpaceGuid.PcdPhyResetGpioPin|0x0|UINT8|0x00001014 + gSophgoTokenSpaceGuid.PcdDwMac4DefaultMacAddress|0x0|UINT64|0x00001015 [PcdsDynamic] gSophgoTokenSpaceGuid.PcdFlashVariableOffset|0x0|UINT64|0x00001003