diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml index e7ee0d9efed83..ead55f0d5e18b 100644 --- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml @@ -78,6 +78,12 @@ properties: phy-names: const: serdes + qcom,rx-prog-swap: + type: boolean + description: + Swap the sampling occasion on the RX side. This can be used for + tuning when connected to a third-party PHY. + required: - compatible - clocks diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index e30bdf72331ac..4e2233fb42272 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -119,6 +119,7 @@ struct qcom_ethqos { bool rgmii_config_loopback_en; bool has_emac_ge_3; bool needs_sgmii_loopback; + bool needs_rx_prog_swap; }; static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) @@ -387,14 +388,12 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) { struct device *dev = ðqos->pdev->dev; - int phase_shift; + int rx_prog_swap = 0; + int phase_shift = 0; int loopback; /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ - if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID || - ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) - phase_shift = 0; - else + if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; /* Disable loopback mode */ @@ -407,6 +406,9 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) else loopback = 0; + if (ethqos->needs_rx_prog_swap) + rx_prog_swap = RGMII_CONFIG2_RX_PROG_SWAP; + /* Select RGMII, write 0 to interface select */ rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, 0, RGMII_IO_MACRO_CONFIG); @@ -470,14 +472,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) BIT(6), RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - - if (ethqos->has_emac_ge_3) - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_IO_MACRO_CONFIG2); - else - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, rx_prog_swap, + RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, @@ -511,13 +507,9 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - if (ethqos->has_emac_ge_3) - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_IO_MACRO_CONFIG2); - else - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, rx_prog_swap, + RGMII_IO_MACRO_CONFIG2); + /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); @@ -759,7 +751,7 @@ static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv) static int qcom_ethqos_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.of_node, *root; const struct ethqos_emac_driver_data *data; struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; @@ -785,6 +777,27 @@ static int qcom_ethqos_probe(struct platform_device *pdev) return -ENOMEM; ethqos->phy_mode = plat_dat->phy_interface; + + root = of_find_node_by_path("/"); + if (!root) + return dev_err_probe(dev, ret, "Failed to get root node\n"); + + if (of_device_is_compatible(root, "qcom,sa8540p-ride")) + ethqos->needs_rx_prog_swap = true; + else + ethqos->needs_rx_prog_swap = + of_property_read_bool(np, "qcom,rx-prog-swap"); + + if (of_device_is_compatible(root, "qcom,qcs404-evb-4000")) + ethqos->phy_mode = PHY_INTERFACE_MODE_RGMII_ID; + else if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII) + return dev_err_probe(dev, -EINVAL, "Invalid phy-mode rgmii\n"); + + of_node_put(root); + + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) + plat_dat->phy_interface = PHY_INTERFACE_MODE_RGMII; + switch (ethqos->phy_mode) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: