From 85b2f213c5293f32becc238e7b1b86002e02eda3 Mon Sep 17 00:00:00 2001 From: Daniel Kestrel Date: Fri, 17 Mar 2023 08:22:06 +0100 Subject: [PATCH] generic: 5.10: replace ramips AR8033 fiber patch with 5.18 patches A patch was added in kernel 5.4 to support the fiber operation of AR8033 with ramips devices. In kernel 5.18 similar enhancements were added to the kernel. Those patches are required for other fiber based devices but when added, build fails for ramips targets. This commit removes the ramips patch and adds the kernel 5.18 ones. Signed-off-by: Daniel Kestrel [ split commit, refresh patch and improve commit title ] Signed-off-by: Christian Marangi --- ...ve-page-selection-fix-to-config_init.patch | 81 ++++++++ ...-02-net-phy-at803x-add-fiber-support.patch | 193 ++++++++++++++++++ ...y-at803x-support-downstream-SFP-cage.patch | 95 +++++++++ ...LL-pointer-dereference-on-AR9331-PHY.patch | 56 +++++ ...ix-error-return-code-in-at803x_probe.patch | 31 +++ .../ramips/patches-5.10/710-at803x.patch | 184 ----------------- 6 files changed, 456 insertions(+), 184 deletions(-) create mode 100644 target/linux/generic/backport-5.10/775-v5.18-01-net-phy-at803x-move-page-selection-fix-to-config_init.patch create mode 100644 target/linux/generic/backport-5.10/775-v5.18-02-net-phy-at803x-add-fiber-support.patch create mode 100644 target/linux/generic/backport-5.10/775-v5.18-03-net-phy-at803x-support-downstream-SFP-cage.patch create mode 100644 target/linux/generic/backport-5.10/775-v5.18-04-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch create mode 100644 target/linux/generic/backport-5.10/775-v5.18-05-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch delete mode 100644 target/linux/ramips/patches-5.10/710-at803x.patch diff --git a/target/linux/generic/backport-5.10/775-v5.18-01-net-phy-at803x-move-page-selection-fix-to-config_init.patch b/target/linux/generic/backport-5.10/775-v5.18-01-net-phy-at803x-move-page-selection-fix-to-config_init.patch new file mode 100644 index 000000000000..5d1246893b13 --- /dev/null +++ b/target/linux/generic/backport-5.10/775-v5.18-01-net-phy-at803x-move-page-selection-fix-to-config_init.patch @@ -0,0 +1,81 @@ +From 4f3a00c7f5b2cfe4e127fd3fe49b55e1b318c01f Mon Sep 17 00:00:00 2001 +From: Robert Hancock +Date: Tue, 25 Jan 2022 10:54:08 -0600 +Subject: [PATCH] net: phy: at803x: move page selection fix to config_init + +The fix to select the copper page on AR8031 was being done in the probe +function rather than config_init, so it would not be redone after resume +from suspend. Move this to config_init so it is always redone when +needed. + +Fixes: c329e5afb42f ("net: phy: at803x: select correct page on config init") +Signed-off-by: Robert Hancock +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 40 ++++++++++++++++------------------------ + 1 file changed, 16 insertions(+), 24 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -651,25 +651,7 @@ static int at803x_probe(struct phy_devic + return ret; + } + +- /* Some bootloaders leave the fiber page selected. +- * Switch to the copper page, as otherwise we read +- * the PHY capabilities from the fiber side. +- */ +- if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { +- phy_lock_mdio_bus(phydev); +- ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); +- phy_unlock_mdio_bus(phydev); +- if (ret) +- goto err; +- } +- + return 0; +- +-err: +- if (priv->vddio) +- regulator_disable(priv->vddio); +- +- return ret; + } + + static void at803x_remove(struct phy_device *phydev) +@@ -745,6 +727,22 @@ static int at803x_config_init(struct phy + { + int ret; + ++ if (phydev->drv->phy_id == ATH8031_PHY_ID) { ++ /* Some bootloaders leave the fiber page selected. ++ * Switch to the copper page, as otherwise we read ++ * the PHY capabilities from the fiber side. ++ */ ++ phy_lock_mdio_bus(phydev); ++ ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); ++ phy_unlock_mdio_bus(phydev); ++ if (ret) ++ return ret; ++ ++ ret = at8031_pll_config(phydev); ++ if (ret < 0) ++ return ret; ++ } ++ + /* The RX and TX delay default is: + * after HW reset: RX delay enabled and TX delay disabled + * after SW reset: RX delay enabled, while TX delay retains the +@@ -770,12 +768,6 @@ static int at803x_config_init(struct phy + if (ret < 0) + return ret; + +- if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { +- ret = at8031_pll_config(phydev); +- if (ret < 0) +- return ret; +- } +- + return 0; + } + diff --git a/target/linux/generic/backport-5.10/775-v5.18-02-net-phy-at803x-add-fiber-support.patch b/target/linux/generic/backport-5.10/775-v5.18-02-net-phy-at803x-add-fiber-support.patch new file mode 100644 index 000000000000..18526591f837 --- /dev/null +++ b/target/linux/generic/backport-5.10/775-v5.18-02-net-phy-at803x-add-fiber-support.patch @@ -0,0 +1,193 @@ +From 3265f421887847db9ae2c01a00645e33608556d8 Mon Sep 17 00:00:00 2001 +From: Robert Hancock +Date: Tue, 25 Jan 2022 10:54:09 -0600 +Subject: [PATCH] net: phy: at803x: add fiber support + +Previously this driver always forced the copper page to be selected, +however for AR8031 in 100Base-FX or 1000Base-X modes, the fiber page +needs to be selected. Set the appropriate mode based on the hardware +mode_cfg strap selection. + +Enable the appropriate interrupt bits to detect fiber-side link up +or down events. + +Update config_aneg and read_status methods to use the appropriate +Clause 37 calls when fiber mode is in use. + +Signed-off-by: Robert Hancock +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 76 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 67 insertions(+), 9 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -48,6 +48,8 @@ + #define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) + #define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) + #define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) ++#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) ++#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) + #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) + #define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) + #define AT803X_INTR_ENABLE_WOL BIT(0) +@@ -82,6 +84,17 @@ + + #define AT803X_MODE_CFG_MASK 0x0F + #define AT803X_MODE_CFG_SGMII 0x01 ++#define AT803X_MODE_CFG_BASET_RGMII 0x00 ++#define AT803X_MODE_CFG_BASET_SGMII 0x01 ++#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 ++#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 ++#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 ++#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 ++#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 ++#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 ++#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B ++#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E ++#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F + + #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ + #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 +@@ -189,6 +202,8 @@ struct at803x_priv { + #define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */ + u16 clk_25m_reg; + u16 clk_25m_mask; ++ bool is_fiber; ++ bool is_1000basex; + struct regulator_dev *vddio_rdev; + struct regulator_dev *vddh_rdev; + struct regulator *vddio; +@@ -651,7 +666,33 @@ static int at803x_probe(struct phy_devic + return ret; + } + ++ if (phydev->drv->phy_id == ATH8031_PHY_ID) { ++ int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); ++ int mode_cfg; ++ ++ if (ccr < 0) ++ goto err; ++ mode_cfg = ccr & AT803X_MODE_CFG_MASK; ++ ++ switch (mode_cfg) { ++ case AT803X_MODE_CFG_BX1000_RGMII_50OHM: ++ case AT803X_MODE_CFG_BX1000_RGMII_75OHM: ++ priv->is_1000basex = true; ++ fallthrough; ++ case AT803X_MODE_CFG_FX100_RGMII_50OHM: ++ case AT803X_MODE_CFG_FX100_RGMII_75OHM: ++ priv->is_fiber = true; ++ break; ++ } ++ } ++ + return 0; ++ ++err: ++ if (priv->vddio) ++ regulator_disable(priv->vddio); ++ ++ return ret; + } + + static void at803x_remove(struct phy_device *phydev) +@@ -664,6 +705,7 @@ static void at803x_remove(struct phy_dev + + static int at803x_get_features(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int err; + + err = genphy_read_abilities(phydev); +@@ -681,12 +723,13 @@ static int at803x_get_features(struct ph + * As a result of that, ESTATUS_1000_XFULL is set + * to 1 even when operating in copper TP mode. + * +- * Remove this mode from the supported link modes, +- * as this driver currently only supports copper +- * operation. ++ * Remove this mode from the supported link modes ++ * when not operating in 1000BaseX mode. + */ +- linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, +- phydev->supported); ++ if (!priv->is_1000basex) ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->supported); ++ + return 0; + } + +@@ -725,15 +768,18 @@ static int at8031_pll_config(struct phy_ + + static int at803x_config_init(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ret; + + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + /* Some bootloaders leave the fiber page selected. +- * Switch to the copper page, as otherwise we read +- * the PHY capabilities from the fiber side. ++ * Switch to the appropriate page (fiber or copper), as otherwise we ++ * read the PHY capabilities from the wrong page. + */ + phy_lock_mdio_bus(phydev); +- ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); ++ ret = at803x_write_page(phydev, ++ priv->is_fiber ? AT803X_PAGE_FIBER : ++ AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; +@@ -782,6 +828,7 @@ static int at803x_ack_interrupt(struct p + + static int at803x_config_intr(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int err; + int value; + +@@ -793,6 +840,10 @@ static int at803x_config_intr(struct phy + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; ++ if (priv->is_fiber) { ++ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; ++ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; ++ } + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } +@@ -859,8 +910,12 @@ static int at803x_aneg_done(struct phy_d + + static int at803x_read_status(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ss, err, old_link = phydev->link; + ++ if (priv->is_1000basex) ++ return genphy_c37_read_status(phydev); ++ + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) +@@ -959,6 +1014,7 @@ static int at803x_config_mdix(struct phy + + static int at803x_config_aneg(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ret; + + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); +@@ -975,6 +1031,9 @@ static int at803x_config_aneg(struct phy + return ret; + } + ++ if (priv->is_1000basex) ++ return genphy_c37_config_aneg(phydev); ++ + return genphy_config_aneg(phydev); + } + diff --git a/target/linux/generic/backport-5.10/775-v5.18-03-net-phy-at803x-support-downstream-SFP-cage.patch b/target/linux/generic/backport-5.10/775-v5.18-03-net-phy-at803x-support-downstream-SFP-cage.patch new file mode 100644 index 000000000000..73dea9c26526 --- /dev/null +++ b/target/linux/generic/backport-5.10/775-v5.18-03-net-phy-at803x-support-downstream-SFP-cage.patch @@ -0,0 +1,95 @@ +From dc4d5fcc5d365c9f70ea3f5c09bdf70e988fad50 Mon Sep 17 00:00:00 2001 +From: Robert Hancock +Date: Tue, 25 Jan 2022 10:54:10 -0600 +Subject: [PATCH] net: phy: at803x: Support downstream SFP cage + +Add support for downstream SFP cages for AR8031 and AR8033. This is +primarily intended for fiber modules or direct-attach cables, however +copper modules which work in 1000Base-X mode may also function. Such +modules are allowed with a warning. + +Signed-off-by: Robert Hancock +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 56 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 56 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 +@@ -551,6 +553,55 @@ static bool at803x_match_phy_id(struct p + == (phy_id & phydev->drv->phy_id_mask); + } + ++static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) ++{ ++ struct phy_device *phydev = upstream; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); ++ phy_interface_t iface; ++ ++ linkmode_zero(phy_support); ++ phylink_set(phy_support, 1000baseX_Full); ++ phylink_set(phy_support, 1000baseT_Full); ++ phylink_set(phy_support, Autoneg); ++ phylink_set(phy_support, Pause); ++ phylink_set(phy_support, Asym_Pause); ++ ++ linkmode_zero(sfp_support); ++ sfp_parse_support(phydev->sfp_bus, id, sfp_support); ++ /* Some modules support 10G modes as well as others we support. ++ * Mask out non-supported modes so the correct interface is picked. ++ */ ++ linkmode_and(sfp_support, phy_support, sfp_support); ++ ++ if (linkmode_empty(sfp_support)) { ++ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); ++ return -EINVAL; ++ } ++ ++ iface = sfp_select_interface(phydev->sfp_bus, sfp_support); ++ ++ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes ++ * interface for use with SFP modules. ++ * However, some copper modules detected as having a preferred SGMII ++ * interface do default to and function in 1000Base-X mode, so just ++ * print a warning and allow such modules, as they may have some chance ++ * of working. ++ */ ++ if (iface == PHY_INTERFACE_MODE_SGMII) ++ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); ++ else if (iface != PHY_INTERFACE_MODE_1000BASEX) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct sfp_upstream_ops at803x_sfp_ops = { ++ .attach = phy_sfp_attach, ++ .detach = phy_sfp_detach, ++ .module_insert = at803x_sfp_insert, ++}; ++ + static int at803x_parse_dt(struct phy_device *phydev) + { + struct device_node *node = phydev->mdio.dev.of_node; +@@ -639,6 +690,11 @@ static int at803x_parse_dt(struct phy_de + phydev_err(phydev, "failed to get VDDIO regulator\n"); + return PTR_ERR(priv->vddio); + } ++ ++ /* Only AR8031/8033 support 1000Base-X for SFP modules */ ++ ret = phy_sfp_probe(phydev, &at803x_sfp_ops); ++ if (ret < 0) ++ return ret; + } + + return 0; diff --git a/target/linux/generic/backport-5.10/775-v5.18-04-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch b/target/linux/generic/backport-5.10/775-v5.18-04-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch new file mode 100644 index 000000000000..61fe3d259d0f --- /dev/null +++ b/target/linux/generic/backport-5.10/775-v5.18-04-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch @@ -0,0 +1,56 @@ +From 9926de7315be3d606cc011a305ad9adb9e8e14c9 Mon Sep 17 00:00:00 2001 +From: Oleksij Rempel +Date: Sat, 18 Jun 2022 14:23:33 +0200 +Subject: [PATCH] net: phy: at803x: fix NULL pointer dereference on AR9331 PHY + +Latest kernel will explode on the PHY interrupt config, since it depends +now on allocated priv. So, run probe to allocate priv to fix it. + + ar9331_switch ethernet.1:10 lan0 (uninitialized): PHY [!ahb!ethernet@1a000000!mdio!switch@10:00] driver [Qualcomm Atheros AR9331 built-in PHY] (irq=13) + CPU 0 Unable to handle kernel paging request at virtual address 0000000a, epc == 8050e8a8, ra == 80504b34 + ... + Call Trace: + [<8050e8a8>] at803x_config_intr+0x5c/0xd0 + [<80504b34>] phy_request_interrupt+0xa8/0xd0 + [<8050289c>] phylink_bringup_phy+0x2d8/0x3ac + [<80502b68>] phylink_fwnode_phy_connect+0x118/0x130 + [<8074d8ec>] dsa_slave_create+0x270/0x420 + [<80743b04>] dsa_port_setup+0x12c/0x148 + [<8074580c>] dsa_register_switch+0xaf0/0xcc0 + [<80511344>] ar9331_sw_probe+0x370/0x388 + [<8050cb78>] mdio_probe+0x44/0x70 + [<804df300>] really_probe+0x200/0x424 + [<804df7b4>] __driver_probe_device+0x290/0x298 + [<804df810>] driver_probe_device+0x54/0xe4 + [<804dfd50>] __device_attach_driver+0xe4/0x130 + [<804dcb00>] bus_for_each_drv+0xb4/0xd8 + [<804dfac4>] __device_attach+0x104/0x1a4 + [<804ddd24>] bus_probe_device+0x48/0xc4 + [<804deb44>] deferred_probe_work_func+0xf0/0x10c + [<800a0ffc>] process_one_work+0x314/0x4d4 + [<800a17fc>] worker_thread+0x2a4/0x354 + [<800a9a54>] kthread+0x134/0x13c + [<8006306c>] ret_from_kernel_thread+0x14/0x1c + +Same Issue would affect some other PHYs (QCA8081, QCA9561), so fix it +too. + +Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") +Signed-off-by: Oleksij Rempel +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1530,6 +1530,8 @@ static struct phy_driver at803x_driver[] + /* ATHEROS AR9331 */ + PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), + .name = "Qualcomm Atheros AR9331 built-in PHY", ++ .probe = at803x_probe, ++ .remove = at803x_remove, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, diff --git a/target/linux/generic/backport-5.10/775-v5.18-05-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch b/target/linux/generic/backport-5.10/775-v5.18-05-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch new file mode 100644 index 000000000000..fc31775c1904 --- /dev/null +++ b/target/linux/generic/backport-5.10/775-v5.18-05-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch @@ -0,0 +1,31 @@ +From 1f0dd412e34e177621769866bef347f0b22364df Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Fri, 18 Nov 2022 10:36:35 +0000 +Subject: [PATCH] net: phy: at803x: fix error return code in at803x_probe() + +Fix to return a negative error code from the ccr read error handling +case instead of 0, as done elsewhere in this function. + +Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") +Signed-off-by: Wei Yongjun +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20221118103635.254256-1-weiyongjun@huaweicloud.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/at803x.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -726,8 +726,10 @@ static int at803x_probe(struct phy_devic + int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + int mode_cfg; + +- if (ccr < 0) ++ if (ccr < 0) { ++ ret = ccr; + goto err; ++ } + mode_cfg = ccr & AT803X_MODE_CFG_MASK; + + switch (mode_cfg) { diff --git a/target/linux/ramips/patches-5.10/710-at803x.patch b/target/linux/ramips/patches-5.10/710-at803x.patch deleted file mode 100644 index 1b59f70cea22..000000000000 --- a/target/linux/ramips/patches-5.10/710-at803x.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 924453aa9d2324e5611f8e2b71df746d8f0c79f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= -Date: Fri, 13 Nov 2020 16:11:32 +0100 -Subject: [PATCH] net: phy: at803x: add support for SFP module in - RGMII-to-x-base mode -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: René van Dorst ---- - drivers/net/phy/at803x.c | 91 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 91 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -20,6 +20,8 @@ - #include - #include - #include -+#include -+#include - - #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 - #define AT803X_SFC_ASSERT_CRS BIT(11) -@@ -82,9 +84,18 @@ - - #define AT803X_MODE_CFG_MASK 0x0F - #define AT803X_MODE_CFG_SGMII 0x01 -+#define AT803X_MODE_CFG_BX1000_RGMII_50 0x02 -+#define AT803X_MODE_CFG_BX1000_RGMII_75 0x03 -+#define AT803X_MODE_FIBER 0x01 -+#define AT803X_MODE_COPPER 0x00 - - #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ - #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 -+#define PSSR_LINK BIT(10) -+#define PSSR_SYNC_STATUS BIT(8) -+#define PSSR_DUPLEX BIT(13) -+#define PSSR_SPEED_1000 BIT(15) -+#define PSSR_SPEED_100 BIT(14) - - #define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 - #define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) -@@ -629,12 +640,75 @@ static int at803x_parse_dt(struct phy_de - return 0; - } - -+static int at803x_mode(struct phy_device *phydev) -+{ -+ int mode; -+ -+ mode = phy_read(phydev, AT803X_REG_CHIP_CONFIG) & AT803X_MODE_CFG_MASK; -+ -+ if (mode == AT803X_MODE_CFG_BX1000_RGMII_50 || -+ mode == AT803X_MODE_CFG_BX1000_RGMII_75) -+ return AT803X_MODE_FIBER; -+ return AT803X_MODE_COPPER; -+} -+ -+static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(at803x_support) = { 0, }; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; -+ struct phy_device *phydev = upstream; -+ phy_interface_t iface; -+ -+ phylink_set(at803x_support, 1000baseX_Full); -+ /* AT803x only support 1000baseX but SGMII works fine when module runs -+ * at 1Gbit. -+ */ -+ phylink_set(at803x_support, 1000baseT_Full); -+ -+ sfp_parse_support(phydev->sfp_bus, id, support); -+ -+ // Limit to interfaces that both sides support -+ linkmode_and(support, support, at803x_support); -+ -+ if (linkmode_empty(support)) -+ goto unsupported_mode; -+ -+ iface = sfp_select_interface(phydev->sfp_bus, support); -+ -+ if (iface != PHY_INTERFACE_MODE_SGMII && -+ iface != PHY_INTERFACE_MODE_1000BASEX) -+ goto unsupported_mode; -+ -+ dev_info(&phydev->mdio.dev, "SFP interface %s", phy_modes(iface)); -+ -+ return 0; -+ -+unsupported_mode: -+ dev_info(&phydev->mdio.dev, "incompatible SFP module inserted;" -+ "Only SGMII at 1Gbit/1000BASEX are supported!\n"); -+ return -EINVAL; -+} -+ -+static const struct sfp_upstream_ops at803x_sfp_ops = { -+ .attach = phy_sfp_attach, -+ .detach = phy_sfp_detach, -+ .module_insert = at803x_sfp_insert, -+}; -+ -+ - static int at803x_probe(struct phy_device *phydev) - { - struct device *dev = &phydev->mdio.dev; - struct at803x_priv *priv; - int ret; - -+ -+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) { -+ ret = phy_sfp_probe(phydev, &at803x_sfp_ops); -+ if (ret < 0) -+ return ret; -+ } -+ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; -@@ -651,6 +725,7 @@ static int at803x_probe(struct phy_devic - return ret; - } - -+#if 0 - /* Some bootloaders leave the fiber page selected. - * Switch to the copper page, as otherwise we read - * the PHY capabilities from the fiber side. -@@ -662,6 +737,7 @@ static int at803x_probe(struct phy_devic - if (ret) - goto err; - } -+#endif - - return 0; - -@@ -841,6 +917,10 @@ static int at803x_read_status(struct phy - { - int ss, err, old_link = phydev->link; - -+ /* Handle (Fiber) SGMII to RGMII mode */ -+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) -+ return genphy_c37_read_status(phydev); -+ - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); - if (err) -@@ -941,6 +1021,12 @@ static int at803x_config_aneg(struct phy - { - int ret; - -+ /* Handle (Fiber) SerDes to RGMII mode */ -+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) { -+ pr_warn("%s: fiber\n", __func__); -+ return genphy_c37_config_aneg(phydev); -+ } -+ - ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); - if (ret < 0) - return ret; -@@ -1040,6 +1126,7 @@ static int at803x_get_features(struct ph - if (err) - return err; - -+#if 0 - if (!at803x_match_phy_id(phydev, ATH8031_PHY_ID)) - return 0; - -@@ -1057,6 +1144,7 @@ static int at803x_get_features(struct ph - */ - linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, - phydev->supported); -+#endif - return 0; - } - -@@ -1381,6 +1469,7 @@ static struct phy_driver at803x_driver[] - /* Qualcomm Atheros AR8031/AR8033 */ - PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), - .name = "Qualcomm Atheros AR8031/AR8033", -+ .config_aneg = at803x_config_aneg, - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .remove = at803x_remove, -- 2.30.2