diff --git a/README.md b/README.md index 935e57e6..9f3e5c93 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Platinum devices are considered to have the best overall support, based on facto - Device Tree and peripherals compatible with mainline Linux. [**Required**] - Active interest from the vendor in supporting their hardware. - Hardware design choices: - - If an Ethernet port is present, Realtek PCIe NIC (for netboot) or RK GMAC. [**Required**] + - If an Ethernet port is present, Realtek PCIe NIC or integrated GMAC. [**Required**] - SPI NOR flash for dedicated firmware storage. [Preferred] Bronze devices may have limitations such as: @@ -91,7 +91,7 @@ Note that this list is subject to change at any time as devices gain better supp | DisplayPort output (USB-C) | 🟡 Partial | Mode fixed at 1080p 60 Hz, only works in one orientation of the Type-C port. Some displays may not work regardless. | | eDP output | 🟡 Partial | Disabled, requires manual configuration depending on the platform and panel. | | DSI output | 🟢 Working | Only enabled on Fydetab Duo. Requires manual configuration depending on the platform and panel. | -| GMAC Ethernet | 🔴 Not working | Only brought-up for OS usage | +| GMAC Ethernet | 🟢 Working | | | Realtek PCIe Ethernet | 🟢 Working | Some platforms don't have MAC addresses set, networking may not work in that case. | | Low-speed (GPIO/UART/I2C/SPI/PWM) | 🟢 Working | UART2 console available at 1500000 baud rate | | SPI NOR Flash | 🟢 Working | | @@ -275,7 +275,7 @@ This has been observed in cases where firmware was present on more than one devi * Make sure the power supply and cable are good. ### Networking does not work -* Only Realtek PCIe and USB controllers are supported. Native Gigabit provided by RK3588 isn't. +* Only integrated Gigabit Ethernet (GMAC), Realtek PCIe and USB controllers are supported. * Some boards with Realtek NICs do not have a MAC address set at factory and will show-up as being all zeros in UEFI, possibly preventing the adapter from obtaining an IP address. diff --git a/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc b/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc index 1311eb4c..4fe437e1 100644 --- a/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc +++ b/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc @@ -27,6 +27,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # No status LED on this platform. DEFINE RK_STATUS_LED_ENABLE = FALSE diff --git a/edk2-rockchip/Platform/FriendlyElec/NanoPC-CM3588-NAS/NanoPC-CM3588-NAS.dsc b/edk2-rockchip/Platform/FriendlyElec/NanoPC-CM3588-NAS/NanoPC-CM3588-NAS.dsc index c4098b1a..f2789b49 100644 --- a/edk2-rockchip/Platform/FriendlyElec/NanoPC-CM3588-NAS/NanoPC-CM3588-NAS.dsc +++ b/edk2-rockchip/Platform/FriendlyElec/NanoPC-CM3588-NAS/NanoPC-CM3588-NAS.dsc @@ -28,6 +28,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc b/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc index 06ed05d8..fb4e9d3b 100644 --- a/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc +++ b/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc @@ -28,6 +28,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc b/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc index 7875625f..6cd9b7de 100644 --- a/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc +++ b/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc @@ -27,6 +27,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc b/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc index 5d570f0a..36a17bf6 100644 --- a/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc +++ b/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc @@ -27,6 +27,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc b/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc index 30cbebbc..a43bf96b 100644 --- a/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc +++ b/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc @@ -27,6 +27,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # No status LED on this platform. DEFINE RK_STATUS_LED_ENABLE = FALSE diff --git a/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc b/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc index 044486fc..946fb3db 100644 --- a/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc +++ b/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc @@ -27,6 +27,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc b/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc index dec56871..6c278b23 100644 --- a/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc +++ b/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc @@ -28,6 +28,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc b/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc index ad3f75f1..2a095d55 100644 --- a/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc +++ b/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc @@ -29,6 +29,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc b/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc index fa7f4081..b13e70d1 100644 --- a/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc +++ b/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc @@ -28,6 +28,9 @@ FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + # GMAC is not exposed + DEFINE RK3588_GMAC_ENABLE = FALSE + # # HYM8563 RTC support # I2C location configured by PCDs below. diff --git a/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c b/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c index 280b4435..45d27872 100644 --- a/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c +++ b/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c @@ -3,42 +3,73 @@ * RK3588 GMAC initializer * * Copyright (c) 2021-2022, Jared McNeill - * Copyright (c) 2023, Mario Bălănică + * Copyright (c) 2023-2025, Mario Bălănică * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ +#include #include +#include #include -#include -#include +#include #include #include -#include +#include +#include +#include + +#include "EthernetPhy.h" + +#define GRF_BIT(nr) (1 << (nr) | 1 << (nr + 16)) +#define GRF_CLR_BIT(nr) (1 << (nr + 16)) +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +/* PHP_GRF registers */ +#define RK3588_PHP_GRF_BASE 0xFD5B0000 + +#define RK3588_PHP_GRF_GMAC_CON0 (RK3588_PHP_GRF_BASE + 0x0008) + +#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \ + (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6)) +#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \ + (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6)) + +#define RK3588_PHP_GRF_CLK_CON1 (RK3588_PHP_GRF_BASE + 0x0070) + +#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id)) +#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id)) + +#define RK3588_GMAC_CLK_SELECT_CRU(id) GRF_BIT(5 * (id) + 4) +#define RK3588_GMAC_CLK_SELECT_IO(id) GRF_CLR_BIT(5 * (id) + 4) + +#define RK3588_GMAC_CLK_SEL_RMII_2_5(id) GRF_BIT(5 * (id) + 2) +#define RK3588_GMAC_CLK_SEL_RMII_25(id) GRF_CLR_BIT(5 * (id) + 2) -#include +#define RK3588_GMAC_CLK_SEL_RGMII_2_5(id) \ + (GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_SEL_RGMII_25(id) \ + (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_SEL_RGMII_125(id) \ + (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3)) -#define CRU_SOFTRST_CON32 (CRU_BASE + 0x0A80) +/* SYS_GRF registers */ +#define RK3588_SYS_GRF_BASE 0xFD58C000 -#define PHP_GRF_BASE 0xFD5B0000 -#define PHP_GRF_CLK_CON1 (PHP_GRF_BASE + 0x0070) -#define PHP_GRF_GMAC_CON0 (PHP_GRF_BASE + 0x0008) +#define RK3588_SYS_GRF_SOC_CON7 (RK3588_SYS_GRF_BASE + 0x031C) -#define SYS_GRF_BASE 0xFD58C000 -#define SYS_GRF_SOC_CON7 (SYS_GRF_BASE + 0x031C) -#define SYS_GRF_SOC_CON8 (SYS_GRF_BASE + 0x0320) -#define SYS_GRF_SOC_CON9 (SYS_GRF_BASE + 0x0324) -#define CLK_RX_DL_CFG_SHIFT 8 -#define CLK_TX_DL_CFG_SHIFT 0 +#define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3) +#define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3) +#define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2) +#define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2) -#define TX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0TxDelay) -#define RX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0RxDelay) -#define TX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1TxDelay) -#define RX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1RxDelay) +#define RK3588_SYS_GRF_SOC_CON8 (RK3588_SYS_GRF_BASE + 0x0320) +#define RK3588_SYS_GRF_SOC_CON9 (RK3588_SYS_GRF_BASE + 0x0324) -#define GMAC0_BASE 0xfe1b0000 -#define GMAC1_BASE 0xfe1c0000 +#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) +#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) /* GMAC registers */ #define GMAC_MAC_MDIO_ADDRESS 0x0200 @@ -52,13 +83,104 @@ #define GMAC_MAC_MDIO_ADDRESS_GB BIT0 #define GMAC_MAC_MDIO_DATA 0x0204 -#define GMAC_MAC_ADDRESS0_LOW 0x0304 -#define GMAC_MAC_ADDRESS0_HIGH 0x0300 - /* MII registers */ #define MII_PHYIDR1 0x02 #define MII_PHYIDR2 0x03 +#pragma pack (1) +typedef struct { + VENDOR_DEVICE_PATH VendorDP; + UINT8 ControllerId; + MAC_ADDR_DEVICE_PATH MacAddrDP; + EFI_DEVICE_PATH_PROTOCOL End; +} GMAC_DEVICE_PATH; +#pragma pack () + +typedef struct { + UINT32 Signature; + UINT8 Id; + EFI_PHYSICAL_ADDRESS BaseAddress; + + BOOLEAN Supported; + UINT8 TxDelay; + UINT8 RxDelay; + + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL EqosPlatform; + GMAC_DEVICE_PATH DevicePath; +} GMAC_DEVICE; + +#define GMAC_DEVICE_SIGNATURE SIGNATURE_32 ('G', 'M', 'a', 'C') + +#define GMAC_DEVICE_FROM_EQOS_PLATFORM(a) \ + CR (a, GMAC_DEVICE, EqosPlatform, GMAC_DEVICE_SIGNATURE) + +#define GMAC_DEVICE_INIT(_Id, _BaseAddress) \ + { \ + .Signature = GMAC_DEVICE_SIGNATURE, \ + .Id = _Id, \ + .BaseAddress = _BaseAddress, \ + .Supported = FixedPcdGetBool(PcdGmac##_Id##Supported), \ + .TxDelay = FixedPcdGet8(PcdGmac##_Id##TxDelay), \ + .RxDelay = FixedPcdGet8(PcdGmac##_Id##RxDelay) \ + } + +STATIC GMAC_DEVICE_PATH mGmacDevicePathTemplate = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(OFFSET_OF (GMAC_DEVICE_PATH, MacAddrDP)), + (UINT8)((OFFSET_OF (GMAC_DEVICE_PATH, MacAddrDP)) >> 8) + } + }, + EFI_CALLER_ID_GUID + }, + 0, + { + { + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + { + (UINT8)(sizeof (MAC_ADDR_DEVICE_PATH)), + (UINT8)((sizeof (MAC_ADDR_DEVICE_PATH)) >> 8) + } + }, + { + { 0 } + }, + NET_IFTYPE_ETHERNET + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +STATIC GMAC_DEVICE mGmacDevices[] = { + GMAC_DEVICE_INIT (0, 0xfe1b0000), + GMAC_DEVICE_INIT (1, 0xfe1c0000), +}; + +// +// XXX: It may be tempting to move all this PHY code to the MAC driver, +// however it is too platform specific and would make the driver less +// generic, as it does not currently need to touch any MII registers in +// order to work -- assuming the PHY has been previously initialized or +// is already usable in its default state. +// +// The proper way to fix this would be to have an MDIO bus/device protocol +// and separate PHY device drivers, including support for additional platform +// data. +// +// It is also important to leave the PHY configured for ACPI OSes that don't +// support initializing it (ESXi, Windows), regardless of whether UEFI uses +// the network interface (see how the MAC address is programmed in this case). +// STATIC ETHERNET_PHY_INIT mPhyInitList[] = { RealtekPhyInit, MotorcommPhyInit @@ -171,170 +293,245 @@ PhyInit ( STATIC VOID -EFIAPI -InitGmac0 ( - VOID +GmacSetToRgmii ( + IN UINT32 Id, + IN UINT8 TxDelay, + IN UINT8 RxDelay ) { - /* Assert reset */ - MmioWrite32 (CRU_SOFTRST_CON32, 0x04000400); // aresetn_gmac0 = 1 - - /* Configure pins */ - GmacIomux (0); - - /* Setup clocks */ - MmioWrite32 (PHP_GRF_CLK_CON1, 0x001d0000); // io_clksel_gmac0 = io - // mii_tx_clk_sel_gamc0 = 125 MHz - // rmii_mode_gmac0 = RGMII mode - - MmioWrite32 (PHP_GRF_GMAC_CON0, 0x00380008); // gmac0_phy_intf_sel = RGMII - - /* Setup DLLs */ - if (TX_DELAY_GMAC0) { - MmioWrite32 (SYS_GRF_SOC_CON7, 0x00040004); // gmac0_txclk_dly_ena = 1 - MmioWrite32 ( - SYS_GRF_SOC_CON8, - 0x007F0000U | - (TX_DELAY_GMAC0 << CLK_TX_DL_CFG_SHIFT) - ); - } + UINT32 ConDlyReg; + + ConDlyReg = (Id == 1) ? RK3588_SYS_GRF_SOC_CON9 + : RK3588_SYS_GRF_SOC_CON8; + + MmioWrite32 (RK3588_PHP_GRF_GMAC_CON0, RK3588_GMAC_PHY_INTF_SEL_RGMII (Id)); - if (RX_DELAY_GMAC0) { - MmioWrite32 (SYS_GRF_SOC_CON7, 0x00080008); // gmac0_rxclk_dly_ena = 1 - MmioWrite32 ( - SYS_GRF_SOC_CON8, - 0x7F000000U | - (RX_DELAY_GMAC0 << CLK_RX_DL_CFG_SHIFT) - ); + MmioWrite32 (RK3588_PHP_GRF_CLK_CON1, RK3588_GMAC_CLK_RGMII_MODE (Id)); + + if (TxDelay) { + MmioWrite32 (RK3588_SYS_GRF_SOC_CON7, RK3588_GMAC_TXCLK_DLY_ENABLE (Id)); + MmioWrite32 (ConDlyReg, RK3588_GMAC_CLK_TX_DL_CFG (TxDelay)); + } else { + MmioWrite32 (RK3588_SYS_GRF_SOC_CON7, RK3588_GMAC_TXCLK_DLY_DISABLE (Id)); } - /* Reset PHY */ - GmacIoPhyReset (0, TRUE); - MicroSecondDelay (20000); - GmacIoPhyReset (0, FALSE); - MicroSecondDelay (200000); + if (RxDelay) { + MmioWrite32 (RK3588_SYS_GRF_SOC_CON7, RK3588_GMAC_RXCLK_DLY_ENABLE (Id)); + MmioWrite32 (ConDlyReg, RK3588_GMAC_CLK_RX_DL_CFG (RxDelay)); + } else { + MmioWrite32 (RK3588_SYS_GRF_SOC_CON7, RK3588_GMAC_RXCLK_DLY_DISABLE (Id)); + } +} - /* Deassert reset */ - MmioWrite32 (CRU_SOFTRST_CON32, 0x04000000); // aresetn_gmac0 = 0 +STATIC +VOID +GmacSetToRmii ( + IN UINT32 Id + ) +{ + MmioWrite32 (RK3588_PHP_GRF_GMAC_CON0, RK3588_GMAC_PHY_INTF_SEL_RMII (Id)); - PhyInit (GMAC0_BASE); + MmioWrite32 (RK3588_PHP_GRF_CLK_CON1, RK3588_GMAC_CLK_RMII_MODE (Id)); } STATIC VOID +GmacSetClockSelectFromIo ( + IN UINT32 Id, + IN BOOLEAN Enable + ) +{ + UINT32 Value; + + Value = Enable ? RK3588_GMAC_CLK_SELECT_IO (Id) + : RK3588_GMAC_CLK_SELECT_CRU (Id); + + MmioWrite32 (RK3588_PHP_GRF_CLK_CON1, Value); +} + +STATIC +EFI_STATUS EFIAPI -InitGmac1 ( - VOID +GmacSetTxClockSpeed ( + IN UINT32 Id, + IN BOOLEAN RgmiiMode, + IN UINT32 Speed ) { - /* Assert reset */ - MmioWrite32 (CRU_SOFTRST_CON32, 0x08000800); // aresetn_gmac1 = 1 - - /* Configure pins */ - GmacIomux (1); - - /* Setup clocks */ - MmioWrite32 (PHP_GRF_CLK_CON1, 0x03a00000); // io_clksel_gmac1 = io - // mii_tx_clk_sel_gamc1 = 125 MHz - // rmii_mode_gmac1 = RGMII mode - - MmioWrite32 (PHP_GRF_GMAC_CON0, 0x0e000200); // gmac1_phy_intf_sel = RGMII - - /* Setup DLLs */ - if (TX_DELAY_GMAC1) { - MmioWrite32 (SYS_GRF_SOC_CON7, 0x00100010); // gmac1_txclk_dly_ena = 1 - MmioWrite32 ( - SYS_GRF_SOC_CON9, - 0x007F0000U | - (TX_DELAY_GMAC1 << CLK_TX_DL_CFG_SHIFT) - ); - } + UINT32 Value; + + switch (Speed) { + case 10: + if (RgmiiMode) { + Value = RK3588_GMAC_CLK_SEL_RGMII_2_5 (Id); + } else { + Value = RK3588_GMAC_CLK_SEL_RMII_2_5 (Id); + } + + break; + + case 100: + if (RgmiiMode) { + Value = RK3588_GMAC_CLK_SEL_RGMII_25 (Id); + } else { + Value = RK3588_GMAC_CLK_SEL_RMII_25 (Id); + } - if (RX_DELAY_GMAC1) { - MmioWrite32 (SYS_GRF_SOC_CON7, 0x00200020); // gmac1_rxclk_dly_ena = 1 - MmioWrite32 ( - SYS_GRF_SOC_CON9, - 0x7F000000U | - (RX_DELAY_GMAC1 << CLK_RX_DL_CFG_SHIFT) - ); + break; + + case 1000: + if (RgmiiMode) { + Value = RK3588_GMAC_CLK_SEL_RGMII_125 (Id); + } else { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + break; + + default: + ASSERT (FALSE); + return EFI_UNSUPPORTED; } - /* Reset PHY */ - GmacIoPhyReset (1, TRUE); - MicroSecondDelay (20000); - GmacIoPhyReset (1, FALSE); - MicroSecondDelay (200000); + MmioWrite32 (RK3588_PHP_GRF_CLK_CON1, Value); - /* Deassert reset */ - MmioWrite32 (CRU_SOFTRST_CON32, 0x08000000); // aresetn_gmac1 = 0 + return EFI_SUCCESS; +} - PhyInit (GMAC1_BASE); +STATIC +VOID +EFIAPI +GmacPlatformGetConfig ( + IN DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *This, + IN DWC_EQOS_CONFIG *Config + ) +{ + Config->CsrClockRate = 125000000; + Config->AxiBusWidth = EqosAxiBusWidth64; + Config->AxiFixedBurst = FALSE; + Config->AxiMixedBurst = TRUE; + Config->AxiWrOsrLmt = 4; + Config->AxiRdOsrLmt = 8; + Config->AxiBlen = EqosAxiBlen16 | EqosAxiBlen8 | EqosAxiBlen4; } +STATIC EFI_STATUS EFIAPI -GmacPlatformDxeInitialize ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable +GmacPlatformSetInterfaceSpeed ( + IN DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *This, + IN UINT32 Speed ) { - UINT8 OtpData[32]; - UINT8 Hash[SHA256_DIGEST_SIZE]; - UINT32 MacLo, MacHi; + GMAC_DEVICE *Gmac = GMAC_DEVICE_FROM_EQOS_PLATFORM (This); - if ( !FixedPcdGetBool (PcdGmac0Supported) - && !FixedPcdGetBool (PcdGmac1Supported)) - { - return EFI_SUCCESS; - } + return GmacSetTxClockSpeed (Gmac->Id, TRUE, Speed); +} + +STATIC +VOID +GmacGetOtpMacAddress ( + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT8 OtpData[32]; + UINT8 Hash[SHA256_DIGEST_SIZE]; - /* Generate MAC addresses from the first 32 bytes in the OTP and write it to GMAC0 and GMAC1 */ - /* Use sequential MAC addresses. Last byte is even for GMAC0, and odd for GMAC1. */ + /* Generate MAC addresses from the first 32 bytes in the OTP */ OtpRead (0x00, sizeof (OtpData), OtpData); Sha256HashAll (OtpData, sizeof (OtpData), Hash); + + /* Clear multicast bit, set locally administered bit. */ Hash[0] &= 0xFE; Hash[0] |= 0x02; - if (FixedPcdGetBool (PcdGmac0Supported)) { - InitGmac0 (); + /* ... and for compatibility with old drivers (see https://github.com/jaredmcneill/quartz64_uefi/pull/68) */ + Hash[3] &= 0xFE; + Hash[3] |= 0x02; - Hash[5] &= ~1; - DEBUG (( - DEBUG_INFO, - "%a: GMAC0 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", - __func__, - Hash[0], - Hash[1], - Hash[2], - Hash[3], - Hash[4], - Hash[5] - )); - MacLo = Hash[3] | (Hash[2] << 8) | (Hash[1] << 16) | (Hash[0] << 24); - MacHi = Hash[5] | (Hash[4] << 8); - MmioWrite32 (GMAC0_BASE + GMAC_MAC_ADDRESS0_LOW, MacLo); - MmioWrite32 (GMAC0_BASE + GMAC_MAC_ADDRESS0_HIGH, MacHi); - } + ZeroMem (MacAddress, sizeof (EFI_MAC_ADDRESS)); + CopyMem (MacAddress, Hash, NET_ETHER_ADDR_LEN); +} + +EFI_STATUS +EFIAPI +GmacPlatformDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_MAC_ADDRESS MacAddress; + UINT32 Index; + GMAC_DEVICE *Gmac; + EFI_HANDLE Handle; + + GmacGetOtpMacAddress (&MacAddress); + + for (Index = 0; Index < ARRAY_SIZE (mGmacDevices); Index++) { + Gmac = &mGmacDevices[Index]; + if (!Gmac->Supported) { + continue; + } + + /* Configure pins */ + GmacIomux (Gmac->Id); - if (FixedPcdGetBool (PcdGmac1Supported)) { - InitGmac1 (); + /* Setup clocks and delays */ + GmacSetClockSelectFromIo (Gmac->Id, FALSE); + GmacSetToRgmii (Gmac->Id, Gmac->TxDelay, Gmac->RxDelay); + + /* Reset PHY */ + GmacIoPhyReset (Gmac->Id, TRUE); + MicroSecondDelay (20000); + GmacIoPhyReset (Gmac->Id, FALSE); + MicroSecondDelay (200000); + + PhyInit (Gmac->BaseAddress); + + Gmac->EqosPlatform.BaseAddress = Gmac->BaseAddress; + Gmac->EqosPlatform.GetConfig = GmacPlatformGetConfig; + Gmac->EqosPlatform.SetInterfaceSpeed = GmacPlatformSetInterfaceSpeed; + + CopyMem (&Gmac->EqosPlatform.MacAddress, &MacAddress, NET_ETHER_ADDR_LEN); + Gmac->EqosPlatform.MacAddress.Addr[5] += Gmac->Id; - Hash[5] |= 1; DEBUG (( DEBUG_INFO, - "%a: GMAC1 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", + "%a: GMAC%u MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, - Hash[0], - Hash[1], - Hash[2], - Hash[3], - Hash[4], - Hash[5] + Gmac->Id, + Gmac->EqosPlatform.MacAddress.Addr[0], + Gmac->EqosPlatform.MacAddress.Addr[1], + Gmac->EqosPlatform.MacAddress.Addr[2], + Gmac->EqosPlatform.MacAddress.Addr[3], + Gmac->EqosPlatform.MacAddress.Addr[4], + Gmac->EqosPlatform.MacAddress.Addr[5] )); - MacLo = Hash[3] | (Hash[2] << 8) | (Hash[1] << 16) | (Hash[0] << 24); - MacHi = Hash[5] | (Hash[4] << 8); - MmioWrite32 (GMAC1_BASE + GMAC_MAC_ADDRESS0_LOW, MacLo); - MmioWrite32 (GMAC1_BASE + GMAC_MAC_ADDRESS0_HIGH, MacHi); + + CopyMem (&Gmac->DevicePath, &mGmacDevicePathTemplate, sizeof (GMAC_DEVICE_PATH)); + CopyMem (&Gmac->DevicePath.MacAddrDP.MacAddress, &Gmac->EqosPlatform.MacAddress, NET_ETHER_ADDR_LEN); + Gmac->DevicePath.ControllerId = Gmac->Id; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gDwcEqosPlatformDeviceProtocolGuid, + &Gmac->EqosPlatform, + &gEfiDevicePathProtocolGuid, + &Gmac->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to install GMAC%u EQOS device. Status=%r", + __func__, + Gmac->Id, + Status + )); + } } return EFI_SUCCESS; diff --git a/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf b/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf index 808e3e15..fd64a3c9 100644 --- a/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf +++ b/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf @@ -2,7 +2,7 @@ # # RK3588 GMAC initializer # -# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023-2025, Mario Bălănică # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -22,22 +22,29 @@ MotorcommPhy.c [Packages] + CryptoPkg/CryptoPkg.dec MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec - CryptoPkg/CryptoPkg.dec + NetworkPkg/NetworkPkg.dec Silicon/Rockchip/RockchipPkg.dec Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Synopsys/DesignWare/DesignWarePkg.dec [LibraryClasses] - UefiDriverEntryPoint + BaseCryptLib DebugLib + DevicePathLib IoLib - TimerLib - BaseCryptLib + NetLib OtpLib RockchipPlatformLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint [Protocols] + gDwcEqosPlatformDeviceProtocolGuid + gEfiDevicePathProtocolGuid [Pcd] gRK3588TokenSpaceGuid.PcdGmac0Supported diff --git a/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf b/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf index 5f37a0af..55cdb6a9 100644 --- a/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf +++ b/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf @@ -127,9 +127,12 @@ READ_LOCK_STATUS = TRUE INF Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf # - # GMAC Init Driver + # Rockchip GMAC Support # +!if $(RK3588_GMAC_ENABLE) == TRUE INF Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf + INF Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.inf +!endif # # ACPI Support diff --git a/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc b/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc index 380672fb..9bcf17bd 100644 --- a/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc +++ b/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc @@ -99,6 +99,9 @@ !ifndef RK3588_PCIE_ENABLE DEFINE RK3588_PCIE_ENABLE = TRUE !endif +!ifndef RK3588_GMAC_ENABLE + DEFINE RK3588_GMAC_ENABLE = TRUE +!endif # # Base platform description @@ -378,9 +381,17 @@ Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf # - # GMAC Init Driver + # Rockchip GMAC Support # +!if $(RK3588_GMAC_ENABLE) == TRUE Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf + Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.inf { + + # 32-bit DMA limit + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x00000000 + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xffffffff + } +!endif # # ACPI Support diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec b/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec index 9354ebfa..fd1b13b4 100644 --- a/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec @@ -23,3 +23,4 @@ [Protocols.common] gPlatformDwMmcProtocolGuid = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85, 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }} + gDwcEqosPlatformDeviceProtocolGuid = { 0x60975136, 0x4601, 0x41b3, { 0xbf, 0x9a, 0x90, 0xe9, 0x59, 0xfc, 0xb0, 0x02 } } diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/AdapterInfo.c b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/AdapterInfo.c new file mode 100644 index 00000000..1879c8ea --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/AdapterInfo.c @@ -0,0 +1,174 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Eqos.h" + +/** + Returns the current state information for the adapter. + + This function returns information of type InformationType from the adapter. + If an adapter does not support the requested informational type, then + EFI_UNSUPPORTED is returned. If an adapter does not contain Information for + the requested InformationType, it fills InformationBlockSize with 0 and + returns EFI_NOT_FOUND. + + @param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance. + @param[in] InformationType A pointer to an EFI_GUID that defines the contents of InformationBlock. + @param[out] InforamtionBlock The service returns a pointer to the buffer with the InformationBlock + structure which contains details about the data specific to InformationType. + @param[out] InforamtionBlockSize The driver returns the size of the InformationBlock in bytes. + + @retval EFI_SUCCESS The InformationType information was retrieved. + @retval EFI_UNSUPPORTED The InformationType is not known. + @retval EFI_NOT_FOUND Information is not available for the requested information type. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. + @retval EFI_INVALID_PARAMETER InformationBlockSize is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosAipGetInformation ( + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, + IN EFI_GUID *InformationType, + OUT VOID **InformationBlock, + OUT UINTN *InformationBlockSize + ) +{ + EFI_ADAPTER_INFO_MEDIA_STATE *AdapterInfo; + EQOS_PRIVATE_DATA *Eqos; + + if ((This == NULL) || (InformationBlock == NULL) || + (InformationBlockSize == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + if (!CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) { + return EFI_UNSUPPORTED; + } + + AdapterInfo = AllocateZeroPool (sizeof (EFI_ADAPTER_INFO_MEDIA_STATE)); + if (AdapterInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *InformationBlock = AdapterInfo; + *InformationBlockSize = sizeof (EFI_ADAPTER_INFO_MEDIA_STATE); + + Eqos = EQOS_PRIVATE_DATA_FROM_AIP_THIS (This); + AdapterInfo->MediaState = EqosUpdateLink (Eqos); + + return EFI_SUCCESS; +} + +/** + Sets state information for an adapter. + + This function sends information of type InformationType for an adapter. + If an adapter does not support the requested information type, then EFI_UNSUPPORTED + is returned. + + @param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance. + @param[in] InformationType A pointer to an EFI_GUID that defines the contents of InformationBlock. + @param[in] InforamtionBlock A pointer to the InformationBlock structure which contains details + about the data specific to InformationType. + @param[in] InforamtionBlockSize The size of the InformationBlock in bytes. + + @retval EFI_SUCCESS The information was received and interpreted successfully. + @retval EFI_UNSUPPORTED The InformationType is not known. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. + @retval EFI_WRITE_PROTECTED The InformationType cannot be modified using EFI_ADAPTER_INFO_SET_INFO(). + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosAipSetInformation ( + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN VOID *InformationBlock, + IN UINTN InformationBlockSize + ) +{ + if ((This == NULL) || (InformationBlock == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) { + return EFI_WRITE_PROTECTED; + } + + return EFI_UNSUPPORTED; +} + +/** + Get a list of supported information types for this instance of the protocol. + + This function returns a list of InformationType GUIDs that are supported on an + adapter with this instance of EFI_ADAPTER_INFORMATION_PROTOCOL. The list is returned + in InfoTypesBuffer, and the number of GUID pointers in InfoTypesBuffer is returned in + InfoTypesBufferCount. + + @param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance. + @param[out] InfoTypesBuffer A pointer to the array of InformationType GUIDs that are supported + by This. + @param[out] InfoTypesBufferCount A pointer to the number of GUIDs present in InfoTypesBuffer. + + @retval EFI_SUCCESS The list of information type GUIDs that are supported on this adapter was + returned in InfoTypesBuffer. The number of information type GUIDs was + returned in InfoTypesBufferCount. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_INVALID_PARAMETER InfoTypesBuffer is NULL. + @retval EFI_INVALID_PARAMETER InfoTypesBufferCount is NULL. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosAipGetSupportedTypes ( + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, + OUT EFI_GUID **InfoTypesBuffer, + OUT UINTN *InfoTypesBufferCount + ) +{ + EFI_GUID *Guid; + + if ((This == NULL) || (InfoTypesBuffer == NULL) || + (InfoTypesBufferCount == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + Guid = AllocatePool (sizeof *Guid); + if (Guid == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyGuid (Guid, &gEfiAdapterInfoMediaStateGuid); + + *InfoTypesBuffer = Guid; + *InfoTypesBufferCount = 1; + + return EFI_SUCCESS; +} + +/// +/// EFI Adapter Information Protocol +/// +CONST EFI_ADAPTER_INFORMATION_PROTOCOL gEqosAipTemplate = { + EqosAipGetInformation, + EqosAipSetInformation, + EqosAipGetSupportedTypes, +}; diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/ComponentName.c b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/ComponentName.c new file mode 100644 index 00000000..80ac3575 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/ComponentName.c @@ -0,0 +1,199 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Eqos.h" + +STATIC EFI_UNICODE_STRING_TABLE mEqosDriverNameTable[] = { + { "eng;en", L"Synopsys DesignWare Ethernet Quality-of-Service (EQoS) Driver" }, + { NULL, NULL } +}; + +STATIC EFI_UNICODE_STRING_TABLE mEqosDeviceNameTable[] = { + { "eng;en", L"Synopsys DesignWare Ethernet Quality-of-Service (EQoS)" }, + { NULL, NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mEqosDriverNameTable, + DriverName, + (BOOLEAN)(This == &gEqosComponentName2) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + Status = EfiTestManagedDevice ( + ControllerHandle, + gEqosDriverBinding.DriverBindingHandle, + &gDwcEqosPlatformDeviceProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mEqosDeviceNameTable, + ControllerName, + (BOOLEAN)(This == &gEqosComponentName2) + ); +} + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME_PROTOCOL gEqosComponentName = { + (EFI_COMPONENT_NAME_GET_DRIVER_NAME)EqosComponentNameGetDriverName, + (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)EqosComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED +EFI_COMPONENT_NAME2_PROTOCOL gEqosComponentName2 = { + EqosComponentNameGetDriverName, + EqosComponentNameGetControllerName, + "en" +}; diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.c b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.c new file mode 100644 index 00000000..726b8798 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.c @@ -0,0 +1,507 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + Copyright (c) 2022 Jared McNeill + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Eqos.h" + +STATIC EFI_EVENT mProtocolNotifyEvent; +STATIC VOID *mProtocolNotifyEventRegistration; + +/** + Tests to see if this driver supports a given controller. + + @param This[in] A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param ControllerHandle[in] The handle of the controller to test. + @param RemainingDevicePath[in] The remaining device path. + (Ignored - this is not a bus driver.) + + @retval EFI_SUCCESS The driver supports this controller. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle is + already being managed by the driver specified + by This. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle is + not supported by the driver specified by This. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *Platform; + EFI_STATUS Status; + + // + // Open the platform device protocol instance. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gDwcEqosPlatformDeviceProtocolGuid, + (VOID **)&Platform, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clean up. + // + gBS->CloseProtocol ( + ControllerHandle, + &gDwcEqosPlatformDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return EFI_SUCCESS; +} + +/** + ExitBootServices notification to stop the network controller. + + @param Event Pointer to this event. + @param Context Event handler private data. + +**/ +STATIC +VOID +EFIAPI +EqosNotifyExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EQOS_PRIVATE_DATA *Eqos = (EQOS_PRIVATE_DATA *)Context; + + EqosDisableTxRx (Eqos); +} + +/** + Starts a device controller or a bus controller. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the device to start. This + handle must support a protocol interface that + supplies an I/O abstraction to the driver. + @param[in] RemainingDevicePath The remaining portion of the device path. + (Ignored - this is not a bus driver.) + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a + device error. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + + Eqos = AllocateZeroPool (sizeof (EQOS_PRIVATE_DATA)); + if (Eqos == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Failed to allocate device context!\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gDwcEqosPlatformDeviceProtocolGuid, + (VOID **)&Eqos->Platform, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to open protocol! Status=%r\n", __func__, Status)); + goto Free; + } + + Status = EqosDmaAllocate (Eqos); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to allocate DMA buffers! Status=%r\n", __func__, Status)); + goto Free; + } + + Eqos->Signature = EQOS_DRIVER_SIGNATURE; + Eqos->Base = Eqos->Platform->BaseAddress; + + EfiInitializeLock (&Eqos->Lock, TPL_CALLBACK); + + CopyMem (&Eqos->Snp, &gEqosSnpTemplate, sizeof Eqos->Snp); + CopyMem (&Eqos->Aip, &gEqosAipTemplate, sizeof Eqos->Aip); + + Eqos->Snp.Mode = &Eqos->SnpMode; + Eqos->SnpMode.State = EfiSimpleNetworkStopped; + Eqos->SnpMode.HwAddressSize = NET_ETHER_ADDR_LEN; + Eqos->SnpMode.MediaHeaderSize = sizeof (ETHER_HEAD); + Eqos->SnpMode.MaxPacketSize = MAX_ETHERNET_PACKET_SIZE; + Eqos->SnpMode.NvRamSize = 0; + Eqos->SnpMode.NvRamAccessSize = 0; + Eqos->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; + Eqos->SnpMode.ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + Eqos->SnpMode.MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; + Eqos->SnpMode.MCastFilterCount = 0; + Eqos->SnpMode.IfType = NET_IFTYPE_ETHERNET; + Eqos->SnpMode.MacAddressChangeable = TRUE; + Eqos->SnpMode.MultipleTxSupported = FALSE; + Eqos->SnpMode.MediaPresentSupported = TRUE; + Eqos->SnpMode.MediaPresent = FALSE; + + SetMem (&Eqos->SnpMode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + CopyMem ( + &Eqos->SnpMode.PermanentAddress, + &Eqos->Platform->MacAddress, + sizeof (EFI_MAC_ADDRESS) + ); + CopyMem ( + &Eqos->SnpMode.CurrentAddress, + &Eqos->Platform->MacAddress, + sizeof (EFI_MAC_ADDRESS) + ); + + Status = EqosIdentify (Eqos); + if (EFI_ERROR (Status)) { + goto Free; + } + + EqosInitializeConfig (Eqos); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + EqosNotifyExitBootServices, + Eqos, + &gEfiEventExitBootServicesGuid, + &Eqos->ExitBootServicesEvent + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_WARN, + "%a: Failed to register for ExitBootServices event. Status=%r\n", + __func__, + Status + )); + goto Free; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, + &Eqos->Snp, + &gEfiAdapterInformationProtocolGuid, + &Eqos->Aip, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to install protocol interfaces. Status=%r\n", + __func__, + Status + )); + gBS->CloseProtocol ( + ControllerHandle, + &gDwcEqosPlatformDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + goto Free; + } + + Eqos->ControllerHandle = ControllerHandle; + return EFI_SUCCESS; + +Free: + if (Eqos->ExitBootServicesEvent != NULL) { + gBS->CloseEvent (Eqos->ExitBootServicesEvent); + } + + EqosDmaFree (Eqos); + FreePool (Eqos); + + return Status; +} + +/** + Stops a device controller or a bus controller. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle + must support a bus specific I/O protocol for the + driver to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in + ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be + NULL if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device + error. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + + Status = gBS->HandleProtocol ( + ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, + (VOID **)&Snp + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (Snp); + + ASSERT (Eqos->ControllerHandle == ControllerHandle); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, + &Eqos->Snp, + &gEfiAdapterInformationProtocolGuid, + &Eqos->Aip, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseEvent (Eqos->ExitBootServicesEvent); + + Status = EqosStop (Eqos); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gDwcEqosPlatformDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + EqosDmaFree (Eqos); + FreePool (Eqos); + + return EFI_SUCCESS; +} + +EFI_DRIVER_BINDING_PROTOCOL gEqosDriverBinding = { + EqosDriverBindingSupported, + EqosDriverBindingStart, + EqosDriverBindingStop, + 0x0a, + NULL, + NULL +}; + +/** + Platform device protocol notification to program the MAC address + into each existing controller, regardless of whether UEFI uses the + interface (and performs the driver binding), so that the OS will + still be able to read it. + + @param Event Pointer to this event. + @param Context Event handler private data. + +**/ +STATIC +VOID +EFIAPI +OnProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *Platform; + + while (TRUE) { + Status = gBS->LocateHandleBuffer ( + ByRegisterNotify, + NULL, + mProtocolNotifyEventRegistration, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + break; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gDwcEqosPlatformDeviceProtocolGuid, + (VOID **)&Platform + ); + ASSERT_EFI_ERROR (Status); + + EqosSetMacAddress (Platform->BaseAddress, &Platform->MacAddress); + } + + FreePool (HandleBuffer); + } +} + +/** + The entry point of EQOS UEFI Driver. + + @param ImageHandle The firmware allocated handle for the UEFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. + +**/ +EFI_STATUS +EFIAPI +EqosEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gEqosDriverBinding, + ImageHandle, + &gEqosComponentName, + &gEqosComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + mProtocolNotifyEvent = EfiCreateProtocolNotifyEvent ( + &gDwcEqosPlatformDeviceProtocolGuid, + TPL_CALLBACK, + OnProtocolNotify, + NULL, + &mProtocolNotifyEventRegistration + ); + ASSERT (mProtocolNotifyEvent != NULL); + + return EFI_SUCCESS; +} + +/** + Unload function of EQOS UEFI Driver. + + @param ImageHandle The allocated handle for the EFI image + + @retval EFI_SUCCESS The driver was unloaded successfully + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + +**/ +EFI_STATUS +EFIAPI +EqosUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + + // + // Retrieve all platform device handles in the handle database + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gDwcEqosPlatformDeviceProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Disconnect the driver from the handles in the handle database + // + for (Index = 0; Index < HandleCount && !EFI_ERROR (Status); Index++) { + Status = gBS->DisconnectController ( + HandleBuffer[Index], + gImageHandle, + NULL + ); + } + + // + // Free the handle array + // + gBS->FreePool (HandleBuffer); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_WARN, + "%a: Failed to disconnect all controllers. Status=%r\n", + __func__, + Status + )); + return Status; + } + + // + // Uninstall protocols installed by the driver in its entrypoint + // + Status = EfiLibUninstallDriverBindingComponentName2 ( + &gEqosDriverBinding, + &gEqosComponentName, + &gEqosComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + gBS->CloseEvent (mProtocolNotifyEvent); + + return EFI_SUCCESS; +} diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.inf b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.inf new file mode 100644 index 00000000..5bf22f01 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/DwcEqosSnpDxe.inf @@ -0,0 +1,56 @@ +## @file +# Synopsys DesignWare Ethernet Quality-of-Service (EQoS) UEFI SNP driver +# +# Copyright (c) 2025, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = DwcEqosSnpDxe + FILE_GUID = 904d9f41-c38a-4c05-833d-9a804ae60c59 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = EqosEntryPoint + UNLOAD_IMAGE = EqosUnload + +[Sources] + AdapterInfo.c + ComponentName.c + DwcEqosSnpDxe.c + EqosUtil.c + SimpleNetwork.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + Silicon/Synopsys/DesignWare/DesignWarePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DmaLib + IoLib + MemoryAllocationLib + NetLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gDwcEqosPlatformDeviceProtocolGuid ## TO_START + gEfiAdapterInformationProtocolGuid ## BY_START + gEfiSimpleNetworkProtocolGuid ## BY_START + +[Guids] + gEfiAdapterInfoMediaStateGuid + gEfiEventExitBootServicesGuid + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/Eqos.h b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/Eqos.h new file mode 100644 index 00000000..5bffffa5 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/Eqos.h @@ -0,0 +1,275 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef DWC_EQOS_H_ +#define DWC_EQOS_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "EqosHw.h" + +// +// XXX: Having more RX descriptors (e.g. 256) affects performance +// and seems to lead to more TCP segments getting dropped. +// +#define EQOS_TX_DESC_COUNT 32 +#define EQOS_RX_DESC_COUNT 2 + +#define EQOS_DESC_ALIGN sizeof (struct EQOS_DMA_DESCRIPTOR) + +#define EQOS_TX_DESC_RING_SIZE (EQOS_TX_DESC_COUNT * EQOS_DESC_ALIGN) +#define EQOS_RX_DESC_RING_SIZE (EQOS_RX_DESC_COUNT * EQOS_DESC_ALIGN) + +#define EQOS_DESC_OFF(n) ((n) * EQOS_DESC_ALIGN) +#define EQOS_TX_NEXT(n) (((n) + 1) % EQOS_TX_DESC_COUNT) +#define EQOS_RX_NEXT(n) (((n) + 1) % EQOS_RX_DESC_COUNT) + +#define MAX_ETHERNET_PACKET_SIZE 1500 + +#define MAX_ETHERNET_FRAME_SIZE (18 + MAX_ETHERNET_PACKET_SIZE + 4) // Header + Data + CRC + +// +// According to the TRM: +// The buffer size must be a multiple of 4, 8, or 16 depending +// on the data bus widths (32-bit, 64-bit, or 128-bit respectively). +// This is required even if the value of buffer address pointer is not +// aligned to data bus width. +// +#define EQOS_RX_BUFFER_SIZE ALIGN_VALUE (MAX_ETHERNET_FRAME_SIZE, EqosAxiBusWidth128) + +typedef struct { + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + EFI_LOCK Lock; + EFI_EVENT ExitBootServicesEvent; + + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + EFI_ADAPTER_INFORMATION_PROTOCOL Aip; + + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *Platform; + DWC_EQOS_CONFIG Config; + + VOID *TxDescs; + VOID *TxDescsMap; + EFI_PHYSICAL_ADDRESS TxDescsPhysAddr; + UINT8 *TxBuffers[EQOS_TX_DESC_COUNT]; + VOID *TxBuffersMap[EQOS_TX_DESC_COUNT]; + UINT32 TxQueued; + UINT32 TxNext; + UINT32 TxCurrent; + + VOID *RxDescs; + VOID *RxDescsMap; + EFI_PHYSICAL_ADDRESS RxDescsPhysAddr; + EFI_PHYSICAL_ADDRESS RxBuffersAddr; + VOID *RxBuffersMap[EQOS_RX_DESC_COUNT]; + UINT32 RxCurrent; + + UINT32 HwFeatures[4]; + + EFI_PHYSICAL_ADDRESS Base; +} EQOS_PRIVATE_DATA; + +extern EFI_COMPONENT_NAME_PROTOCOL gEqosComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gEqosComponentName2; +extern EFI_DRIVER_BINDING_PROTOCOL gEqosDriverBinding; + +extern CONST EFI_SIMPLE_NETWORK_PROTOCOL gEqosSnpTemplate; +extern CONST EFI_ADAPTER_INFORMATION_PROTOCOL gEqosAipTemplate; + +#define EQOS_DRIVER_SIGNATURE SIGNATURE_32 ('E', 'Q', 'o', 'S') +#define EQOS_PRIVATE_DATA_FROM_SNP_THIS(a) CR (a, EQOS_PRIVATE_DATA, Snp, EQOS_DRIVER_SIGNATURE) +#define EQOS_PRIVATE_DATA_FROM_AIP_THIS(a) CR (a, EQOS_PRIVATE_DATA, Aip, EQOS_DRIVER_SIGNATURE) + +#define EQOS_RX_BUFFER(p, idx) ((UINT8 *)(UINTN)(p)->RxBuffersAddr + EQOS_RX_BUFFER_SIZE * (idx)) +#define EQOS_DESC(buf, idx) ((EQOS_DMA_DESCRIPTOR *)((UINTN)(buf) + EQOS_DESC_OFF ((idx)))) + +EFI_STATUS +EqosIdentify ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosInitializeConfig ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosReset ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosInitialize ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosEnableTxRx ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosDisableTxRx ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosDmaInitDescriptorRings ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosStart ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosStop ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosDmaAllocate ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosDmaFree ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosDmaMapTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex, + IN UINTN NumberOfBytes + ); + +EFI_STATUS +EqosDmaMapRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ); + +VOID +EqosDmaUnmapTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ); + +VOID +EqosDmaUnmapRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ); + +EFI_STATUS +EqosDmaMapAllRxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosDmaUnmapAllTxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +VOID +EqosDmaUnmapAllRxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosCheckTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ); + +EFI_STATUS +EqosCheckRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex, + OUT UINTN *FrameLength + ); + +VOID +EqosGetDmaInterruptStatus ( + IN EQOS_PRIVATE_DATA *Eqos, + OUT UINT32 *InterruptStatus OPTIONAL + ); + +VOID +EqosGetPhyIfStatus ( + IN EQOS_PRIVATE_DATA *Eqos, + OUT BOOLEAN *LinkUp OPTIONAL, + OUT UINT32 *Speed OPTIONAL, + OUT BOOLEAN *FullDuplex OPTIONAL + ); + +VOID +EqosSetLinkConfig ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 Speed, + IN BOOLEAN FullDuplex + ); + +EFI_STATUS +EqosUpdateLink ( + IN EQOS_PRIVATE_DATA *Eqos + ); + +EFI_STATUS +EqosSetRxFilters ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 ReceiveFilterSetting, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ); + +VOID +EqosGetMacAddress ( + IN EFI_PHYSICAL_ADDRESS Base, + OUT EFI_MAC_ADDRESS *MacAddress + ); + +VOID +EqosSetMacAddress ( + IN EFI_PHYSICAL_ADDRESS Base, + IN EFI_MAC_ADDRESS *MacAddress + ); + +UINT32 +EqosEtherCrc32Le ( + IN UINT8 *Buffer, + IN UINTN Length + ); + +UINT32 +EqosBitReverse32 ( + IN UINT32 Value + ); + +#endif diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosHw.h b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosHw.h new file mode 100644 index 00000000..1f0c44ed --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosHw.h @@ -0,0 +1,330 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + Copyright (c) 2022 Jared McNeill + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef DWC_EQOS_HW_H_ +#define DWC_EQOS_HW_H_ + +#define LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) +#define SHIFTOUT(__x, __mask) (((__x) & (__mask)) / LOWEST_SET_BIT (__mask)) +#define SHIFTIN(__x, __mask) ((__x) * LOWEST_SET_BIT (__mask)) +#define BITS(hi, lo) ((~((~0) << ((hi) + 1))) & ((~0) << (lo))) + +#define GMAC_MAC_CONFIGURATION 0x0000 +#define GMAC_MAC_CONFIGURATION_CST (1U << 21) +#define GMAC_MAC_CONFIGURATION_ACS (1U << 20) +#define GMAC_MAC_CONFIGURATION_BE (1U << 18) +#define GMAC_MAC_CONFIGURATION_JD (1U << 17) +#define GMAC_MAC_CONFIGURATION_JE (1U << 16) +#define GMAC_MAC_CONFIGURATION_PS (1U << 15) +#define GMAC_MAC_CONFIGURATION_FES (1U << 14) +#define GMAC_MAC_CONFIGURATION_DM (1U << 13) +#define GMAC_MAC_CONFIGURATION_DCRS (1U << 9) +#define GMAC_MAC_CONFIGURATION_TE (1U << 1) +#define GMAC_MAC_CONFIGURATION_RE (1U << 0) +#define GMAC_MAC_EXT_CONFIGURATION 0x0004 +#define GMAC_MAC_PACKET_FILTER 0x0008 +#define GMAC_MAC_PACKET_FILTER_HPF (1U << 10) +#define GMAC_MAC_PACKET_FILTER_PCF_MASK (3U << 6) +#define GMAC_MAC_PACKET_FILTER_PCF_ALL (2U << 6) +#define GMAC_MAC_PACKET_FILTER_DBF (1U << 5) +#define GMAC_MAC_PACKET_FILTER_PM (1U << 4) +#define GMAC_MAC_PACKET_FILTER_HMC (1U << 2) +#define GMAC_MAC_PACKET_FILTER_HUC (1U << 1) +#define GMAC_MAC_PACKET_FILTER_PR (1U << 0) +#define GMAC_MAC_WATCHDOG_TIMEOUT 0x000C +#define GMAC_MAC_HASH_TABLE_REG_BASE 0x0010 +#define GMAC_MAC_HASH_TABLE_COUNT 2 +#define GMAC_MAC_VLAN_TAG 0x0050 +#define GMAC_MAC_Q0_TX_FLOW_CTRL 0x0070 +#define GMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT 16 +#define GMAC_MAC_Q0_TX_FLOW_CTRL_TFE (1U << 1) +#define GMAC_MAC_RX_FLOW_CTRL 0x0090 +#define GMAC_MAC_RX_FLOW_CTRL_RFE (1U << 0) +#define GMAC_RXQ_CTRL0 0x00A0 +#define GMAC_RXQ_CTRL0_EN_MASK 0x3 +#define GMAC_RXQ_CTRL0_EN_AVB 0x1 +#define GMAC_RXQ_CTRL0_EN_DCB 0x2 +#define GMAC_RXQ_CTRL1 0x00A4 +#define GMAC_RXQ_CTRL2 0x00A8 +#define GMAC_MAC_INTERRUPT_STATUS 0x00B0 +#define GMAC_MAC_INTERRUPT_ENABLE 0x00B4 +#define GMAC_MAC_RX_TX_STATUS 0x00B8 +#define GMAC_MAC_RX_TX_STATUS_RWT (1U << 8) +#define GMAC_MAC_RX_TX_STATUS_EXCOL (1U << 5) +#define GMAC_MAC_RX_TX_STATUS_LCOL (1U << 4) +#define GMAC_MAC_RX_TX_STATUS_EXDEF (1U << 3) +#define GMAC_MAC_RX_TX_STATUS_LCARR (1U << 2) +#define GMAC_MAC_RX_TX_STATUS_NCARR (1U << 1) +#define GMAC_MAC_RX_TX_STATUS_TJT (1U << 0) +#define GMAC_MAC_PMT_CONTROL_STATUS 0x00C0 +#define GMAC_MAC_RWK_PACKET_FILTER 0x00C4 +#define GMAC_MAC_LPI_CONTROL_STATUS 0x00D0 +#define GMAC_MAC_LPI_TIMERS_CONTROL 0x00D4 +#define GMAC_MAC_LPI_ENTRY_TIMER 0x00D8 +#define GMAC_MAC_1US_TIC_COUNTER 0x00DC +#define GMAC_MAC_PHYIF_CONTROL_STATUS 0x00F8 +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSTS (1U << 19) +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED BITS(18, 17) +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_2_5 0x0 +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_25 0x1 +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_125 0x2 +#define GMAC_MAC_PHYIF_CONTROL_STATUS_LNKMOD (1U << 16) +#define GMAC_MAC_VERSION 0x0110 +#define GMAC_MAC_VERSION_USERVER_SHIFT 8 +#define GMAC_MAC_VERSION_USERVER_MASK (0xFFU << GMAC_MAC_VERSION_USERVER_SHIFT) +#define GMAC_MAC_VERSION_SNPSVER_MASK 0xFFU +#define GMAC_MAC_DEBUG 0x0114 +#define GMAC_MAC_HW_FEATURE_BASE 0x011C +#define GMAC_MAC_HW_FEATURE1_TXFIFOSIZE BITS(10,6) +#define GMAC_MAC_HW_FEATURE1_RXFIFOSIZE BITS(4,0) +#define GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT 14 +#define GMAC_MAC_HW_FEATURE1_ADDR64_MASK (0x3U << GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT) +#define GMAC_MAC_HW_FEATURE1_ADDR64_32BIT (0x0U << GMAC_MAC_HW_FEATURE1_ADDR64_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS 0x0200 +#define GMAC_MAC_MDIO_ADDRESS_PA_SHIFT 21 +#define GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT 16 +#define GMAC_MAC_MDIO_ADDRESS_CR_SHIFT 8 +#define GMAC_MAC_MDIO_ADDRESS_CR_MASK (0x7U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_60_100 (0U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_100_150 (1U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_20_35 (2U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_35_60 (3U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_150_250 (4U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_250_300 (5U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_300_500 (6U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_CR_500_800 (7U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_SKAP (1U << 4) +#define GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT 2 +#define GMAC_MAC_MDIO_ADDRESS_GOC_READ (3U << GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_GOC_WRITE (1U << GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_C45E (1U << 1) +#define GMAC_MAC_MDIO_ADDRESS_GB (1U << 0) +#define GMAC_MAC_MDIO_DATA 0x0204 +#define GMAC_MAC_CSR_SW_CTRL 0x0230 +#define GMAC_MAC_ADDRESS0_HIGH 0x0300 +#define GMAC_MAC_ADDRESS0_HIGH_AE (1U << 31) +#define GMAC_MAC_ADDRESS0_LOW 0x0304 +#define GMAC_MMC_CONTROL 0x0700 +#define GMAC_MMC_CONTROL_UCDBC (1U << 8) +#define GMAC_MMC_CONTROL_CNTPRSTLVL (1U << 5) +#define GMAC_MMC_CONTROL_CNTPRST (1U << 4) +#define GMAC_MMC_CONTROL_CNTFREEZ (1U << 3) +#define GMAC_MMC_CONTROL_RSTONRD (1U << 2) +#define GMAC_MMC_CONTROL_CNTSTOPRO (1U << 1) +#define GMAC_MMC_CONTROL_CNTRST (1U << 0) +#define GMAC_MMC_RX_INTERRUPT 0x0704 +#define GMAC_MMC_RX_INTERRUPT_RXFOVPIS (1U << 21) +#define GMAC_MMC_RX_INTERRUPT_RXLENERPIS (1U << 18) +#define GMAC_MMC_RX_INTERRUPT_RXCRCERPIS (1U << 5) +#define GMAC_MMC_RX_INTERRUPT_RXMCGPIS (1U << 4) +#define GMAC_MMC_RX_INTERRUPT_RXGOCTIS (1U << 2) +#define GMAC_MMC_RX_INTERRUPT_RXGBOCTIS (1U << 1) +#define GMAC_MMC_RX_INTERRUPT_RXGBPKTIS (1U << 0) +#define GMAC_MMC_TX_INTERRUPT 0x0708 +#define GMAC_MMC_TX_INTERRUPT_TXGPKTIS (1U << 21) +#define GMAC_MMC_TX_INTERRUPT_TXGOCTIS (1U << 20) +#define GMAC_MMC_TX_INTERRUPT_TXCARERPIS (1U << 19) +#define GMAC_MMC_TX_INTERRUPT_TXFLOWERPIS (1U << 13) +#define GMAC_MMC_TX_INTERRUPT_TXGBPKTIS (1U << 1) +#define GMAC_MMC_TX_INTERRUPT_TXGBOCTIS (1U << 0) +#define GMAC_MMC_RX_INTERRUPT_MASK 0x070C +#define GMAC_MMC_TX_INTERRUPT_MASK 0x0710 +#define GMAC_TX_OCTET_COUNT_GOOD_BAD 0x0714 +#define GMAC_TX_PACKET_COUNT_GOOD_BAD 0x0718 +#define GMAC_TX_UNDERFLOW_ERROR_PACKETS 0x0748 +#define GMAC_TX_CARRIER_ERROR_PACKETS 0x0760 +#define GMAC_TX_OCTET_COUNT_GOOD 0x0764 +#define GMAC_TX_PACKET_COUNT_GOOD 0x0768 +#define GMAC_RX_PACKETS_COUNT_GOOD_BAD 0x0780 +#define GMAC_RX_OCTET_COUNT_GOOD_BAD 0x0784 +#define GMAC_RX_OCTET_COUNT_GOOD 0x0788 +#define GMAC_RX_MULTICAST_PACKETS_GOOD 0x0790 +#define GMAC_RX_CRC_ERROR_PACKETS 0x0794 +#define GMAC_RX_LENGTH_ERROR_PACKETS 0x07C8 +#define GMAC_RX_FIFO_OVERFLOW_PACKETS 0x07D4 +#define GMAC_MMC_IPC_RX_INTERRUPT_MASK 0x0800 +#define GMAC_MMC_IPC_RX_INTERRUPT 0x0808 +#define GMAC_RXIPV4_GOOD_PACKETS 0x0810 +#define GMAC_RXIPV4_HEADER_ERROR_PACKETS 0x0814 +#define GMAC_RXIPV6_GOOD_PACKETS 0x0824 +#define GMAC_RXIPV6_HEADER_ERROR_PACKETS 0x0828 +#define GMAC_RXUDP_ERROR_PACKETS 0x0834 +#define GMAC_RXTCP_ERROR_PACKETS 0x083C +#define GMAC_RXICMP_ERROR_PACKETS 0x0844 +#define GMAC_RXIPV4_HEADER_ERROR_OCTETS 0x0854 +#define GMAC_RXIPV6_HEADER_ERROR_OCTETS 0x0868 +#define GMAC_RXUDP_ERROR_OCTETS 0x0874 +#define GMAC_RXTCP_ERROR_OCTETS 0x087C +#define GMAC_RXICMP_ERROR_OCTETS 0x0884 +#define GMAC_MAC_TIMESTAMP_CONTROL 0x0B00 +#define GMAC_MAC_SUB_SECOND_INCREMENT 0x0B04 +#define GMAC_MAC_SYSTEM_TIME_SECS 0x0B08 +#define GMAC_MAC_SYSTEM_TIME_NS 0x0B0C +#define GMAC_MAC_SYS_TIME_SECS_UPDATE 0x0B10 +#define GMAC_MAC_SYS_TIME_NS_UPDATE 0x0B14 +#define GMAC_MAC_TIMESTAMP_ADDEND 0x0B18 +#define GMAC_MAC_TIMESTAMP_STATUS 0x0B20 +#define GMAC_MAC_TX_TS_STATUS_NS 0x0B30 +#define GMAC_MAC_TX_TS_STATUS_SECS 0x0B34 +#define GMAC_MAC_AUXILIARY_CONTROL 0x0B40 +#define GMAC_MAC_AUXILIARY_TS_NS 0x0B48 +#define GMAC_MAC_AUXILIARY_TS_SECS 0x0B4C +#define GMAC_MAC_TS_INGRESS_CORR_NS 0x0B58 +#define GMAC_MAC_TS_EGRESS_CORR_NS 0x0B5C +#define GMAC_MAC_TS_INGRESS_LATENCY 0x0B68 +#define GMAC_MAC_TS_EGRESS_LATENCY 0x0B6C +#define GMAC_MAC_PPS_CONTROL 0x0B70 +#define GMAC_MTL_DBG_CTL 0x0C08 +#define GMAC_MTL_DBG_STS 0x0C0C +#define GMAC_MTL_FIFO_DEBUG_DATA 0x0C10 +#define GMAC_MTL_INTERRUPT_STATUS 0x0C20 +#define GMAC_MTL_INTERRUPT_STATUS_DBGIS (1U << 17) +#define GMAC_MTL_INTERRUPT_STATUS_Q0IS (1U << 0) +#define GMAC_MTL_TXQ0_OPERATION_MODE 0x0D00 +#define GMAC_MTL_TXQ0_OPERATION_MODE_TQS BITS(24,16) +#define GMAC_MTL_TXQ0_OPERATION_MODE_TTC BITS(6,4) +#define GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT 2 +#define GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_MASK (0x3U << GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT) +#define GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_EN (2U << GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT) +#define GMAC_MTL_TXQ0_OPERATION_MODE_TSF (1U << 1) +#define GMAC_MTL_TXQ0_OPERATION_MODE_FTQ (1U << 0) +#define GMAC_MTL_TXQ0_UNDERFLOW 0x0D04 +#define GMAC_MTL_TXQ0_DEBUG 0x0D08 +#define GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS 0x0D2C +#define GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOIE (1U << 24) +#define GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOVFIS (1U << 16) +#define GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUIE (1U << 8) +#define GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUNFIS (1U << 0) +#define GMAC_MTL_RXQ0_OPERATION_MODE 0x0D30 +#define GMAC_MTL_RXQ0_OPERATION_MODE_RQS BITS(29,20) +#define GMAC_MTL_RXQ0_OPERATION_MODE_RFD BITS(19,14) +#define GMAC_MTL_RXQ0_OPERATION_MODE_RFA BITS(13,8) +#define GMAC_MTL_RXQ0_OPERATION_MODE_EHFC (1U << 7) +#define GMAC_MTL_RXQ0_OPERATION_MODE_RSF (1U << 5) +#define GMAC_MTL_RXQ0_OPERATION_MODE_FEP (1U << 4) +#define GMAC_MTL_RXQ0_OPERATION_MODE_FUP (1U << 3) +#define GMAC_MTL_RXQ0_MISS_PKT_OVF_CNT 0x0D34 +#define GMAC_MTL_RXQ0_DEBUG 0x0D38 +#define GMAC_DMA_MODE 0x1000 +#define GMAC_DMA_MODE_SWR (1U << 0) +#define GMAC_DMA_SYSBUS_MODE 0x1004 +#define GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT 24 +#define GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_MASK (0xfU << GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT) +#define GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT 16 +#define GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK (0xfU << GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT) +#define GMAC_DMA_SYSBUS_MODE_MB (1U << 14) +#define GMAC_DMA_SYSBUS_MODE_EAME (1U << 11) +#define GMAC_DMA_SYSBUS_MODE_BLEN16 (1U << 3) +#define GMAC_DMA_SYSBUS_MODE_BLEN8 (1U << 2) +#define GMAC_DMA_SYSBUS_MODE_BLEN4 (1U << 1) +#define GMAC_DMA_SYSBUS_MODE_FB (1U << 0) +#define GMAC_DMA_INTERRUPT_STATUS 0x1008 +#define GMAC_DMA_DEBUG_STATUS0 0x100C +#define GMAC_AXI_LPI_ENTRY_INTERVAL 0x1040 +#define GMAC_RWK_FILTER_BYTE_MASK_BASE 0x10C0 +#define GMAC_RWK_FILTER01_CRC 0x10D0 +#define GMAC_RWK_FILTER23_CRC 0x10D4 +#define GMAC_RWK_FILTER_OFFSET 0x10D8 +#define GMAC_RWK_FILTER_COMMAND 0x10DC +#define GMAC_DMA_CHAN0_CONTROL 0x1100 +#define GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT 18 +#define GMAC_DMA_CHAN0_CONTROL_DSL_MASK (0x7U << GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT) +#define GMAC_DMA_CHAN0_CONTROL_PBLX8 (1U << 16) +#define GMAC_DMA_CHAN0_TX_CONTROL 0x1104 +#define GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_SHIFT 16 +#define GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_MASK (0x3FU << GMAC_DMA_CHAN0_TX_CONTROL_TXPBL_SHIFT) +#define GMAC_DMA_CHAN0_TX_CONTROL_OSP (1U << 4) +#define GMAC_DMA_CHAN0_TX_CONTROL_START (1U << 0) +#define GMAC_DMA_CHAN0_RX_CONTROL 0x1108 +#define GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_SHIFT 16 +#define GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_MASK (0x3FU << GMAC_DMA_CHAN0_RX_CONTROL_RXPBL_SHIFT) +#define GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT 1 +#define GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK (0x3FFFU << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT) +#define GMAC_DMA_CHAN0_RX_CONTROL_START (1U << 0) +#define GMAC_DMA_CHAN0_TX_BASE_ADDR_HI 0x1110 +#define GMAC_DMA_CHAN0_TX_BASE_ADDR 0x1114 +#define GMAC_DMA_CHAN0_RX_BASE_ADDR_HI 0x1118 +#define GMAC_DMA_CHAN0_RX_BASE_ADDR 0x111C +#define GMAC_DMA_CHAN0_TX_END_ADDR 0x1120 +#define GMAC_DMA_CHAN0_RX_END_ADDR 0x1128 +#define GMAC_DMA_CHAN0_TX_RING_LEN 0x112C +#define GMAC_DMA_CHAN0_RX_RING_LEN 0x1130 +#define GMAC_DMA_CHAN0_INTR_ENABLE 0x1134 +#define GMAC_DMA_CHAN0_RX_WATCHDOG 0x1138 +#define GMAC_DMA_CHAN0_SLOT_CTRL_STATUS 0x113C +#define GMAC_DMA_CHAN0_CUR_TX_DESC 0x1144 +#define GMAC_DMA_CHAN0_CUR_RX_DESC 0x114C +#define GMAC_DMA_CHAN0_CUR_TX_BUF_ADDR 0x1154 +#define GMAC_DMA_CHAN0_CUR_RX_BUF_ADDR 0x115C +#define GMAC_DMA_CHAN0_STATUS 0x1160 +#define GMAC_DMA_CHAN0_STATUS_REB_DATA_TRANS (1U << 21) +#define GMAC_DMA_CHAN0_STATUS_REB_DESC_ACC (1U << 20) +#define GMAC_DMA_CHAN0_STATUS_REB_READ_TRANS (1U << 19) +#define GMAC_DMA_CHAN0_STATUS_TEB_DATA_TRANS (1U << 18) +#define GMAC_DMA_CHAN0_STATUS_TEB_DESC_ACC (1U << 17) +#define GMAC_DMA_CHAN0_STATUS_TEB_READ_TRANS (1U << 16) +#define GMAC_DMA_CHAN0_STATUS_NIS (1U << 15) +#define GMAC_DMA_CHAN0_STATUS_AIS (1U << 14) +#define GMAC_DMA_CHAN0_STATUS_CDE (1U << 13) +#define GMAC_DMA_CHAN0_STATUS_FBE (1U << 12) +#define GMAC_DMA_CHAN0_STATUS_RWT (1U << 9) +#define GMAC_DMA_CHAN0_STATUS_RPS (1U << 8) +#define GMAC_DMA_CHAN0_STATUS_RBU (1U << 7) +#define GMAC_DMA_CHAN0_STATUS_RI (1U << 6) +#define GMAC_DMA_CHAN0_STATUS_TBU (1U << 2) +#define GMAC_DMA_CHAN0_STATUS_TPS (1U << 1) +#define GMAC_DMA_CHAN0_STATUS_TI (1U << 0) + +#define GMAC_MAC_HASH_TABLE_REG(n) (GMAC_MAC_HASH_TABLE_REG_BASE + 0x4 * (n)) +#define GMAC_MAC_HW_FEATURE(n) (GMAC_MAC_HW_FEATURE_BASE + 0x4 * (n)) +#define GMAC_RWK_FILTER_BYTE_MASK(n) (GMAC_RWK_FILTER_BYTE_MASK_BASE + 0x4 * (n)) + +#pragma pack(1) +typedef struct EQOS_DMA_DESCRIPTOR { + UINT32 Tdes0; + UINT32 Tdes1; + UINT32 Tdes2; + #define EQOS_TDES2_TX_IOC (1U << 31) /* TX */ + #define EQOS_TDES2_RX_DAF (1U << 17) /* RX (WB) */ + #define EQOS_TDES2_RX_SAF (1U << 16) /* RX (WB) */ + UINT32 Tdes3; + #define EQOS_TDES3_TX_OWN (1U << 31) /* TX */ + #define EQOS_TDES3_TX_FD (1U << 29) /* TX */ + #define EQOS_TDES3_TX_LD (1U << 28) /* TX */ + #define EQOS_TDES3_TX_DE (1U << 23) /* TX (WB) */ + #define EQOS_TDES3_TX_EUE (1U << 16) /* TX (WB) */ + #define EQOS_TDES3_TX_ES (1U << 15) /* TX (WB) */ + #define EQOS_TDES3_TX_JT (1U << 14) /* TX (WB) */ + #define EQOS_TDES3_TX_PF (1U << 13) /* TX (WB) */ + #define EQOS_TDES3_TX_PCE (1U << 12) /* TX (WB) */ + #define EQOS_TDES3_TX_LOC (1U << 11) /* TX (WB) */ + #define EQOS_TDES3_TX_NC (1U << 10) /* TX (WB) */ + #define EQOS_TDES3_TX_LC (1U << 9) /* TX (WB) */ + #define EQOS_TDES3_TX_EC (1U << 8) /* TX (WB) */ + #define EQOS_TDES3_TX_ED (1U << 3) /* TX (WB) */ + #define EQOS_TDES3_TX_UF (1U << 2) /* TX (WB) */ + #define EQOS_TDES3_TX_IHE (1U << 0) /* TX (WB) */ + #define EQOS_TDES3_RX_OWN (1U << 31) /* RX */ + #define EQOS_TDES3_RX_IOC (1U << 30) /* RX */ + #define EQOS_TDES3_RX_BUF1V (1U << 24) /* RX */ + #define EQOS_TDES3_RX_CTXT (1U << 30) /* RX (WB) */ + #define EQOS_TDES3_RX_FD (1U << 29) /* RX (WB) */ + #define EQOS_TDES3_RX_LD (1U << 28) /* RX (WB) */ + #define EQOS_TDES3_RX_CE (1U << 24) /* RX (WB) */ + #define EQOS_TDES3_RX_GP (1U << 23) /* RX (WB) */ + #define EQOS_TDES3_RX_RWT (1U << 22) /* RX (WB) */ + #define EQOS_TDES3_RX_OE (1U << 21) /* RX (WB) */ + #define EQOS_TDES3_RX_RE (1U << 20) /* RX (WB) */ + #define EQOS_TDES3_RX_DE (1U << 19) /* RX (WB) */ + #define EQOS_TDES3_RX_ES (1U << 15) /* RX (WB) */ + #define EQOS_TDES3_RX_LENGTH_MASK 0x7FFFU /* RX */ +} EQOS_DMA_DESCRIPTOR; +#pragma pack() + +#endif diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosUtil.c b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosUtil.c new file mode 100644 index 00000000..b8d0da98 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/EqosUtil.c @@ -0,0 +1,1177 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + Copyright (c) 2022 Jared McNeill + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include "Eqos.h" + +#define DMA_DEVICE_ADDRESS_LIMIT \ + (FixedPcdGet64 (PcdDmaDeviceLimit) - FixedPcdGet64 (PcdDmaDeviceOffset)) + +EFI_STATUS +EqosIdentify ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Version; + UINT32 UserVersion; + UINT32 SnpsVersion; + UINT32 Index; + + Version = MmioRead32 (Eqos->Base + GMAC_MAC_VERSION); + UserVersion = (Version & GMAC_MAC_VERSION_USERVER_MASK) >> + GMAC_MAC_VERSION_USERVER_SHIFT; + SnpsVersion = Version & GMAC_MAC_VERSION_SNPSVER_MASK; + + if ((SnpsVersion < 0x51) || (SnpsVersion > 0x52)) { + DEBUG (( + DEBUG_ERROR, + "%a: Ver 0x%02x not supported!\n", + __func__, + SnpsVersion + )); + return EFI_UNSUPPORTED; + } + + DEBUG (( + DEBUG_ERROR, + "%a: Synopsys DesignWare EQOS ver 0x%02x (0x%02x) @ 0x%lx\n", + __func__, + SnpsVersion, + UserVersion, + Eqos->Base + )); + + for (Index = 0; Index < 4; Index++) { + Eqos->HwFeatures[Index] = MmioRead32 (Eqos->Base + GMAC_MAC_HW_FEATURE (Index)); + } + + DEBUG (( + DEBUG_ERROR, + "%a: HW Features: 0x%08x 0x%08x 0x%08x 0x%08x\n", + __func__, + Eqos->HwFeatures[0], + Eqos->HwFeatures[1], + Eqos->HwFeatures[2], + Eqos->HwFeatures[3] + )); + + return EFI_SUCCESS; +} + +VOID +EqosInitializeConfig ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + DWC_EQOS_CONFIG *Config; + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *Platform; + + Config = &Eqos->Config; + + // + // Default values + // + Config->CsrClockRate = 125000000; + Config->AxiBusWidth = EqosAxiBusWidth64; + Config->AxiFixedBurst = FALSE; + Config->AxiMixedBurst = FALSE; + Config->AxiWrOsrLmt = 1; + Config->AxiRdOsrLmt = 1; + Config->AxiBlen = 0; + + // + // Allow platform to override defaults + // + Platform = Eqos->Platform; + if (Platform->GetConfig != NULL) { + Platform->GetConfig (Platform, Config); + } +} + +EFI_STATUS +EqosReset ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Value; + UINT32 Retry; + + MmioWrite32 (Eqos->Base + GMAC_DMA_MODE, GMAC_DMA_MODE_SWR); + for (Retry = 2000; Retry > 0; Retry--) { + gBS->Stall (1000); + Value = MmioRead32 (Eqos->Base + GMAC_DMA_MODE); + if ((Value & GMAC_DMA_MODE_SWR) == 0) { + return EFI_SUCCESS; + } + } + + DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__)); + return EFI_TIMEOUT; +} + +EFI_STATUS +EqosInitialize ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EFI_STATUS Status; + DWC_EQOS_CONFIG *Config; + UINT32 Value; + UINT32 Tqs; + UINT32 Rqs; + + Status = EqosReset (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Config = &Eqos->Config; + + MmioWrite32 ( + Eqos->Base + GMAC_MAC_1US_TIC_COUNTER, + (Config->CsrClockRate / 1000000) - 1 + ); + + // + // Set AXI configuration + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_SYSBUS_MODE); + if (Config->AxiFixedBurst) { + Value |= GMAC_DMA_SYSBUS_MODE_FB; + } + + if (Config->AxiMixedBurst) { + Value |= GMAC_DMA_SYSBUS_MODE_MB; + } + + Value &= ~GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_MASK; + Value |= Config->AxiWrOsrLmt << GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT; + Value &= ~GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK; + Value |= Config->AxiRdOsrLmt << GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT; + + Value |= Config->AxiBlen; + + MmioWrite32 (Eqos->Base + GMAC_DMA_SYSBUS_MODE, Value); + + // + // Configure transmit and receive DMA + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_CONTROL); + Value &= ~GMAC_DMA_CHAN0_CONTROL_DSL_MASK; + Value |= ((EQOS_DESC_ALIGN - 16) / Config->AxiBusWidth) << GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT; + Value |= GMAC_DMA_CHAN0_CONTROL_PBLX8; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_CONTROL, Value); + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL); + Value |= GMAC_DMA_CHAN0_TX_CONTROL_OSP; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL, Value); + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL); + Value &= ~GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK; + Value |= (EQOS_RX_BUFFER_SIZE << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT); + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL, Value); + + // + // Disable counters + // + MmioWrite32 ( + Eqos->Base + GMAC_MMC_CONTROL, + GMAC_MMC_CONTROL_CNTFREEZ | + GMAC_MMC_CONTROL_CNTPRST | + GMAC_MMC_CONTROL_CNTPRSTLVL + ); + + // + // Configure operation modes + // + MmioWrite32 ( + Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE, + GMAC_MTL_TXQ0_OPERATION_MODE_TSF | + GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_EN + ); + MmioWrite32 ( + Eqos->Base + GMAC_MTL_RXQ0_OPERATION_MODE, + GMAC_MTL_RXQ0_OPERATION_MODE_RSF | + GMAC_MTL_RXQ0_OPERATION_MODE_FEP | + GMAC_MTL_RXQ0_OPERATION_MODE_FUP + ); + + // + // TX/RX fifo size in hw_feature[1] are log2(n/128), and + // TQS/RQS in TXQ0/RXQ0_OPERATION_MODE are n/256-1. + // + Tqs = (128 << SHIFTOUT ( + Eqos->HwFeatures[1], + GMAC_MAC_HW_FEATURE1_TXFIFOSIZE + ) / 256) - 1; + Value = MmioRead32 (Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE); + Value &= ~GMAC_MTL_TXQ0_OPERATION_MODE_TQS; + Value |= SHIFTIN (Tqs, GMAC_MTL_TXQ0_OPERATION_MODE_TQS); + MmioWrite32 (Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE, Value); + + Rqs = (128 << SHIFTOUT ( + Eqos->HwFeatures[1], + GMAC_MAC_HW_FEATURE1_RXFIFOSIZE + ) / 256) - 1; + Value = MmioRead32 (Eqos->Base + GMAC_MTL_RXQ0_OPERATION_MODE); + Value &= ~GMAC_MTL_RXQ0_OPERATION_MODE_RQS; + Value |= SHIFTIN (Rqs, GMAC_MTL_RXQ0_OPERATION_MODE_RQS); + MmioWrite32 (Eqos->Base + GMAC_MTL_RXQ0_OPERATION_MODE, Value); + + // + // Enable flow control + // + Value = MmioRead32 (Eqos->Base + GMAC_MAC_Q0_TX_FLOW_CTRL); + Value |= 0xFFFFU << GMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT; + Value |= GMAC_MAC_Q0_TX_FLOW_CTRL_TFE; + MmioWrite32 (Eqos->Base + GMAC_MAC_Q0_TX_FLOW_CTRL, Value); + Value = MmioRead32 (Eqos->Base + GMAC_MAC_RX_FLOW_CTRL); + Value |= GMAC_MAC_RX_FLOW_CTRL_RFE; + MmioWrite32 (Eqos->Base + GMAC_MAC_RX_FLOW_CTRL, Value); + + // + // Set RX queue mode to DCB + // + Value = SHIFTIN (GMAC_RXQ_CTRL0_EN_DCB, GMAC_RXQ_CTRL0_EN_MASK); + MmioWrite32 (Eqos->Base + GMAC_RXQ_CTRL0, Value); + + // + // Configure transmitter and receiver + // + Value = MmioRead32 (Eqos->Base + GMAC_MAC_CONFIGURATION); + Value |= GMAC_MAC_CONFIGURATION_BE; + Value |= GMAC_MAC_CONFIGURATION_DCRS; + MmioWrite32 (Eqos->Base + GMAC_MAC_CONFIGURATION, Value); + + EqosSetMacAddress (Eqos->Base, &Eqos->SnpMode.CurrentAddress); + + return EFI_SUCCESS; +} + +VOID +EqosEnableTxRx ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Value; + + // + // Start transmit DMA + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL); + Value |= GMAC_DMA_CHAN0_TX_CONTROL_START; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL, Value); + + // + // Start receive DMA + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL); + Value |= GMAC_DMA_CHAN0_RX_CONTROL_START; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL, Value); + + // + // Enable transmitter and receiver + // + Value = MmioRead32 (Eqos->Base + GMAC_MAC_CONFIGURATION); + Value |= GMAC_MAC_CONFIGURATION_TE; + Value |= GMAC_MAC_CONFIGURATION_RE; + MmioWrite32 (Eqos->Base + GMAC_MAC_CONFIGURATION, Value); + + // + // Enable interrupts + // + MmioWrite32 ( + Eqos->Base + GMAC_DMA_CHAN0_INTR_ENABLE, + GMAC_DMA_CHAN0_STATUS_NIS | + GMAC_DMA_CHAN0_STATUS_AIS | + GMAC_DMA_CHAN0_STATUS_CDE | + GMAC_DMA_CHAN0_STATUS_FBE | + GMAC_DMA_CHAN0_STATUS_RI | + GMAC_DMA_CHAN0_STATUS_TI + ); +} + +VOID +EqosDisableTxRx ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Value; + INT32 Retry; + + // + // Disable receiver + // + Value = MmioRead32 (Eqos->Base + GMAC_MAC_CONFIGURATION); + Value &= ~GMAC_MAC_CONFIGURATION_RE; + MmioWrite32 (Eqos->Base + GMAC_MAC_CONFIGURATION, Value); + + // + // Stop receive DMA + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL); + Value &= ~GMAC_DMA_CHAN0_RX_CONTROL_START; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_CONTROL, Value); + + // + // Stop transmit DMA + // + Value = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL); + Value &= ~GMAC_DMA_CHAN0_TX_CONTROL_START; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_CONTROL, Value); + + // + // Flush data in the TX FIFO + // + Value = MmioRead32 (Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE); + Value |= GMAC_MTL_TXQ0_OPERATION_MODE_FTQ; + MmioWrite32 (Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE, Value); + + // Wait for flush to complete + for (Retry = 10000; Retry > 0; Retry--) { + Value = MmioRead32 (Eqos->Base + GMAC_MTL_TXQ0_OPERATION_MODE); + if ((Value & GMAC_MTL_TXQ0_OPERATION_MODE_FTQ) == 0) { + break; + } + + gBS->Stall (1); + } + + if (Retry == 0) { + DEBUG ((DEBUG_ERROR, "%a: Timeout flushing TX queue!\n", __func__)); + } + + // + // Disable transmitter + // + Value = MmioRead32 (Eqos->Base + GMAC_MAC_CONFIGURATION); + Value &= ~GMAC_MAC_CONFIGURATION_TE; + MmioWrite32 (Eqos->Base + GMAC_MAC_CONFIGURATION, Value); + + // + // Disable interrupts + // + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_INTR_ENABLE, 0); +} + +VOID +EqosDmaInitDescriptorRings ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + Eqos->TxQueued = 0; + Eqos->TxNext = 0; + Eqos->TxCurrent = 0; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_BASE_ADDR_HI, (UINT32)(Eqos->TxDescsPhysAddr >> 32)); + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_BASE_ADDR, (UINT32)(Eqos->TxDescsPhysAddr)); + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_RING_LEN, EQOS_TX_DESC_COUNT - 1); + + Eqos->RxCurrent = 0; + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_BASE_ADDR_HI, (UINT32)(Eqos->RxDescsPhysAddr >> 32)); + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_BASE_ADDR, (UINT32)Eqos->RxDescsPhysAddr); + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_RING_LEN, EQOS_RX_DESC_COUNT - 1); +} + +EFI_STATUS +EqosStart ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EFI_STATUS Status; + + Status = EqosInitialize (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EqosDmaMapAllRxDescriptors (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + EqosDmaInitDescriptorRings (Eqos); + + EqosEnableTxRx (Eqos); + + return EFI_SUCCESS; +} + +EFI_STATUS +EqosStop ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EqosDisableTxRx (Eqos); + + EqosDmaUnmapAllTxDescriptors (Eqos); + EqosDmaUnmapAllRxDescriptors (Eqos); + + return EFI_SUCCESS; +} + +EFI_STATUS +EqosDmaAllocate ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + Eqos->RxBuffersAddr = DMA_DEVICE_ADDRESS_LIMIT; + + BufferSize = EQOS_RX_BUFFER_SIZE * EQOS_RX_DESC_COUNT; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Eqos->RxBuffersAddr + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to allocate RX DMA buffer. Status=%r\n", + __func__, + Status + )); + Eqos->RxBuffersAddr = 0; + return Status; + } + + BufferSize = EQOS_TX_DESC_RING_SIZE; + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Eqos->TxDescs + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to allocate TX DMA descriptors buffer. Status=%r\n", + __func__, + Status + )); + goto Fail; + } + + Status = DmaMap ( + MapOperationBusMasterCommonBuffer, + Eqos->TxDescs, + &BufferSize, + &Eqos->TxDescsPhysAddr, + &Eqos->TxDescsMap + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to map TX DMA descriptors buffer. Status=%r\n", + __func__, + Status + )); + goto Fail; + } + + ZeroMem (Eqos->TxDescs, BufferSize); + + BufferSize = EQOS_RX_DESC_RING_SIZE; + Status = DmaAllocateBuffer ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Eqos->RxDescs + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to allocate RX DMA descriptors buffer. Status=%r\n", + __func__, + Status + )); + goto Fail; + } + + Status = DmaMap ( + MapOperationBusMasterCommonBuffer, + Eqos->RxDescs, + &BufferSize, + &Eqos->RxDescsPhysAddr, + &Eqos->RxDescsMap + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to map RX DMA descriptors buffer. Status=%r\n", + __func__, + Status + )); + goto Fail; + } + + ZeroMem (Eqos->RxDescs, BufferSize); + + return EFI_SUCCESS; + +Fail: + EqosDmaFree (Eqos); + + return Status; +} + +VOID +EqosDmaFree ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + if (Eqos->RxBuffersAddr != 0) { + gBS->FreePages ( + Eqos->RxBuffersAddr, + EFI_SIZE_TO_PAGES (EQOS_RX_BUFFER_SIZE * EQOS_RX_DESC_COUNT) + ); + Eqos->RxBuffersAddr = 0; + } + + if (Eqos->TxDescs != NULL) { + DmaUnmap (Eqos->TxDescsMap); + DmaFreeBuffer (EFI_SIZE_TO_PAGES (EQOS_TX_DESC_RING_SIZE), Eqos->TxDescs); + Eqos->TxDescs = NULL; + } + + if (Eqos->RxDescs != NULL) { + DmaUnmap (Eqos->RxDescsMap); + DmaFreeBuffer (EFI_SIZE_TO_PAGES (EQOS_RX_DESC_RING_SIZE), Eqos->RxDescs); + Eqos->RxDescs = NULL; + } +} + +EFI_STATUS +EqosDmaMapTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex, + IN UINTN NumberOfBytes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BufferPhysAddr; + EQOS_DMA_DESCRIPTOR *Descriptor; + + ASSERT (Eqos->TxBuffersMap[DescIndex] == NULL); + ASSERT (Eqos->TxBuffers[DescIndex] != NULL); + + Status = DmaMap ( + MapOperationBusMasterRead, + Eqos->TxBuffers[DescIndex], + &NumberOfBytes, + &BufferPhysAddr, + &Eqos->TxBuffersMap[DescIndex] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to map TX buffer. Status=%r\n", __func__, Status)); + return Status; + } + + Descriptor = EQOS_DESC (Eqos->TxDescs, DescIndex); + + Descriptor->Tdes0 = (UINT32)(BufferPhysAddr); + Descriptor->Tdes1 = (UINT32)(BufferPhysAddr >> 32); + Descriptor->Tdes2 = EQOS_TDES2_TX_IOC | NumberOfBytes; + MemoryFence (); + Descriptor->Tdes3 = EQOS_TDES3_TX_OWN | EQOS_TDES3_TX_FD | EQOS_TDES3_TX_LD | NumberOfBytes; + + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_TX_END_ADDR, (UINT32)(UINTN)Descriptor); + + return EFI_SUCCESS; +} + +EFI_STATUS +EqosDmaMapRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ) +{ + EFI_STATUS Status; + UINTN NumberOfBytes; + EFI_PHYSICAL_ADDRESS BufferPhysAddr; + EQOS_DMA_DESCRIPTOR *Descriptor; + + ASSERT (Eqos->RxBuffersMap[DescIndex] == NULL); + ASSERT (Eqos->RxBuffersAddr != 0); + + NumberOfBytes = EQOS_RX_BUFFER_SIZE; + + Status = DmaMap ( + MapOperationBusMasterWrite, + EQOS_RX_BUFFER (Eqos, DescIndex), + &NumberOfBytes, + &BufferPhysAddr, + &Eqos->RxBuffersMap[DescIndex] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to map RX buffer. Status=%r\n", __func__, Status)); + return Status; + } + + Descriptor = EQOS_DESC (Eqos->RxDescs, DescIndex); + + Descriptor->Tdes0 = (UINT32)(BufferPhysAddr); + Descriptor->Tdes1 = (UINT32)(BufferPhysAddr >> 32); + Descriptor->Tdes2 = 0; + MemoryFence (); + Descriptor->Tdes3 = EQOS_TDES3_RX_OWN | EQOS_TDES3_RX_IOC | EQOS_TDES3_RX_BUF1V; + + MmioWrite32 (Eqos->Base + GMAC_DMA_CHAN0_RX_END_ADDR, (UINT32)(UINTN)Descriptor); + + return EFI_SUCCESS; +} + +VOID +EqosDmaUnmapTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ) +{ + if (Eqos->TxBuffersMap[DescIndex] != NULL) { + DmaUnmap (Eqos->TxBuffersMap[DescIndex]); + Eqos->TxBuffersMap[DescIndex] = NULL; + } +} + +VOID +EqosDmaUnmapRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ) +{ + if (Eqos->RxBuffersMap[DescIndex] != NULL) { + DmaUnmap (Eqos->RxBuffersMap[DescIndex]); + Eqos->RxBuffersMap[DescIndex] = NULL; + } +} + +EFI_STATUS +EqosDmaMapAllRxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EFI_STATUS Status; + UINT32 Index; + + for (Index = 0; Index < EQOS_RX_DESC_COUNT; Index++) { + Status = EqosDmaMapRxDescriptor (Eqos, Index); + if (EFI_ERROR (Status)) { + EqosDmaUnmapAllRxDescriptors (Eqos); + return Status; + } + } + + return EFI_SUCCESS; +} + +VOID +EqosDmaUnmapAllTxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Index; + + for (Index = 0; Index < EQOS_TX_DESC_COUNT; Index++) { + EqosDmaUnmapTxDescriptor (Eqos, Index); + } +} + +VOID +EqosDmaUnmapAllRxDescriptors ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + UINT32 Index; + + for (Index = 0; Index < EQOS_RX_DESC_COUNT; Index++) { + EqosDmaUnmapRxDescriptor (Eqos, Index); + } +} + +EFI_STATUS +EqosCheckTxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex + ) +{ + EQOS_DMA_DESCRIPTOR *Descriptor; + UINT32 Tdes3; + + Descriptor = EQOS_DESC (Eqos->TxDescs, DescIndex); + Tdes3 = Descriptor->Tdes3; + + if (Tdes3 & EQOS_TDES3_TX_OWN) { + return EFI_NOT_READY; + } + + if (Tdes3 & EQOS_TDES3_TX_DE) { + DEBUG ((DEBUG_ERROR, "%a: Descriptor Error\n", __func__)); + return EFI_DEVICE_ERROR; + } + + if (Tdes3 & EQOS_TDES3_TX_ES) { + if (Tdes3 & EQOS_TDES3_TX_EUE) { + DEBUG ((DEBUG_ERROR, "%a: ECC Uncorrectable Error Status\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_JT) { + DEBUG ((DEBUG_ERROR, "%a: Jabber Timeout\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_PF) { + DEBUG ((DEBUG_ERROR, "%a: Packet Flushed\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_PCE) { + DEBUG ((DEBUG_ERROR, "%a: Payload Checksum Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_LOC) { + DEBUG ((DEBUG_ERROR, "%a: Loss of Carrier\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_NC) { + DEBUG ((DEBUG_ERROR, "%a: No Carrier\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_LC) { + DEBUG ((DEBUG_ERROR, "%a: Late Collision\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_EC) { + DEBUG ((DEBUG_ERROR, "%a: Excessive Collision\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_ED) { + DEBUG ((DEBUG_ERROR, "%a: Excessive Deferral\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_UF) { + DEBUG ((DEBUG_ERROR, "%a: Underflow Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_TX_IHE) { + DEBUG ((DEBUG_ERROR, "%a: IP Header Error\n", __func__)); + } + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EqosCheckRxDescriptor ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 DescIndex, + OUT UINTN *FrameLength + ) +{ + EQOS_DMA_DESCRIPTOR *Descriptor; + UINT32 Tdes2; + UINT32 Tdes3; + + Descriptor = EQOS_DESC (Eqos->RxDescs, DescIndex); + Tdes2 = Descriptor->Tdes2; + Tdes3 = Descriptor->Tdes3; + + if (Tdes3 & EQOS_TDES3_RX_OWN) { + return EFI_NOT_READY; + } + + if (Tdes3 & EQOS_TDES3_RX_ES) { + if (Tdes3 & EQOS_TDES3_RX_CE) { + DEBUG ((DEBUG_ERROR, "%a: CRC Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_GP) { + DEBUG ((DEBUG_ERROR, "%a: Giant Packet\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_RWT) { + DEBUG ((DEBUG_ERROR, "%a: Receive Watchdog Timeout\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_OE) { + DEBUG ((DEBUG_ERROR, "%a: Overflow Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_RE) { + DEBUG ((DEBUG_ERROR, "%a: Receive Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_DE) { + DEBUG ((DEBUG_ERROR, "%a: Dribble Bit Error\n", __func__)); + } + + if (Tdes3 & EQOS_TDES3_RX_OE) { + DEBUG ((DEBUG_ERROR, "%a: Overflow Error\n", __func__)); + } + + if (Tdes2 & EQOS_TDES2_RX_DAF) { + DEBUG ((DEBUG_ERROR, "%a: Destination Address Filter Fail\n", __func__)); + } + + if (Tdes2 & EQOS_TDES2_RX_SAF) { + DEBUG ((DEBUG_ERROR, "%a: Source Address Filter Fail\n", __func__)); + } + + return EFI_DEVICE_ERROR; + } + + *FrameLength = Tdes3 & EQOS_TDES3_RX_LENGTH_MASK; + if (*FrameLength == 0) { + DEBUG ((DEBUG_ERROR, "%a: Invalid Frame Length\n", __func__)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +VOID +EqosGetDmaInterruptStatus ( + IN EQOS_PRIVATE_DATA *Eqos, + OUT UINT32 *InterruptStatus OPTIONAL + ) +{ + UINT32 DmaStatus; + UINT32 Mask; + + if (InterruptStatus != NULL) { + *InterruptStatus = 0; + } + + DmaStatus = MmioRead32 (Eqos->Base + GMAC_DMA_CHAN0_STATUS); + Mask = 0; + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_NIS) { + Mask |= GMAC_DMA_CHAN0_STATUS_NIS; + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_RI) { + if (InterruptStatus != NULL) { + Mask |= GMAC_DMA_CHAN0_STATUS_RI; + *InterruptStatus = EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_TI) { + if (InterruptStatus != NULL) { + Mask |= GMAC_DMA_CHAN0_STATUS_TI; + *InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + } + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_AIS) { + Mask |= GMAC_DMA_CHAN0_STATUS_AIS; + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_CDE) { + Mask |= GMAC_DMA_CHAN0_STATUS_CDE; + DEBUG ((DEBUG_ERROR, "%a: Context Descriptor Error\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_FBE) { + Mask |= GMAC_DMA_CHAN0_STATUS_FBE; + DEBUG ((DEBUG_ERROR, "%a: Fatal Bus Error\n", __func__)); + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_REB_DATA_TRANS) { + DEBUG ((DEBUG_ERROR, "%a: Rx DMA Error Bits: Error during data transfer by Rx DMA\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_REB_DESC_ACC) { + DEBUG ((DEBUG_ERROR, "%a: Rx DMA Error Bits: Error during descriptor access\n", __func__)); + } else { + DEBUG ((DEBUG_ERROR, "%a: Rx DMA Error Bits: Error during data buffer access\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_REB_READ_TRANS) { + DEBUG ((DEBUG_ERROR, "%a: Rx DMA Error Bits: Error during read transfer\n", __func__)); + } else { + DEBUG ((DEBUG_ERROR, "%a: Rx DMA Error Bits: Error during write transfer\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_TEB_DATA_TRANS) { + DEBUG ((DEBUG_ERROR, "%a: Tx DMA Error Bits: Error during data transfer by Tx DMA\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_TEB_DESC_ACC) { + DEBUG ((DEBUG_ERROR, "%a: Tx DMA Error Bits: Error during descriptor access\n", __func__)); + } else { + DEBUG ((DEBUG_ERROR, "%a: Tx DMA Error Bits: Error during data buffer access\n", __func__)); + } + + if (DmaStatus & GMAC_DMA_CHAN0_STATUS_TEB_READ_TRANS) { + DEBUG ((DEBUG_ERROR, "%a: Tx DMA Error Bits: Error during read transfer\n", __func__)); + } else { + DEBUG ((DEBUG_ERROR, "%a: Tx DMA Error Bits: Error during write transfer\n", __func__)); + } + } + } + + MmioOr32 (Eqos->Base + GMAC_DMA_CHAN0_STATUS, Mask); +} + +VOID +EqosGetPhyIfStatus ( + IN EQOS_PRIVATE_DATA *Eqos, + OUT BOOLEAN *LinkUp OPTIONAL, + OUT UINT32 *Speed OPTIONAL, + OUT BOOLEAN *FullDuplex OPTIONAL + ) +{ + UINT32 PhyIfStatus; + + PhyIfStatus = MmioRead32 (Eqos->Base + GMAC_MAC_PHYIF_CONTROL_STATUS); + + if (LinkUp != NULL) { + *LinkUp = (PhyIfStatus & GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSTS) != 0; + } + + if (FullDuplex != NULL) { + *FullDuplex = (PhyIfStatus & GMAC_MAC_PHYIF_CONTROL_STATUS_LNKMOD) != 0; + } + + if (Speed != NULL) { + switch (SHIFTOUT (PhyIfStatus, GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED)) { + case GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_2_5: + *Speed = 10; + break; + case GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_25: + *Speed = 100; + break; + case GMAC_MAC_PHYIF_CONTROL_STATUS_LNKSPEED_125: + *Speed = 1000; + break; + default: + ASSERT (FALSE); + *Speed = 0; + break; + } + } +} + +VOID +EqosSetLinkConfig ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 Speed, + IN BOOLEAN FullDuplex + ) +{ + UINT32 Config; + + Config = MmioRead32 (Eqos->Base + GMAC_MAC_CONFIGURATION); + + switch (Speed) { + case 10: + Config |= GMAC_MAC_CONFIGURATION_PS; + Config &= ~GMAC_MAC_CONFIGURATION_FES; + break; + case 100: + Config |= GMAC_MAC_CONFIGURATION_PS; + Config |= GMAC_MAC_CONFIGURATION_FES; + break; + case 1000: + Config &= ~GMAC_MAC_CONFIGURATION_PS; + Config &= ~GMAC_MAC_CONFIGURATION_FES; + break; + default: + ASSERT (FALSE); + break; + } + + if (FullDuplex) { + Config |= GMAC_MAC_CONFIGURATION_DM; + } else { + Config &= ~GMAC_MAC_CONFIGURATION_DM; + } + + MmioWrite32 (Eqos->Base + GMAC_MAC_CONFIGURATION, Config); +} + +EFI_STATUS +EqosUpdateLink ( + IN EQOS_PRIVATE_DATA *Eqos + ) +{ + EFI_STATUS Status; + BOOLEAN LinkUp; + UINT32 Speed; + BOOLEAN FullDuplex; + DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *Platform; + + EqosGetPhyIfStatus (Eqos, &LinkUp, &Speed, &FullDuplex); + + if (Eqos->SnpMode.MediaPresent != LinkUp) { + if (LinkUp) { + DEBUG ((DEBUG_VERBOSE, "%a: Link is up\n", __func__)); + + EqosSetLinkConfig (Eqos, Speed, FullDuplex); + + Platform = Eqos->Platform; + if (Platform->SetInterfaceSpeed != NULL) { + Status = Platform->SetInterfaceSpeed (Platform, Speed); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to set platform interface speed to %u. Status=%r\n", + __func__, + Speed, + Status + )); + } + } + } else { + DEBUG ((DEBUG_VERBOSE, "%a: Link is down\n", __func__)); + } + + Eqos->SnpMode.MediaPresent = LinkUp; + } + + return LinkUp ? EFI_SUCCESS : EFI_NOT_READY; +} + +EFI_STATUS +EqosSetRxFilters ( + IN EQOS_PRIVATE_DATA *Eqos, + IN UINT32 ReceiveFilterSetting, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ) +{ + UINT32 Index; + UINT32 PacketFilter; + UINT32 Crc; + UINT32 HashReg; + UINT32 HashBit; + UINT32 Hash; + + if (ResetMCastFilter) { + for (HashReg = 0; HashReg < GMAC_MAC_HASH_TABLE_COUNT; HashReg++) { + MmioWrite32 (Eqos->Base + GMAC_MAC_HASH_TABLE_REG (HashReg), 0x0); + } + } + + PacketFilter = MmioRead32 (Eqos->Base + GMAC_MAC_PACKET_FILTER); + + PacketFilter &= ~(GMAC_MAC_PACKET_FILTER_PCF_MASK | + GMAC_MAC_PACKET_FILTER_DBF | + GMAC_MAC_PACKET_FILTER_PM | + GMAC_MAC_PACKET_FILTER_HMC | + GMAC_MAC_PACKET_FILTER_PR); + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + PacketFilter |= GMAC_MAC_PACKET_FILTER_PR | + GMAC_MAC_PACKET_FILTER_PCF_ALL; + } else if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) { + PacketFilter |= GMAC_MAC_PACKET_FILTER_PM; + } else if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + PacketFilter |= GMAC_MAC_PACKET_FILTER_HMC; + + for (Index = 0; Index < MCastFilterCnt; Index++) { + Crc = EqosEtherCrc32Le (MCastFilter[Index].Addr, NET_ETHER_ADDR_LEN); + Crc &= 0x7f; + Crc = EqosBitReverse32 (~Crc) >> 26; + HashReg = Crc >> 5; + HashBit = 1 << (Crc & 0x1f); + + Hash = MmioRead32 (Eqos->Base + GMAC_MAC_HASH_TABLE_REG (HashReg)); + Hash |= HashBit; + MmioWrite32 (Eqos->Base + GMAC_MAC_HASH_TABLE_REG (HashReg), Hash); + } + } + + if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) == 0) { + PacketFilter |= GMAC_MAC_PACKET_FILTER_DBF; + } + + MmioWrite32 (Eqos->Base + GMAC_MAC_PACKET_FILTER, PacketFilter); + + return EFI_SUCCESS; +} + +VOID +EqosGetMacAddress ( + IN EFI_PHYSICAL_ADDRESS Base, + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT32 AddrLow; + UINT32 AddrHigh; + + AddrLow = MmioRead32 (Base + GMAC_MAC_ADDRESS0_LOW); + AddrHigh = MmioRead32 (Base + GMAC_MAC_ADDRESS0_HIGH); + + MacAddress->Addr[0] = AddrLow & 0xff; + MacAddress->Addr[1] = (AddrLow >> 8) & 0xff; + MacAddress->Addr[2] = (AddrLow >> 16) & 0xff; + MacAddress->Addr[3] = (AddrLow >> 24) & 0xff; + MacAddress->Addr[4] = AddrHigh & 0xff; + MacAddress->Addr[5] = (AddrHigh >> 8) & 0xff; +} + +VOID +EqosSetMacAddress ( + IN EFI_PHYSICAL_ADDRESS Base, + IN EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT32 AddrLow; + UINT32 AddrHigh; + + AddrLow = MacAddress->Addr[0]; + AddrLow |= MacAddress->Addr[1] << 8; + AddrLow |= MacAddress->Addr[2] << 16; + AddrLow |= MacAddress->Addr[3] << 24; + AddrHigh = MacAddress->Addr[4]; + AddrHigh |= MacAddress->Addr[5] << 8; + AddrHigh |= GMAC_MAC_ADDRESS0_HIGH_AE; + + MmioWrite32 (Base + GMAC_MAC_ADDRESS0_LOW, AddrLow); + MmioWrite32 (Base + GMAC_MAC_ADDRESS0_HIGH, AddrHigh); +} + +UINT32 +EqosEtherCrc32Le ( + IN UINT8 *Buffer, + IN UINTN Length + ) +{ + STATIC CONST UINT32 CrcTable[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + + UINT32 Crc; + UINTN Index; + + Crc = 0xffffffffU; + + for (Index = 0; Index < Length; Index++) { + Crc ^= Buffer[Index]; + Crc = (Crc >> 4) ^ CrcTable[Crc & 0xf]; + Crc = (Crc >> 4) ^ CrcTable[Crc & 0xf]; + } + + return (Crc); +} + +UINT32 +EqosBitReverse32 ( + IN UINT32 Value + ) +{ + Value = (((Value & 0xaaaaaaaa) >> 1) | ((Value & 0x55555555) << 1)); + Value = (((Value & 0xcccccccc) >> 2) | ((Value & 0x33333333) << 2)); + Value = (((Value & 0xf0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f) << 4)); + Value = (((Value & 0xff00ff00) >> 8) | ((Value & 0x00ff00ff) << 8)); + + return (Value >> 16) | (Value << 16); +} diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/SimpleNetwork.c b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/SimpleNetwork.c new file mode 100644 index 00000000..62af659f --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwcEqosSnpDxe/SimpleNetwork.c @@ -0,0 +1,915 @@ +/** @file + + Copyright (c) 2025, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Eqos.h" + +/** + Changes the state of a network interface from "stopped" to "started". + + @param This Protocol instance pointer. + + @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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EQOS_PRIVATE_DATA *Eqos; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStarted) { + return EFI_ALREADY_STARTED; + } else if (Eqos->SnpMode.State != EfiSimpleNetworkStopped) { + return EFI_DEVICE_ERROR; + } + + Eqos->SnpMode.State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +/** + Changes the state of a network interface from "started" to "stopped". + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was stopped. + @retval EFI_ALREADY_STARTED The network interface is already in the stopped state. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EQOS_PRIVATE_DATA *Eqos; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } else if (Eqos->SnpMode.State != EfiSimpleNetworkStarted) { + return EFI_DEVICE_ERROR; + } + + Eqos->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. + + @param This The protocol instance pointer. + @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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } else if (Eqos->SnpMode.State != EfiSimpleNetworkStarted) { + return EFI_DEVICE_ERROR; + } + + Status = EqosStart (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Eqos->SnpMode.State = EfiSimpleNetworkInitialized; + + return EFI_SUCCESS; +} + +/** + Resets a network adapter and re-initializes it with the parameters that were + provided in the previous call to Initialize(). + + @param This The protocol instance pointer. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + Status = EqosStop (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EqosStart (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EqosSetRxFilters ( + Eqos, + Eqos->SnpMode.ReceiveFilterSetting, + Eqos->SnpMode.MCastFilterCount == 0, + Eqos->SnpMode.MCastFilterCount, + Eqos->SnpMode.MCastFilter + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Resets a network adapter and leaves it in a state that is safe for + another driver to initialize. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was shutdown. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + Status = EqosStop (Eqos); + if (EFI_ERROR (Status)) { + return Status; + } + + Eqos->SnpMode.State = EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +/** + Manages the multicast receive filters of a network interface. + + @param This The protocol instance pointer. + @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. + @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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpReceiveFilters ( + 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 + ) +{ + EQOS_PRIVATE_DATA *Eqos; + UINT32 ReceiveFilterSetting; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if ((((Enable | Disable) & ~Eqos->SnpMode.ReceiveFilterMask) != 0)) { + return EFI_INVALID_PARAMETER; + } + + ReceiveFilterSetting = (Eqos->SnpMode.ReceiveFilterSetting | Enable) & (~Disable); + + if (ResetMCastFilter) { + Eqos->SnpMode.MCastFilterCount = 0; + } else if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + if ((MCastFilterCnt == 0) || + (MCastFilterCnt > Eqos->SnpMode.MaxMCastFilterCount) || + (MCastFilter == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + Eqos->SnpMode.MCastFilterCount = MCastFilterCnt; + CopyMem (Eqos->SnpMode.MCastFilter, MCastFilter, MCastFilterCnt * sizeof (EFI_MAC_ADDRESS)); + } + + Eqos->SnpMode.ReceiveFilterSetting = ReceiveFilterSetting; + + return EqosSetRxFilters ( + Eqos, + ReceiveFilterSetting, + ResetMCastFilter, + MCastFilterCnt, + MCastFilter + ); +} + +/** + Modifies or resets the current station address, if supported. + + @param This The protocol instance pointer. + @param Reset Flag used to reset the station address to the network interfaces + permanent address. + @param New The new station address to be used for the network interface. + + @retval EFI_SUCCESS The network interfaces station address was updated. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + + if ((This == NULL) || (This->Mode == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Reset == FALSE) && (New == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if (Reset) { + CopyMem ( + &This->Mode->CurrentAddress, + &This->Mode->PermanentAddress, + sizeof (This->Mode->CurrentAddress) + ); + } else { + CopyMem ( + &This->Mode->CurrentAddress, + New, + sizeof (This->Mode->CurrentAddress) + ); + } + + EqosSetMacAddress (Eqos->Base, &Eqos->SnpMode.CurrentAddress); + + return EFI_SUCCESS; +} + +/** + Resets or collects the statistics on a network interface. + + @param This Protocol instance pointer. + @param Reset Set to TRUE to reset the statistics for the network interface. + @param StatisticsSize On input the size, in bytes, of StatisticsTable. On + output the size, in bytes, of the resulting table of + statistics. + @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that + contains the statistics. + + @retval EFI_SUCCESS The statistics were collected from the network interface. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Converts a multicast IP address to a multicast HW MAC address. + + @param This The protocol instance pointer. + @param IPv6 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 MAC 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 network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpMCastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ) +{ + EQOS_PRIVATE_DATA *Eqos; + + if ((This == NULL) || (IP == NULL) || (MAC == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // https://en.wikipedia.org/wiki/Multicast_address + // + if ((IPv6 && ((IP->v6.Addr[0]) != 0xFF)) || // invalid IPv6 mcast addr + (!IPv6 && ((IP->v4.Addr[0] & 0xF0) != 0xE0)) // invalid IPv4 mcast addr + ) + { + DEBUG (( + DEBUG_ERROR, + "%a: Invalid IPv4/IPv6 multicast address!\n", + __func__ + )); + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + ZeroMem (MAC, sizeof (EFI_MAC_ADDRESS)); + + // + // https://en.wikipedia.org/wiki/IP_multicast#Layer_2_delivery + // + if (IPv6) { + MAC->Addr[0] = 0x33; + MAC->Addr[1] = 0x33; + MAC->Addr[2] = IP->v6.Addr[12]; + MAC->Addr[3] = IP->v6.Addr[13]; + MAC->Addr[4] = IP->v6.Addr[14]; + MAC->Addr[5] = IP->v6.Addr[15]; + } else { + MAC->Addr[0] = 0x01; + MAC->Addr[1] = 0x00; + MAC->Addr[2] = 0x5E; + MAC->Addr[3] = IP->v4.Addr[1] & 0x7F; + MAC->Addr[4] = IP->v4.Addr[2]; + MAC->Addr[5] = IP->v4.Addr[3]; + } + + return EFI_SUCCESS; +} + +/** + Performs read and write operations on the NVRAM device attached to a + network interface. + + @param This The protocol instance pointer. + @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. + @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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpNvData ( + 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. + + @param This The protocol instance pointer. + @param InterruptStatus A pointer to the bit mask of the currently active interrupts + 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 TxBuf 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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + UINT32 DescIndex; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + EqosUpdateLink (Eqos); + + if (TxBuf != NULL) { + *TxBuf = NULL; + + if (Eqos->TxQueued > 0) { + DescIndex = Eqos->TxCurrent; + + Status = EqosCheckTxDescriptor (Eqos, DescIndex); + if (Status != EFI_NOT_READY) { + ASSERT (Eqos->TxBuffersMap[DescIndex] != NULL); + EqosDmaUnmapTxDescriptor (Eqos, DescIndex); + + *TxBuf = Eqos->TxBuffers[DescIndex]; + + Eqos->TxCurrent = EQOS_TX_NEXT (DescIndex); + Eqos->TxQueued--; + } + } + } + + // + // InterruptStatus is not currently consumed by the upper layers, + // but we still read it for compliance and to log any detected + // errors, which can be helpful for debugging. + // + EqosGetDmaInterruptStatus (Eqos, InterruptStatus); + + return EFI_SUCCESS; +} + +/** + Places a packet in the transmit queue of a network interface. + + @param This The protocol instance pointer. + @param HeaderSize The size, in bytes, of the media header to be filled in by + the Transmit() function. If HeaderSize is non-zero, then it + must be equal to This->Mode->MediaHeaderSize and the DestAddr + and Protocol parameters must not be NULL. + @param BufferSize The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param Buffer 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 non-zero, 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 non-zero and SrcAddr is NULL, then + This->Mode->CurrentAddress is used for the source HW MAC address. + @param DestAddr The destination 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + UINT8 *Frame; + UINT32 DescIndex; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + if (HeaderSize != 0) { + if (HeaderSize != Eqos->SnpMode.MediaHeaderSize) { + DEBUG (( + DEBUG_ERROR, + "%a: Header size mismatch: HeaderSize=0x%X, SnpMode.MediaHeaderSize=0x%X)\n", + __func__, + HeaderSize, + Eqos->SnpMode.MediaHeaderSize + )); + return EFI_INVALID_PARAMETER; + } + + if ((DestAddr == NULL) || (Protocol == NULL)) { + return EFI_INVALID_PARAMETER; + } + } + + if (BufferSize < Eqos->SnpMode.MediaHeaderSize) { + DEBUG ((DEBUG_ERROR, "%a: Buffer too small!\n", __func__)); + return EFI_BUFFER_TOO_SMALL; + } + + Status = EfiAcquireLockOrFail (&Eqos->Lock); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to get lock. Status=%r\n", __func__, Status)); + return EFI_ACCESS_DENIED; + } + + if (Eqos->TxQueued == EQOS_TX_DESC_COUNT - 1) { + Status = EFI_NOT_READY; + goto Exit; + } + + Frame = Buffer; + + if (HeaderSize != 0) { + CopyMem (&Frame[0], &DestAddr->Addr[0], NET_ETHER_ADDR_LEN); + CopyMem (&Frame[6], &SrcAddr->Addr[0], NET_ETHER_ADDR_LEN); + Frame[12] = (*Protocol & 0xFF00) >> 8; + Frame[13] = *Protocol & 0xFF; + } + + DescIndex = Eqos->TxNext; + + Eqos->TxBuffers[DescIndex] = Frame; + + Status = EqosDmaMapTxDescriptor (Eqos, DescIndex, BufferSize); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Eqos->TxNext = EQOS_TX_NEXT (DescIndex); + Eqos->TxQueued++; + + Status = EFI_SUCCESS; + +Exit: + EfiReleaseLock (&Eqos->Lock); + return Status; +} + +/** + Receives a packet from a network interface. + + @param This The protocol instance pointer. + @param HeaderSize 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 BufferSize 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 Buffer 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 DestAddr The destination HW MAC address. If this parameter is NULL, + the HW MAC destination 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 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. + +**/ +STATIC +EFI_STATUS +EFIAPI +EqosSnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + EQOS_PRIVATE_DATA *Eqos; + EFI_STATUS Status; + EFI_STATUS MapStatus; + UINT32 DescIndex; + UINT8 *Frame; + UINTN FrameLength; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Eqos = EQOS_PRIVATE_DATA_FROM_SNP_THIS (This); + if (Eqos->SnpMode.State == EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + if (Eqos->SnpMode.State != EfiSimpleNetworkInitialized) { + return EFI_DEVICE_ERROR; + } + + Status = EfiAcquireLockOrFail (&Eqos->Lock); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to get lock. Status=%r\n", __func__, Status)); + return EFI_ACCESS_DENIED; + } + + DescIndex = Eqos->RxCurrent; + FrameLength = 0; + + Status = EqosCheckRxDescriptor (Eqos, DescIndex, &FrameLength); + if (Status == EFI_NOT_READY) { + goto Exit; + } else if (EFI_ERROR (Status)) { + ASSERT (Eqos->RxBuffersMap[DescIndex] != NULL); + EqosDmaUnmapRxDescriptor (Eqos, DescIndex); + goto ReleaseDesc; + } + + if (*BufferSize < FrameLength) { + DEBUG (( + DEBUG_ERROR, + "%a: Buffer size (0x%X) is too small for frame (0x%X)!\n", + __func__, + *BufferSize, + FrameLength + )); + *BufferSize = FrameLength; + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + + ASSERT (Eqos->RxBuffersMap[DescIndex] != NULL); + EqosDmaUnmapRxDescriptor (Eqos, DescIndex); + + Frame = EQOS_RX_BUFFER (Eqos, DescIndex); + + if (DestAddr != NULL) { + CopyMem (&DestAddr->Addr[0], &Frame[0], NET_ETHER_ADDR_LEN); + } + + if (SrcAddr != NULL) { + CopyMem (&SrcAddr->Addr[0], &Frame[6], NET_ETHER_ADDR_LEN); + } + + if (Protocol != NULL) { + *Protocol = (UINT16)((Frame[12] << 8) | Frame[13]); + } + + if (HeaderSize != NULL) { + *HeaderSize = Eqos->SnpMode.MediaHeaderSize; + } + + CopyMem (Buffer, Frame, FrameLength); + *BufferSize = FrameLength; + + Status = EFI_SUCCESS; + +ReleaseDesc: + MapStatus = EqosDmaMapRxDescriptor (Eqos, DescIndex); + if (EFI_ERROR (MapStatus)) { + Status = MapStatus; + goto Exit; + } + + Eqos->RxCurrent = EQOS_RX_NEXT (Eqos->RxCurrent); + +Exit: + EfiReleaseLock (&Eqos->Lock); + return Status; +} + +/// +/// Simple Network Protocol +/// +CONST EFI_SIMPLE_NETWORK_PROTOCOL gEqosSnpTemplate = { + EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, // Revision + EqosSnpStart, // Start + EqosSnpStop, // Stop + EqosSnpInitialize, // Initialize + EqosSnpReset, // Reset + EqosSnpShutdown, // Shutdown + EqosSnpReceiveFilters, // ReceiveFilters + EqosSnpStationAddress, // StationAddress + EqosSnpStatistics, // Statistics + EqosSnpMCastIptoMac, // MCastIpToMac + EqosSnpNvData, // NvData + EqosSnpGetStatus, // GetStatus + EqosSnpTransmit, // Transmit + EqosSnpReceive, // Receive + NULL, // WaitForPacket + NULL // Mode +}; diff --git a/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/DwcEqosPlatformDevice.h b/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/DwcEqosPlatformDevice.h new file mode 100644 index 00000000..0b5f5b91 --- /dev/null +++ b/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/DwcEqosPlatformDevice.h @@ -0,0 +1,94 @@ +/** @file + Synopsys DesignWare Ethernet Quality-of-Service (EQoS) Platform Protocol + + To register an EQOS controller with the SNP driver, configure and install both + an instance of this protocol and a device path ending with MAC_ADDR_DEVICE_PATH. + + Note: Both the MAC and the PHY must be initialized prior (i.e. clocks, resets, + PHY auto-negotiation), as the necessary abstractions for that are not currently + implemented in EDK2. + + Copyright (c) 2025, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef DWC_EQOS_PLATFORM_DEVICE_PROTOCOL_H_ +#define DWC_EQOS_PLATFORM_DEVICE_PROTOCOL_H_ + +#define DWC_EQOS_PLATFORM_DEVICE_PROTOCOL_GUID \ + { 0x60975136, 0x4601, 0x41b3, { 0xbf, 0x9a, 0x90, 0xe9, 0x59, 0xfc, 0xb0, 0x02 } } + +typedef struct _DWC_EQOS_PLATFORM_DEVICE_PROTOCOL DWC_EQOS_PLATFORM_DEVICE_PROTOCOL; + +typedef enum { + EqosAxiBusWidth128 = 16, + EqosAxiBusWidth64 = 8, + EqosAxiBusWidth32 = 4, +} DWC_EQOS_AXI_BUS_WIDTH; + +typedef enum { + EqosAxiBlen256 = BIT7, + EqosAxiBlen128 = BIT6, + EqosAxiBlen64 = BIT5, + EqosAxiBlen32 = BIT4, + EqosAxiBlen16 = BIT3, + EqosAxiBlen8 = BIT2, + EqosAxiBlen4 = BIT1, +} DWC_EQOS_AXI_BLEN; + +typedef struct { + UINT32 CsrClockRate; + DWC_EQOS_AXI_BUS_WIDTH AxiBusWidth; + BOOLEAN AxiFixedBurst; + BOOLEAN AxiMixedBurst; + UINT8 AxiWrOsrLmt; + UINT8 AxiRdOsrLmt; + DWC_EQOS_AXI_BLEN AxiBlen; +} DWC_EQOS_CONFIG; + +/** + Overrides the default device configuration. + + @param[in] This The protocol instance pointer. + @param[in] Config A pointer to the current configuration. + +**/ +typedef +VOID +(EFIAPI *DWC_EQOS_GET_CONFIG)( + IN DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *This, + IN DWC_EQOS_CONFIG *Config + ); + +/** + Adjusts platform clocks depending on the negotiated interface speed. + + @param[in] This The protocol instance pointer. + @param[in] Speed The interface speed in Mbps (10/100/1000). + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The operation is unsupported. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the operation. + +**/ +typedef +EFI_STATUS +(EFIAPI *DWC_EQOS_SET_INTERFACE_SPEED)( + IN DWC_EQOS_PLATFORM_DEVICE_PROTOCOL *This, + IN UINT32 Speed + ); + +struct _DWC_EQOS_PLATFORM_DEVICE_PROTOCOL { + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_MAC_ADDRESS MacAddress; + + DWC_EQOS_GET_CONFIG GetConfig; + DWC_EQOS_SET_INTERFACE_SPEED SetInterfaceSpeed; +}; + +extern EFI_GUID gDwcEqosPlatformDeviceProtocolGuid; + +#endif