diff options
Diffstat (limited to 'drivers/net')
41 files changed, 3033 insertions, 526 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ed07e286676..4399c6c7a99 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -184,10 +184,10 @@ config CALXEDA_XGMAC config DWC_ETH_XGMAC bool select PHYLIB - help - This driver supports the Synopsys Designware Ethernet XGMAC (10G - Ethernet MAC) IP block. The IP supports many options for bus type, - clocking/reset structure, and feature list. + help + This driver supports the Synopsys Designware Ethernet XGMAC (10G + Ethernet MAC) IP block. The IP supports many options for bus type, + clocking/reset structure, and feature list. config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" @@ -229,8 +229,8 @@ config DWC_ETH_QOS_ADI bool "Synopsys DWC Ethernet QOS device support for ADI SC59x-64 parts" depends on DWC_ETH_QOS && ARCH_SC5XX help - The Synopsis Designware Ethernet QoS IP block with the specific - configuration used in the ADI ADSP-SC59X 64 bit SoCs + The Synopsis Designware Ethernet QoS IP block with the specific + configuration used in the ADI ADSP-SC59X 64 bit SoCs config DWC_ETH_QOS_IMX bool "Synopsys DWC Ethernet QOS device support for IMX" @@ -246,6 +246,20 @@ config DWC_ETH_QOS_INTEL The Synopsys Designware Ethernet QOS IP block with the specific configuration used in the Intel Elkhart-Lake soc. +config DWC_ETH_QOS_MTK + bool "Synopsys DWC Ethernet QOS device support for MediaTek SoCs" + depends on DWC_ETH_QOS && ARCH_MEDIATEK + help + The Synopsys Designware Ethernet QOS IP block with the specific + configuration used in MediaTek SoCs. + +config DWC_ETH_QOS_QCOM + bool "Synopsys DWC Ethernet QOS device support for Qcom SoCs" + depends on DWC_ETH_QOS + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in Qcom QCS404 SoC. + config DWC_ETH_QOS_ROCKCHIP bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs" depends on DWC_ETH_QOS && ARCH_ROCKCHIP @@ -254,6 +268,13 @@ config DWC_ETH_QOS_ROCKCHIP The Synopsys Designware Ethernet QOS IP block with specific configuration used in Rockchip SoCs. +config DWC_ETH_QOS_STARFIVE + bool "Synopsys DWC Ethernet QOS device support for STARFIVE" + depends on DWC_ETH_QOS + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in STARFIVE JH7110 soc. + config DWC_ETH_QOS_STM32 bool "Synopsys DWC Ethernet QOS device support for STM32" depends on DWC_ETH_QOS && ARCH_STM32MP @@ -271,20 +292,6 @@ config DWC_ETH_QOS_TEGRA186 The Synopsys Designware Ethernet QOS IP block with specific configuration used in NVIDIA's Tegra186 chip. -config DWC_ETH_QOS_QCOM - bool "Synopsys DWC Ethernet QOS device support for Qcom SoCs" - depends on DWC_ETH_QOS - help - The Synopsys Designware Ethernet QOS IP block with specific - configuration used in Qcom QCS404 SoC. - -config DWC_ETH_QOS_STARFIVE - bool "Synopsys DWC Ethernet QOS device support for STARFIVE" - depends on DWC_ETH_QOS - help - The Synopsys Designware Ethernet QOS IP block with specific - configuration used in STARFIVE JH7110 soc. - config E1000 bool "Intel PRO/1000 Gigabit Ethernet support" depends on PCI @@ -339,7 +346,7 @@ config ESSEDMA config ETH_SANDBOX depends on SANDBOX - depends on NET || NET_LWIP + depends on NET default y bool "Sandbox: Mocked Ethernet driver" help @@ -350,7 +357,7 @@ config ETH_SANDBOX config ETH_SANDBOX_RAW depends on SANDBOX - depends on NET + depends on NET_LEGACY default y bool "Sandbox: Bridge to Linux Raw Sockets" help @@ -460,9 +467,9 @@ config FSL_FM_10GEC_REGULAR_NOTATION help On SoCs T4240, T2080, LS1043A, etc, the notation between 10GEC and MAC as below: - 10GEC1->MAC9, 10GEC2->MAC10, 10GEC3->MAC1, 10GEC4->MAC2 + 10GEC1->MAC9, 10GEC2->MAC10, 10GEC3->MAC1, 10GEC4->MAC2 While on SoCs T1024, etc, the notation between 10GEC and MAC as below: - 10GEC1->MAC1, 10GEC2->MAC2 + 10GEC1->MAC1, 10GEC2->MAC2 so we introduce CONFIG_FSL_FM_10GEC_REGULAR_NOTATION to identify the new SoCs on which 10GEC enumeration is consistent with MAC enumeration. @@ -476,7 +483,7 @@ config FTMAC100 config FTGMAC100 bool "Ftgmac100 Ethernet Support" select PHYLIB - depends on NET + depends on NET_LEGACY help This driver supports the Faraday's FTGMAC100 Gigabit SoC Ethernet controller that can be found on Aspeed SoCs (which @@ -529,7 +536,7 @@ config KSZ9477 config LITEETH bool "LiteX LiteEth Ethernet MAC" help - Driver for the LiteEth Ethernet MAC from LiteX. + Driver for the LiteEth Ethernet MAC from LiteX. config MV88E6XXX bool "Marvell MV88E6xxx Ethernet switch DSA driver" @@ -701,12 +708,12 @@ config SJA1105 family. These are 5-port devices and are managed over an SPI interface. Probing is handled based on OF bindings. The driver supports the following revisions: - - SJA1105E (Gen. 1, No TT-Ethernet) - - SJA1105T (Gen. 1, TT-Ethernet) - - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet) - - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet) - - SJA1105R (Gen. 2, SGMII, No TT-Ethernet) - - SJA1105S (Gen. 2, SGMII, TT-Ethernet) + - SJA1105E (Gen. 1, No TT-Ethernet) + - SJA1105T (Gen. 1, TT-Ethernet) + - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet) + - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet) + - SJA1105R (Gen. 2, SGMII, No TT-Ethernet) + - SJA1105S (Gen. 2, SGMII, TT-Ethernet) config SMC911X bool "SMSC LAN911x and LAN921x controller driver" @@ -740,11 +747,11 @@ config SUN4I_EMAC This driver supports the Allwinner based SUN4I Ethernet MAC. config SUN8I_EMAC - bool "Allwinner Sun8i Ethernet MAC support" - select PHYLIB + bool "Allwinner Sun8i Ethernet MAC support" + select PHYLIB select PHY_GIGE - help - This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC. + help + This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC. It can be found in H3/A64/A83T based SoCs and compatible with both External and Internal PHYs. @@ -905,7 +912,7 @@ config FEC1_PHY help Define to the hardcoded PHY address which corresponds to the given FEC; i. e. - #define CONFIG_FEC1_PHY 4 + #define CONFIG_FEC1_PHY 4 means that the PHY with address 4 is connected to FEC1 When set to -1, means to probe for first available. @@ -929,7 +936,7 @@ config FEC2_PHY help Define to the hardcoded PHY address which corresponds to the given FEC; i. e. - #define CONFIG_FEC1_PHY 4 + #define CONFIG_FEC1_PHY 4 means that the PHY with address 4 is connected to FEC1 When set to -1, means to probe for first available. @@ -1018,8 +1025,8 @@ config FSL_ENETC config FSL_ENETC_NETC_BLK_CTRL bool "NXP ENETC NETC blocks control driver" depends on FSL_ENETC - depends on IMX95 || IMX94 - default y if IMX95 || IMX94 + depends on IMX95 || IMX94 || IMX952 + default y if IMX95 || IMX94 || IMX952 help This driver configures Integrated Endpoint Register Block (IERB) and Privileged Register Block (PRB) of NETC. For i.MX platforms, it also @@ -1034,7 +1041,7 @@ config MDIO_GPIO_BITBANG bool "GPIO bitbanging MDIO driver" depends on DM_MDIO && DM_GPIO help - Driver for bitbanging MDIO + Driver for bitbanging MDIO config MDIO_MUX_I2CREG bool "MDIO MUX accessed as a register over I2C" @@ -1080,8 +1087,8 @@ config MDIO_MSCC_MIIM depends on DM_MDIO select REGMAP help - This driver supports MDIO interface found in Microsemi and Microchip - network switches. + This driver supports MDIO interface found in Microsemi and Microchip + network switches. config MDIO_MUX_MMIOREG bool "MDIO MUX accessed as a MMIO register access" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5e90183d090..761f7f0f451 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_AG7XXX) += ag7xxx.o -obj-y += airoha/ obj-$(CONFIG_AIROHA_ETH) += airoha_eth.o obj-$(CONFIG_ALTERA_TSE) += altera_tse.o obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o @@ -22,12 +21,13 @@ obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_DWC_ETH_QOS_ADI) += dwc_eth_qos_adi.o obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o -obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o +obj-$(CONFIG_DWC_ETH_QOS_MTK) += dwc_eth_qos_mtk.o obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o -obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o -obj-$(CONFIG_DWC_ETH_XGMAC_SOCFPGA) += dwc_eth_xgmac_socfpga.o +obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o obj-$(CONFIG_DWC_ETH_QOS_STM32) += dwc_eth_qos_stm32.o +obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o +obj-$(CONFIG_DWC_ETH_XGMAC_SOCFPGA) += dwc_eth_xgmac_socfpga.o obj-$(CONFIG_E1000) += e1000.o obj-$(CONFIG_E1000_SPI) += e1000_spi.o obj-$(CONFIG_EEPRO100) += eepro100.o @@ -62,9 +62,9 @@ obj-$(CONFIG_KSZ9477) += ksz9477.o obj-$(CONFIG_LITEETH) += liteeth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o +obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o -obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o @@ -109,6 +109,7 @@ obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o obj-$(CONFIG_XILINX_AXIMRMAC) += xilinx_axi_mrmac.o obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o +obj-y += airoha/ obj-y += mscc_eswitch/ obj-y += phy/ obj-y += qe/ diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c index 84ee9b2ad76..e5d39b95cc5 100644 --- a/drivers/net/airoha_eth.c +++ b/drivers/net/airoha_eth.c @@ -845,11 +845,45 @@ static int airoha_alloc_gdm_port(struct udevice *dev, ofnode node) (ulong)eth, node, &gdm_dev); } +static struct udevice *airoha_switch_mdio_init(struct udevice *dev) +{ + struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); + ofnode switch_node, mdio_node; + struct udevice *mdio_dev; + int ret; + + if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO)) + return NULL; + + switch_node = ofnode_by_compatible(ofnode_null(), + data->switch_compatible); + if (!ofnode_valid(switch_node)) { + debug("Warning: missing airoha switch node\n"); + return ERR_PTR(-EINVAL); + } + + mdio_node = ofnode_find_subnode(switch_node, "mdio"); + if (!ofnode_valid(mdio_node)) { + debug("Warning: missing airoha switch mdio subnode\n"); + return ERR_PTR(-EINVAL); + } + + ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio", + mdio_node, &mdio_dev); + if (ret) { + debug("Warning: failed to bind airoha switch mdio\n"); + return ERR_PTR(ret); + } + + return mdio_dev; +} + static int airoha_eth_probe(struct udevice *dev) { struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); struct airoha_eth *eth = dev_get_priv(dev); struct regmap *scu_regmap; + struct udevice *mdio_dev; ofnode node; int i, ret; @@ -908,10 +942,10 @@ static int airoha_eth_probe(struct udevice *dev) if (ret) return ret; - if (eth->switch_mdio_dev) { - if (!device_probe(eth->switch_mdio_dev)) - debug("Warning: failed to probe airoha switch mdio\n"); - } + /* Airoha switch mdio PHYs maybe used by several GDM devices */ + mdio_dev = airoha_switch_mdio_init(dev); + if (!IS_ERR_OR_NULL(mdio_dev)) + eth->switch_mdio_dev = mdio_dev; ofnode_for_each_subnode(node, dev_ofnode(dev)) { if (!ofnode_device_is_compatible(node, "airoha,eth-mac")) @@ -957,6 +991,16 @@ static int airoha_eth_port_probe(struct udevice *dev) #else return -EINVAL; #endif + } else { + /* + * GDM1 device connected to airoha switch. Probe airoha switch + * mdio to be able set/query states of corresponding LAN ports. + */ + ret = device_probe(eth->switch_mdio_dev); + if (ret) { + debug("Warning: failed to probe airoha switch mdio\n"); + eth->switch_mdio_dev = NULL; + } } return 0; @@ -1202,38 +1246,12 @@ static int arht_eth_write_hwaddr(struct udevice *dev) static int airoha_eth_bind(struct udevice *dev) { - struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); - struct airoha_eth *eth = dev_get_priv(dev); - ofnode switch_node, mdio_node; - int ret; - /* * Force Probe as we set the Main ETH driver as misc * to register multiple eth port for each GDM */ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); - if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO)) - return 0; - - switch_node = ofnode_by_compatible(ofnode_null(), - data->switch_compatible); - if (!ofnode_valid(switch_node)) { - debug("Warning: missing switch node\n"); - return 0; - } - - mdio_node = ofnode_find_subnode(switch_node, "mdio"); - if (!ofnode_valid(mdio_node)) { - debug("Warning: missing mdio node\n"); - return 0; - } - - ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio", - mdio_node, ð->switch_mdio_dev); - if (ret) - debug("Warning: failed to bind mdio controller\n"); - return 0; } diff --git a/drivers/net/calxedaxgmac.c b/drivers/net/calxedaxgmac.c index 92990fa6d47..df0ed820e06 100644 --- a/drivers/net/calxedaxgmac.c +++ b/drivers/net/calxedaxgmac.c @@ -555,7 +555,7 @@ static int xgmac_ofdata_to_platdata(struct udevice *dev) return -ENOMEM; dev_set_priv(dev, priv); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); if (pdata->iobase == FDT_ADDR_T_NONE) { printf("%s: Cannot find XGMAC base address\n", __func__); return -EINVAL; diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 8fa549280aa..2a21eceac57 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -653,7 +653,7 @@ static int dc2114x_of_to_plat(struct udevice *dev) struct eth_pdata *plat = dev_get_plat(dev); struct dc2114x_priv *priv = dev_get_priv(dev); - plat->iobase = (phys_addr_t)map_physmem((phys_addr_t)devfdt_get_addr(dev), 0, MAP_NOCACHE); + plat->iobase = (phys_addr_t)dev_remap_addr(dev); priv->iobase = (void *)plat->iobase; return 0; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 0f31d646845..b7e6299c307 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1659,6 +1659,12 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_adi_config }, #endif +#if IS_ENABLED(CONFIG_DWC_ETH_QOS_MTK) + { + .compatible = "mediatek,mt8189-gmac", + .data = (ulong)&eqos_mtk_config + }, +#endif { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index ba16f1a37cb..978b848b46e 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -97,6 +97,7 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_PA_MASK GENMASK(25, 21) #define EQOS_MAC_MDIO_ADDRESS_RDA_MASK GENMASK(20, 16) #define EQOS_MAC_MDIO_ADDRESS_CR_MASK GENMASK(11, 8) +#define EQOS_MAC_MDIO_ADDRESS_CR_60_100 0 #define EQOS_MAC_MDIO_ADDRESS_CR_100_150 1 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 #define EQOS_MAC_MDIO_ADDRESS_CR_150_250 4 @@ -316,3 +317,4 @@ extern struct eqos_config eqos_stm32mp15_config; extern struct eqos_config eqos_stm32mp25_config; extern struct eqos_config eqos_jh7110_config; extern struct eqos_config eqos_adi_config; +extern struct eqos_config eqos_mtk_config; diff --git a/drivers/net/dwc_eth_qos_mtk.c b/drivers/net/dwc_eth_qos_mtk.c new file mode 100644 index 00000000000..43e1085dfe5 --- /dev/null +++ b/drivers/net/dwc_eth_qos_mtk.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 BayLibre, SAS. + * Author: Julien Stephan <[email protected]> + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <net.h> +#include <phy.h> +#include <regmap.h> +#include <syscon.h> + +#include "dwc_eth_qos.h" + +/* + * Peri Configuration register is SoC specific, + * so add a SoC specific prefix. + */ +#define MT8189_PERI_ETH_CTRL0 0x270 +#define MT8189_PERI_ETH_CTRL1 0x274 +#define MT8189_PERI_ETH_CTRL2 0x278 + +#define EQOS_MTK_RMII_CLK_SRC_INTERNAL BIT(28) +#define EQOS_MTK_RMII_CLK_SRC_RXC BIT(27) +#define EQOS_MTK_ETH_INTF_SEL GENMASK(26, 24) +#define EQOS_MTK_PHY_INTF_MII 0 +#define EQOS_MTK_PHY_INTF_RGMII 1 +#define EQOS_MTK_PHY_INTF_RMII 4 +#define EQOS_MTK_RGMII_TXC_PHASE_CTRL BIT(22) +#define EQOS_MTK_EXT_PHY_MODE BIT(21) +#define EQOS_MTK_TXC_OUT_OP BIT(20) +#define EQOS_MTK_DLY_GTXC_INV BIT(12) +#define EQOS_MTK_DLY_GTXC_STAGE_FINE GENMASK(11, 6) +#define EQOS_MTK_DLY_GTXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_GTXC_STAGES GENMASK(4, 0) + +#define EQOS_MTK_DLY_RXC_INV BIT(25) +#define EQOS_MTK_DLY_RXC_ENABLE BIT(18) +#define EQOS_MTK_DLY_RXC_STAGES GENMASK(17, 13) +#define EQOS_MTK_DLY_TXC_INV BIT(12) +#define EQOS_MTK_DLY_TXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_TXC_STAGES GENMASK(4, 0) + +#define EQOS_MTK_DLY_RMII_RXC_INV BIT(25) +#define EQOS_MTK_DLY_RMII_RXC_ENABLE BIT(18) +#define EQOS_MTK_DLY_RMII_RXC_STAGES GENMASK(17, 13) +#define EQOS_MTK_DLY_RMII_TXC_INV BIT(12) +#define EQOS_MTK_DLY_RMII_TXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_RMII_TXC_STAGES GENMASK(4, 0) + +#define DELAY_MAX_PS 9800 +#define DELAY_PS_PER_STAGE 290 + +struct eqos_mtk_priv { + struct regmap *peri_regmap; + bool rmii_clk_from_mac; + bool rmii_rxc; + u32 tx_delay_stage; + u32 rx_delay_stage; + bool tx_inv; + bool rx_inv; +}; + +static int mtk_clk_init(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = clk_get_by_name(dev, "mac_main", &eqos->clk_tx); + if (ret) { + dev_err(dev, "clk_get_by_name(mac_main) failed: %d", ret); + return ret; + } + + ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); + if (ret) { + dev_err(dev, "clk_get_by_name(ptp_ref) failed: %d", ret); + return ret; + } + + return 0; +} + +static int mtk_set_delay(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0; + + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_MII: + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_STAGES, mtk_pdata->tx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_INV, mtk_pdata->tx_inv); + + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, mtk_pdata->rx_inv); + break; + case PHY_INTERFACE_MODE_RMII: + if (mtk_pdata->rmii_clk_from_mac) { + /* case 1: mac provides the rmii reference clock, + * and the clock output to TXC pin. + * The egress timing can be adjusted by RMII_TXC delay macro circuit. + * The ingress timing can be adjusted by RMII_RXC delay macro circuit. + */ + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_STAGES, + mtk_pdata->tx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_INV, + mtk_pdata->tx_inv); + + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_STAGES, + mtk_pdata->rx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_INV, + mtk_pdata->rx_inv); + } else { + /* case 2: the rmii reference clock is from external phy, + * and the property "rmii_rxc" indicates which pin(TXC/RXC) + * the reference clk is connected to. The reference clock is a + * received signal, so rx_delay_stage/rx_inv are used to indicate + * the reference clock timing adjustment + */ + if (mtk_pdata->rmii_rxc) { + /* the rmii reference clock from outside is connected + * to RXC pin, the reference clock will be adjusted + * by RXC delay macro circuit. + */ + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, + mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, + mtk_pdata->rx_inv); + } else { + /* the rmii reference clock from outside is connected + * to TXC pin, the reference clock will be adjusted + * by TXC delay macro circuit. + */ + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_STAGES, + mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_INV, + mtk_pdata->rx_inv); + } + } + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_STAGES, + mtk_pdata->tx_delay_stage); + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_INV, mtk_pdata->tx_inv); + gtxc_delay_val |= EQOS_MTK_DLY_GTXC_STAGE_FINE; + + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, mtk_pdata->rx_inv); + + break; + default: + dev_err(dev, "phy interface not supported\n"); + return -EINVAL; + } + + regmap_update_bits(mtk_pdata->peri_regmap, + MT8189_PERI_ETH_CTRL0, + EQOS_MTK_RGMII_TXC_PHASE_CTRL | + EQOS_MTK_DLY_GTXC_ENABLE | + EQOS_MTK_DLY_GTXC_INV | + EQOS_MTK_DLY_GTXC_STAGE_FINE | + EQOS_MTK_DLY_GTXC_STAGES, + gtxc_delay_val); + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL1, delay_val); + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL2, rmii_delay_val); + + return 0; +} + +static int mtk_set_interface(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + int rmii_clk_from_mac = mtk_pdata->rmii_clk_from_mac ? EQOS_MTK_RMII_CLK_SRC_INTERNAL : 0; + int rmii_rxc = mtk_pdata->rmii_rxc ? EQOS_MTK_RMII_CLK_SRC_RXC : 0; + u32 intf_val = 0; + + /* select phy interface in top control domain */ + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_MII: + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_MII); + break; + case PHY_INTERFACE_MODE_RMII: + intf_val |= (rmii_rxc | rmii_clk_from_mac); + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_RMII); + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_RGMII); + break; + default: + dev_err(dev, "phy interface not supported\n"); + return -EINVAL; + } + + /* only support external PHY */ + intf_val |= EQOS_MTK_EXT_PHY_MODE; + + intf_val |= EQOS_MTK_TXC_OUT_OP; + + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL0, intf_val); + + return 0; +} + +static int mtk_config_dt(struct udevice *dev) +{ struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + struct ofnode_phandle_args args; + u32 tx_delay_ps = 0, rx_delay_ps = 0; + int ret; + + if (!dev_read_u32(dev, "mediatek,tx-delay-ps", &tx_delay_ps)) { + if (tx_delay_ps > DELAY_MAX_PS) { + dev_err(dev, "Invalid TX clock delay: %dps\n", tx_delay_ps); + return -EINVAL; + } + } + + if (!dev_read_u32(dev, "mediatek,rx-delay-ps", &rx_delay_ps)) { + if (rx_delay_ps > DELAY_MAX_PS) { + dev_err(dev, "Invalid RX clock delay: %dps\n", rx_delay_ps); + return -EINVAL; + } + } + + mtk_pdata->tx_delay_stage = tx_delay_ps / DELAY_PS_PER_STAGE; + mtk_pdata->rx_delay_stage = rx_delay_ps / DELAY_PS_PER_STAGE; + + mtk_pdata->tx_inv = dev_read_bool(dev, "mediatek,txc-inverse"); + mtk_pdata->rx_inv = dev_read_bool(dev, "mediatek,rxc-inverse"); + mtk_pdata->rmii_clk_from_mac = dev_read_bool(dev, "mediatek,rmii-clk-from-mac"); + mtk_pdata->rmii_rxc = dev_read_bool(dev, "mediatek,rmii-rxc"); + + ret = dev_read_phandle_with_args(dev, "mediatek,pericfg", NULL, 0, 0, &args); + if (ret) { + dev_err(dev, "Failed to get mediatek,pericfg property: %d\n", ret); + return ret; + } + + mtk_pdata->peri_regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(mtk_pdata->peri_regmap)) { + dev_err(dev, "fail to get regmap: %d\n", (int)PTR_ERR(mtk_pdata->peri_regmap)); + return PTR_ERR(mtk_pdata->peri_regmap); + } + + return 0; +} + +static int eqos_probe_resources_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata; + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = eqos_get_base_addr_dt(dev); + if (ret) { + dev_err(dev, "eqos_get_base_addr_dt failed: %d\n", ret); + return ret; + } + + mtk_pdata = calloc(1, sizeof(struct eqos_mtk_priv)); + if (!mtk_pdata) + return -ENOMEM; + + pdata->priv_pdata = mtk_pdata; + + ret = mtk_config_dt(dev); + if (ret) { + dev_err(dev, "mtk config dt failed: %d\n", ret); + goto err; + } + + ret = mtk_clk_init(dev); + if (ret) + goto err; + + pdata->phy_interface = eqos->config->interface(dev); + if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + dev_err(dev, "Invalid PHY interface\n"); + ret = -EINVAL; + goto err; + } + + ret = mtk_set_interface(dev); + if (ret) + goto err; + + ret = mtk_set_delay(dev); + if (ret) + goto err; + + debug("%s: OK\n", __func__); + return 0; +err: + free(mtk_pdata); + return ret; +} + +static int eqos_remove_resources_mtk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + + debug("%s(dev=%p):\n", __func__, dev); + + free(mtk_pdata); + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_stop_clks_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_disable(&eqos->clk_ptp_ref); + clk_disable(&eqos->clk_tx); + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_start_clks_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + dev_err(dev, "clk_enable(mac_main) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_ptp_ref); + if (ret < 0) { + dev_err(dev, "clk_enable(ptp_ref) failed: %d", ret); + goto err_disable_clk_mac_main; + } + + debug("%s: OK\n", __func__); + return 0; + +err_disable_clk_mac_main: + clk_disable(&eqos->clk_tx); +err: + debug("%s: FAILED: %d\n", __func__, ret); + return ret; +} + +static int eqos_fix_mac_speed_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + + debug("%s(dev=%p):\n", __func__, dev); + + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + if (eqos->phy->speed == SPEED_1000) + regmap_update_bits(mtk_pdata->peri_regmap, + MT8189_PERI_ETH_CTRL0, + EQOS_MTK_RGMII_TXC_PHASE_CTRL | + EQOS_MTK_DLY_GTXC_ENABLE | + EQOS_MTK_DLY_GTXC_INV | + EQOS_MTK_DLY_GTXC_STAGE_FINE | + EQOS_MTK_DLY_GTXC_STAGES, + EQOS_MTK_RGMII_TXC_PHASE_CTRL); + else + mtk_set_delay(dev); + break; + default: + debug("%s: dev=%p no need to adjust mac delay\n", __func__, dev); + break; + } + + debug("%s: OK\n", __func__); + return 0; +} + +static struct eqos_ops eqos_mtk_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_mtk, + .eqos_remove_resources = eqos_remove_resources_mtk, + .eqos_stop_resets = eqos_null_ops, + .eqos_start_resets = eqos_null_ops, + .eqos_stop_clks = eqos_stop_clks_mtk, + .eqos_start_clks = eqos_start_clks_mtk, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_fix_mac_speed_mtk, + .eqos_get_enetaddr = eqos_null_ops, +}; + +struct eqos_config eqos_mtk_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .swr_wait = 10, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_60_100, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_mtk_ops +}; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index dc7e6f1929f..87b2b3426c8 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -686,7 +686,7 @@ static int ethoc_of_to_plat(struct udevice *dev) fdt_addr_t addr; pdata->eth_pdata.iobase = dev_read_addr(dev); - addr = devfdt_get_addr_index(dev, 1); + addr = dev_read_addr_index(dev, 1); if (addr != FDT_ADDR_T_NONE) pdata->packet_base = addr; return 0; diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index a4ba27904bc..f393af40e27 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -8,6 +8,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <fdt_support.h> #include <malloc.h> @@ -17,17 +18,25 @@ #include <asm/io.h> #include <pci.h> #include <miiphy.h> +#include <linux/bitfield.h> #include <linux/bug.h> #include <linux/delay.h> #include <linux/build_bug.h> +#include <linux/bitfield.h> +#include <power/regulator.h> +#include "fsl_enetc.h" #ifdef CONFIG_ARCH_IMX9 #include <asm/mach-imx/sys_proto.h> #include <cpu_func.h> +#include "fsl_enetc_xpcs_phy.c" +#else +static inline int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + return 0; +} #endif -#include "fsl_enetc.h" - #define ENETC_DRIVER_NAME "enetc_eth" /* @@ -66,10 +75,36 @@ static int enetc_is_ls1028a(struct udevice *dev) pplat->vendor == PCI_VENDOR_ID_FREESCALE; } +static int enetc_dev_id_imx(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_IMX952)) { + int bus_devfn; + u32 reg[5]; + int error; + + error = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg)); + if (error) + return error; + + bus_devfn = (reg[0] >> 8) & 0xffff; + + switch (bus_devfn) { + case 0: + return 0; + case 0x100: + return 1; + default: + return -EINVAL; + } + } + + return PCI_DEV(pci_get_devfn(dev)) >> 3; +} + static int enetc_dev_id(struct udevice *dev) { if (enetc_is_imx95(dev)) - return PCI_DEV(pci_get_devfn(dev)) >> 3; + return enetc_dev_id_imx(dev); if (enetc_is_ls1028a(dev)) return PCI_FUNC(pci_get_devfn(dev)); @@ -388,7 +423,7 @@ static int enetc_init_sgmii(struct udevice *dev) /* set up MAC for RGMII */ static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev) { - u32 old_val, val, dpx = 0; + u32 old_val, val = 0; old_val = val = enetc_read_mac_port(dev, ENETC_PM_IF_MODE); @@ -408,15 +443,14 @@ static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev) val |= ENETC_PM_IFM_SSP_10; } - if (enetc_is_imx95(dev)) - dpx = ENETC_PM_IFM_FULL_DPX_IMX; + if (enetc_is_imx95(dev)) + val = u32_replace_bits(val, + phydev->duplex == DUPLEX_FULL ? 0 : 1, + ENETC_PM_IFM_FULL_DPX_IMX); else if (enetc_is_ls1028a(dev)) - dpx = ENETC_PM_IFM_FULL_DPX_LS; - - if (phydev->duplex == DUPLEX_FULL) - val |= dpx; - else - val &= ~dpx; + val = u32_replace_bits(val, + phydev->duplex == DUPLEX_FULL ? 1 : 0, + ENETC_PM_IFM_FULL_DPX_LS); if (val == old_val) return; @@ -454,19 +488,23 @@ static void enetc_setup_mac_iface(struct udevice *dev, /* set up serdes for SXGMII */ static int enetc_init_sxgmii(struct udevice *dev) { - struct enetc_priv *priv = dev_get_priv(dev); - if (!enetc_has_imdio(dev)) return 0; - /* Dev ability - SXGMII */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); + if (enetc_is_imx95(dev)) { + xpcs_phy_usxgmii_pma_config(dev); + } else { + struct enetc_priv *priv = dev_get_priv(dev); - /* Restart PCS AN */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_CR, - ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + /* Dev ability - SXGMII */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); + + /* Restart PCS AN */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_CR, + ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + } return 0; } @@ -523,6 +561,10 @@ static int enetc_config_phy(struct udevice *dev) return -ENODEV; supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; + + if (enetc_is_imx95(dev)) + supported |= PHY_10G_FEATURES; + priv->phy->supported &= supported; priv->phy->advertising &= supported; @@ -537,12 +579,31 @@ static int enetc_probe(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); int res; + struct udevice *supply = NULL; if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_enabled(dev_ofnode(dev))) { enetc_dbg(dev, "interface disabled\n"); return -ENODEV; } + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + res = device_get_supply_regulator(dev, "serdes-supply", + &supply); + if (res && res != -ENOENT) { + printf("%s: device_get_supply_regulator failed: %d\n", + __func__, res); + return res; + } + + if (supply) { + res = regulator_set_enable_if_allowed(supply, true); + if (res) { + printf("%s: Error enabling phy supply\n", dev->name); + return res; + } + } + } + priv->enetc_txbd = memalign(ENETC_BD_ALIGN, sizeof(struct enetc_tx_bd) * ENETC_BD_CNT); priv->enetc_rxbd = memalign(ENETC_BD_ALIGN, diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 804df853bf5..6d868e82f8c 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -205,6 +205,7 @@ struct enetc_data { /* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */ #define ENETC_PCS_PHY_ADDR 0 +#define ENETC_NON_PCS_PHY_ADDR 16 /* PCS registers */ #define ENETC_PCS_CR 0x00 diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c index 8577bb75632..0c87d80ea5c 100644 --- a/drivers/net/fsl_enetc_netc_blk_ctrl.c +++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c @@ -35,6 +35,7 @@ #define MII_PROT_RGMII 0x2 #define MII_PROT_SERIAL 0x3 #define MII_PROT(port, prot) (((prot) & 0xf) << ((port) << 2)) +#define MII_PROT_GET(reg, port) (((reg) >> ((port) << 2)) & 0xf) #define IMX95_CFG_LINK_PCS_PROT(a) (0x8 + (a) * 4) #define PCS_PROT_1G_SGMII BIT(0) @@ -97,6 +98,9 @@ #define IMX94_TIMER1_ID 1 #define IMX94_TIMER2_ID 2 +#define IMX952_ENETC0_BUS_DEVFN 0x0 +#define IMX952_ENETC1_BUS_DEVFN 0x100 + /* Flags for different platforms */ #define NETC_HAS_NETCMIX BIT(0) @@ -567,6 +571,69 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv) return 0; } +static int imx952_netcmix_init(struct udevice *dev) +{ + struct netc_blk_ctrl *priv = dev_get_priv(dev); + ofnode child, gchild; + phy_interface_t interface; + int bus_devfn, mii_proto; + u32 val; + + /* Default setting */ + val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII); + + /* Update the link MII protocol through parsing phy-mode */ + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + ofnode_for_each_subnode(gchild, child) { + if (!ofnode_is_enabled(gchild)) + continue; + + if (!ofnode_device_is_compatible(gchild, "pci1131,e101")) + continue; + + bus_devfn = netc_of_pci_get_bus_devfn(gchild); + if (bus_devfn < 0) + return -EINVAL; + + interface = ofnode_read_phy_mode(gchild); + if (interface == -1) + continue; + + mii_proto = netc_get_link_mii_protocol(interface); + if (mii_proto < 0) + return -EINVAL; + + switch (bus_devfn) { + case IMX952_ENETC0_BUS_DEVFN: + val &= ~CFG_LINK_MII_PORT_0; + val |= FIELD_PREP(CFG_LINK_MII_PORT_0, mii_proto); + break; + case IMX952_ENETC1_BUS_DEVFN: + val &= ~CFG_LINK_MII_PORT_1; + val |= FIELD_PREP(CFG_LINK_MII_PORT_1, mii_proto); + break; + default: + return -EINVAL; + } + } + } + + if (MII_PROT_GET(val, 1) == MII_PROT_SERIAL) { + /* Configure Link I/O variant */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR, + IO_VAR(1, IO_VAR_16FF_16G_SERDES)); + /* Configure Link 2 PCS protocol */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(1), + PCS_PROT_2500M_SGMII); + } + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val); + + return 0; +} + static const struct netc_devinfo imx95_devinfo = { .netcmix_init = imx95_netcmix_init, .ierb_init = imx95_ierb_init, @@ -578,9 +645,14 @@ static const struct netc_devinfo imx94_devinfo = { .xpcs_port_init = imx94_netc_xpcs_port_init, }; +static const struct netc_devinfo imx952_devinfo = { + .netcmix_init = imx952_netcmix_init, +}; + static const struct udevice_id netc_blk_ctrl_match[] = { { .compatible = "nxp,imx95-netc-blk-ctrl", .data = (ulong)&imx95_devinfo }, { .compatible = "nxp,imx94-netc-blk-ctrl", .data = (ulong)&imx94_devinfo }, + { .compatible = "nxp,imx952-netc-blk-ctrl", .data = (ulong)&imx952_devinfo }, {}, }; diff --git a/drivers/net/fsl_enetc_xpcs_phy.c b/drivers/net/fsl_enetc_xpcs_phy.c new file mode 100644 index 00000000000..4039690223d --- /dev/null +++ b/drivers/net/fsl_enetc_xpcs_phy.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP + */ + +#define XPCS_PHY_GLOBAL 0x0 +#define XPCS_PHY_MPLLA 0x1 +#define XPCS_PHY_MPLLB 0x2 +#define XPCS_PHY_LANE 0x3 +#define XPCS_PHY_MAC_ADAPTER 0x1f + +#define XPCS_PHY_REG(x) (((x) & 0x1fffe) >> 1) + +/* MAC ADAPTER */ +#define MAC_ADAPTER_LOCK_PHY 0x200 +#define MAC_ADAPTER_LOCK_MPLLA 0x204 +#define MAC_ADAPTER_LOCK_MPLLB 0x208 +#define MAC_ADAPTER_LOCK_ROM 0x20c +#define MAC_ADAPTER_LOCK_RAM 0x210 +#define MAC_ADAPTER_LOCK_EVENT 0x214 + +#define MAC_ADAPTER_LOCK_LOCK BIT(7) + +/* PMA */ +#define PMA_RX_LSTS 0x10040 +#define PMA_RX_LSTS_RX_VALID_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL0 0x10060 +#define PMA_TX_GENCTRL0_TX_RST_0 BIT(8) +#define PMA_TX_GENCTRL0_TX_DT_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL1 0x10062 +#define PMA_TX_GENCTRL1_VBOOST_EN_0 BIT(4) +#define PMA_TX_GENCTRL1_VBOOST_LVL_MASK GENMASK(10, 8) +#define PMA_TX_GENCTRL1_VBOOST_LVL(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_TX_GENCTRL1_TX_CLK_RDY_0 BIT(12) +#define PMA_MP_12G_16G_TX_GENCTRL2 0x10064 +#define PMA_TX_GENCTRL2_TX_REQ_0 BIT(0) +#define PMA_TX_GENCTRL2_TX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_TX_GENCTRL2_TX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_25G_TX_BOOST_CTRL 0x10066 +#define PMA_TX_BOOST_CTRL_TX0_IBOOST_MASK GENMASK(3, 0) +#define PMA_TX_BOOST_CTRL_TX0_IBOOST(x) ((x) & GENMASK(3, 0)) +#define PMA_MP_12G_16G_25G_TX_RATE_CTRL 0x10068 +#define PMA_TX_RATE_CTRL_TX0_RATE_MASK GENMASK(2, 0) +#define PMA_TX_RATE_CTRL_TX0_RATE(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL 0x1006A +#define PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_POWER_STATE_CTRL_TX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_POWER_STATE_CTRL_TX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL0 0x1006C +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE(x) ((x) & GENMASK(5, 0)) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK GENMASK(13, 8) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN(x) (((x) << 8) & GENMASK(13, 8)) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL1 0x1006E +#define PMA_TX_EQ_CTRL1_TX_EQ_POST_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL1_TX_EQ_POST(x) ((x) & GENMASK(5, 0)) +#define PMA_MP_16G_25G_TX_MISC_CTRL0 0x1007C +#define PMA_TX_MISC_CTRL0_TX0_MISC_MASK GENMASK(7, 0) +#define PMA_TX_MISC_CTRL0_TX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_12G_16G_25G_RX_GENCTRL0 0x100A0 +#define PMA_RX_GENCTRL0_RX_DT_EN_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_GENCTRL1 0x100A2 +#define PMA_RX_GENCTRL1_RX_RST_0 BIT(4) +#define PMA_RX_GENCTRL1_RX_TERM_ACDC_0 BIT(8) +#define PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0 BIT(12) +#define PMA_MP_12G_16G_RX_GENCTRL2 0x100A4 +#define PMA_RX_GENCTRL2_RX_REQ_0 BIT(0) +#define PMA_RX_GENCTRL2_RX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_RX_GENCTRL2_RX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_RX_GENCTRL3 0x100A6 +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK GENMASK(2, 0) +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0(x) ((x) & GENMASK(2, 0)) +#define PMA_RX_GENCTRL3_LOS_LFPS_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_RX_RATE_CTRL 0x100A8 +#define PMA_RX_RATE_CTRL_RX0_RATE_MASK GENMASK(1, 0) +#define PMA_RX_RATE_CTRL_RX0_RATE(x) ((x) & GENMASK(1, 0)) +#define PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL 0x100AA +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_CDR_CTRL 0x100AC +#define PMA_RX_CDR_CTRL_CDR_SSC_EN_0 BIT(4) +#define PMA_MP_12G_16G_25G_RX_ATTN_CTRL 0x100AE +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL_MASK GENMASK(2, 0) +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_16G_25G_RX_EQ_CTRL0 0x100B0 +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK GENMASK(4, 0) +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0(x) ((x) & GENMASK(4, 0)) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK GENMASK(6, 5) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0(x) (((x) << 5) & GENMASK(6, 5)) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK GENMASK(10, 8) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK GENMASK(14, 12) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0(x) (((x) << 12) & GENMASK(14, 12)) +#define PMA_MP_12G_16G_25G_RX_EQ_CTRL4 0x100B8 +#define PMA_RX_EQ_CTRL4_CONT_ADAPT_0 BIT(0) +#define PMA_RX_EQ_CTRL4_RX_AD_REQ BIT(12) +#define PMA_MP_16G_25G_RX_EQ_CTRL5 0x100BA +#define PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0 BIT(0) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK GENMASK(5, 4) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE(x) (((x) << 4) & GENMASK(5, 4)) +#define PMA_MP_12G_16G_25G_DFE_TAP_CTRL0 0x100BC +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0_MASK GENMASK(7, 0) +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_RX_CDR_CTRL1 0x100C8 +#define PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0 BIT(0) +#define PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0 BIT(4) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK GENMASK(9, 8) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_16G_25G_RX_PPM_CTRL0 0x100CA +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX_MASK GENMASK(4, 0) +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(x) ((x) & GENMASK(4, 0)) +#define PMA_MP_16G_25G_RX_GENCTRL4 0x100D0 +#define PMA_RX_GENCTRL4_RX_DFE_BYP_0 BIT(8) +#define PMA_MP_16G_25G_RX_MISC_CTRL0 0x100D2 +#define PMA_RX_MISC_CTRL0_RX0_MISC_MASK GENMASK(7, 0) +#define PMA_RX_MISC_CTRL0_RX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_25G_RX_IQ_CTRL0 0x100D6 +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ_MASK GENMASK(6, 0) +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ(x) ((x) & GENMASK(6, 0)) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK GENMASK(11, 8) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ(x) (((x) << 8) & GENMASK(11, 8)) +#define PMA_MP_12G_16G_25G_MPLL_CMN_CTRL 0x100E0 +#define PMA_MPLL_CMN_CTRL_MPLL_EN_0 BIT(0) +#define PMA_MPLL_CMN_CTRL_MPLLB_SEL_0 BIT(4) +#define PMA_MP_12G_16G_MPLLA_CTRL0 0x100E2 +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_MPLLA_CTRL1 0x100E4 +#define PMA_MPLLA_CTRL1_MPLLA_SSC_EN BIT(0) +#define PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL BIT(4) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK GENMASK(15, 5) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL(x) (((x) << 5) & GENMASK(15, 5)) +#define PMA_MP_12G_16G_MPLLA_CTRL2 0x100E6 +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK GENMASK(6, 0) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT(x) ((x) & GENMASK(6, 0)) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN BIT(7) +#define PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN BIT(8) +#define PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN BIT(9) +#define PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN BIT(10) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK GENMASK(12, 11) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV(x) (((x) << 11) & GENMASK(12, 11)) +#define PMA_MP_16G_MPLLA_CTRL3 0x100EE +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH_MASK GENMASK(15, 0) +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(x) ((x) & GENMASK(15, 0)) +#define PMA_MP_16G_MPLLA_CTRL4 0x100F2 +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT_MASK GENMASK(11, 0) +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT(x) ((x) & GENMASK(11, 0)) +#define PMA_MP_16G_MPLLA_CTRL5 0x100F4 +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK(x) ((x) & GENMASK(7, 0)) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN BIT(8) +#define PMA_MP_12G_16G_25G_MISC_CTRL0 0x10120 +#define PMA_MISC_CTRL0_RX_VREF_CTRL_MASK GENMASK(12, 8) +#define PMA_MISC_CTRL0_RX_VREF_CTRL(x) (((x) << 8) & GENMASK(12, 8)) +#define PMA_MP_12G_16G_25G_REF_CLK_CTRL 0x10122 +#define PMA_REF_CLK_CTRL_REF_CLK_DIV2 BIT(2) +#define PMA_REF_CLK_CTRL_REF_RANGE_MASK GENMASK(5, 3) +#define PMA_REF_CLK_CTRL_REF_RANGE(x) (((x) << 3) & GENMASK(5, 3)) +#define PMA_REF_CLK_CTRL_REF_MPLLA_DIV2 BIT(6) +#define PMA_MP_12G_16G_25G_VCO_CAL_LD0 0x10124 +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0_MASK GENMASK(12, 0) +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0(x) ((x) & GENMASK(12, 0)) +#define PMA_MP_16G_25G_VCO_CAL_REF0 0x1012C +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0_MASK GENMASK(6, 0) +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0(x) ((x) & GENMASK(6, 0)) +#define PMA_MP_12G_16G_25G_MISC_STS 0x10130 +#define PMA_MISC_STS_RX_ADPT_ACK BIT(12) +#define PMA_MP_12G_16G_25G_SRAM 0x10136 +#define PMA_SRAM_INIT_DN BIT(0) +#define PMA_SRAM_EXT_LD_DN BIT(1) +#define PMA_MP_16G_25G_MISC_CTRL2 0x10138 +#define PMA_MISC_CTRL2_SUP_MISC_MASK GENMASK(7, 0) +#define PMA_MISC_CTRL2_SUP_MISC(x) ((x) & GENMASK(7, 0)) + +/* PCS */ +#define PCS_CTRL1 0x0 +#define PCS_CTRL1_RESET BIT(15) +#define PCS_CTRL2 0xE +#define PCS_CTRL2_PCS_TYPE_SEL_MASK GENMASK(3, 0) +#define PCS_CTRL2_PCS_TYPE_SEL(x) ((x) & GENMASK(3, 0)) +#define PCS_DIG_CTRL1 0x10000 +#define PCS_DIG_CTRL1_USXG_EN BIT(9) +#define PCS_DIG_CTRL1_USRA_RST BIT(10) +#define PCS_DIG_CTRL1_VR_RST BIT(15) +#define PCS_DEBUG_CTRL 0x1000A +#define PCS_DEBUG_CTRL_SUPRESS_LOS_DET BIT(4) +#define PCS_DEBUG_CTRL_RX_DT_EN_CTL BIT(6) +#define PCS_DEBUG_CTRL_TX_PMBL_CTL BIT(8) +#define PCS_KR_CTRL1 0x1000E +#define PCS_KR_CTRL1_USXG_MODE_MASK GENMASK(12, 10) +#define PCS_KR_CTRL1_USXG_MODE(x) (((x) << 10) & GENMASK(12, 10)) + +/* VS MII MMD */ +#define MII_CTRL 0x0 +#define MII_CTRL_SS5 BIT(5) +#define MII_CTRL_SS6 BIT(6) +#define MII_CTRL_AN_ENABLE BIT(12) +#define MII_CTRL_SS13 BIT(13) +#define MII_DIG_CTRL1 0x10000 +#define MII_DIG_CTRL1_CL37_TMR_OVR_RIDE BIT(3) +#define MII_AN_CTRL 0x10002 +#define MII_AN_CTRL_MII_AN_INTR_EN BIT(0) +#define MII_AN_CTRL_TX_CONFIG BIT(3) +#define MII_AN_INTR_STS 0x10004 +#define MII_AN_INTR_STS_CL37_ANCMPLT_INTR BIT(0) +#define MII_LINK_TIMER_CTRL 0x10014 +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME_MASK GENMASK(15, 0) +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME(x) ((x) & GENMASK(15, 0)) + +/* E16 MEM MAP */ +#define IDCODE_LO 0x0 +#define IDCODE_HI 0x4 +#define GLOBAL_CTRL_EX_0 0x114 +#define GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS BIT(0) +#define L0_RX_VCO_OVRD_OUT_0 0x20c +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE_MASK GENMASK(12, 3) +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE(x) (((x) << 3) & GENMASK(12, 3)) +#define L0_RX_VCO_OVRD_OUT_0_RX_CDR_FREQ_TUNE_OVRD_EN BIT(15) +#define L0_RX_VCO_OVRD_OUT_2 0x214 +#define L0_RX_VCO_OVRD_OUT_2_RX_ANA_CDR_FREQ_TUNE_CLK BIT(0) + +static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg); +static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val); + +int xpcs_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_phy_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read_pma(struct udevice *dev, u32 reg) +{ + return xpcs_read(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg)); +} + +int xpcs_phy_write_pma(struct udevice *dev, int reg, u16 val) +{ + return xpcs_write(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg), val); +} + +int xpcs_phy_usxgmii_init_seq_2(struct udevice *dev) +{ + ulong begin; + u16 val; + + /* Seq 2.1 Keep preamble data */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_TX_PMBL_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* Seq 2.2 Power up MPLLA to P1 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 2, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.3 Assert request of transmitand receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.4 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* Seq 2.5 Turn transmit to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 0, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val &= ~PMA_POWER_STATE_CTRL_TX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.6 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* Seq 2.7 Enable transmitter output driver in the PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* Seq 2.8 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* Seq 2.9 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.10 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + return 0; + +timeout: + return -ETIMEDOUT; +} + +void xpcs_phy_reg_lock(struct udevice *dev) +{ + u16 val; + ulong begin; + + if (xpcs_phy_read(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY)) & MAC_ADAPTER_LOCK_LOCK) + return; + + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLA), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLB), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_ROM), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_RAM), MAC_ADAPTER_LOCK_LOCK); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* Work around */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_CTRL1_RESET); + + mdelay(1); + +timeout: + return; +} + +int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + ulong begin; + u16 val; + + xpcs_phy_reg_lock(dev); + + /* 1.6 Turn off C37 auto-negotiation */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_AN_ENABLE; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + /* 1.7 Assert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.8 Wait for more than 1us */ + udelay(5); + + /* 1.9 Deassert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.10 Power down MPLLA */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* 1.11 Change RX0 power state to P2 */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val &= ~PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* TODO: check if it is needed */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 1, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 1.12 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 1.13 Poll for acknlowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 2 Config MPLL for 10G XGMII */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val = u16_replace_bits(val, 6, PMA_REF_CLK_CTRL_REF_RANGE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val &= ~PMA_REF_CLK_CTRL_REF_CLK_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val |= PMA_REF_CLK_CTRL_REF_MPLLA_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val = u16_replace_bits(val, 5, PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL4, 0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 33, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val = u16_replace_bits(val, 5, PMA_TX_GENCTRL1_VBOOST_LVL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0); + val = u16_replace_bits(val, 0x11, PMA_MISC_CTRL0_RX_VREF_CTRL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0, val); + + val = PMA_MISC_CTRL2_SUP_MISC(1); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_MISC_CTRL2, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_PPM_CTRL0, val); + + /* 3 Configure LANE0 for 10G XGMII */ + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_TX_MISC_CTRL0, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLLB_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_TX_BOOST_CTRL_TX0_IBOOST(0xf); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_BOOST_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0, PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + val = PMA_TX_EQ_CTRL1_TX_EQ_POST(0x20); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0x20, PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x2, PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val = u16_replace_bits(val, 0x7, PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_CDR_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val &= ~PMA_RX_GENCTRL3_LOS_LFPS_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_ATTN_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_DFE_TAP_CTRL0, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_TERM_ACDC_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val &= ~PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + /* 4 Configure XPCS for 10G XGMII */ + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL2), 0x0); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_USXG_EN; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1)); + val = u16_replace_bits(val, 0x0, PCS_KR_CTRL1_USXG_MODE_MASK); + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1), val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 0x21, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_CONT_ADAPT_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val &= ~PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* 5 Assert soft reset */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_VR_RST; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + /* 6 Poll for SRAM initialization done */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* 7 Assert SRAM external loading done */ + /* Workaround */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + /* 8 Poll for vendor-specific soft reset */ + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_DIG_CTRL1_VR_RST); + + /* 9 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 10 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* 11 Assert request of receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 11.1 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 12 Assert TX0 clock is active and stable */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* + * 13.1 Configure XPCS to consider Loss-of-Signal indicated by the + * PHY while evaluating the receive link status + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_SUPRESS_LOS_DET; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + /* + * 13.2 Configure XPCS to deassert "receiver data enable" on + * detecting of Loss-of-Signal + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_RX_DT_EN_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* 14 Poll for DPLL lock status for Lane 0 */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_RX_LSTS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_RX_LSTS_RX_VALID_0)); + + /* 15 Assert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 16 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_STS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_MISC_STS_RX_ADPT_ACK)); + + /* 17 Deassert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val &= ~PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 18 Set the value of Config_Reg to 0 for Clause 37 autonegotiation. */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL)); + val &= ~MII_AN_CTRL_TX_CONFIG; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL), val); + + /* 19 Select XGMII speed */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_SS5; + val |= MII_CTRL_SS6 | MII_CTRL_SS13; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + val = xpcs_phy_usxgmii_init_seq_2(dev); + if (val) + return val; + + return 0; + +timeout: + return -ETIMEDOUT; +} + +u32 xpcs_phy_get_id(struct udevice *dev) +{ + int ret; + u32 id; + + /* First, search C73 PCS using PCS MMD */ + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_HI)); + if (ret < 0) + return 0xffffffff; + + id = ret << 16; + + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_LO)); + if (ret < 0) + return 0xffffffff; + + /* If Device IDs are not all zeros or all ones, + * we found C73 AN-type device + */ + if ((id | ret) && (id | ret) != 0xffffffff) + return id | ret; + + return 0xffffffff; +} diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 62182f922f8..7dda8cb8815 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -401,9 +401,6 @@ static void hisi_femac_get_strings(struct udevice *dev, u8 *data) strcpy(data + i * ETH_GSTRING_LEN, hisi_femac_stats_table[i].name); } -/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - static void hisi_femac_get_stats(struct udevice *dev, u64 *data) { int i; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index cbf5f605518..bea1dfed892 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -38,9 +38,13 @@ #include <linux/mii.h> #include <asm/io.h> #include <linux/dma-mapping.h> -#include <asm/arch/clk.h> #include <linux/errno.h> +/* Without CLK, we rely on the arch definition */ +#if !defined(CONFIG_CLK) +#include <asm/arch/clk.h> +#endif + #include "macb.h" DECLARE_GLOBAL_DATA_PTR; @@ -768,18 +772,40 @@ static int macb_phy_init(struct udevice *dev, const char *name) lpa); } else { /* if macb port is a fixed link */ - /* TODO : manage gigabit capable processors */ + const char *human_readable_speed; + speed = macb->speed; duplex = macb->duplex; + switch (speed) { + case 2: + human_readable_speed = "1000"; + break; + case 1: + human_readable_speed = "100"; + break; + case 0: + human_readable_speed = "10"; + break; + default: + printf("%s: speed %d not supported\n", name, speed); + return -EINVAL; + } printf("%s: link up, %sMbps %s-duplex\n", name, - speed ? "100" : "10", + human_readable_speed, duplex ? "full" : "half"); } ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); - if (speed) { + if (speed == 2) { + if (!gem_is_gigabit_capable(macb)) { + printf("%s: is not gigabit Ethernet capable\n", name); + return -EINVAL; + } + ncfgr |= GEM_BIT(GBE); + ret = macb_linkspd_cb(dev, _1000BASET); + } else if (speed == 1) { ncfgr |= MACB_BIT(SPD); ret = macb_linkspd_cb(dev, _100BASET); } else { @@ -923,26 +949,39 @@ static int _macb_init(struct udevice *dev, const char *name) /* Check the multi queue and initialize the queue for tx */ gmac_init_multi_queues(macb); - /* - * When the GMAC IP with GE feature, this bit is used to - * select interface between RGMII and GMII. - * When the GMAC IP without GE feature, this bit is used - * to select interface between RMII and MII. + /* This driver uses the user I/O to select the PHY features, + * but some GEM instances come with a fixed configuration and + * no USERIO. */ - if (macb->phy_interface == PHY_INTERFACE_MODE_RGMII || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) - val = macb->config->usrio->rgmii; - else if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) - val = macb->config->usrio->rmii; - else if (macb->phy_interface == PHY_INTERFACE_MODE_MII) - val = macb->config->usrio->mii; + if (gem_readl(macb, DCFG1) & GEM_BIT(USERIO)) { + /* + * When the GMAC IP with GE feature, this bit is used to + * select interface between RGMII and GMII. + * When he GMAC IP without GE feature, this bit is used + * to select interface between RMII and MII. + */ + switch (macb->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + val = macb->config->usrio->rgmii; + break; + case PHY_INTERFACE_MODE_RMII: + val = macb->config->usrio->rmii; + break; + case PHY_INTERFACE_MODE_MII: + val = macb->config->usrio->mii; + break; + default: + break; + } - if (macb->config->caps & MACB_CAPS_USRIO_HAS_CLKEN) - val |= macb->config->usrio->clken; + if (macb->config->caps & MACB_CAPS_USRIO_HAS_CLKEN) + val |= macb->config->usrio->clken; - gem_writel(macb, USRIO, val); + gem_writel(macb, USRIO, val); + } if (macb->phy_interface == PHY_INTERFACE_MODE_SGMII) { unsigned int ncfgr = macb_readl(macb, NCFGR); @@ -1003,9 +1042,14 @@ static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) /* set hardware address */ hwaddr_bottom = enetaddr[0] | enetaddr[1] << 8 | enetaddr[2] << 16 | enetaddr[3] << 24; - macb_writel(macb, SA1B, hwaddr_bottom); hwaddr_top = enetaddr[4] | enetaddr[5] << 8; - macb_writel(macb, SA1T, hwaddr_top); + if (macb_is_gem(macb)) { + gem_writel(macb, SA1B, hwaddr_bottom); + gem_writel(macb, SA1T, hwaddr_top); + } else { + macb_writel(macb, SA1B, hwaddr_bottom); + macb_writel(macb, SA1T, hwaddr_top); + } return 0; } @@ -1307,7 +1351,9 @@ static int macb_eth_of_to_plat(struct udevice *dev) macb->phy_addr = PHY_MAX_ADDR + 1; macb->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex"); speed_fdt = fdtdec_get_int(blob, fl_node, "speed", 0); - if (speed_fdt == 100) { + if (speed_fdt == 1000) { + macb->speed = 2; + } else if (speed_fdt == 100) { macb->speed = 1; } else if (speed_fdt == 10) { macb->speed = 0; diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 0eb90574618..002d5bd31b2 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -443,6 +443,8 @@ #define MACB_REV_SIZE 16 /* Bitfields in DCFG1. */ +#define GEM_USERIO_OFFSET 9 +#define GEM_USERIO_SIZE 1 #define GEM_IRQCOR_OFFSET 23 #define GEM_IRQCOR_SIZE 1 #define GEM_DBWDEF_OFFSET 25 diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index 9bf887035d7..79ad6348de8 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -112,7 +112,7 @@ uint mii_send(uint mii_cmd) ep->eir = FEC_EIR_MII; /* clear MII complete */ #ifdef ET_DEBUG printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n", - __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply); + __FILE__, __LINE__, __func__, mii_cmd, mii_reply); #endif return (mii_reply & 0xffff); /* data read from phy */ diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index 5d4e54ab90e..7d58f542bde 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -5,6 +5,7 @@ config MEDIATEK_ETH select PHYLIB select DM_GPIO select DM_RESET + select LMB_LIMIT_DMA_BELOW_RAM_TOP help This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 107a33aa9f5..4dc738980cb 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -256,8 +256,8 @@ static void set_dram_access(struct mvgbe_registers *regs) win_param.access_ctrl = EWIN_ACCESS_FULL; win_param.high_addr = 0; /* Get bank base and size */ - win_param.base_addr = gd->bd->bi_dram[i].start; - win_param.size = gd->bd->bi_dram[i].size; + win_param.base_addr = gd->dram[i].start; + win_param.size = gd->dram[i].size; if (win_param.size == 0) win_param.enable = 0; else diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index f9e979c4d58..ae5920a0201 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -4528,7 +4528,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) */ if (phy_dev && phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ - dev_warn(port->phy_dev->dev, + dev_warn(dev, "Marking phy as invalid, link will not be checked\n"); /* set phy_addr to invalid value */ port->phyaddr = PHY_MAX_ADDR; @@ -4540,7 +4540,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) port->phy_dev = phy_dev; if (!phy_dev) { - dev_err(port->phy_dev->dev, "cannot connect to phy\n"); + dev_err(dev, "cannot connect to phy\n"); return; } phy_dev->supported &= PHY_GBIT_FEATURES; @@ -4731,33 +4731,32 @@ static int mvpp2_port_init(struct udevice *dev, struct mvpp2_port *port) static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) { - int port_node = dev_of_offset(dev); - int phy_node; + ofnode port_node = dev_ofnode(dev); + ofnode phy_node; u32 id; int phyaddr = 0; - int fixed_link = 0; + ofnode fixed_link; int ret; - phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); - fixed_link = fdt_subnode_offset(gd->fdt_blob, port_node, "fixed-link"); + phy_node = ofnode_parse_phandle(port_node, "phy", 0); + fixed_link = ofnode_find_subnode(port_node, "fixed-link"); - if (phy_node > 0) { - int parent; + if (ofnode_valid(phy_node)) { + ofnode parent; - if (fixed_link != -FDT_ERR_NOTFOUND) { + if (ofnode_valid(fixed_link)) { /* phy_addr is set to invalid value for fixed links */ phyaddr = PHY_MAX_ADDR; } else { - phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, - "reg", 0); + phyaddr = ofnode_read_s32_default(phy_node, "reg", 0); if (phyaddr < 0) { dev_err(dev, "could not find phy address\n"); return -1; } } - parent = fdt_parent_offset(gd->fdt_blob, phy_node); - ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent, - &port->mdio_dev); + parent = ofnode_get_parent(phy_node); + ret = uclass_get_device_by_ofnode(UCLASS_MDIO, parent, + &port->mdio_dev); if (ret) return ret; } else { @@ -4771,7 +4770,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) return -EINVAL; } - id = fdtdec_get_int(gd->fdt_blob, port_node, "port-id", -1); + id = dev_read_s32_default(dev, "port-id", -1); if (id == -1) { dev_err(dev, "missing port-id value\n"); return -EINVAL; @@ -4812,7 +4811,7 @@ static void mvpp2_gpio_init(struct mvpp2_port *port) /* Ports initialization */ static int mvpp2_port_probe(struct udevice *dev, struct mvpp2_port *port, - int port_node, + ofnode port_node, struct mvpp2 *priv) { int err; @@ -5296,16 +5295,16 @@ static int mvpp2_base_probe(struct udevice *dev) } /* Save base addresses for later use */ - priv->base = devfdt_get_addr_index_ptr(dev, 0); + priv->base = dev_read_addr_index_ptr(dev, 0); if (!priv->base) return -EINVAL; if (priv->hw_version == MVPP21) { - priv->lms_base = devfdt_get_addr_index_ptr(dev, 1); + priv->lms_base = dev_read_addr_index_ptr(dev, 1); if (!priv->lms_base) return -EINVAL; } else { - priv->iface_base = devfdt_get_addr_index_ptr(dev, 1); + priv->iface_base = dev_read_addr_index_ptr(dev, 1); if (!priv->iface_base) return -EINVAL; @@ -5346,13 +5345,11 @@ static int mvpp2_probe(struct udevice *dev) if (priv->hw_version == MVPP21) { int priv_common_regs_num = 2; - port->base = devfdt_get_addr_index_ptr( - dev->parent, priv_common_regs_num + port->id); + port->base = dev_read_addr_index_ptr(dev->parent, priv_common_regs_num + port->id); if (!port->base) return -EINVAL; } else { - port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "gop-port-id", -1); + port->gop_id = ofnode_read_s32_default(dev_ofnode(dev), "gop-port-id", -1); if (port->gop_id == -1) { dev_err(dev, "missing gop-port-id value\n"); return -EINVAL; @@ -5376,7 +5373,7 @@ static int mvpp2_probe(struct udevice *dev) priv->probe_done = 1; } - err = mvpp2_port_probe(dev, port, dev_of_offset(dev), priv); + err = mvpp2_port_probe(dev, port, dev_ofnode(dev), priv); if (err) return err; @@ -5437,13 +5434,11 @@ static struct driver mvpp2_driver = { */ static int mvpp2_base_bind(struct udevice *parent) { - const void *blob = gd->fdt_blob; - int node = dev_of_offset(parent); struct uclass_driver *drv; struct udevice *dev; struct eth_pdata *plat; char *name; - int subnode; + ofnode subnode; u32 id; int base_id_add; @@ -5456,19 +5451,19 @@ static int mvpp2_base_bind(struct udevice *parent) base_id_add = base_id; - fdt_for_each_subnode(subnode, blob, node) { + dev_for_each_subnode(subnode, parent) { /* Increment base_id for all subnodes, also the disabled ones */ base_id++; /* Skip disabled ports */ - if (!fdtdec_get_is_enabled(blob, subnode)) + if (!ofnode_is_enabled(subnode)) continue; plat = calloc(1, sizeof(*plat)); if (!plat) return -ENOMEM; - id = fdtdec_get_int(blob, subnode, "port-id", -1); + id = ofnode_read_s32_default(subnode, "port-id", -1); id += base_id_add; name = calloc(1, 16); @@ -5479,8 +5474,7 @@ static int mvpp2_base_bind(struct udevice *parent) sprintf(name, "mvpp2-%d", id); /* Create child device UCLASS_ETH and bind it */ - device_bind(parent, &mvpp2_driver, name, plat, - offset_to_ofnode(subnode), &dev); + device_bind(parent, &mvpp2_driver, name, plat, subnode, &dev); } return 0; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5d2277a4602..ee438524490 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -7,7 +7,7 @@ config MV88E6352_SWITCH menuconfig PHYLIB bool "Ethernet PHY (physical media interface) support" - depends on NET || NET_LWIP + depends on NET help Enable Ethernet PHY (physical media interface) support. @@ -81,7 +81,7 @@ config PHYLIB_10G config PHY_ADIN bool "Analog Devices Industrial Ethernet PHYs" help - Add support for configuring RGMII on Analog Devices ADIN PHYs. + Add support for configuring RGMII on Analog Devices ADIN PHYs. menuconfig PHY_AQUANTIA bool "Aquantia Ethernet PHYs support" @@ -126,9 +126,9 @@ config SYS_CORTINA_NO_FW_UPLOAD bool "Cortina firmware loading support" depends on PHY_CORTINA help - Cortina phy has provision to store phy firmware in attached dedicated - EEPROM. And boards designed with such EEPROM does not require firmware - upload. + Cortina phy has provision to store phy firmware in attached dedicated + EEPROM. And boards designed with such EEPROM does not require firmware + upload. choice prompt "Location of the Cortina firmware" @@ -167,7 +167,7 @@ config PHY_CORTINA_ACCESS default y depends on CORTINA_NI_ENET help - Cortina Access Ethernet PHYs init process + Cortina Access Ethernet PHYs init process config PHY_DAVICOM bool "Davicom Ethernet PHYs support" @@ -233,7 +233,7 @@ config PHY_MICREL_KSZ8XXX endif # PHY_MICREL config PHY_MOTORCOMM - tristate "Motorcomm PHYs" + bool "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. Currently supports the YT8511 and YT8531 Gigabit Ethernet PHYs. @@ -246,7 +246,7 @@ config PHY_NATSEMI bool "National Semiconductor Ethernet PHYs support" config PHY_NXP_C45_TJA11XX - tristate "NXP C45 TJA11XX PHYs" + bool "NXP C45 TJA11XX PHYs" select DEVRES help Enable support for NXP C45 TJA11XX PHYs. @@ -317,13 +317,13 @@ config PHY_TERANETICS config PHY_TI bool "Texas Instruments Ethernet PHYs support" - ---help--- + help Adds PHY registration support for TI PHYs. config PHY_TI_DP83867 select PHY_TI bool "Texas Instruments Ethernet DP83867 PHY support" - ---help--- + help Adds support for the TI DP83867 1Gbit PHY. config SPL_PHY_TI_DP83867 @@ -333,13 +333,13 @@ config SPL_PHY_TI_DP83867 config PHY_TI_DP83869 select PHY_TI bool "Texas Instruments Ethernet DP83869 PHY support" - ---help--- + help Adds support for the TI DP83869 1Gbit PHY. config PHY_TI_GENERIC select PHY_TI bool "Texas Instruments Generic Ethernet PHYs support" - ---help--- + help Adds support for Generic TI PHYs that don't need special handling but the PHY name is associated with a PHY ID. @@ -381,7 +381,7 @@ config PHY_FIXED config PHY_NCSI bool "NC-SI based PHY" - depends on NET + depends on NET_LEGACY endif #PHYLIB diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index ce448810ff6..4d42e56dada 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/bitfield.h> +#define PHY_ID_ADIN1200 0x0283bc20 #define PHY_ID_ADIN1300 0x0283bc30 #define ADIN1300_EXT_REG_PTR 0x10 #define ADIN1300_EXT_REG_DATA 0x11 @@ -263,6 +264,18 @@ static int adin1300_config(struct phy_device *phydev) return genphy_config(phydev); } +U_BOOT_PHY_DRIVER(ADIN1200) = { + .name = "ADIN1200", + .uid = PHY_ID_ADIN1200, + .mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .config = adin1300_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, + .readext = adin_extread, + .writeext = adin_extwrite, +}; + U_BOOT_PHY_DRIVER(ADIN1300) = { .name = "ADIN1300", .uid = PHY_ID_ADIN1300, diff --git a/drivers/net/phy/airoha/Kconfig b/drivers/net/phy/airoha/Kconfig index da8747939e3..2d58d674200 100644 --- a/drivers/net/phy/airoha/Kconfig +++ b/drivers/net/phy/airoha/Kconfig @@ -2,11 +2,25 @@ menuconfig PHY_AIROHA bool "Airoha Ethernet PHYs support" +config PHY_AIROHA_AN8801 + bool "Airoha Ethernet AN8801 support" + depends on PHY_AIROHA + select PHY_AIROHA_PHYLIB + help + Currently support AIROHA AN8801 1G PHY. + config PHY_AIROHA_EN8811 bool "Airoha Ethernet EN8811H support" depends on PHY_AIROHA depends on SUPPORTS_FW_LOADER select FW_LOADER + select PHY_AIROHA_PHYLIB + select PHY_COMMON_PROPS help AIROHA EN8811H supported. AIROHA AN8811HB supported. + +config PHY_AIROHA_PHYLIB + bool + help + Airoha Ethernet PHY common library diff --git a/drivers/net/phy/airoha/Makefile b/drivers/net/phy/airoha/Makefile index 84d23b19ab0..25e44004cfd 100644 --- a/drivers/net/phy/airoha/Makefile +++ b/drivers/net/phy/airoha/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_AIROHA_AN8801) += air_an8801.o obj-$(CONFIG_PHY_AIROHA_EN8811) += air_en8811.o +obj-$(CONFIG_PHY_AIROHA_PHYLIB) += air_phy_lib.o diff --git a/drivers/net/phy/airoha/air_an8801.c b/drivers/net/phy/airoha/air_an8801.c new file mode 100644 index 00000000000..9d9958fc665 --- /dev/null +++ b/drivers/net/phy/airoha/air_an8801.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * air_an8801.c - PHY driver for Airoha AN8801. + * Copyright (c) 2026 Airoha Technology Corp. + * Copyright (C) 2026 BayLibre, SAS. + * Author: Kevin-KW Huang <[email protected]> + * Sita Huang <[email protected]> + * Julien Stephan <[email protected]> + */ + +#include <malloc.h> +#include <phy.h> +#include <dm/device_compat.h> + +#include "air_phy_lib.h" + +#define AN8801R_PHY_ID1 0xc0ff +#define AN8801R_PHY_ID2 0x0421 +#define AN8801R_PHY_ID ((u32)((AN8801R_PHY_ID1 << 16) | AN8801R_PHY_ID2)) + +#define AN8801R_MAX_LED_SIZE 3 + +/* MII Registers - Airoha Page 4 */ +#define AN8801_PBUS_ACCESS BIT(28) + +/* BPBUS Registers */ +#define AN8801_BPBUS_REG_LED_GPIO 0x54 +#define AN8801_BPBUS_REG_LED_ID_SEL 0x58 +#define LED_ID_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3)) + +#define AN8801_BPBUS_REG_GPIO_MODE 0x70 + +#define AN8801_BPBUS_REG_LINK_MODE 0x5054 +#define AN8801_BPBUS_LINK_MODE_1000 BIT(0) + +#define AN8801_BPBUS_REG_BYPASS_PTP 0x21c004 +#define AN8801_BYP_PTP_RGMII_TO_GPHY BIT(0) + +#define AN8801_BPBUS_REG_TXDLY_STEP 0x21c024 +#define RGMII_DELAY_STEP_MASK GENMASK(2, 0) +#define AIR_RGMII_DELAY_NOSTEP 0 +#define AIR_RGMII_DELAY_STEP_1 1 +#define AIR_RGMII_DELAY_STEP_2 2 +#define AIR_RGMII_DELAY_STEP_3 3 +#define AIR_RGMII_DELAY_STEP_4 4 +#define AIR_RGMII_DELAY_STEP_5 5 +#define AIR_RGMII_DELAY_STEP_6 6 +#define AIR_RGMII_DELAY_STEP_7 7 +#define RGMII_TXDELAY_FORCE_MODE BIT(24) + +#define AN8801_BPBUS_REG_RXDLY_STEP 0x21c02c +#define RGMII_RXDELAY_ALIGN BIT(4) +#define RGMII_RXDELAY_FORCE_MODE BIT(24) + +#define AN8801_BPBUS_REG_EFIFO_CTL(x) (0x270004 + (0x100 * (x))) /* 0..2 */ +#define AN8801_EFIFO_ALL_EN GENMASK(7, 0) +#define AN8801_EFIFO_RX_EN BIT(0) +#define AN8801_EFIFO_TX_EN BIT(1) +#define AN8801_EFIFO_RX_CLK_EN BIT(2) +#define AN8801_EFIFO_TX_CLK_EN BIT(3) +#define AN8801_EFIFO_RX_EEE_EN BIT(4) +#define AN8801_EFIFO_TX_EEE_EN BIT(5) +#define AN8801_EFIFO_RX_ODD_NIBBLE_EN BIT(6) +#define AN8801_EFIFO_TX_ODD_NIBBLE_EN BIT(7) + +#define AN8801_BPBUS_REG_HWRST_DE_GLITCH 0xc8 +#define AN8801_DE_GLITCH_EN BIT(2) +#define AN8801_11_CYCLE_XTAL_PERIOD_DE_GLITCH GENMASK(1, 0) + +#define LED_BCR 0x21 +#define LED_BCR_MODE_MASK GENMASK(1, 0) +#define LED_BCR_TIME_TEST BIT(2) +#define LED_BCR_CLK_EN BIT(3) +#define LED_BCR_EVT_ALL BIT(4) +#define LED_BCR_EXT_CTRL BIT(15) +#define LED_BCR_MODE_DISABLE 0 +#define LED_BCR_MODE_2LED 1 +#define LED_BCR_MODE_3LED_1 2 +#define LED_BCR_MODE_3LED_2 3 + +#define LED_ON_DUR 0x22 +#define LED_ON_DUR_MASK GENMASK(15, 0) + +#define LED_BLINK_DUR 0x23 +#define LED_BLINK_DUR_MASK GENMASK(15, 0) + +#define LED_ON_CTRL(i) (0x024 + ((i) * 2)) +#define LED_ON_EVT_MASK GENMASK(6, 0) +#define LED_ON_EVT_LINK_1000M BIT(0) +#define LED_ON_EVT_LINK_100M BIT(1) +#define LED_ON_EVT_LINK_10M BIT(2) +#define LED_ON_EVT_LINK_DN BIT(3) +#define LED_ON_EVT_FDX BIT(4) +#define LED_ON_EVT_HDX BIT(5) +#define LED_ON_EVT_FORCE BIT(6) +#define LED_ON_POL BIT(14) +#define LED_ON_EN BIT(15) + +#define LED_BLINK_CTRL(i) (0x025 + ((i) * 2)) +#define LED_BLINK_EVT_MASK GENMASK(9, 0) +#define LED_BLINK_EVT_1000M_TX BIT(0) +#define LED_BLINK_EVT_1000M_RX BIT(1) +#define LED_BLINK_EVT_100M_TX BIT(2) +#define LED_BLINK_EVT_100M_RX BIT(3) +#define LED_BLINK_EVT_10M_TX BIT(4) +#define LED_BLINK_EVT_10M_RX BIT(5) +#define LED_BLINK_EVT_FORCE BIT(9) + +#define UNIT_LED_BLINK_DURATION 780 +#define LED_BLINK_DURATION(f) (UNIT_LED_BLINK_DURATION << (f)) + +/* Link on(1G/100M/10M), no activity */ +#define AIR_LED0_ON \ + (LED_ON_EVT_LINK_1000M | LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M) +#define AIR_LED0_BLINK 0x0 +/* No link on, activity(1G/100M/10M TX/RX) */ +#define AIR_LED1_ON 0x0 +#define AIR_LED1_BLINK \ + (LED_BLINK_EVT_1000M_TX | LED_BLINK_EVT_1000M_RX | \ + LED_BLINK_EVT_100M_TX | LED_BLINK_EVT_100M_RX | \ + LED_BLINK_EVT_10M_TX | LED_BLINK_EVT_10M_RX) +/* Link on(100M/10M), activity(100M/10M TX/RX) */ +#define AIR_LED2_ON \ + (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M) +#define AIR_LED2_BLINK \ + (LED_BLINK_EVT_100M_TX | LED_BLINK_EVT_100M_RX | \ + LED_BLINK_EVT_10M_TX | LED_BLINK_EVT_10M_RX) + +#define INVALID_DATA GENMASK(31, 0) + +#define AN8801_REG_PHY_INTERNAL0 0x600 +#define AN8801_REG_PHY_INTERNAL1 0x601 + +#define AN8801_LED_ENABLE 1 + +enum air_led_gpio_pin { + AIR_LED_GPIO1 = 1, + AIR_LED_GPIO2, + AIR_LED_GPIO3 +}; + +enum air_led { + AIR_LED0 = 0, + AIR_LED1, + AIR_LED2, + AIR_LED3 +}; + +enum air_led_blink_dut { + AIR_LED_BLINK_DUR_32M = 0, + AIR_LED_BLINK_DUR_64M, + AIR_LED_BLINK_DUR_128M, + AIR_LED_BLINK_DUR_256M, + AIR_LED_BLINK_DUR_512M, + AIR_LED_BLINK_DUR_1024M, + AIR_LED_BLINK_DUR_LAST +}; + +enum air_led_polarity { + AIR_ACTIVE_LOW = 0, + AIR_ACTIVE_HIGH, +}; + +enum air_led_mode { + AIR_LED_MODE_DISABLE = 0, + AIR_LED_MODE_USER_DEFINE, + AIR_LED_MODE_LAST +}; + +struct air_led_cfg { + u16 led_en; + u16 gpio; + u16 led_polarity; + u16 led_on_cfg; + u16 led_blk_cfg; +}; + +struct an8801r_priv { + struct air_led_cfg led_cfg[AN8801R_MAX_LED_SIZE]; + u32 led_blink_cfg; + u8 rxdelay_force; + u8 txdelay_force; + u16 rxdelay_step; + u8 rxdelay_align; + u16 txdelay_step; +}; + +#define phydev_cfg(phy) ((struct an8801r_priv *)(phy)->priv) + +/* + * GPIO1 <-> LED0, + * GPIO2 <-> LED1, + * GPIO3 <-> LED2, + */ +static const struct an8801r_priv an8801r_priv_defaults = { + .led_cfg = { + /* LED Enable, GPIO, LED Polarity, LED ON, LED Blink */ + {AN8801_LED_ENABLE, AIR_LED_GPIO1, AIR_ACTIVE_LOW, AIR_LED0_ON, AIR_LED0_BLINK}, + {AN8801_LED_ENABLE, AIR_LED_GPIO2, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLINK}, + {AN8801_LED_ENABLE, AIR_LED_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLINK}, + }, + .led_blink_cfg = AIR_LED_BLINK_DUR_64M, + .rxdelay_force = false, + .txdelay_force = false, + .rxdelay_step = AIR_RGMII_DELAY_NOSTEP, + .rxdelay_align = false, + .txdelay_step = AIR_RGMII_DELAY_NOSTEP, +}; + +static int an8801_buckpbus_reg_rmw(struct phy_device *phydev, + u32 addr, u32 mask, u32 set) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, set); +} + +static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, mask); +} + +static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, 0); +} + +static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr, u32 data) +{ + return air_phy_buckpbus_reg_write(phydev, addr | AN8801_PBUS_ACCESS, data); +} + +static int an8801r_led_set_usr_def(struct phy_device *phydev, u8 entity, + u16 polar, u16 on_evt, u16 blk_evt) +{ + int ret; + + if (polar == AIR_ACTIVE_HIGH) + on_evt |= LED_ON_POL; + else + on_evt &= ~LED_ON_POL; + + on_evt |= LED_ON_EN; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity), on_evt); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(entity), blk_evt); +} + +static int an8801r_led_set_blink(struct phy_device *phydev, u16 blink) +{ + int ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR, + LED_BLINK_DURATION(blink)); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR, + LED_BLINK_DURATION(blink) / 2); +} + +static int an8801r_led_set_mode(struct phy_device *phydev, u8 mode) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BCR); + if (ret < 0) + return ret; + + switch (mode) { + case AIR_LED_MODE_DISABLE: + ret &= ~LED_BCR_EXT_CTRL; + ret &= ~LED_BCR_MODE_MASK; + ret |= LED_BCR_MODE_DISABLE; + break; + case AIR_LED_MODE_USER_DEFINE: + ret |= LED_BCR_EXT_CTRL | LED_BCR_CLK_EN; + break; + } + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BCR, ret); +} + +static int an8801r_led_set_state(struct phy_device *phydev, u8 entity, u8 state) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity)); + if (ret < 0) + return ret; + + if (state) + ret |= LED_ON_EN; + else + ret &= ~LED_ON_EN; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity), ret); +} + +static int an8801r_led_init(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + struct air_led_cfg *led_cfg = priv->led_cfg; + u16 led_blink_cfg = priv->led_blink_cfg; + int ret, led_id; + + ret = an8801r_led_set_blink(phydev, led_blink_cfg); + if (ret) + return ret; + + ret = an8801r_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED mode, ret %d!\n", ret); + return ret; + } + + for (led_id = AIR_LED0; led_id < AN8801R_MAX_LED_SIZE; led_id++) { + ret = an8801r_led_set_state(phydev, led_id, led_cfg[led_id].led_en); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED%d state, ret %d!\n", + led_id, ret); + return ret; + } + + if (!led_cfg[led_id].led_en) + continue; + + ret = an8801_buckpbus_reg_set_bits(phydev, AN8801_BPBUS_REG_LED_GPIO, + BIT(led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_set_bits(phydev, AN8801_BPBUS_REG_LED_ID_SEL, + LED_ID_GPIO_SEL(led_id, + led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_clear_bits(phydev, AN8801_BPBUS_REG_GPIO_MODE, + BIT(led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801r_led_set_usr_def(phydev, led_id, + led_cfg[led_id].led_polarity, + led_cfg[led_id].led_on_cfg, + led_cfg[led_id].led_blk_cfg); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED%d, ret %d!\n", + led_id, ret); + return ret; + } + } + return 0; +} + +static int an8801r_of_init(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + ofnode node = phy_get_ofnode(phydev); + u32 val = 0; + int ret; + + if (!ofnode_valid(node)) + return -EINVAL; + + if (ofnode_has_property(node, "airoha,rxclk-delay")) { + ret = ofnode_read_u32(node, "airoha,rxclk-delay", &val); + if (ret) { + dev_err(phydev->dev, "airoha,rxclk-delay value is invalid.\n"); + return ret; + } + if (val > AIR_RGMII_DELAY_STEP_7) { + dev_err(phydev->dev, "airoha,rxclk-delay value %u out of range.\n", val); + return -EINVAL; + } + priv->rxdelay_force = true; + priv->rxdelay_step = val; + priv->rxdelay_align = ofnode_read_bool(node, + "airoha,rxclk-delay-align"); + } + + if (ofnode_has_property(node, "airoha,txclk-delay")) { + ret = ofnode_read_u32(node, "airoha,txclk-delay", &val); + if (ret) { + dev_err(phydev->dev, "airoha,txclk-delay value is invalid.\n"); + return ret; + } + if (val > AIR_RGMII_DELAY_STEP_7) { + dev_err(phydev->dev, "airoha,txclk-delay value %u out of range.\n", val); + return -EINVAL; + } + priv->txdelay_force = true; + priv->txdelay_step = val; + } + return 0; +} + +static int an8801r_rgmii_rxdelay(struct phy_device *phydev, u16 delay, u8 align) +{ + u32 reg_val = delay & RGMII_DELAY_STEP_MASK; + int ret; + + if (align) { + reg_val |= RGMII_RXDELAY_ALIGN; + debug("AN8801R: Rxdelay align\n"); + } + reg_val |= RGMII_RXDELAY_FORCE_MODE; + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP, reg_val); + if (ret) + return ret; + + debug("AN8801R: Force rxdelay = %d(0x%x)\n", delay, reg_val); + return 0; +} + +static int an8801r_rgmii_txdelay(struct phy_device *phydev, u16 delay) +{ + u32 reg_val = delay & RGMII_DELAY_STEP_MASK; + int ret; + + reg_val |= RGMII_TXDELAY_FORCE_MODE; + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP, reg_val); + if (ret) + return ret; + + debug("AN8801R: Force txdelay = %d(0x%x)\n", delay, reg_val); + return 0; +} + +static int an8801r_rgmii_delay_config(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + int ret; + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII_TXID: + return an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4); + case PHY_INTERFACE_MODE_RGMII_RXID: + return an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, true); + case PHY_INTERFACE_MODE_RGMII_ID: + ret = an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4); + if (ret) + return ret; + return an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, true); + case PHY_INTERFACE_MODE_RGMII: + default: + if (priv->rxdelay_force) { + ret = an8801r_rgmii_rxdelay(phydev, priv->rxdelay_step, + priv->rxdelay_align); + if (ret) + return ret; + } + if (priv->txdelay_force) + return an8801r_rgmii_txdelay(phydev, priv->txdelay_step); + return 0; + } +} + +static int an8801r_config_init(struct phy_device *phydev) +{ + int ret; + + ret = an8801r_of_init(phydev); + if (ret < 0) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_HWRST_DE_GLITCH, + AN8801_DE_GLITCH_EN | + AN8801_11_CYCLE_XTAL_PERIOD_DE_GLITCH); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0, 0x1e); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1, 0x02); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP, + AN8801_BYP_PTP_RGMII_TO_GPHY); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0), + AN8801_EFIFO_RX_EN | + AN8801_EFIFO_TX_EN | + AN8801_EFIFO_RX_CLK_EN | + AN8801_EFIFO_TX_CLK_EN | + AN8801_EFIFO_RX_EEE_EN | + AN8801_EFIFO_TX_EEE_EN); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret = an8801r_rgmii_delay_config(phydev); + if (ret) + return ret; + + ret = an8801r_led_init(phydev); + if (ret) { + dev_err(phydev->dev, "AN8801R: LED initialize fail, ret %d!\n", ret); + return ret; + } + return 0; +} + +static int an8801r_phy_probe(struct phy_device *phydev) +{ + struct an8801r_priv *priv; + u32 phy_id; + int ret; + + ret = get_phy_id(phydev->bus, phydev->addr, MDIO_DEVAD_NONE, &phy_id); + if (ret) + return ret; + + if (phy_id != AN8801R_PHY_ID) { + dev_err(phydev->dev, + "AN8801R can't be detected (id=0x%08x).\n", phy_id); + return -ENODEV; + } + + priv = malloc(sizeof(*priv)); + if (!priv) + return -ENOMEM; + + *priv = an8801r_priv_defaults; + + phydev->priv = priv; + + return 0; +} + +static int an8801r_read_status(struct phy_device *phydev) +{ + u32 data; + + if (!phydev->link) + return 0; + + debug("AN8801R: SPEED %d\n", phydev->speed); + data = phydev->speed == SPEED_1000 ? AN8801_BPBUS_LINK_MODE_1000 : 0; + + return an8801_buckpbus_reg_rmw(phydev, AN8801_BPBUS_REG_LINK_MODE, + AN8801_BPBUS_LINK_MODE_1000, data); +} + +static int an8801r_startup(struct phy_device *phydev) +{ + int ret; + + ret = genphy_startup(phydev); + if (ret) + return ret; + + return an8801r_read_status(phydev); +} + +U_BOOT_PHY_DRIVER(an8801r) = { + .name = "Airoha AN8801R", + .uid = AN8801R_PHY_ID, + .mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES, + .probe = &an8801r_phy_probe, + .config = &an8801r_config_init, + .read_page = &air_phy_read_page, + .write_page = &air_phy_write_page, + .startup = &an8801r_startup, + .shutdown = &genphy_shutdown, +}; diff --git a/drivers/net/phy/airoha/air_en8811.c b/drivers/net/phy/airoha/air_en8811.c index 0b974472732..7a07be2e956 100644 --- a/drivers/net/phy/airoha/air_en8811.c +++ b/drivers/net/phy/airoha/air_en8811.c @@ -23,6 +23,9 @@ #include <linux/compat.h> #include <dm/device_compat.h> #include <u-boot/crc.h> +#include <linux/phy/phy-common-props.h> + +#include "air_phy_lib.h" /* MII Registers */ #define AIR_AUX_CTRL_STATUS 0x1d @@ -32,10 +35,6 @@ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc -#define AIR_EXT_PAGE_ACCESS 0x1f -#define AIR_PHY_PAGE_STANDARD 0x0000 -#define AIR_PHY_PAGE_EXTENDED_4 0x0004 - #define AIR_PBUS_MODE_ADDR_HIGH 0x1c /* MII Registers Page 4 */ #define AIR_BPBUS_MODE 0x10 @@ -309,166 +308,6 @@ static int air_pbus_reg_write(struct phy_device *phydev, return ret; } -static int air_buckpbus_reg_write(struct phy_device *phydev, - u32 pbus_address, u32 pbus_data) -{ - int ret, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data)); - if (ret < 0) - goto restore_page; - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - -static int air_buckpbus_reg_read(struct phy_device *phydev, - u32 pbus_address, u32 *pbus_data) -{ - int pbus_data_low, pbus_data_high; - int ret = 0, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) { - ret = pbus_data_high; - goto restore_page; - } - - pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) { - ret = pbus_data_low; - goto restore_page; - } - - *pbus_data = pbus_data_low | (pbus_data_high << 16); - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - -static int air_buckpbus_reg_modify(struct phy_device *phydev, - u32 pbus_address, u32 mask, u32 set) -{ - int pbus_data_low, pbus_data_high; - u32 pbus_data_old, pbus_data_new; - int ret = 0, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) { - ret = pbus_data_high; - goto restore_page; - } - - pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) { - ret = pbus_data_low; - goto restore_page; - } - - pbus_data_old = pbus_data_low | (pbus_data_high << 16); - pbus_data_new = (pbus_data_old & ~mask) | set; - if (pbus_data_new == pbus_data_old) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data_new)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data_new)); - if (ret < 0) - goto restore_page; - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - static int air_write_buf(struct phy_device *phydev, unsigned long address, unsigned long array_size, const unsigned char *buffer) { @@ -539,12 +378,12 @@ static int an8811hb_check_crc(struct phy_device *phydev, u32 pbus_value; /* Configure CRC */ - ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, - AN8811HB_CRC_RD_EN); + ret = air_phy_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, + AN8811HB_CRC_RD_EN); if (ret < 0) return ret; - ret = air_buckpbus_reg_read(phydev, set1, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, set1, &pbus_value); if (ret < 0) return ret; @@ -553,14 +392,14 @@ static int an8811hb_check_crc(struct phy_device *phydev, do { mdelay(300); - ret = air_buckpbus_reg_read(phydev, mon2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, mon2, &pbus_value); if (ret < 0) return ret; debug("%d: reg 0x%x val 0x%x!\n", __LINE__, mon2, pbus_value); if (pbus_value & AN8811HB_CRC_ST) { - ret = air_buckpbus_reg_read(phydev, mon3, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, mon3, &pbus_value); if (ret < 0) return ret; @@ -584,11 +423,11 @@ static int an8811hb_check_crc(struct phy_device *phydev, } } while (--retry); - ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, 0); + ret = air_phy_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, 0); if (ret < 0) return ret; - ret = air_buckpbus_reg_read(phydev, set1, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, set1, &pbus_value); if (ret < 0) return ret; @@ -646,9 +485,9 @@ static int an8811hb_surge_protect_cfg(struct phy_device *phydev) return ret; } - ret = air_buckpbus_reg_modify(phydev, AIR_PHY_CONTROL, - AIR_PHY_CONTROL_SURGE_5R, - AIR_PHY_CONTROL_SURGE_5R); + ret = air_phy_buckpbus_reg_modify(phydev, AIR_PHY_CONTROL, + AIR_PHY_CONTROL_SURGE_5R, + AIR_PHY_CONTROL_SURGE_5R); if (ret < 0) return ret; @@ -706,14 +545,14 @@ static int en8811h_load_firmware(struct phy_device *phydev) goto en8811h_load_firmware_out; } - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, - EN8811H_FW_CTRL_2_LOADING); + ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, + EN8811H_FW_CTRL_2_LOADING); if (ret < 0) goto en8811h_load_firmware_out; @@ -727,13 +566,13 @@ static int en8811h_load_firmware(struct phy_device *phydev) if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, 0); + ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, 0); if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); if (ret < 0) goto en8811h_load_firmware_out; @@ -741,8 +580,8 @@ static int en8811h_load_firmware(struct phy_device *phydev) if (ret < 0) goto en8811h_load_firmware_out; - air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, - &priv->firmware_version); + air_phy_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, + &priv->firmware_version); dev_info(phydev->dev, "MD32 firmware version: %08x\n", priv->firmware_version); @@ -778,8 +617,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_START); if (ret < 0) goto an8811hb_load_firmware_out; @@ -803,8 +642,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_FINISH); if (ret < 0) goto an8811hb_load_firmware_out; @@ -817,7 +656,7 @@ static int an8811hb_load_firmware(struct phy_device *phydev) do { mdelay(300); - ret = air_buckpbus_reg_read(phydev, AIR_PHY_FW_CTRL_1, ®_val); + ret = air_phy_buckpbus_reg_read(phydev, AIR_PHY_FW_CTRL_1, ®_val); if (ret < 0) goto an8811hb_load_firmware_out; @@ -827,8 +666,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) debug("%d: reg 0x%x val 0x%x!\n", __LINE__, AIR_PHY_FW_CTRL_1, reg_val); - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_FINISH); if (ret < 0) goto an8811hb_load_firmware_out; @@ -838,8 +677,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - air_buckpbus_reg_read(phydev, AIR_PHY_MD32FW_VERSION, - &priv->firmware_version); + air_phy_buckpbus_reg_read(phydev, AIR_PHY_MD32FW_VERSION, + &priv->firmware_version); debug("MD32 firmware version: %08x\n", priv->firmware_version); @@ -858,17 +697,17 @@ int an8811hb_cko_cfg(struct phy_device *phydev) int ret = 0; if (!ofnode_read_bool(node, "airoha,phy-output-clock")) { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, - AN8811HB_CLK_DRV_CKO_MASK, - AN8811HB_CLK_DRV_CKOPWD | - AN8811HB_CLK_DRV_CKO_LDPWD | - AN8811HB_CLK_DRV_CKO_LPPWD); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, + AN8811HB_CLK_DRV_CKO_MASK, + AN8811HB_CLK_DRV_CKOPWD | + AN8811HB_CLK_DRV_CKO_LDPWD | + AN8811HB_CLK_DRV_CKO_LPPWD); if (ret < 0) return ret; debug("CKO Output mode - Disabled\n"); } else { - ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); if (ret < 0) return ret; @@ -887,13 +726,13 @@ static int en8811h_restart_mcu(struct phy_device *phydev) if (ret < 0) return ret; - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) return ret; - return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); + return air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); } static int air_led_hw_control_set(struct phy_device *phydev, u8 index, @@ -1046,11 +885,51 @@ static int air_leds_init(struct phy_device *phydev, int num, u16 dur, int mode) return 0; } -static int en8811h_config(struct phy_device *phydev) +static int en8811h_config_serdes_polarity(struct phy_device *phydev) { - struct en8811h_priv *priv = phydev->priv; ofnode node = phy_get_ofnode(phydev); + unsigned int pol, default_pol; u32 pbus_value = 0; + int ret; + + if (!ofnode_valid(node)) + return 0; + + default_pol = PHY_POL_NORMAL; + if (ofnode_read_bool(node, "airoha,pnswap-rx")) + default_pol = PHY_POL_INVERT; + + ret = phy_get_rx_polarity(node, + phy_string_for_interface(phydev->interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + if (ret) + return ret; + if (pol == PHY_POL_INVERT) + pbus_value |= EN8811H_POLARITY_RX_REVERSE; + + default_pol = PHY_POL_NORMAL; + if (ofnode_read_bool(node, "airoha,pnswap-tx")) + default_pol = PHY_POL_INVERT; + + ret = phy_get_tx_polarity(node, + phy_string_for_interface(phydev->interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + if (ret) + return ret; + if (pol == PHY_POL_NORMAL) + pbus_value |= EN8811H_POLARITY_TX_NORMAL; + + return air_phy_buckpbus_reg_modify(phydev, EN8811H_POLARITY, + EN8811H_POLARITY_RX_REVERSE | + EN8811H_POLARITY_TX_NORMAL, + pbus_value); +} + +static int en8811h_config(struct phy_device *phydev) +{ + struct en8811h_priv *priv = phydev->priv; int ret = 0; /* If restart happened in .probe(), no need to restart now */ @@ -1081,20 +960,8 @@ static int en8811h_config(struct phy_device *phydev) if (ret < 0) return ret; - /* Serdes polarity */ - pbus_value = 0; - if (ofnode_read_bool(node, "airoha,pnswap-rx")) - pbus_value |= EN8811H_POLARITY_RX_REVERSE; - else - pbus_value &= ~EN8811H_POLARITY_RX_REVERSE; - if (ofnode_read_bool(node, "airoha,pnswap-tx")) - pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; - else - pbus_value |= EN8811H_POLARITY_TX_NORMAL; - ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, - EN8811H_POLARITY_RX_REVERSE | - EN8811H_POLARITY_TX_NORMAL, - pbus_value); + /* Configure Serdes polarity from device tree */ + ret = en8811h_config_serdes_polarity(phydev); if (ret < 0) return ret; @@ -1142,12 +1009,12 @@ static int an8811hb_config(struct phy_device *phydev) priv->mcu_needs_restart = true; } - ret = air_buckpbus_reg_read(phydev, AN8811HB_PRO_ID, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_PRO_ID, &pbus_value); if (ret < 0) return ret; priv->pro_id = (pbus_value & AN8811HB_PRO_ID_VERSION) + 1; - ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); if (ret < 0) return ret; priv->pkg_sel = (pbus_value & AN8811HB_HWTRAP2_PKG) >> 12; @@ -1163,8 +1030,8 @@ static int an8811hb_config(struct phy_device *phydev) pbus_value |= AN8811HB_RX_POLARITY_NORMAL; debug("1 pbus_value 0x%x\n", pbus_value); - ret = air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, - AN8811HB_RX_POLARITY_NORMAL, pbus_value); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, + AN8811HB_RX_POLARITY_NORMAL, pbus_value); if (ret < 0) return ret; @@ -1175,35 +1042,35 @@ static int an8811hb_config(struct phy_device *phydev) pbus_value |= AN8811HB_TX_POLARITY_NORMAL; debug("2 pbus_value 0x%x\n", pbus_value); - ret = air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, - AN8811HB_TX_POLARITY_NORMAL, pbus_value); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, + AN8811HB_TX_POLARITY_NORMAL, pbus_value); if (ret < 0) return ret; /* Configure led gpio pins as output */ if (priv->pkg_sel) { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, - AN8811HB_GPIO_OUTPUT_MASK, - AN8811HB_GPIO_OUTPUT_0115); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, + AN8811HB_GPIO_OUTPUT_MASK, + AN8811HB_GPIO_OUTPUT_0115); if (ret < 0) return ret; - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_1, - AN8811HB_GPIO_SEL_1_0_MASK | - AN8811HB_GPIO_SEL_1_1_MASK, - AN8811HB_GPIO_SEL_1_0 | - AN8811HB_GPIO_SEL_1_1); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_1, + AN8811HB_GPIO_SEL_1_0_MASK | + AN8811HB_GPIO_SEL_1_1_MASK, + AN8811HB_GPIO_SEL_1_0 | + AN8811HB_GPIO_SEL_1_1); if (ret < 0) return ret; - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_2, - AN8811HB_GPIO_SEL_2_15_MASK, - AN8811HB_GPIO_SEL_2_15); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_2, + AN8811HB_GPIO_SEL_2_15_MASK, + AN8811HB_GPIO_SEL_2_15); if (ret < 0) return ret; } else { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, - AN8811HB_GPIO_OUTPUT_345, - AN8811HB_GPIO_OUTPUT_345); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, + AN8811HB_GPIO_OUTPUT_345, + AN8811HB_GPIO_OUTPUT_345); if (ret < 0) return ret; } @@ -1373,16 +1240,6 @@ static int en8811h_probe(struct phy_device *phydev) return 0; } -static int air_phy_read_page(struct phy_device *phydev) -{ - return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS); -} - -static int air_phy_write_page(struct phy_device *phydev, int page) -{ - return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page); -} - U_BOOT_PHY_DRIVER(en8811h) = { .name = "Airoha EN8811H", .uid = EN8811H_PHY_ID, diff --git a/drivers/net/phy/airoha/air_phy_lib.c b/drivers/net/phy/airoha/air_phy_lib.c new file mode 100644 index 00000000000..61c3bf82822 --- /dev/null +++ b/drivers/net/phy/airoha/air_phy_lib.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Airoha Ethernet PHY common library + * + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud <[email protected]> + * + * Adapated from https://lore.kernel.org/all/20260326-add-airoha-an8801-support-v2-2-1a42d6b6050f@collabora.com/ + */ + +#include <dm/device_compat.h> +#include <linux/compat.h> +#include <phy.h> + +#include "air_phy_lib.h" + +#define AIR_EXT_PAGE_ACCESS 0x1f + +static int __air_buckpbus_reg_read(struct phy_device *phydev, + u32 pbus_address, u32 *pbus_data) +{ + int pbus_data_low, pbus_data_high; + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +} + +static int __air_buckpbus_reg_write(struct phy_device *phydev, + u32 pbus_address, u32 pbus_data) +{ + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data)); + if (ret < 0) + return ret; + + return 0; +} + +static int __air_buckpbus_reg_modify(struct phy_device *phydev, + u32 pbus_address, u32 mask, u32 set) +{ + int pbus_data_low, pbus_data_high; + u32 pbus_data_old, pbus_data_new; + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + pbus_data_old = pbus_data_low | (pbus_data_high << 16); + pbus_data_new = (pbus_data_old & ~mask) | set; + if (pbus_data_new == pbus_data_old) + return 0; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + return 0; +} + +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_write(phydev, pbus_address, + pbus_data); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, + set); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_read_page(struct phy_device *phydev) +{ + return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS); +} + +int air_phy_write_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page); +} + +MODULE_DESCRIPTION("Airoha PHY Library"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Louis-Alexis Eyraud"); diff --git a/drivers/net/phy/airoha/air_phy_lib.h b/drivers/net/phy/airoha/air_phy_lib.h new file mode 100644 index 00000000000..845d2f7cfb4 --- /dev/null +++ b/drivers/net/phy/airoha/air_phy_lib.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud <[email protected]> + */ + +#ifndef __AIR_PHY_LIB_H +#define __AIR_PHY_LIB_H + +#define AIR_EXT_PAGE_ACCESS 0x1f + +#define AIR_PHY_PAGE_STANDARD 0x0000 +#define AIR_PHY_PAGE_EXTENDED_1 0x0001 +#define AIR_PHY_PAGE_EXTENDED_4 0x0004 + +/* MII Registers Page 4*/ +#define AIR_BPBUS_MODE 0x10 +#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 +#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) +#define AIR_BPBUS_WR_ADDR_HIGH 0x11 +#define AIR_BPBUS_WR_ADDR_LOW 0x12 +#define AIR_BPBUS_WR_DATA_HIGH 0x13 +#define AIR_BPBUS_WR_DATA_LOW 0x14 +#define AIR_BPBUS_RD_ADDR_HIGH 0x15 +#define AIR_BPBUS_RD_ADDR_LOW 0x16 +#define AIR_BPBUS_RD_DATA_HIGH 0x17 +#define AIR_BPBUS_RD_DATA_LOW 0x18 + +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set); +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data); +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data); +int air_phy_read_page(struct phy_device *phydev); +int air_phy_write_page(struct phy_device *phydev, int page); + +#endif /* __AIR_PHY_LIB_H */ diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 10b87dfb8ab..83da3e1cc77 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -400,7 +400,7 @@ int aquantia_config(struct phy_device *phydev) int interface = phydev->interface; u32 val, id, rstatus, fault; u32 reg_val1 = 0; - int num_retries = 5; + int num_retries = 200; int usx_an = 0; /* diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 7ce03b59b6a..ebed61de133 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -203,32 +203,24 @@ static int dp83867_of_init(struct phy_device *phydev) "Should be 'rgmii-id' to use internal delays\n"); } - /* RX delay *must* be specified if internal delay of RX is used. */ + dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_00_NS; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { ret = ofnode_read_u32(node, "ti,rx-internal-delay", &dp83867->rx_id_delay); - if (ret) { - pr_debug("ti,rx-internal-delay must be specified\n"); - return ret; - } - if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { + if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { pr_debug("ti,rx-internal-delay value of %u out of range\n", dp83867->rx_id_delay); return -EINVAL; } } - /* TX delay *must* be specified if internal delay of RX is used. */ + dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_00_NS; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { ret = ofnode_read_u32(node, "ti,tx-internal-delay", &dp83867->tx_id_delay); - if (ret) { - debug("ti,tx-internal-delay must be specified\n"); - return ret; - } - if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { + if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { pr_debug("ti,tx-internal-delay value of %u out of range\n", dp83867->tx_id_delay); return -EINVAL; diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index a65e81dff0c..d96970949bc 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -23,6 +23,7 @@ #define PHY_ID_VSC8502 0x00070630 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 +#define PHY_ID_VSC8572 0x000704d0 #define PHY_ID_VSC8574 0x000704a0 #define PHY_ID_VSC8584 0x000707c0 @@ -1612,6 +1613,16 @@ U_BOOT_PHY_DRIVER(vsc8541) = { .shutdown = &genphy_shutdown, }; +U_BOOT_PHY_DRIVER(vsc8572) = { + .name = "Microsemi VSC8572", + .uid = PHY_ID_VSC8572, + .mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8574_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + U_BOOT_PHY_DRIVER(vsc8574) = { .name = "Microsemi VSC8574", .uid = PHY_ID_VSC8574, diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index a1e4c3d053b..9814ac498ed 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -343,7 +343,7 @@ static int nxp_c45_probe(struct phy_device *phydev) { struct nxp_c45_phy *priv; - priv = devm_kzalloc(phydev->priv, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/net/qe/dm_qe_uec.c b/drivers/net/qe/dm_qe_uec.c index ac3aedd8b49..f9bc5d49c8f 100644 --- a/drivers/net/qe/dm_qe_uec.c +++ b/drivers/net/qe/dm_qe_uec.c @@ -1133,7 +1133,7 @@ static int qe_uec_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = (phys_addr_t)dev_read_addr(dev); pdata->phy_interface = dev_read_phy_mode(dev); if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 5b093623619..e203faed26b 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -404,7 +404,7 @@ static int rtl8169_init_board(unsigned long dev_iobase, const char *name) u32 tmp; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -534,7 +534,7 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase, int length = 0; #ifdef DEBUG_RTL8169_RX - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -608,7 +608,7 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase, #ifdef DEBUG_RTL8169_TX int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); printf("sending %d bytes\n", len); #endif @@ -679,7 +679,7 @@ static void rtl8169_set_rx_mode(void) u32 tmp = 0; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif /* IFF_ALLMULTI */ @@ -701,7 +701,7 @@ static void rtl8169_hw_start(struct udevice *dev) #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif #if 0 @@ -771,7 +771,7 @@ static void rtl8169_init_ring(struct udevice *dev) #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif tpc->cur_rx = 0; @@ -810,7 +810,7 @@ static void rtl8169_common_start(struct udevice *dev, unsigned char *enetaddr, #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -851,7 +851,7 @@ static void rtl_halt_common(struct udevice *dev) int i; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = priv->iobase; @@ -906,7 +906,7 @@ static int rtl_init(unsigned long dev_ioaddr, const char *name, int option = -1, Cap10_100 = 0, Cap1000 = 0; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_ioaddr; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 0ea50c484c0..e1daeb6c1e6 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,7 +15,7 @@ /* * Structure definitions for network protocols. Since this file is used for - * both NET and NET_LWIP, and given that the two network stacks do have + * both NET_LEGACY and NET_LWIP, and given that the two network stacks do have * conflicting types (for instance struct icmp_hdr), it is on purpose that the * structures are defined locally with minimal dependencies -- <asm/types.h> is * included for the bit types and that's it. diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index 93c3a0c35f2..2d72af8aade 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -14,7 +14,7 @@ config DRIVER_TI_EMAC bool "TI Davinci EMAC" depends on ARCH_DAVINCI || ARCH_OMAP2PLUS help - Support for davinci emac + Support for davinci emac config DRIVER_TI_EMAC_USE_RMII depends on DRIVER_TI_EMAC @@ -26,7 +26,7 @@ config DRIVER_TI_KEYSTONE_NET bool "TI Keystone 2 Ethernet" depends on ARCH_KEYSTONE help - This driver supports the TI Keystone 2 Ethernet subsystem + This driver supports the TI Keystone 2 Ethernet subsystem choice prompt "TI Keystone 2 Ethernet NETCP IP revision" diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c index d7746f454ba..7a7cb83bd98 100644 --- a/drivers/net/ti/cpsw.c +++ b/drivers/net/ti/cpsw.c @@ -33,6 +33,7 @@ #define PKT_MAX (1500 + 14 + 4 + 4) #define CLEAR_BIT 1 #define GIGABITEN BIT(7) +#define GMII_EN BIT(5) #define FULLDUPLEXEN BIT(0) #define MIIEN BIT(15) #define CTL_EXT_EN BIT(18) @@ -216,6 +217,10 @@ struct cpsw_priv { u32 phy_mask; }; +struct cpsw_driver_data { + void (*gmii_sel)(struct cpsw_priv *priv, phy_interface_t phy_mode); +}; + static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) { int idx; @@ -1064,9 +1069,17 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv, writel(reg, priv->data->gmii_sel); } -static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat, - phy_interface_t phy_mode) +static void cpsw_phy_sel(struct cpsw_priv *priv, phy_interface_t phy_mode) { + const char *compat = priv->data->phy_sel_compat; + const struct cpsw_driver_data *drv_data = + (const struct cpsw_driver_data *)dev_get_driver_data(priv->dev); + + if (drv_data && drv_data->gmii_sel) { + drv_data->gmii_sel(priv, phy_mode); + return; + } + if (!strcmp(compat, "ti,am3352-cpsw-phy-sel")) cpsw_gmii_sel_am3352(priv, phy_mode); if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel")) @@ -1084,8 +1097,7 @@ static int cpsw_eth_probe(struct udevice *dev) priv->data = pdata->priv_pdata; ti_cm_get_macid(dev, priv->data, pdata->enetaddr); /* Select phy interface in control module */ - cpsw_phy_sel(priv, priv->data->phy_sel_compat, - pdata->phy_interface); + cpsw_phy_sel(priv, pdata->phy_interface); return _cpsw_register(priv); } @@ -1122,33 +1134,13 @@ static void cpsw_eth_of_parse_slave(struct cpsw_platform_data *data, "max-speed", 0); } -static int cpsw_eth_of_to_plat(struct udevice *dev) +static int cpsw_eth_of_to_plat_legacy(struct udevice *dev, + struct cpsw_platform_data *data) { - struct eth_pdata *pdata = dev_get_plat(dev); - struct cpsw_platform_data *data; - struct gpio_desc *mode_gpios; int slave_index = 0; - int num_mode_gpios; ofnode subnode; int ret; - data = calloc(1, sizeof(struct cpsw_platform_data)); - if (!data) - return -ENOMEM; - - pdata->priv_pdata = data; - pdata->iobase = dev_read_addr(dev); - data->version = CPSW_CTRL_VERSION_2; - data->bd_ram_ofs = CPSW_BD_OFFSET; - data->ale_reg_ofs = CPSW_ALE_OFFSET; - data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET; - data->mdio_div = CPSW_MDIO_DIV; - data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET, - - pdata->phy_interface = -1; - - data->cpsw_base = pdata->iobase; - ret = dev_read_s32(dev, "cpdma_channels", &data->channels); if (ret) { printf("error: cpdma_channels not found in dt\n"); @@ -1177,21 +1169,10 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) ret = dev_read_u32(dev, "mac_control", &data->mac_control); if (ret) { - printf("error: ale_entries not found in dt\n"); + printf("error: mac_control not found in dt\n"); return ret; } - num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); - if (num_mode_gpios > 0) { - mode_gpios = malloc(sizeof(struct gpio_desc) * - num_mode_gpios); - gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, - num_mode_gpios, GPIOD_IS_OUT); - free(mode_gpios); - } - - data->active_slave = dev_read_u32_default(dev, "active_slave", 0); - ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { const char *name; @@ -1222,16 +1203,118 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) if (ofnode_read_bool(subnode, "rmii-clock-ext")) data->rmii_clock_external = true; + } + } - data->phy_sel_compat = ofnode_read_string(subnode, - "compatible"); - if (!data->phy_sel_compat) { - pr_err("Not able to get gmii_sel compatible\n"); - return -ENOENT; - } + return 0; +} + +static int cpsw_eth_of_to_plat_switch(struct udevice *dev, + struct cpsw_platform_data *data) +{ + ofnode eth_ports_node, subnode; + int ret; + + data->channels = 8; + data->ale_entries = 1024; + data->mac_control = GMII_EN; + + eth_ports_node = ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports"); + data->slaves = ofnode_get_child_count(eth_ports_node); + if (!data->slaves) { + pr_err("cpsw: No ethernet-ports defined\n"); + return -EINVAL; + } + + data->slave_data = malloc(sizeof(struct cpsw_slave_data) * data->slaves); + if (!data->slave_data) + return -ENOMEM; + + ofnode_for_each_subnode(subnode, eth_ports_node) { + struct ofnode_phandle_args args; + u32 port_id; + + ret = ofnode_read_u32(subnode, "reg", &port_id); + if (ret || !port_id || port_id > data->slaves) { + pr_err("cpsw: invalid or missing reg in port node\n"); + return -EINVAL; + } + + cpsw_eth_of_parse_slave(data, port_id - 1, subnode); + + if (!data->gmii_sel) { + ret = ofnode_parse_phandle_with_args(subnode, "phys", "#phy-cells", + 0, 0, &args); + if (!ret) + data->gmii_sel = ofnode_get_addr(args.node); + } + } + + if (!data->gmii_sel) { + pr_err("No port specified phys correctly\n"); + return -ENOENT; + } + + ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { + const char *name = ofnode_get_name(subnode); + + if (strncmp(name, "mdio", 4)) + continue; + + data->mdio_base = ofnode_get_addr(subnode); + if (data->mdio_base == FDT_ADDR_T_NONE) { + pr_err("Not able to get MDIO address space\n"); + return -ENOENT; } } + return 0; +} + +static int cpsw_eth_of_to_plat(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct cpsw_platform_data *data; + struct gpio_desc *mode_gpios; + int num_mode_gpios; + int ret; + bool switch_dt_bindings = + ofnode_valid(ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports")); + + data = calloc(1, sizeof(struct cpsw_platform_data)); + if (!data) + return -ENOMEM; + + pdata->priv_pdata = data; + pdata->iobase = dev_read_addr(dev); + data->version = CPSW_CTRL_VERSION_2; + data->bd_ram_ofs = CPSW_BD_OFFSET; + data->ale_reg_ofs = CPSW_ALE_OFFSET; + data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET; + data->mdio_div = CPSW_MDIO_DIV; + data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET; + + pdata->phy_interface = -1; + + data->cpsw_base = pdata->iobase; + + num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); + if (num_mode_gpios > 0) { + mode_gpios = malloc(sizeof(struct gpio_desc) * num_mode_gpios); + gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, + num_mode_gpios, GPIOD_IS_OUT); + free(mode_gpios); + } + + data->active_slave = dev_read_u32_default(dev, "active_slave", 0); + + if (switch_dt_bindings) + ret = cpsw_eth_of_to_plat_switch(dev, data); + else + ret = cpsw_eth_of_to_plat_legacy(dev, data); + if (ret) + return ret; + data->slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET; data->slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET; @@ -1253,9 +1336,22 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) return 0; } +static const struct cpsw_driver_data cpsw_data_am3352 = { + .gmii_sel = cpsw_gmii_sel_am3352, +}; + +static const struct cpsw_driver_data cpsw_data_dra7xx = { + .gmii_sel = cpsw_gmii_sel_dra7xx, +}; + static const struct udevice_id cpsw_eth_ids[] = { - { .compatible = "ti,cpsw" }, - { .compatible = "ti,am335x-cpsw" }, + { .compatible = "ti,cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am335x-cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am4372-cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,dra7-cpsw", .data = (ulong)&cpsw_data_dra7xx }, + { .compatible = "ti,am335x-cpsw-switch", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am4372-cpsw-switch", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,dra7-cpsw-switch", .data = (ulong)&cpsw_data_dra7xx }, { } }; #endif diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c index 12a162b9d68..4796d0d67cd 100644 --- a/drivers/net/ti/icssg_prueth.c +++ b/drivers/net/ti/icssg_prueth.c @@ -496,14 +496,15 @@ static int prueth_port_probe(struct udevice *dev) { struct prueth_priv *priv = dev_get_priv(dev); struct prueth *prueth; - char portname[15]; + char portname[64]; int ret; priv->dev = dev; prueth = dev_get_priv(dev->parent); priv->prueth = prueth; - sprintf(portname, "%s-%s", dev->parent->name, dev->name); + snprintf(portname, sizeof(portname), "%s-%s", dev->parent->name, dev->name); + portname[sizeof(portname) - 1] = '\0'; device_set_name(dev, portname); diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index bd4ebdd745a..d03368b9408 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -37,6 +37,23 @@ ) #endif /* CFG_TSEC_TBICR_SETTINGS */ +struct tsec_private { + struct txbd8 __iomem txbd[TX_BUF_CNT]; + struct rxbd8 __iomem rxbd[PKTBUFSRX]; + struct tsec __iomem *regs; + struct tsec_mii_mng __iomem *phyregs_sgmii; + struct phy_device *phydev; + phy_interface_t interface; + struct mii_dev *bus; + uint phyaddr; + uint tbiaddr; + char mii_devname[16]; + u32 flags; + uint rx_idx; /* index of the current RX buffer */ + uint tx_idx; /* index of the current TX buffer */ + struct udevice *dev; +}; + /* Configure the TBI for SGMII operation */ static void tsec_configure_serdes(struct tsec_private *priv) { diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index e9cc5db52d2..1ea81fe1830 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -28,6 +28,10 @@ #define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */ #define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */ +/* Reset and Address Filter (RAF) Register bit definitions */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject rx multicast dst addr */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject rx broadcast dst addr */ + /* Interrupt Status/Enable/Mask Registers bit definitions */ #define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */ #define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */ @@ -153,7 +157,8 @@ static struct axidma_bd tx_bd __attribute((aligned(DMAALIGN))); static struct axidma_bd rx_bd __attribute((aligned(DMAALIGN))); struct axi_regs { - u32 reserved[3]; + u32 raf; /* 0x0: Reset and Address Filter */ + u32 reserved[2]; u32 is; /* 0xC: Interrupt status */ u32 reserved2; u32 ie; /* 0x14: Interrupt enable */ @@ -528,6 +533,19 @@ static int axi_ethernet_init(struct axidma_priv *priv) /* Set default MDIO divisor */ writel(XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK, ®s->mdio_mc); + /* + * Reject broadcast and multicast frames at MAC level to reduce + * unnecessary traffic processing. Multicast rejection is only + * enabled when IPv6 is not configured because IPv6 Neighbor + * Discovery and DHCPv6 rely on multicast. + */ + if (!IS_ENABLED(CONFIG_IPV6)) + writel(readl(®s->raf) | XAE_RAF_MCSTREJ_MASK | + XAE_RAF_BCSTREJ_MASK, ®s->raf); + else + writel(readl(®s->raf) | XAE_RAF_BCSTREJ_MASK, + ®s->raf); + debug("axiemac: InitHw done\n"); return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index a50d5aee03f..f570ae9ee73 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -69,10 +69,13 @@ #define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x08000000 /* SGMII Enable */ #define ZYNQ_GEM_NWCFG_PCS_SEL 0x00000800 /* PCS select */ +#define ZYNQ_GEM_DBUS_WIDTH_MASK (3 << 21) /* bits 22:21 */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (2 << 21) /* 128 bit bus */ #else # define ZYNQ_GEM_DBUS_WIDTH (0 << 21) /* 32 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (0 << 21) /* 32 bit bus */ #endif #define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_DBUS_WIDTH | \ @@ -134,6 +137,7 @@ #define ZYNQ_GEM_FREQUENCY_10 2500000UL #define ZYNQ_GEM_FREQUENCY_100 25000000UL #define ZYNQ_GEM_FREQUENCY_1000 125000000UL +#define ZYNQ_GEM_FREQUENCY_10000 150000000UL #define RXCLK_EN BIT(0) @@ -470,28 +474,6 @@ static int zynq_gem_init(struct udevice *dev) for (i = 0; i < STAT_SIZE; i++) readl(®s->stat[i]); - /* Setup RxBD space */ - memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); - - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = - (lower_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#if defined(CONFIG_PHYS_64BIT) - priv->rx_bd[i].addr_hi = - (upper_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#endif - } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); -#if defined(CONFIG_PHYS_64BIT) - writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); -#endif - /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); @@ -520,6 +502,35 @@ static int zynq_gem_init(struct udevice *dev) priv->init++; } + /* + * Reinitialize RX BDs on every init. The 10GBE USX block asserts + * RX_SYNC_RESET during setup which resets the GEM RX DMA pointer + * back to rxqbase, so BDs and rxqbase must be refreshed each time + * to keep the hardware and driver ring indices in sync. + */ + priv->rxbd_current = 0; + priv->rx_first_buf = 0; + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (lower_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#if defined(CONFIG_PHYS_64BIT) + priv->rx_bd[i].addr_hi = + (upper_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#endif + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + + /* Write RxBDs to IP */ + writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); +#if defined(CONFIG_PHYS_64BIT) + writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); +#endif + ret = phy_startup(priv->phydev); if (ret) return ret; @@ -532,6 +543,8 @@ static int zynq_gem_init(struct udevice *dev) nwconfig = ZYNQ_GEM_NWCFG_INIT; if (device_is_compatible(dev, "amd,versal2-10gbe")) { + nwconfig &= ~ZYNQ_GEM_DBUS_WIDTH_MASK; + nwconfig |= ZYNQ_GEM_DBUS_WIDTH_128; if (priv->interface == PHY_INTERFACE_MODE_10GBASER) { ctrl = readl(®s->nwcfg); ctrl |= PCSSEL; @@ -602,6 +615,9 @@ static int zynq_gem_init(struct udevice *dev) } switch (priv->phydev->speed) { + case SPEED_10000: + clk_rate = ZYNQ_GEM_FREQUENCY_10000; + break; case SPEED_1000: nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000; clk_rate = ZYNQ_GEM_FREQUENCY_1000; @@ -615,6 +631,7 @@ static int zynq_gem_init(struct udevice *dev) break; } nwcfg = readl(®s->nwcfg); + nwcfg &= ~(ZYNQ_GEM_NWCFG_SPEED100 | ZYNQ_GEM_NWCFG_SPEED1000); nwcfg |= nwconfig; if (nwcfg) writel(nwcfg, ®s->nwcfg); |
