/** @file * * RK3588 GMAC initializer * * Copyright (c) 2021-2022, Jared McNeill * Copyright (c) 2023, Mario Bălănică * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include #include #include #include #include #define CRU_SOFTRST_CON32 (CRU_BASE + 0x0A80) #define PHP_GRF_BASE 0xFD5B0000 #define PHP_GRF_CLK_CON1 (PHP_GRF_BASE + 0x0070) #define PHP_GRF_GMAC_CON0 (PHP_GRF_BASE + 0x0008) #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 TX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0TxDelay) #define RX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0RxDelay) #define TX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1TxDelay) #define RX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1RxDelay) #define GMAC0_BASE 0xfe1b0000 #define GMAC1_BASE 0xfe1c0000 /* GMAC registers */ #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_100_150 (1U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) #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_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 STATIC ETHERNET_PHY_INIT mPhyInitList[] = { RealtekPhyInit, MotorcommPhyInit }; VOID PhyRead ( IN EFI_PHYSICAL_ADDRESS GmacBase, IN UINT8 Phy, IN UINT16 Reg, OUT UINT16 *Value ) { UINT32 Addr; UINTN Retry; Addr = GMAC_MAC_MDIO_ADDRESS_CR_100_150 | (Phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | (Reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | GMAC_MAC_MDIO_ADDRESS_GOC_READ | GMAC_MAC_MDIO_ADDRESS_GB; MmioWrite32 (GmacBase + GMAC_MAC_MDIO_ADDRESS, Addr); MicroSecondDelay (10000); for (Retry = 1000; Retry > 0; Retry--) { Addr = MmioRead32 (GmacBase + GMAC_MAC_MDIO_ADDRESS); if ((Addr & GMAC_MAC_MDIO_ADDRESS_GB) == 0) { *Value = MmioRead32 (GmacBase + GMAC_MAC_MDIO_DATA) & 0xFFFFu; break; } MicroSecondDelay (10); } if (Retry == 0) { DEBUG ((DEBUG_WARN, "MDIO: PHY read timeout!\n")); *Value = 0xFFFFU; ASSERT (FALSE); } } VOID PhyWrite ( IN EFI_PHYSICAL_ADDRESS GmacBase, IN UINT8 Phy, IN UINT16 Reg, IN UINT16 Value ) { UINT32 Addr; UINTN Retry; MmioWrite32 (GmacBase + GMAC_MAC_MDIO_DATA, Value); Addr = GMAC_MAC_MDIO_ADDRESS_CR_100_150 | (Phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | (Reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | GMAC_MAC_MDIO_ADDRESS_GOC_WRITE | GMAC_MAC_MDIO_ADDRESS_GB; MmioWrite32 (GmacBase + GMAC_MAC_MDIO_ADDRESS, Addr); MicroSecondDelay (10000); for (Retry = 1000; Retry > 0; Retry--) { Addr = MmioRead32 (GmacBase + GMAC_MAC_MDIO_ADDRESS); if ((Addr & GMAC_MAC_MDIO_ADDRESS_GB) == 0) { break; } MicroSecondDelay (10); } if (Retry == 0) { DEBUG ((DEBUG_WARN, "MDIO: PHY write timeout!\n")); ASSERT (FALSE); } } STATIC VOID EFIAPI PhyInit ( IN EFI_PHYSICAL_ADDRESS GmacBase ) { EFI_STATUS Status; UINT16 PhyIdReg; UINT32 PhyId; UINT32 Index; PhyRead (GmacBase, 0, MII_PHYIDR1, &PhyIdReg); PhyId = PhyIdReg << 16; PhyRead (GmacBase, 0, MII_PHYIDR2, &PhyIdReg); PhyId |= PhyIdReg; for (Index = 0; Index < ARRAY_SIZE (mPhyInitList); Index++) { Status = mPhyInitList[Index] (GmacBase, PhyId); if (Status == EFI_UNSUPPORTED) { continue; } else if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: mPhyInitList[%d]() failed: %r\n", __func__, Index, Status)); } return; } DEBUG ((DEBUG_ERROR, "%a: Unknown PHY ID %08X\n", __func__, PhyId)); } STATIC VOID EFIAPI InitGmac0 ( VOID ) { /* 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)); } 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)); } /* Reset PHY */ GmacIoPhyReset (0, TRUE); MicroSecondDelay (20000); GmacIoPhyReset (0, FALSE); MicroSecondDelay (200000); /* Deassert reset */ MmioWrite32 (CRU_SOFTRST_CON32, 0x04000000); // aresetn_gmac0 = 0 PhyInit (GMAC0_BASE); } STATIC VOID EFIAPI InitGmac1 ( VOID ) { /* 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 /* serg (RK3588, 0x42, -1, 1) * #define DELAY_ENABLE_BY_ID(soc, tx, rx, id) // For R6C GRF_BIT(4) | GRF_CLR_BIT(5) * ((((tx) >= 0) ? soc##_GMAC_TXCLK_DLY_ENABLE(id) : soc##_GMAC_TXCLK_DLY_DISABLE(id)) | \ * (((rx) >= 0) ? soc##_GMAC_RXCLK_DLY_ENABLE(id) : soc##_GMAC_RXCLK_DLY_DISABLE(id))) * * #define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3) // serg For R6C id=1 GRF_BIT(5) * #define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3) // serg For R6C id=1 GRF_CLR_BIT(5) * #define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2) // serg For R6C id=1 GRF_BIT(4) * #define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2) // serg For R6C id=1 GRF_CLR_BIT(4) * * #define DELAY_VALUE(soc, tx, rx) \ * ((((tx) >= 0) ? soc##_GMAC_CLK_TX_DL_CFG(tx) : 0) | \ * (((rx) >= 0) ? soc##_GMAC_CLK_RX_DL_CFG(rx) : 0)) * #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) * * #define CLK_RX_DL_CFG_SHIFT 8 * #define CLK_TX_DL_CFG_SHIFT 0 * * #define RK3588_GRF_GMAC_CON7 0X031c * #define RK3588_GRF_GMAC_CON8 0X0320 * #define RK3588_GRF_GMAC_CON9 0X0324 * #define RK3588_GRF_GMAC_CON0 0X0008 * #define RK3588_GRF_CLK_CON1 0X0070 * * for R6C * gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 * gRK3588TokenSpaceGuid.PcdGmac1RxDelay|0x0 // or undefine * * From * static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv, * int tx_delay, int rx_delay) * { * struct device *dev = &bsp_priv->pdev->dev; * u32 offset_con, id = bsp_priv->bus_id; * * if (IS_ERR(bsp_priv->grf) || IS_ERR(bsp_priv->php_grf)) { * dev_err(dev, "Missing rockchip,grf or rockchip,php_grf property\n"); * return; * } * * offset_con = bsp_priv->bus_id == 1 ? RK3588_GRF_GMAC_CON9 : * RK3588_GRF_GMAC_CON8; * * regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0, * RK3588_GMAC_PHY_INTF_SEL_RGMII(id)); * * regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, * RK3588_GMAC_CLK_RGMII_MODE(id)); * * regmap_write(bsp_priv->grf, RK3588_GRF_GMAC_CON7, * DELAY_ENABLE_BY_ID(RK3588, tx_delay, rx_delay, id)); * * regmap_write(bsp_priv->grf, offset_con, * DELAY_VALUE(RK3588, tx_delay, rx_delay)); * } */ /* XXX */ /* 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)); } 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)); } /* XXX */ /* Reset PHY */ GmacIoPhyReset (1, TRUE); MicroSecondDelay (20000); GmacIoPhyReset (1, FALSE); MicroSecondDelay (200000); /* Deassert reset */ MmioWrite32 (CRU_SOFTRST_CON32, 0x08000000); // aresetn_gmac1 = 0 PhyInit (GMAC1_BASE); } EFI_STATUS EFIAPI GmacPlatformDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 OtpData[32]; UINT8 Hash[SHA256_DIGEST_SIZE]; UINT32 MacLo, MacHi; if (!FixedPcdGetBool (PcdGmac0Supported) && !FixedPcdGetBool (PcdGmac1Supported)) { return EFI_SUCCESS; } /* 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. */ OtpRead (0x00, sizeof (OtpData), OtpData); Sha256HashAll (OtpData, sizeof (OtpData), Hash); Hash[0] &= 0xFE; Hash[0] |= 0x02; if (FixedPcdGetBool (PcdGmac0Supported)) { InitGmac0 (); 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); } if (FixedPcdGetBool (PcdGmac1Supported)) { InitGmac1 (); Hash[5] |= 1; DEBUG ((DEBUG_INFO, "%a: GMAC1 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 (GMAC1_BASE + GMAC_MAC_ADDRESS0_LOW, MacLo); MmioWrite32 (GMAC1_BASE + GMAC_MAC_ADDRESS0_HIGH, MacHi); } return EFI_SUCCESS; }