From 537c06c7ae0e98cbb72569af66111c2c8cbf82d0 Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Tue, 21 Jan 2025 15:54:54 +0800 Subject: [PATCH 1/3] FROMLIST: net: stmmac: dwmac-qcom-ethqos: Mask PHY mode if configured with rgmii-id The Qualcomm board always chooses the MAC to provide the delay instead of the PHY, which is completely opposite to the suggestion of the Linux kernel. The usage of phy-mode in legacy DTS was also incorrect. Change the phy_mode passed from the DTS to the driver from PHY_INTERFACE_MODE_RGMII_ID to PHY_INTERFACE_MODE_RGMII to ensure correct operation and adherence to the definition. To address the ABI compatibility issue between the kernel and DTS caused by this change, handle the compatible string 'qcom,qcs404-evb-4000' in the code, as it is the only legacy board that mistakenly uses the 'rgmii' phy-mode. Link: https://lore.kernel.org/all/20250121-dts_qcs615-v3-2-fa4496950d8a@quicinc.com/ Signed-off-by: Yijie Yang --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index e30bdf72331ac..a70d2d96ec3e0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -387,14 +387,11 @@ 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 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 */ @@ -759,7 +756,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 +782,17 @@ 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 && 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: From 3af14c96f39b1b7e21a560d3d8a2e36340fcb81c Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Wed, 25 Dec 2024 18:04:45 +0800 Subject: [PATCH 2/3] FROMLIST: dt-bindings: net: stmmac: Tune rx sampling occasion Add documentation detailing the capability for tuning the RX sampling occasion of the Qualcomm MAC. Introduce a new flag to indicate that a board requires switching the timing of signal sampling, instead of relying solely on the EMAC version in the driver code. For older DTS, the logic for current boards is hard-coded in the driver code to ensure they function as previously. Link: https://lore.kernel.org/all/20241225-support_10m100m-v1-1-4b52ef48b488@quicinc.com/ Signed-off-by: Yijie Yang --- Documentation/devicetree/bindings/net/qcom,ethqos.yaml | 6 ++++++ 1 file changed, 6 insertions(+) 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 From 27e28d730e81eadba1ef7a1f7ec1cde714c4eabb Mon Sep 17 00:00:00 2001 From: Yijie Yang Date: Wed, 25 Dec 2024 18:04:46 +0800 Subject: [PATCH 3/3] FROMLIST: net: stmmac: qcom-ethqos: Enable RX programmable swap on qcs615 The sampling timing of the MAC varies per board due to differences in hardware layout or peer PHY, even within the same version. For instance, the EMAC version on the qcs615-ride board is below 3, but it requires swapping the RX timing to enable 10M/100M speeds. Therefore, this setting should be adjustable rather than solely determined by the version. The RGMII_CONFIG2_RX_PROG_SWAP bit is used to switch the RX sampling timing between the rising edge and the falling edge of the clock. Consequently, the condition for setting this bit should be revised to ensure correct data sampling. The compatible string matching for 'qcom,sa8540p-ride' in this change is intended to ensure ABI compatibility for DTS files that do not include the new 'qcom,rx-prog-swap' property, allowing legacy boards to function as before. This board is the only one among legacy boards using RGMII and needs to enable RX swap. Link: https://lore.kernel.org/all/20241225-support_10m100m-v1-2-4b52ef48b488@quicinc.com/ Signed-off-by: Yijie Yang --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index a70d2d96ec3e0..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,6 +388,7 @@ 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 rx_prog_swap = 0; int phase_shift = 0; int loopback; @@ -404,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); @@ -467,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, @@ -508,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); @@ -784,10 +779,20 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->phy_mode = plat_dat->phy_interface; root = of_find_node_by_path("/"); - if (root && of_device_is_compatible(root, "qcom,qcs404-evb-4000")) + 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)