From deab928a8213a2f2f9ff46accfa85c41500b722d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
Date: Tue, 23 Apr 2024 12:51:00 +0200
Subject: [PATCH] patches/openwrt: Backport SFP changes from upstream

---
 NEWS                                          |    3 +
 ...5-Backport-SFP-changes-from-upstream.patch | 8526 +++++++++++++++++
 ...bu-add-support-for-Turris-SFP-module.patch | 2297 -----
 3 files changed, 8529 insertions(+), 2297 deletions(-)
 create mode 100644 patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch
 delete mode 100644 patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch

diff --git a/NEWS b/NEWS
index 4533070d7..215aee406 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 7.0.1
 -----
 
+🚀 New Features
+  • Backport support for more SFP modules from mainline kernel
+
 đź“Ś Updates
   • ethtool: Update to 6.6
   • iproute2: Update to 6.7.0
diff --git a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch
new file mode 100644
index 000000000..c6c28683c
--- /dev/null
+++ b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-5.15-Backport-SFP-changes-from-upstream.patch
@@ -0,0 +1,8526 @@
+From ea2ce87cc28cab1eba8236425d3604314e3aebdb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+Date: Tue, 23 Apr 2024 12:45:24 +0200
+Subject: [PATCH] mvebu: 5.15: Backport SFP changes from upstream
+
+---
+ .../790-SFP-GE-T-ignore-TX_FAULT.patch        |  65 ---
+ ...rtl8221-allow-to-configure-SERDES-mo.patch | 101 -----
+ target/linux/mvebu/config-5.15                |   2 +
+ ...t-phylink-use-pe-for-printing-errors.patch |  68 +++
+ ...2-net-sfp-use-pe-for-printing-errors.patch | 165 +++++++
+ ...ability-to-validate-a-set-of-interfa.patch |  60 +++
+ ...SFP-parsing-with-phy_interface_t-bit.patch | 322 +++++++++++++
+ ...phy_interface_t-bitmaps-for-optical-.patch | 238 ++++++++++
+ ...et-phylink-rename-phylink_sfp_config.patch |  51 +++
+ ...-supported-host-PHY-interface-modes-.patch |  83 ++++
+ ...0g-Use-tabs-instead-of-spaces-for-in.patch |  44 ++
+ ...0g-select-host-interface-configurati.patch | 216 +++++++++
+ ...w-attaching-phy-for-SFP-modules-on-8.patch |  41 ++
+ ...use-macros-for-SFP-quirks-definition.patch |  85 ++++
+ ...estroy-I2C-mdiobus-before-PHY-probe-.patch | 171 +++++++
+ ...-support-I2C-MDIO-protocol-for-RollB.patch | 421 +++++++++++++++++
+ ...ort-for-multigig-RollBall-transceive.patch | 152 +++++++
+ ...o-5gbase-r-and-25gbase-r-modes-in-sf.patch |  44 ++
+ ...fp-check-firmware-provided-max-power.patch |  57 +++
+ ...ower-level-2-prior-to-SFF-8472-Rev-1.patch |  27 ++
+ ...ower-level-3-prior-to-SFF-8472-Rev-1.patch |  28 ++
+ ...a-definition-for-the-power-level-sel.patch |  42 ++
+ ...5-5-net-sfp-add-sfp_modify_u8-helper.patch |  61 +++
+ ...of-DM7052-hack-when-enabling-high-po.patch |  53 +++
+ ...register-indexes-from-hex-to-decimal.patch | 234 ++++++++++
+ ...ld-definitions-along-side-register-i.patch |  83 ++++
+ ...6-07-1-net-sfp-add-A2h-presence-flag.patch | 100 +++++
+ ...e-soft-polling-if-we-have-A2h-access.patch |  28 ++
+ ...ate-loss-when-updating-state_hw_mask.patch |  41 ++
+ ...w-SFP-quirks-to-override-Autoneg-and.patch |  43 ++
+ ...et-sfp-add-quirk-for-2.5G-copper-SFP.patch |  51 +++
+ ...k-enabling-2500Base-x-for-HG-MXPD-48.patch |  34 ++
+ ...oid-EEPROM-read-of-absent-SFP-module.patch |  36 ++
+ ...p-add-helper-to-modify-signal-states.patch |  64 +++
+ ...ove-rtnl-lock-to-cover-reading-state.patch |  42 ++
+ ...wap-order-of-rtnl-and-st_mutex-locks.patch |  36 ++
+ ...p-move-sm_mutex-into-sfp_check_state.patch |  66 +++
+ ...12-5-net-sfp-change-st_mutex-locking.patch | 182 ++++++++
+ ...-support-for-setting-signalling-rate.patch | 142 ++++++
+ ...t-sfp-add-support-for-rate-selection.patch | 422 ++++++++++++++++++
+ ...ort-for-a-couple-of-copper-multi-rat.patch |  93 ++++
+ ...ort-for-HXSX-ATRI-1-copper-SFP-modul.patch |  30 ++
+ ...king-PHY-on-SFP-module-into-SFP-code.patch |  39 ++
+ ...uirk-for-Fiberstone-GPON-ONU-34-20BI.patch |  29 ++
+ ...p-add-quirk-for-FS-s-2.5G-copper-SFP.patch |  26 ++
+ ...ment-ignoring-the-hardware-TX_FAULT-.patch |  82 ++++
+ ...net-sfp-improve-Nokia-GPON-sfp-fixup.patch |  54 +++
+ ...et-linkmode-add-linkmode_fill-helper.patch |  26 ++
+ ...6-19-2-net-phylink-use-linkmode_fill.patch |  31 ++
+ ...se-linkmode_-rather-than-open-coding.patch |  23 +
+ ...rework-the-RollBall-PHY-waiting-code.patch | 131 ++++++
+ ...HY-discovery-for-FS-SFP-10G-T-module.patch |  82 ++++
+ ...bus-fix-SFP-mode-detect-from-bitrate.patch |  43 ++
+ ...ell10g-add-downshift-tunable-support.patch | 212 +++++++++
+ ...-02-net-phylink-use-for_each_set_bit.patch |  43 ++
+ ...ort-disabling-autonegotiation-for-PC.patch |  79 ++++
+ ...4-net-phy-Introduce-QUSGMII-PHY-mode.patch | 117 +++++
+ ...t-phy-Add-1000BASE-KX-interface-mode.patch |  80 ++++
+ ...et-phylink-Document-MAC_-A-SYM_PAUSE.patch |  66 +++
+ ...ink-Export-phylink_caps_to_linkmodes.patch |  62 +++
+ ...rate-caps-and-convert-to-linkmodes-s.patch | 113 +++++
+ ...et-phy-Add-support-for-rate-matching.patch | 284 ++++++++++++
+ ...st-link-settings-based-on-rate-match.patch | 256 +++++++++++
+ ...st-advertisement-based-on-rate-match.patch | 187 ++++++++
+ ...07-1-net-phy-add-possible-interfaces.patch |  56 +++
+ ...rvell10g-table-driven-mactype-decode.patch | 295 ++++++++++++
+ ...rvell10g-fill-in-possible_interfaces.patch |  47 ++
+ ...bcm84881-fill-in-possible_interfaces.patch |  44 ++
+ ...g-and-5g-related-PMA-speed-constants.patch |  27 ++
+ ...y-realtek-use-generic-MDIO-constants.patch |  90 ++++
+ ...add-5Gbps-support-to-rtl822x_config_.patch |  39 ++
+ ...use-generic-MDIO-helpers-to-simplify.patch |  49 ++
+ ...configure-SerDes-mode-for-rtl822xb-P.patch | 206 +++++++++
+ ...add-get_rate_matching-for-rtl822xb-P.patch |  74 +++
+ ...Add-driver-instances-for-rtl8221b-vi.patch | 215 +++++++++
+ ...Change-rtlgen_get_speed-to-rtlgen_de.patch | 122 +++++
+ ...add-rtl822x_c45_get_features-to-set-.patch |  45 ++
+ ...k-for-another-multigig-RollBall-tran.patch |  27 ++
+ ...pdate-comment-for-FS-SFP-10G-T-quirk.patch |  30 ++
+ ...quirk-for-Fibrestore-2.5G-copper-SFP.patch |  71 +++
+ ...k-for-ATS-SFP-GE-T-1000Base-TX-modul.patch |  30 ++
+ 81 files changed, 7690 insertions(+), 166 deletions(-)
+ delete mode 100644 target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch
+ delete mode 100644 target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch
+ create mode 100644 target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch
+
+diff --git a/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch b/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch
+deleted file mode 100644
+index 83b2c304e2..0000000000
+--- a/target/linux/generic/hack-5.15/790-SFP-GE-T-ignore-TX_FAULT.patch
++++ /dev/null
+@@ -1,65 +0,0 @@
+-From 7cc39a6bedbd85f3ff7e16845f310e4ce8d9833f Mon Sep 17 00:00:00 2001
+-From: Daniel Golle <daniel@makrotopia.org>
+-Date: Tue, 6 Sep 2022 00:31:19 +0100
+-Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module
+-To: netdev@vger.kernel.org,
+-    linux-kernel@vger.kernel.org,
+-    Russell King <linux@armlinux.org.uk>,
+-    Andrew Lunn <andrew@lunn.ch>,
+-    Heiner Kallweit <hkallweit1@gmail.com>
+-Cc: David S. Miller <davem@davemloft.net>,
+-    Eric Dumazet <edumazet@google.com>,
+-    Jakub Kicinski <kuba@kernel.org>,
+-    Paolo Abeni <pabeni@redhat.com>,
+-    Josef Schlehofer <pepe.schlehofer@gmail.com>
+-
+-This copper module comes with broken TX_FAULT indicator which must be
+-ignored for it to work. Implement ignoring TX_FAULT state bit also
+-during reset/insertion and mute the warning telling the user that the
+-module indicates TX_FAULT.
+-
+-Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
+-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+----
+- drivers/net/phy/sfp.c | 14 +++++++++++---
+- 1 file changed, 11 insertions(+), 3 deletions(-)
+-
+---- a/drivers/net/phy/sfp.c
+-+++ b/drivers/net/phy/sfp.c
+-@@ -373,6 +373,11 @@ static const struct sfp_quirk sfp_quirks
+- 		.modes = sfp_quirk_2500basex,
+- 		.fixup = sfp_fixup_ignore_tx_fault,
+- 	}, {
+-+		// OEM SFP-GE-T is 1000Base-T module
+-+		.vendor = "OEM",
+-+		.part = "SFP-GE-T",
+-+		.fixup = sfp_fixup_ignore_tx_fault,
+-+	}, {
+- 		// Lantech 8330-262D-E can operate at 2500base-X, but
+- 		// incorrectly report 2500MBd NRZ in their EEPROM
+- 		.vendor = "Lantech",
+-@@ -2306,7 +2311,8 @@ static void sfp_sm_main(struct sfp *sfp,
+- 			 * or t_start_up, so assume there is a fault.
+- 			 */
+- 			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
+--				     sfp->sm_fault_retries == N_FAULT_INIT);
+-+				     !sfp->tx_fault_ignore &&
+-+				     (sfp->sm_fault_retries == N_FAULT_INIT));
+- 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+- 	init_done:
+- 			sfp->sm_phy_retries = R_PHY_RETRY;
+-@@ -2529,10 +2535,12 @@ static void sfp_check_state(struct sfp *
+- 	mutex_lock(&sfp->st_mutex);
+- 	state = sfp_get_state(sfp);
+- 	changed = state ^ sfp->state;
+--	if (sfp->tx_fault_ignore)
+-+	if (sfp->tx_fault_ignore) {
+- 		changed &= SFP_F_PRESENT | SFP_F_LOS;
+--	else
+-+		state &= ~SFP_F_TX_FAULT;
+-+	} else {
+- 		changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
+-+	}
+- 
+- 	for (i = 0; i < GPIO_MAX; i++)
+- 		if (changed & BIT(i))
+diff --git a/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch b/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch
+deleted file mode 100644
+index 703a0b8b72..0000000000
+--- a/target/linux/generic/pending-5.15/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch
++++ /dev/null
+@@ -1,101 +0,0 @@
+-From ace6abaa0f9203083fe4c0a6a74da2d96410b625 Mon Sep 17 00:00:00 2001
+-From: Alexander Couzens <lynxis@fe80.eu>
+-Date: Sat, 13 Aug 2022 12:49:33 +0200
+-Subject: [PATCH 01/10] net: phy: realtek: rtl8221: allow to configure SERDES
+- mode
+-
+-The rtl8221 supports multiple SERDES modes:
+-- SGMII
+-- 2500base-x
+-- HiSGMII
+-
+-Further it supports rate adaption on SERDES links to allow
+-slow ethernet speeds (10/100/1000mbit) to work on 2500base-x/HiSGMII
+-links without reducing the SERDES speed.
+-
+-When operating without rate adapters the SERDES link will follow the
+-ethernet speed.
+-
+-Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
+----
+- drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++++++++++++++
+- 1 file changed, 48 insertions(+)
+-
+---- a/drivers/net/phy/realtek.c
+-+++ b/drivers/net/phy/realtek.c
+-@@ -53,6 +53,15 @@
+- 						 RTL8201F_ISR_LINK)
+- #define RTL8201F_IER				0x13
+- 
+-+#define RTL8221B_MMD_SERDES_CTRL		MDIO_MMD_VEND1
+-+#define RTL8221B_MMD_PHY_CTRL			MDIO_MMD_VEND2
+-+#define RTL8221B_SERDES_OPTION			0x697a
+-+#define RTL8221B_SERDES_OPTION_MODE_MASK	GENMASK(5, 0)
+-+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII	0
+-+#define RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII	1
+-+#define RTL8221B_SERDES_OPTION_MODE_2500BASEX		2
+-+#define RTL8221B_SERDES_OPTION_MODE_HISGMII		3
+-+
+- #define RTL8366RB_POWER_SAVE			0x15
+- #define RTL8366RB_POWER_SAVE_ON			BIT(12)
+- 
+-@@ -841,6 +850,43 @@ static irqreturn_t rtl9000a_handle_inter
+- 	return IRQ_HANDLED;
+- }
+- 
+-+static int rtl8221b_config_init(struct phy_device *phydev)
+-+{
+-+	u16 option_mode;
+-+
+-+	switch (phydev->interface) {
+-+	case PHY_INTERFACE_MODE_SGMII:
+-+	case PHY_INTERFACE_MODE_2500BASEX:
+-+		option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII;
+-+		break;
+-+	default:
+-+		return 0;
+-+	}
+-+
+-+	phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL,
+-+                      0x75f3, 0);
+-+
+-+	phy_modify_mmd_changed(phydev, RTL8221B_MMD_SERDES_CTRL,
+-+			       RTL8221B_SERDES_OPTION,
+-+			       RTL8221B_SERDES_OPTION_MODE_MASK, option_mode);
+-+	switch (option_mode) {
+-+        case RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII:
+-+        case RTL8221B_SERDES_OPTION_MODE_2500BASEX:
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd455);
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+-+                break;
+-+        case RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII:
+-+        case RTL8221B_SERDES_OPTION_MODE_HISGMII:
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503);
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd433);
+-+                phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020);
+-+                break;
+-+	}
+-+
+-+	return 0;
+-+}
+-+
+- static struct phy_driver realtek_drvs[] = {
+- 	{
+- 		PHY_ID_MATCH_EXACT(0x00008201),
+-@@ -981,6 +1027,7 @@ static struct phy_driver realtek_drvs[]
+- 		PHY_ID_MATCH_EXACT(0x001cc849),
+- 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY",
+- 		.get_features   = rtl822x_get_features,
+-+		.config_init	= rtl8221b_config_init,
+- 		.config_aneg    = rtl822x_config_aneg,
+- 		.read_status    = rtl822x_read_status,
+- 		.suspend        = genphy_suspend,
+-@@ -992,6 +1039,7 @@ static struct phy_driver realtek_drvs[]
+- 		.name           = "RTL8221B-VM-CG 2.5Gbps PHY",
+- 		.get_features   = rtl822x_get_features,
+- 		.config_aneg    = rtl822x_config_aneg,
+-+		.config_init	= rtl8221b_config_init,
+- 		.read_status    = rtl822x_read_status,
+- 		.suspend        = genphy_suspend,
+- 		.resume         = rtlgen_resume,
+diff --git a/target/linux/mvebu/config-5.15 b/target/linux/mvebu/config-5.15
+index bf432cd183..42351e6ff2 100644
+--- a/target/linux/mvebu/config-5.15
++++ b/target/linux/mvebu/config-5.15
+@@ -241,6 +241,7 @@ CONFIG_MACH_MVEBU_V7=y
+ CONFIG_MAGIC_SYSRQ=y
+ CONFIG_MANGLE_BOOTARGS=y
+ CONFIG_MARVELL_PHY=y
++CONFIG_MARVELL_10G_PHY=y
+ CONFIG_MDIO_BUS=y
+ CONFIG_MDIO_DEVICE=y
+ CONFIG_MDIO_DEVRES=y
+@@ -347,6 +348,7 @@ CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+ CONFIG_PWM=y
+ CONFIG_PWM_SYSFS=y
+ CONFIG_RATIONAL=y
++CONFIG_REALTEK_PHY=y
+ CONFIG_REGMAP=y
+ CONFIG_REGMAP_I2C=y
+ CONFIG_REGMAP_MMIO=y
+diff --git a/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch b/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch
+new file mode 100644
+index 0000000000..50fddcf6e8
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-01-1-net-phylink-use-pe-for-printing-errors.patch
+@@ -0,0 +1,68 @@
++From ab1198e5a1dc02970a4ba490d4ec3c80d4d027f2 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 1 Mar 2022 08:51:34 +0000
++Subject: [PATCH] net: phylink: use %pe for printing errors
++
++Convert phylink to use %pe for printing error codes, which can print
++them as errno symbols rather than numbers.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1nOyEI-00Buu8-K9@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -1176,9 +1176,8 @@ static int phylink_register_sfp(struct p
++ 
++ 	bus = sfp_bus_find_fwnode(fwnode);
++ 	if (IS_ERR(bus)) {
++-		ret = PTR_ERR(bus);
++-		phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
++-		return ret;
+++		phylink_err(pl, "unable to attach SFP bus: %pe\n", bus);
+++		return PTR_ERR(bus);
++ 	}
++ 
++ 	pl->sfp_bus = bus;
++@@ -1405,11 +1404,11 @@ static int phylink_bringup_phy(struct ph
++ 
++ 	ret = phylink_validate(pl, supported, &config);
++ 	if (ret) {
++-		phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %d\n",
+++		phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
++ 			     phy_modes(config.interface),
++ 			     __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported,
++ 			     __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising,
++-			     ret);
+++			     ERR_PTR(ret));
++ 		return ret;
++ 	}
++ 
++@@ -2603,8 +2602,9 @@ static int phylink_sfp_config(struct phy
++ 	/* Ignore errors if we're expecting a PHY to attach later */
++ 	ret = phylink_validate(pl, support, &config);
++ 	if (ret) {
++-		phylink_err(pl, "validation with support %*pb failed: %d\n",
++-			    __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
+++		phylink_err(pl, "validation with support %*pb failed: %pe\n",
+++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support,
+++			    ERR_PTR(ret));
++ 		return ret;
++ 	}
++ 
++@@ -2620,10 +2620,12 @@ static int phylink_sfp_config(struct phy
++ 	linkmode_copy(support1, support);
++ 	ret = phylink_validate(pl, support1, &config);
++ 	if (ret) {
++-		phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n",
+++		phylink_err(pl,
+++			    "validation of %s/%s with support %*pb failed: %pe\n",
++ 			    phylink_an_mode_str(mode),
++ 			    phy_modes(config.interface),
++-			    __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
+++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support,
+++			    ERR_PTR(ret));
++ 		return ret;
++ 	}
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch b/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch
+new file mode 100644
+index 0000000000..4237130e35
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-01-2-net-sfp-use-pe-for-printing-errors.patch
+@@ -0,0 +1,165 @@
++From 9ae1ef4b1634547d7ab7d15a9ffd48df8ce6883c Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 1 Mar 2022 08:51:39 +0000
++Subject: [PATCH] net: sfp: use %pe for printing errors
++
++Convert sfp to use %pe for printing error codes, which can print them
++as errno symbols rather than numbers.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1nOyEN-00BuuE-OB@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -595,8 +595,8 @@ static unsigned int sfp_soft_get_state(s
++ 			state |= SFP_F_TX_FAULT;
++ 	} else {
++ 		dev_err_ratelimited(sfp->dev,
++-				    "failed to read SFP soft status: %d\n",
++-				    ret);
+++				    "failed to read SFP soft status: %pe\n",
+++				    ERR_PTR(ret));
++ 		/* Preserve the current state */
++ 		state = sfp->state;
++ 	}
++@@ -1437,7 +1437,8 @@ static void sfp_hwmon_probe(struct work_
++ 			mod_delayed_work(system_wq, &sfp->hwmon_probe,
++ 					 T_PROBE_RETRY_SLOW);
++ 		} else {
++-			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
+++			dev_warn(sfp->dev, "hwmon probe failed: %pe\n",
+++				 ERR_PTR(err));
++ 		}
++ 		return;
++ 	}
++@@ -1642,14 +1643,15 @@ static int sfp_sm_probe_phy(struct sfp *
++ 	if (phy == ERR_PTR(-ENODEV))
++ 		return PTR_ERR(phy);
++ 	if (IS_ERR(phy)) {
++-		dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy));
+++		dev_err(sfp->dev, "mdiobus scan returned %pe\n", phy);
++ 		return PTR_ERR(phy);
++ 	}
++ 
++ 	err = phy_device_register(phy);
++ 	if (err) {
++ 		phy_device_free(phy);
++-		dev_err(sfp->dev, "phy_device_register failed: %d\n", err);
+++		dev_err(sfp->dev, "phy_device_register failed: %pe\n",
+++			ERR_PTR(err));
++ 		return err;
++ 	}
++ 
++@@ -1657,7 +1659,7 @@ static int sfp_sm_probe_phy(struct sfp *
++ 	if (err) {
++ 		phy_device_remove(phy);
++ 		phy_device_free(phy);
++-		dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err);
+++		dev_err(sfp->dev, "sfp_add_phy failed: %pe\n", ERR_PTR(err));
++ 		return err;
++ 	}
++ 
++@@ -1834,7 +1836,7 @@ static int sfp_sm_mod_hpower(struct sfp
++ 
++ 	err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
++ 	if (err != sizeof(val)) {
++-		dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
+++		dev_err(sfp->dev, "Failed to read EEPROM: %pe\n", ERR_PTR(err));
++ 		return -EAGAIN;
++ 	}
++ 
++@@ -1852,7 +1854,8 @@ static int sfp_sm_mod_hpower(struct sfp
++ 
++ 	err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
++ 	if (err != sizeof(val)) {
++-		dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
+++		dev_err(sfp->dev, "Failed to write EEPROM: %pe\n",
+++			ERR_PTR(err));
++ 		return -EAGAIN;
++ 	}
++ 
++@@ -1904,7 +1907,9 @@ static int sfp_cotsworks_fixup_check(str
++ 		id->base.connector = SFF8024_CONNECTOR_LC;
++ 		err = sfp_write(sfp, false, SFP_PHYS_ID, &id->base, 3);
++ 		if (err != 3) {
++-			dev_err(sfp->dev, "Failed to rewrite module EEPROM: %d\n", err);
+++			dev_err(sfp->dev,
+++				"Failed to rewrite module EEPROM: %pe\n",
+++				ERR_PTR(err));
++ 			return err;
++ 		}
++ 
++@@ -1915,7 +1920,9 @@ static int sfp_cotsworks_fixup_check(str
++ 		check = sfp_check(&id->base, sizeof(id->base) - 1);
++ 		err = sfp_write(sfp, false, SFP_CC_BASE, &check, 1);
++ 		if (err != 1) {
++-			dev_err(sfp->dev, "Failed to update base structure checksum in fiber module EEPROM: %d\n", err);
+++			dev_err(sfp->dev,
+++				"Failed to update base structure checksum in fiber module EEPROM: %pe\n",
+++				ERR_PTR(err));
++ 			return err;
++ 		}
++ 	}
++@@ -1936,12 +1943,13 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
++ 	if (ret < 0) {
++ 		if (report)
++-			dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
+++			dev_err(sfp->dev, "failed to read EEPROM: %pe\n",
+++				ERR_PTR(ret));
++ 		return -EAGAIN;
++ 	}
++ 
++ 	if (ret != sizeof(id.base)) {
++-		dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
+++		dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret));
++ 		return -EAGAIN;
++ 	}
++ 
++@@ -1961,13 +1969,15 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
++ 		if (ret < 0) {
++ 			if (report)
++-				dev_err(sfp->dev, "failed to read EEPROM: %d\n",
++-					ret);
+++				dev_err(sfp->dev,
+++					"failed to read EEPROM: %pe\n",
+++					ERR_PTR(ret));
++ 			return -EAGAIN;
++ 		}
++ 
++ 		if (ret != sizeof(id.base)) {
++-			dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
+++			dev_err(sfp->dev, "EEPROM short read: %pe\n",
+++				ERR_PTR(ret));
++ 			return -EAGAIN;
++ 		}
++ 	}
++@@ -2009,12 +2019,13 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext));
++ 	if (ret < 0) {
++ 		if (report)
++-			dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
+++			dev_err(sfp->dev, "failed to read EEPROM: %pe\n",
+++				ERR_PTR(ret));
++ 		return -EAGAIN;
++ 	}
++ 
++ 	if (ret != sizeof(id.ext)) {
++-		dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
+++		dev_err(sfp->dev, "EEPROM short read: %pe\n", ERR_PTR(ret));
++ 		return -EAGAIN;
++ 	}
++ 
++@@ -2179,7 +2190,8 @@ static void sfp_sm_module(struct sfp *sf
++ 
++ 		err = sfp_hwmon_insert(sfp);
++ 		if (err)
++-			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
+++			dev_warn(sfp->dev, "hwmon probe failed: %pe\n",
+++				 ERR_PTR(err));
++ 
++ 		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
++ 		fallthrough;
+diff --git a/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch b/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch
+new file mode 100644
+index 0000000000..6d730934a1
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-01-net-phylink-add-ability-to-validate-a-set-of-interfa.patch
+@@ -0,0 +1,60 @@
++From 1645f44dd5b846a473d7789fe622c278eb880d48 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 30 Sep 2022 16:20:59 +0200
++Subject: [PATCH] net: phylink: add ability to validate a set of interface
++ modes
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Rather than having the ability to validate all supported interface
++modes or a single interface mode, introduce the ability to validate
++a subset of supported modes.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++[ rebased on current net-next ]
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -467,8 +467,9 @@ void phylink_generic_validate(struct phy
++ }
++ EXPORT_SYMBOL_GPL(phylink_generic_validate);
++ 
++-static int phylink_validate_any(struct phylink *pl, unsigned long *supported,
++-				struct phylink_link_state *state)
+++static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
+++				 struct phylink_link_state *state,
+++				 const unsigned long *interfaces)
++ {
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
++@@ -477,7 +478,7 @@ static int phylink_validate_any(struct p
++ 	int intf;
++ 
++ 	for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
++-		if (test_bit(intf, pl->config->supported_interfaces)) {
+++		if (test_bit(intf, interfaces)) {
++ 			linkmode_copy(s, supported);
++ 
++ 			t = *state;
++@@ -498,12 +499,14 @@ static int phylink_validate_any(struct p
++ static int phylink_validate(struct phylink *pl, unsigned long *supported,
++ 			    struct phylink_link_state *state)
++ {
++-	if (!phy_interface_empty(pl->config->supported_interfaces)) {
+++	const unsigned long *interfaces = pl->config->supported_interfaces;
+++
+++	if (!phy_interface_empty(interfaces)) {
++ 		if (state->interface == PHY_INTERFACE_MODE_NA)
++-			return phylink_validate_any(pl, supported, state);
+++			return phylink_validate_mask(pl, supported, state,
+++						     interfaces);
++ 
++-		if (!test_bit(state->interface,
++-			      pl->config->supported_interfaces))
+++		if (!test_bit(state->interface, interfaces))
++ 			return -EINVAL;
++ 	}
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch b/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
+new file mode 100644
+index 0000000000..9ff137d7b1
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-02-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
+@@ -0,0 +1,322 @@
++From fd580c9830316edad6f8b1d9f542563730658efe Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Fri, 30 Sep 2022 16:21:00 +0200
++Subject: [PATCH] net: sfp: augment SFP parsing with phy_interface_t bitmap
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++We currently parse the SFP EEPROM to a bitmap of ethtool link modes,
++and then attempt to convert the link modes to a PHY interface mode.
++While this works at present, there are cases where this is sub-optimal.
++For example, where a module can operate with several different PHY
++interface modes.
++
++To start addressing this, arrange for the SFP EEPROM parsing to also
++provide a bitmap of the possible PHY interface modes.
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++[ backported to 5.15 ]
++
++--- a/drivers/net/phy/marvell-88x2222.c
+++++ b/drivers/net/phy/marvell-88x2222.c
++@@ -478,6 +478,7 @@ static int mv2222_config_init(struct phy
++ 
++ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++ {
+++	DECLARE_PHY_INTERFACE_MASK(interfaces);
++ 	struct phy_device *phydev = upstream;
++ 	phy_interface_t sfp_interface;
++ 	struct mv2222_data *priv;
++@@ -489,7 +490,7 @@ static int mv2222_sfp_insert(void *upstr
++ 	priv = (struct mv2222_data *)phydev->priv;
++ 	dev = &phydev->mdio.dev;
++ 
++-	sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
+++	sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces);
++ 	sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
++ 
++ 	dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
++--- a/drivers/net/phy/marvell.c
+++++ b/drivers/net/phy/marvell.c
++@@ -2808,6 +2808,7 @@ static int marvell_probe(struct phy_devi
++ 
++ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++ {
+++	DECLARE_PHY_INTERFACE_MASK(interfaces);
++ 	struct phy_device *phydev = upstream;
++ 	phy_interface_t interface;
++ 	struct device *dev;
++@@ -2819,7 +2820,7 @@ static int m88e1510_sfp_insert(void *ups
++ 
++ 	dev = &phydev->mdio.dev;
++ 
++-	sfp_parse_support(phydev->sfp_bus, id, supported);
+++	sfp_parse_support(phydev->sfp_bus, id, supported, interfaces);
++ 	interface = sfp_select_interface(phydev->sfp_bus, supported);
++ 
++ 	dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -394,9 +394,10 @@ static int mv3310_sfp_insert(void *upstr
++ {
++ 	struct phy_device *phydev = upstream;
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+++	DECLARE_PHY_INTERFACE_MASK(interfaces);
++ 	phy_interface_t iface;
++ 
++-	sfp_parse_support(phydev->sfp_bus, id, support);
+++	sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
++ 	iface = sfp_select_interface(phydev->sfp_bus, support);
++ 
++ 	if (iface != PHY_INTERFACE_MODE_10GBASER) {
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -78,6 +78,7 @@ struct phylink {
++ 
++ 	struct sfp_bus *sfp_bus;
++ 	bool sfp_may_have_phy;
+++	DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
++ 	u8 sfp_port;
++ };
++@@ -2677,7 +2678,8 @@ static int phylink_sfp_module_insert(voi
++ 	ASSERT_RTNL();
++ 
++ 	linkmode_zero(support);
++-	sfp_parse_support(pl->sfp_bus, id, support);
+++	phy_interface_zero(pl->sfp_interfaces);
+++	sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces);
++ 	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
++ 
++ 	/* If this module may have a PHY connecting later, defer until later */
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -139,12 +139,14 @@ EXPORT_SYMBOL_GPL(sfp_may_have_phy);
++  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
++  * @id: a pointer to the module's &struct sfp_eeprom_id
++  * @support: pointer to an array of unsigned long for the ethtool support mask
+++ * @interfaces: pointer to an array of unsigned long for phy interface modes
+++ *		mask
++  *
++  * Parse the EEPROM identification information and derive the supported
++  * ethtool link modes for the module.
++  */
++ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
++-		       unsigned long *support)
+++		       unsigned long *support, unsigned long *interfaces)
++ {
++ 	unsigned int br_min, br_nom, br_max;
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
++@@ -171,54 +173,81 @@ void sfp_parse_support(struct sfp_bus *b
++ 	}
++ 
++ 	/* Set ethtool support from the compliance fields. */
++-	if (id->base.e10g_base_sr)
+++	if (id->base.e10g_base_sr) {
++ 		phylink_set(modes, 10000baseSR_Full);
++-	if (id->base.e10g_base_lr)
+++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++	}
+++	if (id->base.e10g_base_lr) {
++ 		phylink_set(modes, 10000baseLR_Full);
++-	if (id->base.e10g_base_lrm)
+++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++	}
+++	if (id->base.e10g_base_lrm) {
++ 		phylink_set(modes, 10000baseLRM_Full);
++-	if (id->base.e10g_base_er)
+++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++	}
+++	if (id->base.e10g_base_er) {
++ 		phylink_set(modes, 10000baseER_Full);
+++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++	}
++ 	if (id->base.e1000_base_sx ||
++ 	    id->base.e1000_base_lx ||
++-	    id->base.e1000_base_cx)
+++	    id->base.e1000_base_cx) {
++ 		phylink_set(modes, 1000baseX_Full);
+++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++	}
++ 	if (id->base.e1000_base_t) {
++ 		phylink_set(modes, 1000baseT_Half);
++ 		phylink_set(modes, 1000baseT_Full);
+++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++		__set_bit(PHY_INTERFACE_MODE_SGMII, interfaces);
++ 	}
++ 
++ 	/* 1000Base-PX or 1000Base-BX10 */
++ 	if ((id->base.e_base_px || id->base.e_base_bx10) &&
++-	    br_min <= 1300 && br_max >= 1200)
+++	    br_min <= 1300 && br_max >= 1200) {
++ 		phylink_set(modes, 1000baseX_Full);
+++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++	}
++ 
++ 	/* 100Base-FX, 100Base-LX, 100Base-PX, 100Base-BX10 */
++-	if (id->base.e100_base_fx || id->base.e100_base_lx)
+++	if (id->base.e100_base_fx || id->base.e100_base_lx) {
++ 		phylink_set(modes, 100baseFX_Full);
++-	if ((id->base.e_base_px || id->base.e_base_bx10) && br_nom == 100)
+++		__set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces);
+++	}
+++	if ((id->base.e_base_px || id->base.e_base_bx10) && br_nom == 100) {
++ 		phylink_set(modes, 100baseFX_Full);
+++		__set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces);
+++	}
++ 
++ 	/* For active or passive cables, select the link modes
++ 	 * based on the bit rates and the cable compliance bytes.
++ 	 */
++ 	if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
++ 		/* This may look odd, but some manufacturers use 12000MBd */
++-		if (br_min <= 12000 && br_max >= 10300)
+++		if (br_min <= 12000 && br_max >= 10300) {
++ 			phylink_set(modes, 10000baseCR_Full);
++-		if (br_min <= 3200 && br_max >= 3100)
+++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++		}
+++		if (br_min <= 3200 && br_max >= 3100) {
++ 			phylink_set(modes, 2500baseX_Full);
++-		if (br_min <= 1300 && br_max >= 1200)
+++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
+++		}
+++		if (br_min <= 1300 && br_max >= 1200) {
++ 			phylink_set(modes, 1000baseX_Full);
+++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++		}
++ 	}
++ 	if (id->base.sfp_ct_passive) {
++-		if (id->base.passive.sff8431_app_e)
+++		if (id->base.passive.sff8431_app_e) {
++ 			phylink_set(modes, 10000baseCR_Full);
+++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+++		}
++ 	}
++ 	if (id->base.sfp_ct_active) {
++ 		if (id->base.active.sff8431_app_e ||
++ 		    id->base.active.sff8431_lim) {
++ 			phylink_set(modes, 10000baseCR_Full);
+++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
++ 		}
++ 	}
++ 
++@@ -243,12 +272,14 @@ void sfp_parse_support(struct sfp_bus *b
++ 	case SFF8024_ECC_10GBASE_T_SFI:
++ 	case SFF8024_ECC_10GBASE_T_SR:
++ 		phylink_set(modes, 10000baseT_Full);
+++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
++ 		break;
++ 	case SFF8024_ECC_5GBASE_T:
++ 		phylink_set(modes, 5000baseT_Full);
++ 		break;
++ 	case SFF8024_ECC_2_5GBASE_T:
++ 		phylink_set(modes, 2500baseT_Full);
+++		__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
++ 		break;
++ 	default:
++ 		dev_warn(bus->sfp_dev,
++@@ -261,10 +292,14 @@ void sfp_parse_support(struct sfp_bus *b
++ 	if (id->base.fc_speed_100 ||
++ 	    id->base.fc_speed_200 ||
++ 	    id->base.fc_speed_400) {
++-		if (id->base.br_nominal >= 31)
+++		if (id->base.br_nominal >= 31) {
++ 			phylink_set(modes, 2500baseX_Full);
++-		if (id->base.br_nominal >= 12)
+++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
+++		}
+++		if (id->base.br_nominal >= 12) {
++ 			phylink_set(modes, 1000baseX_Full);
+++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++		}
++ 	}
++ 
++ 	/* If we haven't discovered any modes that this module supports, try
++@@ -277,14 +312,18 @@ void sfp_parse_support(struct sfp_bus *b
++ 	 * 2500BASE-X, so we allow some slack here.
++ 	 */
++ 	if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) {
++-		if (br_min <= 1300 && br_max >= 1200)
+++		if (br_min <= 1300 && br_max >= 1200) {
++ 			phylink_set(modes, 1000baseX_Full);
++-		if (br_min <= 3200 && br_max >= 2500)
+++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+++		}
+++		if (br_min <= 3200 && br_max >= 2500) {
++ 			phylink_set(modes, 2500baseX_Full);
+++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
+++		}
++ 	}
++ 
++ 	if (bus->sfp_quirk && bus->sfp_quirk->modes)
++-		bus->sfp_quirk->modes(id, modes);
+++		bus->sfp_quirk->modes(id, modes, interfaces);
++ 
++ 	linkmode_or(support, support, modes);
++ 
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -337,13 +337,16 @@ static void sfp_fixup_halny_gsfp(struct
++ }
++ 
++ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
++-				unsigned long *modes)
+++				unsigned long *modes,
+++				unsigned long *interfaces)
++ {
++ 	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
+++	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
++ }
++ 
++ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
++-				      unsigned long *modes)
+++				      unsigned long *modes,
+++				      unsigned long *interfaces)
++ {
++ 	/* Ubiquiti U-Fiber Instant module claims that support all transceiver
++ 	 * types including 10G Ethernet which is not truth. So clear all claimed
++@@ -351,6 +354,7 @@ static void sfp_quirk_ubnt_uf_instant(co
++ 	 */
++ 	linkmode_zero(modes);
++ 	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes);
+++	__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
++ }
++ 
++ static const struct sfp_quirk sfp_quirks[] = {
++--- a/drivers/net/phy/sfp.h
+++++ b/drivers/net/phy/sfp.h
++@@ -9,7 +9,8 @@ struct sfp;
++ struct sfp_quirk {
++ 	const char *vendor;
++ 	const char *part;
++-	void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
+++	void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes,
+++		      unsigned long *interfaces);
++ 	void (*fixup)(struct sfp *sfp);
++ };
++ 
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -535,7 +535,7 @@ int sfp_parse_port(struct sfp_bus *bus,
++ 		   unsigned long *support);
++ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
++ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
++-		       unsigned long *support);
+++		       unsigned long *support, unsigned long *interfaces);
++ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
++ 				     unsigned long *link_modes);
++ 
++@@ -568,7 +568,8 @@ static inline bool sfp_may_have_phy(stru
++ 
++ static inline void sfp_parse_support(struct sfp_bus *bus,
++ 				     const struct sfp_eeprom_id *id,
++-				     unsigned long *support)
+++				     unsigned long *support,
+++				     unsigned long *interfaces)
++ {
++ }
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch b/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
+new file mode 100644
+index 0000000000..89eb65d350
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-03-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
+@@ -0,0 +1,238 @@
++From f81fa96d8a6c7a7723b7cfa2ef8f6e514843d577 Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Fri, 30 Sep 2022 16:21:01 +0200
++Subject: [PATCH] net: phylink: use phy_interface_t bitmaps for optical modules
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Where a MAC provides a phy_interface_t bitmap, use these bitmaps to
++select the operating interface mode for optical SFP modules, rather
++than using the linkmode bitmaps.
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -2582,6 +2582,70 @@ static void phylink_sfp_detach(void *ups
++ 	pl->netdev->sfp_bus = NULL;
++ }
++ 
+++static const phy_interface_t phylink_sfp_interface_preference[] = {
+++	PHY_INTERFACE_MODE_25GBASER,
+++	PHY_INTERFACE_MODE_USXGMII,
+++	PHY_INTERFACE_MODE_10GBASER,
+++	PHY_INTERFACE_MODE_5GBASER,
+++	PHY_INTERFACE_MODE_2500BASEX,
+++	PHY_INTERFACE_MODE_SGMII,
+++	PHY_INTERFACE_MODE_1000BASEX,
+++	PHY_INTERFACE_MODE_100BASEX,
+++};
+++
+++static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
+++						    const unsigned long *intf)
+++{
+++	phy_interface_t interface;
+++	size_t i;
+++
+++	interface = PHY_INTERFACE_MODE_NA;
+++	for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++)
+++		if (test_bit(phylink_sfp_interface_preference[i], intf)) {
+++			interface = phylink_sfp_interface_preference[i];
+++			break;
+++		}
+++
+++	return interface;
+++}
+++
+++static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
+++				   unsigned long *supported,
+++				   struct phylink_link_state *state)
+++{
+++	bool changed = false;
+++
+++	phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
+++		    phylink_an_mode_str(mode), phy_modes(state->interface),
+++		    __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
+++
+++	if (!linkmode_equal(pl->supported, supported)) {
+++		linkmode_copy(pl->supported, supported);
+++		changed = true;
+++	}
+++
+++	if (!linkmode_equal(pl->link_config.advertising, state->advertising)) {
+++		linkmode_copy(pl->link_config.advertising, state->advertising);
+++		changed = true;
+++	}
+++
+++	if (pl->cur_link_an_mode != mode ||
+++	    pl->link_config.interface != state->interface) {
+++		pl->cur_link_an_mode = mode;
+++		pl->link_config.interface = state->interface;
+++
+++		changed = true;
+++
+++		phylink_info(pl, "switched to %s/%s link mode\n",
+++			     phylink_an_mode_str(mode),
+++			     phy_modes(state->interface));
+++	}
+++
+++	if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
+++				 &pl->phylink_disable_state))
+++		phylink_mac_initial_config(pl, false);
+++}
+++
++ static int phylink_sfp_config(struct phylink *pl, u8 mode,
++ 			      const unsigned long *supported,
++ 			      const unsigned long *advertising)
++@@ -2590,7 +2654,6 @@ static int phylink_sfp_config(struct phy
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
++ 	struct phylink_link_state config;
++ 	phy_interface_t iface;
++-	bool changed;
++ 	int ret;
++ 
++ 	linkmode_copy(support, supported);
++@@ -2633,61 +2696,103 @@ static int phylink_sfp_config(struct phy
++ 		return ret;
++ 	}
++ 
++-	phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
++-		    phylink_an_mode_str(mode), phy_modes(config.interface),
++-		    __ETHTOOL_LINK_MODE_MASK_NBITS, support);
++-
++ 	if (phy_interface_mode_is_8023z(iface) && pl->phydev)
++ 		return -EINVAL;
++ 
++-	changed = !linkmode_equal(pl->supported, support) ||
++-		  !linkmode_equal(pl->link_config.advertising,
++-				  config.advertising);
++-	if (changed) {
++-		linkmode_copy(pl->supported, support);
++-		linkmode_copy(pl->link_config.advertising, config.advertising);
+++	pl->link_port = pl->sfp_port;
+++
+++	phylink_sfp_set_config(pl, mode, support, &config);
+++
+++	return 0;
+++}
+++
+++static int phylink_sfp_config_optical(struct phylink *pl)
+++{
+++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
+++	DECLARE_PHY_INTERFACE_MASK(interfaces);
+++	struct phylink_link_state config;
+++	phy_interface_t interface;
+++	int ret;
+++
+++	phylink_dbg(pl, "optical SFP: interfaces=[mac=%*pbl, sfp=%*pbl]\n",
+++		    (int)PHY_INTERFACE_MODE_MAX,
+++		    pl->config->supported_interfaces,
+++		    (int)PHY_INTERFACE_MODE_MAX,
+++		    pl->sfp_interfaces);
+++
+++	/* Find the union of the supported interfaces by the PCS/MAC and
+++	 * the SFP module.
+++	 */
+++	phy_interface_and(interfaces, pl->config->supported_interfaces,
+++			  pl->sfp_interfaces);
+++	if (phy_interface_empty(interfaces)) {
+++		phylink_err(pl, "unsupported SFP module: no common interface modes\n");
+++		return -EINVAL;
++ 	}
++ 
++-	if (pl->cur_link_an_mode != mode ||
++-	    pl->link_config.interface != config.interface) {
++-		pl->link_config.interface = config.interface;
++-		pl->cur_link_an_mode = mode;
+++	memset(&config, 0, sizeof(config));
+++	linkmode_copy(support, pl->sfp_support);
+++	linkmode_copy(config.advertising, pl->sfp_support);
+++	config.speed = SPEED_UNKNOWN;
+++	config.duplex = DUPLEX_UNKNOWN;
+++	config.pause = MLO_PAUSE_AN;
+++	config.an_enabled = true;
++ 
++-		changed = true;
+++	/* For all the interfaces that are supported, reduce the sfp_support
+++	 * mask to only those link modes that can be supported.
+++	 */
+++	ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
+++	if (ret) {
+++		phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
+++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+++		return ret;
+++	}
++ 
++-		phylink_info(pl, "switched to %s/%s link mode\n",
++-			     phylink_an_mode_str(mode),
++-			     phy_modes(config.interface));
+++	interface = phylink_choose_sfp_interface(pl, interfaces);
+++	if (interface == PHY_INTERFACE_MODE_NA) {
+++		phylink_err(pl, "failed to select SFP interface\n");
+++		return -EINVAL;
+++	}
+++
+++	phylink_dbg(pl, "optical SFP: chosen %s interface\n",
+++		    phy_modes(interface));
+++
+++	config.interface = interface;
+++
+++	/* Ignore errors if we're expecting a PHY to attach later */
+++	ret = phylink_validate(pl, support, &config);
+++	if (ret) {
+++		phylink_err(pl, "validation with support %*pb failed: %pe\n",
+++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support,
+++			    ERR_PTR(ret));
+++		return ret;
++ 	}
++ 
++ 	pl->link_port = pl->sfp_port;
++ 
++-	if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
++-				 &pl->phylink_disable_state))
++-		phylink_mac_initial_config(pl, false);
+++	phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
++ 
++-	return ret;
+++	return 0;
++ }
++ 
++ static int phylink_sfp_module_insert(void *upstream,
++ 				     const struct sfp_eeprom_id *id)
++ {
++ 	struct phylink *pl = upstream;
++-	unsigned long *support = pl->sfp_support;
++ 
++ 	ASSERT_RTNL();
++ 
++-	linkmode_zero(support);
+++	linkmode_zero(pl->sfp_support);
++ 	phy_interface_zero(pl->sfp_interfaces);
++-	sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces);
++-	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
+++	sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces);
+++	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support);
++ 
++ 	/* If this module may have a PHY connecting later, defer until later */
++ 	pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
++ 	if (pl->sfp_may_have_phy)
++ 		return 0;
++ 
++-	return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
+++	return phylink_sfp_config_optical(pl);
++ }
++ 
++ static int phylink_sfp_module_start(void *upstream)
++@@ -2706,8 +2811,7 @@ static int phylink_sfp_module_start(void
++ 	if (!pl->sfp_may_have_phy)
++ 		return 0;
++ 
++-	return phylink_sfp_config(pl, MLO_AN_INBAND,
++-				  pl->sfp_support, pl->sfp_support);
+++	return phylink_sfp_config_optical(pl);
++ }
++ 
++ static void phylink_sfp_module_stop(void *upstream)
+diff --git a/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch b/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch
+new file mode 100644
+index 0000000000..459fb57704
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-04-net-phylink-rename-phylink_sfp_config.patch
+@@ -0,0 +1,51 @@
++From e60846370ca96a042d0e203782b84ed9558a8546 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 30 Sep 2022 16:21:02 +0200
++Subject: [PATCH] net: phylink: rename phylink_sfp_config()
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++phylink_sfp_config() now only deals with configuring the MAC for a
++SFP containing a PHY. Rename it to be specific.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -2646,9 +2646,8 @@ static void phylink_sfp_set_config(struc
++ 		phylink_mac_initial_config(pl, false);
++ }
++ 
++-static int phylink_sfp_config(struct phylink *pl, u8 mode,
++-			      const unsigned long *supported,
++-			      const unsigned long *advertising)
+++static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
+++				  struct phy_device *phy)
++ {
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
++@@ -2656,10 +2655,10 @@ static int phylink_sfp_config(struct phy
++ 	phy_interface_t iface;
++ 	int ret;
++ 
++-	linkmode_copy(support, supported);
+++	linkmode_copy(support, phy->supported);
++ 
++ 	memset(&config, 0, sizeof(config));
++-	linkmode_copy(config.advertising, advertising);
+++	linkmode_copy(config.advertising, phy->advertising);
++ 	config.interface = PHY_INTERFACE_MODE_NA;
++ 	config.speed = SPEED_UNKNOWN;
++ 	config.duplex = DUPLEX_UNKNOWN;
++@@ -2872,7 +2871,7 @@ static int phylink_sfp_connect_phy(void
++ 		mode = MLO_AN_INBAND;
++ 
++ 	/* Do the initial configuration */
++-	ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising);
+++	ret = phylink_sfp_config_phy(pl, mode, phy);
++ 	if (ret < 0)
++ 		return ret;
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch b/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch
+new file mode 100644
+index 0000000000..5e9c007c8a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-05-net-phylink-pass-supported-host-PHY-interface-modes-.patch
+@@ -0,0 +1,83 @@
++From eca68a3c7d05b38b4e728cead0c49718f2bc1d5a Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:03 +0200
++Subject: [PATCH] net: phylink: pass supported host PHY interface modes to
++ phylib for SFP's PHYs
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Pass the supported PHY interface types to phylib if the PHY we are
++connecting is inside a SFP, so that the PHY driver can select an
++appropriate host configuration mode for their interface according to
++the host capabilities.
++
++For example the Marvell 88X3310 PHY inside RollBall SFP modules
++defaults to 10gbase-r mode on host's side, and the marvell10g
++driver currently does not change this setting. But a host may not
++support 10gbase-r. For example Turris Omnia only supports sgmii,
++1000base-x and 2500base-x modes. The PHY can be configured to use
++those modes, but in order for the PHY driver to do that, it needs
++to know which modes are supported.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -2593,6 +2593,8 @@ static const phy_interface_t phylink_sfp
++ 	PHY_INTERFACE_MODE_100BASEX,
++ };
++ 
+++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+++
++ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
++ 						    const unsigned long *intf)
++ {
++@@ -2870,6 +2872,10 @@ static int phylink_sfp_connect_phy(void
++ 	else
++ 		mode = MLO_AN_INBAND;
++ 
+++	/* Set the PHY's host supported interfaces */
+++	phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
+++			  pl->config->supported_interfaces);
+++
++ 	/* Do the initial configuration */
++ 	ret = phylink_sfp_config_phy(pl, mode, phy);
++ 	if (ret < 0)
++@@ -3253,4 +3259,15 @@ void phylink_mii_c45_pcs_get_state(struc
++ }
++ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
++ 
+++static int __init phylink_init(void)
+++{
+++	for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i)
+++		__set_bit(phylink_sfp_interface_preference[i],
+++			  phylink_sfp_interfaces);
+++
+++	return 0;
+++}
+++
+++module_init(phylink_init);
+++
++ MODULE_LICENSE("GPL v2");
++--- a/include/linux/phy.h
+++++ b/include/linux/phy.h
++@@ -563,6 +563,7 @@ struct macsec_ops;
++  * @advertising: Currently advertised linkmodes
++  * @adv_old: Saved advertised while power saving for WoL
++  * @lp_advertising: Current link partner advertised linkmodes
+++ * @host_interfaces: PHY interface modes supported by host
++  * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
++  * @autoneg: Flag autoneg being used
++  * @link: Current link state
++@@ -658,6 +659,9 @@ struct phy_device {
++ 	/* used with phy_speed_down */
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
++ 
+++	/* Host supported PHY interface types. Should be ignored if empty. */
+++	DECLARE_PHY_INTERFACE_MASK(host_interfaces);
+++
++ 	/* Energy efficient ethernet modes which should be prohibited */
++ 	u32 eee_broken_modes;
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch b/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
+new file mode 100644
+index 0000000000..2c327f2e28
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-06-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
+@@ -0,0 +1,44 @@
++From 3891569b2fc378e7fb882f5dbdc001ee8f78f024 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:04 +0200
++Subject: [PATCH] net: phy: marvell10g: Use tabs instead of spaces for
++ indentation
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Some register definitions were defined with spaces used for indentation.
++Change them to tabs.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -105,16 +105,16 @@ enum {
++ 	MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN	= 0x5,
++ 	MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH	= 0x6,
++ 	MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII			= 0x7,
++-	MV_V2_PORT_INTR_STS     = 0xf040,
++-	MV_V2_PORT_INTR_MASK    = 0xf043,
++-	MV_V2_PORT_INTR_STS_WOL_EN      = BIT(8),
++-	MV_V2_MAGIC_PKT_WORD0   = 0xf06b,
++-	MV_V2_MAGIC_PKT_WORD1   = 0xf06c,
++-	MV_V2_MAGIC_PKT_WORD2   = 0xf06d,
+++	MV_V2_PORT_INTR_STS		= 0xf040,
+++	MV_V2_PORT_INTR_MASK		= 0xf043,
+++	MV_V2_PORT_INTR_STS_WOL_EN	= BIT(8),
+++	MV_V2_MAGIC_PKT_WORD0		= 0xf06b,
+++	MV_V2_MAGIC_PKT_WORD1		= 0xf06c,
+++	MV_V2_MAGIC_PKT_WORD2		= 0xf06d,
++ 	/* Wake on LAN registers */
++-	MV_V2_WOL_CTRL          = 0xf06e,
++-	MV_V2_WOL_CTRL_CLEAR_STS        = BIT(15),
++-	MV_V2_WOL_CTRL_MAGIC_PKT_EN     = BIT(0),
+++	MV_V2_WOL_CTRL			= 0xf06e,
+++	MV_V2_WOL_CTRL_CLEAR_STS	= BIT(15),
+++	MV_V2_WOL_CTRL_MAGIC_PKT_EN	= BIT(0),
++ 	/* Temperature control/read registers (88X3310 only) */
++ 	MV_V2_TEMP_CTRL		= 0xf08a,
++ 	MV_V2_TEMP_CTRL_MASK	= 0xc000,
+diff --git a/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch b/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch
+new file mode 100644
+index 0000000000..575f3f967b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-07-net-phy-marvell10g-select-host-interface-configurati.patch
+@@ -0,0 +1,216 @@
++From d6d29292640d3f778a28a74c53ae1733c023392f Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Fri, 30 Sep 2022 16:21:05 +0200
++Subject: [PATCH] net: phy: marvell10g: select host interface configuration
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Select the host interface configuration according to the capabilities of
++the host if the host provided them. This is currently provided only when
++connecting PHY that is inside a SFP.
++
++The PHY supports several configurations of host communication:
++- always communicate with host in 10gbase-r, even if copper speed is
++  lower (rate matching mode),
++- the same as above but use xaui/rxaui instead of 10gbase-r,
++- switch host SerDes mode between 10gbase-r, 5gbase-r, 2500base-x and
++  sgmii according to copper speed,
++- the same as above but use xaui/rxaui instead of 10gbase-r.
++
++This mode of host communication, called MACTYPE, is by default selected
++by strapping pins, but it can be changed in software.
++
++This adds support for selecting this mode according to which modes are
++supported by the host.
++
++This allows the kernel to:
++- support SFP modules with 88X33X0 or 88E21X0 inside them
++
++Note: we use mv3310_select_mactype() for both 88X3310 and 88X3340,
++although 88X3340 does not support XAUI. This is not a problem because
++88X3340 does not declare XAUI in it's supported_interfaces, and so this
++function will never choose that MACTYPE.
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++[ rebase, updated, also added support for 88E21X0 ]
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -84,6 +84,11 @@ enum {
++ 	MV_PCS_PORT_INFO_NPORTS_MASK	= 0x0380,
++ 	MV_PCS_PORT_INFO_NPORTS_SHIFT	= 7,
++ 
+++	/* SerDes reinitialization 88E21X0 */
+++	MV_AN_21X0_SERDES_CTRL2	= 0x800f,
+++	MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS	= BIT(13),
+++	MV_AN_21X0_SERDES_CTRL2_RUN_INIT	= BIT(15),
+++
++ 	/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
++ 	 * registers appear to set themselves to the 0x800X when AN is
++ 	 * restarted, but status registers appear readable from either.
++@@ -127,6 +132,8 @@ enum {
++ struct mv3310_chip {
++ 	void (*init_supported_interfaces)(unsigned long *mask);
++ 	int (*get_mactype)(struct phy_device *phydev);
+++	int (*set_mactype)(struct phy_device *phydev, int mactype);
+++	int (*select_mactype)(unsigned long *interfaces);
++ 	int (*init_interface)(struct phy_device *phydev, int mactype);
++ 
++ #ifdef CONFIG_HWMON
++@@ -519,6 +526,49 @@ static int mv2110_get_mactype(struct phy
++ 	return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
++ }
++ 
+++static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
+++{
+++	int err, val;
+++
+++	mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
+++	err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
+++			     MV_PMA_21X0_PORT_CTRL_SWRST |
+++			     MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
+++			     MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
+++	if (err)
+++		return err;
+++
+++	err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+++			       MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
+++			       MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
+++	if (err)
+++		return err;
+++
+++	err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
+++					MV_AN_21X0_SERDES_CTRL2, val,
+++					!(val &
+++					  MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
+++					5000, 100000, true);
+++	if (err)
+++		return err;
+++
+++	return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+++				  MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
+++}
+++
+++static int mv2110_select_mactype(unsigned long *interfaces)
+++{
+++	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
+++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+++		 !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
+++	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+++	else
+++		return -1;
+++}
+++
++ static int mv3310_get_mactype(struct phy_device *phydev)
++ {
++ 	int mactype;
++@@ -530,6 +580,46 @@ static int mv3310_get_mactype(struct phy
++ 	return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
++ }
++ 
+++static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
+++{
+++	int ret;
+++
+++	mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
+++	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+++				     MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
+++				     mactype);
+++	if (ret <= 0)
+++		return ret;
+++
+++	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+++				MV_V2_33X0_PORT_CTRL_SWRST);
+++}
+++
+++static int mv3310_select_mactype(unsigned long *interfaces)
+++{
+++	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
+++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+++		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+++		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
+++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+++		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+++		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
+++	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+++	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
+++	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+++		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
+++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
+++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+++	else
+++		return -1;
+++}
+++
++ static int mv2110_init_interface(struct phy_device *phydev, int mactype)
++ {
++ 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++@@ -613,6 +703,20 @@ static int mv3310_config_init(struct phy
++ 	if (err)
++ 		return err;
++ 
+++	/* If host provided host supported interface modes, try to select the
+++	 * best one
+++	 */
+++	if (!phy_interface_empty(phydev->host_interfaces)) {
+++		mactype = chip->select_mactype(phydev->host_interfaces);
+++		if (mactype >= 0) {
+++			phydev_info(phydev, "Changing MACTYPE to %i\n",
+++				    mactype);
+++			err = chip->set_mactype(phydev, mactype);
+++			if (err)
+++				return err;
+++		}
+++	}
+++
++ 	mactype = chip->get_mactype(phydev);
++ 	if (mactype < 0)
++ 		return mactype;
++@@ -953,6 +1057,8 @@ static void mv2111_init_supported_interf
++ static const struct mv3310_chip mv3310_type = {
++ 	.init_supported_interfaces = mv3310_init_supported_interfaces,
++ 	.get_mactype = mv3310_get_mactype,
+++	.set_mactype = mv3310_set_mactype,
+++	.select_mactype = mv3310_select_mactype,
++ 	.init_interface = mv3310_init_interface,
++ 
++ #ifdef CONFIG_HWMON
++@@ -963,6 +1069,8 @@ static const struct mv3310_chip mv3310_t
++ static const struct mv3310_chip mv3340_type = {
++ 	.init_supported_interfaces = mv3340_init_supported_interfaces,
++ 	.get_mactype = mv3310_get_mactype,
+++	.set_mactype = mv3310_set_mactype,
+++	.select_mactype = mv3310_select_mactype,
++ 	.init_interface = mv3340_init_interface,
++ 
++ #ifdef CONFIG_HWMON
++@@ -973,6 +1081,8 @@ static const struct mv3310_chip mv3340_t
++ static const struct mv3310_chip mv2110_type = {
++ 	.init_supported_interfaces = mv2110_init_supported_interfaces,
++ 	.get_mactype = mv2110_get_mactype,
+++	.set_mactype = mv2110_set_mactype,
+++	.select_mactype = mv2110_select_mactype,
++ 	.init_interface = mv2110_init_interface,
++ 
++ #ifdef CONFIG_HWMON
++@@ -983,6 +1093,8 @@ static const struct mv3310_chip mv2110_t
++ static const struct mv3310_chip mv2111_type = {
++ 	.init_supported_interfaces = mv2111_init_supported_interfaces,
++ 	.get_mactype = mv2110_get_mactype,
+++	.set_mactype = mv2110_set_mactype,
+++	.select_mactype = mv2110_select_mactype,
++ 	.init_interface = mv2110_init_interface,
++ 
++ #ifdef CONFIG_HWMON
+diff --git a/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch b/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
+new file mode 100644
+index 0000000000..84404d6839
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-08-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
+@@ -0,0 +1,41 @@
++From 31eb8907aa5b9e9be1a63f2ac574973715172ab4 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:06 +0200
++Subject: [PATCH] net: phylink: allow attaching phy for SFP modules on 802.3z
++ mode
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Some SFPs may contain an internal PHY which may in some cases want to
++connect with the host interface in 1000base-x/2500base-x mode.
++Do not fail if such PHY is being attached in one of these PHY interface
++modes.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Pali Rohár <pali@kernel.org>
++Cc: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -1459,7 +1459,7 @@ static int phylink_attach_phy(struct phy
++ {
++ 	if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
++ 		    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
++-		     phy_interface_mode_is_8023z(interface))))
+++		     phy_interface_mode_is_8023z(interface) && !pl->sfp_bus)))
++ 		return -EINVAL;
++ 
++ 	if (pl->phydev)
++@@ -2697,9 +2697,6 @@ static int phylink_sfp_config_phy(struct
++ 		return ret;
++ 	}
++ 
++-	if (phy_interface_mode_is_8023z(iface) && pl->phydev)
++-		return -EINVAL;
++-
++ 	pl->link_port = pl->sfp_port;
++ 
++ 	phylink_sfp_set_config(pl, mode, support, &config);
+diff --git a/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch b/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch
+new file mode 100644
+index 0000000000..afd627c460
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-09-net-sfp-Add-and-use-macros-for-SFP-quirks-definition.patch
+@@ -0,0 +1,85 @@
++From 13c8adcf221f1ff407115d3269e0fb57e8cecf82 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:07 +0200
++Subject: [PATCH] net: sfp: Add and use macros for SFP quirks definitions
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Add macros SFP_QUIRK(), SFP_QUIRK_M() and SFP_QUIRK_F() for defining SFP
++quirk table entries. Use them to deduplicate the code a little bit.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -357,42 +357,33 @@ static void sfp_quirk_ubnt_uf_instant(co
++ 	__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
++ }
++ 
+++#define SFP_QUIRK(_v, _p, _m, _f) \
+++	{ .vendor = _v, .part = _p, .modes = _m, .fixup = _f, }
+++#define SFP_QUIRK_M(_v, _p, _m) SFP_QUIRK(_v, _p, _m, NULL)
+++#define SFP_QUIRK_F(_v, _p, _f) SFP_QUIRK(_v, _p, NULL, _f)
+++
++ static const struct sfp_quirk sfp_quirks[] = {
++-	{
++-		// Alcatel Lucent G-010S-P can operate at 2500base-X, but
++-		// incorrectly report 2500MBd NRZ in their EEPROM
++-		.vendor = "ALCATELLUCENT",
++-		.part = "G010SP",
++-		.modes = sfp_quirk_2500basex,
++-	}, {
++-		// Alcatel Lucent G-010S-A can operate at 2500base-X, but
++-		// report 3.2GBd NRZ in their EEPROM
++-		.vendor = "ALCATELLUCENT",
++-		.part = "3FE46541AA",
++-		.modes = sfp_quirk_2500basex,
++-		.fixup = sfp_fixup_long_startup,
++-	}, {
++-		.vendor = "HALNy",
++-		.part = "HL-GSFP",
++-		.fixup = sfp_fixup_halny_gsfp,
++-	}, {
++-		// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
++-		// NRZ in their EEPROM
++-		.vendor = "HUAWEI",
++-		.part = "MA5671A",
++-		.modes = sfp_quirk_2500basex,
++-		.fixup = sfp_fixup_ignore_tx_fault,
++-	}, {
++-		// Lantech 8330-262D-E can operate at 2500base-X, but
++-		// incorrectly report 2500MBd NRZ in their EEPROM
++-		.vendor = "Lantech",
++-		.part = "8330-262D-E",
++-		.modes = sfp_quirk_2500basex,
++-	}, {
++-		.vendor = "UBNT",
++-		.part = "UF-INSTANT",
++-		.modes = sfp_quirk_ubnt_uf_instant,
++-	}
+++	// Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly
+++	// report 2500MBd NRZ in their EEPROM
+++	SFP_QUIRK_M("ALCATELLUCENT", "G010SP", sfp_quirk_2500basex),
+++
+++	// Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd
+++	// NRZ in their EEPROM
+++	SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
+++		  sfp_fixup_long_startup),
+++
+++	SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
+++
+++	// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
+++	// their EEPROM
+++	SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
+++		  sfp_fixup_ignore_tx_fault),
+++
+++	// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
+++	// 2500MBd NRZ in their EEPROM
+++	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
+++
+++	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
++ };
++ 
++ static size_t sfp_strlen(const char *str, size_t maxlen)
+diff --git a/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch b/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
+new file mode 100644
+index 0000000000..235f5d4b10
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-10-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
+@@ -0,0 +1,171 @@
++From e85b1347ace677c3822c12d9332dfaaffe594da6 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:08 +0200
++Subject: [PATCH] net: sfp: create/destroy I2C mdiobus before PHY probe/after
++ PHY release
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Instead of configuring the I2C mdiobus when SFP driver is probed,
++create/destroy the mdiobus before the PHY is probed for/after it is
++released.
++
++This way we can tell the mdio-i2c code which protocol to use for each
++SFP transceiver.
++
++Move the code that determines MDIO I2C protocol from
++sfp_sm_probe_for_phy() to sfp_sm_mod_probe(), where most of the SFP ID
++parsing is done. Don't allocate I2C bus if no PHY is expected.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -224,6 +224,7 @@ struct sfp {
++ 	struct i2c_adapter *i2c;
++ 	struct mii_bus *i2c_mii;
++ 	struct sfp_bus *sfp_bus;
+++	enum mdio_i2c_proto mdio_protocol;
++ 	struct phy_device *mod_phy;
++ 	const struct sff_data *type;
++ 	size_t i2c_block_size;
++@@ -537,9 +538,6 @@ static int sfp_i2c_write(struct sfp *sfp
++ 
++ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
++ {
++-	struct mii_bus *i2c_mii;
++-	int ret;
++-
++ 	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
++ 		return -EINVAL;
++ 
++@@ -547,7 +545,15 @@ static int sfp_i2c_configure(struct sfp
++ 	sfp->read = sfp_i2c_read;
++ 	sfp->write = sfp_i2c_write;
++ 
++-	i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
+++	return 0;
+++}
+++
+++static int sfp_i2c_mdiobus_create(struct sfp *sfp)
+++{
+++	struct mii_bus *i2c_mii;
+++	int ret;
+++
+++	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c);
++ 	if (IS_ERR(i2c_mii))
++ 		return PTR_ERR(i2c_mii);
++ 
++@@ -565,6 +571,12 @@ static int sfp_i2c_configure(struct sfp
++ 	return 0;
++ }
++ 
+++static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
+++{
+++	mdiobus_unregister(sfp->i2c_mii);
+++	sfp->i2c_mii = NULL;
+++}
+++
++ /* Interface */
++ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
++ {
++@@ -1730,6 +1742,14 @@ static void sfp_sm_fault(struct sfp *sfp
++ 	}
++ }
++ 
+++static int sfp_sm_add_mdio_bus(struct sfp *sfp)
+++{
+++	if (sfp->mdio_protocol != MDIO_I2C_NONE)
+++		return sfp_i2c_mdiobus_create(sfp);
+++
+++	return 0;
+++}
+++
++ /* Probe a SFP for a PHY device if the module supports copper - the PHY
++  * normally sits at I2C bus address 0x56, and may either be a clause 22
++  * or clause 45 PHY.
++@@ -1745,19 +1765,19 @@ static int sfp_sm_probe_for_phy(struct s
++ {
++ 	int err = 0;
++ 
++-	switch (sfp->id.base.extended_cc) {
++-	case SFF8024_ECC_10GBASE_T_SFI:
++-	case SFF8024_ECC_10GBASE_T_SR:
++-	case SFF8024_ECC_5GBASE_T:
++-	case SFF8024_ECC_2_5GBASE_T:
++-		err = sfp_sm_probe_phy(sfp, true);
+++	switch (sfp->mdio_protocol) {
+++	case MDIO_I2C_NONE:
++ 		break;
++ 
++-	default:
++-		if (sfp->id.base.e1000_base_t)
++-			err = sfp_sm_probe_phy(sfp, false);
+++	case MDIO_I2C_MARVELL_C22:
+++		err = sfp_sm_probe_phy(sfp, false);
+++		break;
+++
+++	case MDIO_I2C_C45:
+++		err = sfp_sm_probe_phy(sfp, true);
++ 		break;
++ 	}
+++
++ 	return err;
++ }
++ 
++@@ -2080,6 +2100,16 @@ static int sfp_sm_mod_probe(struct sfp *
++ 
++ 	sfp->tx_fault_ignore = false;
++ 
+++	if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
+++	    sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
+++	    sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T ||
+++	    sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T)
+++		sfp->mdio_protocol = MDIO_I2C_C45;
+++	else if (sfp->id.base.e1000_base_t)
+++		sfp->mdio_protocol = MDIO_I2C_MARVELL_C22;
+++	else
+++		sfp->mdio_protocol = MDIO_I2C_NONE;
+++
++ 	sfp->quirk = sfp_lookup_quirk(&id);
++ 	if (sfp->quirk && sfp->quirk->fixup)
++ 		sfp->quirk->fixup(sfp);
++@@ -2256,6 +2286,8 @@ static void sfp_sm_main(struct sfp *sfp,
++ 			sfp_module_stop(sfp->sfp_bus);
++ 		if (sfp->mod_phy)
++ 			sfp_sm_phy_detach(sfp);
+++		if (sfp->i2c_mii)
+++			sfp_i2c_mdiobus_destroy(sfp);
++ 		sfp_module_tx_disable(sfp);
++ 		sfp_soft_stop_poll(sfp);
++ 		sfp_sm_next(sfp, SFP_S_DOWN, 0);
++@@ -2318,6 +2350,12 @@ static void sfp_sm_main(struct sfp *sfp,
++ 				     sfp->sm_fault_retries == N_FAULT_INIT);
++ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
++ 	init_done:
+++			/* Create mdiobus and start trying for PHY */
+++			ret = sfp_sm_add_mdio_bus(sfp);
+++			if (ret < 0) {
+++				sfp_sm_next(sfp, SFP_S_FAIL, 0);
+++				break;
+++			}
++ 			sfp->sm_phy_retries = R_PHY_RETRY;
++ 			goto phy_probe;
++ 		}
++--- a/include/linux/mdio/mdio-i2c.h
+++++ b/include/linux/mdio/mdio-i2c.h
++@@ -11,6 +11,12 @@ struct device;
++ struct i2c_adapter;
++ struct mii_bus;
++ 
+++enum mdio_i2c_proto {
+++	MDIO_I2C_NONE,
+++	MDIO_I2C_MARVELL_C22,
+++	MDIO_I2C_C45,
+++};
+++
++ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
++ 
++ #endif
+diff --git a/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch b/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
+new file mode 100644
+index 0000000000..865f107a78
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-11-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
+@@ -0,0 +1,421 @@
++From 09bbedac72d5a9267088c15d1a71c8c3a8fb47e7 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:09 +0200
++Subject: [PATCH] net: phy: mdio-i2c: support I2C MDIO protocol for RollBall
++ SFP modules
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Some multigig SFPs from RollBall and Hilink do not expose functional
++MDIO access to the internal PHY of the SFP via I2C address 0x56
++(although there seems to be read-only clause 22 access on this address).
++
++Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
++Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
++selected to 3 and the password must be filled with 0xff bytes for this
++PHY communication to work.
++
++This extends the mdio-i2c driver to support this protocol by adding a
++special parameter to mdio_i2c_alloc function via which this RollBall
++protocol can be selected.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Cc: Andrew Lunn <andrew@lunn.ch>
++Cc: Russell King <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/mdio/mdio-i2c.c
+++++ b/drivers/net/mdio/mdio-i2c.c
++@@ -3,6 +3,7 @@
++  * MDIO I2C bridge
++  *
++  * Copyright (C) 2015-2016 Russell King
+++ * Copyright (C) 2021 Marek Behun
++  *
++  * Network PHYs can appear on I2C buses when they are part of SFP module.
++  * This driver exposes these PHYs to the networking PHY code, allowing
++@@ -12,6 +13,7 @@
++ #include <linux/i2c.h>
++ #include <linux/mdio/mdio-i2c.h>
++ #include <linux/phy.h>
+++#include <linux/sfp.h>
++ 
++ /*
++  * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
++@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int
++ 	return phy_id + 0x40;
++ }
++ 
++-static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
+++static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg)
++ {
++ 	struct i2c_adapter *i2c = bus->priv;
++ 	struct i2c_msg msgs[2];
++@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *
++ 	return data[0] << 8 | data[1];
++ }
++ 
++-static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+++static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg,
+++				 u16 val)
++ {
++ 	struct i2c_adapter *i2c = bus->priv;
++ 	struct i2c_msg msg;
++@@ -91,9 +94,288 @@ static int i2c_mii_write(struct mii_bus
++ 	return ret < 0 ? ret : 0;
++ }
++ 
++-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
+++/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
+++ * instead via address 0x51, when SFP page is set to 0x03 and password to
+++ * 0xffffffff.
+++ *
+++ * address  size  contents  description
+++ * -------  ----  --------  -----------
+++ * 0x80     1     CMD       0x01/0x02/0x04 for write/read/done
+++ * 0x81     1     DEV       Clause 45 device
+++ * 0x82     2     REG       Clause 45 register
+++ * 0x84     2     VAL       Register value
+++ */
+++#define ROLLBALL_PHY_I2C_ADDR		0x51
+++
+++#define ROLLBALL_PASSWORD		(SFP_VSL + 3)
+++
+++#define ROLLBALL_CMD_ADDR		0x80
+++#define ROLLBALL_DATA_ADDR		0x81
+++
+++#define ROLLBALL_CMD_WRITE		0x01
+++#define ROLLBALL_CMD_READ		0x02
+++#define ROLLBALL_CMD_DONE		0x04
+++
+++#define SFP_PAGE_ROLLBALL_MDIO		3
+++
+++static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs,
+++			      int num)
+++{
+++	int ret;
+++
+++	ret = __i2c_transfer(i2c, msgs, num);
+++	if (ret < 0)
+++		return ret;
+++	else if (ret != num)
+++		return -EIO;
+++	else
+++		return 0;
+++}
+++
+++static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr,
+++				   u8 *page)
+++{
+++	struct i2c_msg msgs[2];
+++	u8 addr = SFP_PAGE;
+++
+++	msgs[0].addr = bus_addr;
+++	msgs[0].flags = 0;
+++	msgs[0].len = 1;
+++	msgs[0].buf = &addr;
+++
+++	msgs[1].addr = bus_addr;
+++	msgs[1].flags = I2C_M_RD;
+++	msgs[1].len = 1;
+++	msgs[1].buf = page;
+++
+++	return __i2c_transfer_err(i2c, msgs, 2);
+++}
+++
+++static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr,
+++				   u8 page)
+++{
+++	struct i2c_msg msg;
+++	u8 buf[2];
+++
+++	buf[0] = SFP_PAGE;
+++	buf[1] = page;
+++
+++	msg.addr = bus_addr;
+++	msg.flags = 0;
+++	msg.len = 2;
+++	msg.buf = buf;
+++
+++	return __i2c_transfer_err(i2c, &msg, 1);
+++}
+++
+++/* In order to not interfere with other SFP code (which possibly may manipulate
+++ * SFP_PAGE), for every transfer we do this:
+++ *   1. lock the bus
+++ *   2. save content of SFP_PAGE
+++ *   3. set SFP_PAGE to 3
+++ *   4. do the transfer
+++ *   5. restore original SFP_PAGE
+++ *   6. unlock the bus
+++ * Note that one might think that steps 2 to 5 could be theoretically done all
+++ * in one call to i2c_transfer (by constructing msgs array in such a way), but
+++ * unfortunately tests show that this does not work :-( Changed SFP_PAGE does
+++ * not take into account until i2c_transfer() is done.
+++ */
+++static int i2c_transfer_rollball(struct i2c_adapter *i2c,
+++				 struct i2c_msg *msgs, int num)
+++{
+++	int ret, main_err = 0;
+++	u8 saved_page;
+++
+++	i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
+++
+++	/* save original page */
+++	ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
+++	if (ret)
+++		goto unlock;
+++
+++	/* change to RollBall MDIO page */
+++	ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
+++	if (ret)
+++		goto unlock;
+++
+++	/* do the transfer; we try to restore original page if this fails */
+++	ret = __i2c_transfer_err(i2c, msgs, num);
+++	if (ret)
+++		main_err = ret;
+++
+++	/* restore original page */
+++	ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page);
+++
+++unlock:
+++	i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
+++
+++	return main_err ? : ret;
+++}
+++
+++static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
+++				 size_t len)
+++{
+++	struct i2c_adapter *i2c = bus->priv;
+++	struct i2c_msg msgs[2];
+++	u8 cmd_addr, tmp, *res;
+++	int i, ret;
+++
+++	cmd_addr = ROLLBALL_CMD_ADDR;
+++
+++	res = buf ? buf : &tmp;
+++	len = buf ? len : 1;
+++
+++	msgs[0].addr = bus_addr;
+++	msgs[0].flags = 0;
+++	msgs[0].len = 1;
+++	msgs[0].buf = &cmd_addr;
+++
+++	msgs[1].addr = bus_addr;
+++	msgs[1].flags = I2C_M_RD;
+++	msgs[1].len = len;
+++	msgs[1].buf = res;
+++
+++	/* By experiment it takes up to 70 ms to access a register for these
+++	 * SFPs. Sleep 20ms between iterations and try 10 times.
+++	 */
+++	i = 10;
+++	do {
+++		msleep(20);
+++
+++		ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
+++		if (ret)
+++			return ret;
+++
+++		if (*res == ROLLBALL_CMD_DONE)
+++			return 0;
+++	} while (i-- > 0);
+++
+++	dev_dbg(&bus->dev, "poll timed out\n");
+++
+++	return -ETIMEDOUT;
+++}
+++
+++static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd,
+++				u8 *data, size_t len)
+++{
+++	struct i2c_adapter *i2c = bus->priv;
+++	struct i2c_msg msgs[2];
+++	u8 cmdbuf[2];
+++
+++	cmdbuf[0] = ROLLBALL_CMD_ADDR;
+++	cmdbuf[1] = cmd;
+++
+++	msgs[0].addr = bus_addr;
+++	msgs[0].flags = 0;
+++	msgs[0].len = len;
+++	msgs[0].buf = data;
+++
+++	msgs[1].addr = bus_addr;
+++	msgs[1].flags = 0;
+++	msgs[1].len = sizeof(cmdbuf);
+++	msgs[1].buf = cmdbuf;
+++
+++	return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
+++}
+++
+++static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg)
+++{
+++	u8 buf[4], res[6];
+++	int bus_addr, ret;
+++	u16 val;
+++
+++	if (!(reg & MII_ADDR_C45))
+++		return -EOPNOTSUPP;
+++
+++	bus_addr = i2c_mii_phy_addr(phy_id);
+++	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
+++		return 0xffff;
+++
+++	buf[0] = ROLLBALL_DATA_ADDR;
+++	buf[1] = (reg >> 16) & 0x1f;
+++	buf[2] = (reg >> 8) & 0xff;
+++	buf[3] = reg & 0xff;
+++
+++	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf,
+++				   sizeof(buf));
+++	if (ret < 0)
+++		return ret;
+++
+++	ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res));
+++	if (ret == -ETIMEDOUT)
+++		return 0xffff;
+++	else if (ret < 0)
+++		return ret;
+++
+++	val = res[4] << 8 | res[5];
+++
+++	return val;
+++}
+++
+++static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg,
+++				  u16 val)
+++{
+++	int bus_addr, ret;
+++	u8 buf[6];
+++
+++	if (!(reg & MII_ADDR_C45))
+++		return -EOPNOTSUPP;
+++
+++	bus_addr = i2c_mii_phy_addr(phy_id);
+++	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
+++		return 0;
+++
+++	buf[0] = ROLLBALL_DATA_ADDR;
+++	buf[1] = (reg >> 16) & 0x1f;
+++	buf[2] = (reg >> 8) & 0xff;
+++	buf[3] = reg & 0xff;
+++	buf[4] = val >> 8;
+++	buf[5] = val & 0xff;
+++
+++	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf,
+++				   sizeof(buf));
+++	if (ret < 0)
+++		return ret;
+++
+++	ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0);
+++	if (ret < 0)
+++		return ret;
+++
+++	return 0;
+++}
+++
+++static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
+++{
+++	struct i2c_msg msg;
+++	u8 pw[5];
+++	int ret;
+++
+++	pw[0] = ROLLBALL_PASSWORD;
+++	pw[1] = 0xff;
+++	pw[2] = 0xff;
+++	pw[3] = 0xff;
+++	pw[4] = 0xff;
+++
+++	msg.addr = ROLLBALL_PHY_I2C_ADDR;
+++	msg.flags = 0;
+++	msg.len = sizeof(pw);
+++	msg.buf = pw;
+++
+++	ret = i2c_transfer(i2c, &msg, 1);
+++	if (ret < 0)
+++		return ret;
+++	else if (ret != 1)
+++		return -EIO;
+++	else
+++		return 0;
+++}
+++
+++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
+++			       enum mdio_i2c_proto protocol)
++ {
++ 	struct mii_bus *mii;
+++	int ret;
++ 
++ 	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
++ 		return ERR_PTR(-EINVAL);
++@@ -104,10 +386,28 @@ struct mii_bus *mdio_i2c_alloc(struct de
++ 
++ 	snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
++ 	mii->parent = parent;
++-	mii->read = i2c_mii_read;
++-	mii->write = i2c_mii_write;
++ 	mii->priv = i2c;
++ 
+++	switch (protocol) {
+++	case MDIO_I2C_ROLLBALL:
+++		ret = i2c_mii_init_rollball(i2c);
+++		if (ret < 0) {
+++			dev_err(parent,
+++				"Cannot initialize RollBall MDIO I2C protocol: %d\n",
+++				ret);
+++			mdiobus_free(mii);
+++			return ERR_PTR(ret);
+++		}
+++
+++		mii->read = i2c_mii_read_rollball;
+++		mii->write = i2c_mii_write_rollball;
+++		break;
+++	default:
+++		mii->read = i2c_mii_read_default;
+++		mii->write = i2c_mii_write_default;
+++		break;
+++	}
+++
++ 	return mii;
++ }
++ EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -553,7 +553,7 @@ static int sfp_i2c_mdiobus_create(struct
++ 	struct mii_bus *i2c_mii;
++ 	int ret;
++ 
++-	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c);
+++	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
++ 	if (IS_ERR(i2c_mii))
++ 		return PTR_ERR(i2c_mii);
++ 
++@@ -1776,6 +1776,10 @@ static int sfp_sm_probe_for_phy(struct s
++ 	case MDIO_I2C_C45:
++ 		err = sfp_sm_probe_phy(sfp, true);
++ 		break;
+++
+++	case MDIO_I2C_ROLLBALL:
+++		err = -EOPNOTSUPP;
+++		break;
++ 	}
++ 
++ 	return err;
++--- a/include/linux/mdio/mdio-i2c.h
+++++ b/include/linux/mdio/mdio-i2c.h
++@@ -15,8 +15,10 @@ enum mdio_i2c_proto {
++ 	MDIO_I2C_NONE,
++ 	MDIO_I2C_MARVELL_C22,
++ 	MDIO_I2C_C45,
+++	MDIO_I2C_ROLLBALL,
++ };
++ 
++-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
+++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
+++			       enum mdio_i2c_proto protocol);
++ 
++ #endif
+diff --git a/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch b/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch
+new file mode 100644
+index 0000000000..ecac95fb86
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-03-12-net-sfp-add-support-for-multigig-RollBall-transceive.patch
+@@ -0,0 +1,152 @@
++From 324e88cbe3b7be03af67828469cedb52c8610bd1 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 30 Sep 2022 16:21:10 +0200
++Subject: [PATCH] net: sfp: add support for multigig RollBall transceivers
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++This adds support for multigig copper SFP modules from RollBall/Hilink.
++These modules have a specific way to access clause 45 registers of the
++internal PHY.
++
++We also need to wait at least 22 seconds after deasserting TX disable
++before accessing the PHY. The code waits for 25 seconds just to be sure.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -166,6 +166,7 @@ static const enum gpiod_flags gpio_flags
++  * on board (for a copper SFP) time to initialise.
++  */
++ #define T_WAIT			msecs_to_jiffies(50)
+++#define T_WAIT_ROLLBALL		msecs_to_jiffies(25000)
++ #define T_START_UP		msecs_to_jiffies(300)
++ #define T_START_UP_BAD_GPON	msecs_to_jiffies(60000)
++ 
++@@ -205,8 +206,11 @@ static const enum gpiod_flags gpio_flags
++ 
++ /* SFP modules appear to always have their PHY configured for bus address
++  * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
+++ * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface
+++ * via address 0x51 (mdio-i2c will use RollBall protocol on this address).
++  */
++-#define SFP_PHY_ADDR	22
+++#define SFP_PHY_ADDR		22
+++#define SFP_PHY_ADDR_ROLLBALL	17
++ 
++ /* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM
++  * at a time. Some SFP modules and also some Linux I2C drivers do not like
++@@ -258,6 +262,7 @@ struct sfp {
++ 	struct sfp_eeprom_id id;
++ 	unsigned int module_power_mW;
++ 	unsigned int module_t_start_up;
+++	unsigned int module_t_wait;
++ 	bool tx_fault_ignore;
++ 
++ 	const struct sfp_quirk *quirk;
++@@ -337,6 +342,22 @@ static void sfp_fixup_halny_gsfp(struct
++ 	sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
++ }
++ 
+++static void sfp_fixup_rollball(struct sfp *sfp)
+++{
+++	sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
+++	sfp->module_t_wait = T_WAIT_ROLLBALL;
+++}
+++
+++static void sfp_fixup_rollball_cc(struct sfp *sfp)
+++{
+++	sfp_fixup_rollball(sfp);
+++
+++	/* Some RollBall SFPs may have wrong (zero) extended compliance code
+++	 * burned in EEPROM. For PHY probing we need the correct one.
+++	 */
+++	sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI;
+++}
+++
++ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
++ 				unsigned long *modes,
++ 				unsigned long *interfaces)
++@@ -385,6 +406,12 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
++ 
++ 	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
+++
+++	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
+++	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
+++	SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
+++	SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
+++	SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball),
++ };
++ 
++ static size_t sfp_strlen(const char *str, size_t maxlen)
++@@ -1641,12 +1668,12 @@ static void sfp_sm_phy_detach(struct sfp
++ 	sfp->mod_phy = NULL;
++ }
++ 
++-static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
+++static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
++ {
++ 	struct phy_device *phy;
++ 	int err;
++ 
++-	phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
+++	phy = get_phy_device(sfp->i2c_mii, addr, is_c45);
++ 	if (phy == ERR_PTR(-ENODEV))
++ 		return PTR_ERR(phy);
++ 	if (IS_ERR(phy)) {
++@@ -1770,15 +1797,15 @@ static int sfp_sm_probe_for_phy(struct s
++ 		break;
++ 
++ 	case MDIO_I2C_MARVELL_C22:
++-		err = sfp_sm_probe_phy(sfp, false);
+++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, false);
++ 		break;
++ 
++ 	case MDIO_I2C_C45:
++-		err = sfp_sm_probe_phy(sfp, true);
+++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, true);
++ 		break;
++ 
++ 	case MDIO_I2C_ROLLBALL:
++-		err = -EOPNOTSUPP;
+++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true);
++ 		break;
++ 	}
++ 
++@@ -2101,6 +2128,7 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		sfp->state_hw_mask |= SFP_F_LOS;
++ 
++ 	sfp->module_t_start_up = T_START_UP;
+++	sfp->module_t_wait = T_WAIT;
++ 
++ 	sfp->tx_fault_ignore = false;
++ 
++@@ -2315,9 +2343,10 @@ static void sfp_sm_main(struct sfp *sfp,
++ 
++ 		/* We need to check the TX_FAULT state, which is not defined
++ 		 * while TX_DISABLE is asserted. The earliest we want to do
++-		 * anything (such as probe for a PHY) is 50ms.
+++		 * anything (such as probe for a PHY) is 50ms (or more on
+++		 * specific modules).
++ 		 */
++-		sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
+++		sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
++ 		break;
++ 
++ 	case SFP_S_WAIT:
++@@ -2331,8 +2360,8 @@ static void sfp_sm_main(struct sfp *sfp,
++ 			 * deasserting.
++ 			 */
++ 			timeout = sfp->module_t_start_up;
++-			if (timeout > T_WAIT)
++-				timeout -= T_WAIT;
+++			if (timeout > sfp->module_t_wait)
+++				timeout -= sfp->module_t_wait;
++ 			else
++ 				timeout = 1;
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch b/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch
+new file mode 100644
+index 0000000000..494cfbb021
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-04-net-sfp-fill-also-5gbase-r-and-25gbase-r-modes-in-sf.patch
+@@ -0,0 +1,44 @@
++From 5b4c189d660a9b8a852f0863360eb40a100226fc Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Fri, 7 Oct 2022 10:48:44 +0200
++Subject: [PATCH] net: sfp: fill also 5gbase-r and 25gbase-r modes in
++ sfp_parse_support()
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Fill in also 5gbase-r and 25gbase-r PHY interface modes into the
++phy_interface_t bitmap in sfp_parse_support().
++
++Fixes: fd580c983031 ("net: sfp: augment SFP parsing with phy_interface_t bitmap")
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Link: https://lore.kernel.org/r/20221007084844.20352-1-kabel@kernel.org
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -257,6 +257,7 @@ void sfp_parse_support(struct sfp_bus *b
++ 	case SFF8024_ECC_100GBASE_SR4_25GBASE_SR:
++ 		phylink_set(modes, 100000baseSR4_Full);
++ 		phylink_set(modes, 25000baseSR_Full);
+++		__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
++ 		break;
++ 	case SFF8024_ECC_100GBASE_LR4_25GBASE_LR:
++ 	case SFF8024_ECC_100GBASE_ER4_25GBASE_ER:
++@@ -268,6 +269,7 @@ void sfp_parse_support(struct sfp_bus *b
++ 	case SFF8024_ECC_25GBASE_CR_S:
++ 	case SFF8024_ECC_25GBASE_CR_N:
++ 		phylink_set(modes, 25000baseCR_Full);
+++		__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
++ 		break;
++ 	case SFF8024_ECC_10GBASE_T_SFI:
++ 	case SFF8024_ECC_10GBASE_T_SR:
++@@ -276,6 +278,7 @@ void sfp_parse_support(struct sfp_bus *b
++ 		break;
++ 	case SFF8024_ECC_5GBASE_T:
++ 		phylink_set(modes, 5000baseT_Full);
+++		__set_bit(PHY_INTERFACE_MODE_5GBASER, interfaces);
++ 		break;
++ 	case SFF8024_ECC_2_5GBASE_T:
++ 		phylink_set(modes, 2500baseT_Full);
+diff --git a/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch b/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch
+new file mode 100644
+index 0000000000..0789da6f55
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-1-net-sfp-check-firmware-provided-max-power.patch
+@@ -0,0 +1,57 @@
++From 02eaf5a79100468425fae2d0baf144b6068fc4cc Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:09:43 +0100
++Subject: [PATCH] net: sfp: check firmware provided max power
++
++Check that the firmware provided maximum power is at least 1W, which
++is the minimum power level for any SFP module.
++
++Now that we enforce the minimum of 1W, we can exit early from
++sfp_module_parse_power() if the module power is 1W or less.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1822,6 +1822,12 @@ static int sfp_module_parse_power(struct
++ 	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
++ 		power_mW = 2000;
++ 
+++	/* Power level 1 modules (max. 1W) are always supported. */
+++	if (power_mW <= 1000) {
+++		sfp->module_power_mW = power_mW;
+++		return 0;
+++	}
+++
++ 	supports_a2 = sfp->id.ext.sff8472_compliance !=
++ 				SFP_SFF8472_COMPLIANCE_NONE ||
++ 		      sfp->id.ext.diagmon & SFP_DIAGMON_DDM;
++@@ -1845,12 +1851,6 @@ static int sfp_module_parse_power(struct
++ 		}
++ 	}
++ 
++-	if (power_mW <= 1000) {
++-		/* Modules below 1W do not require a power change sequence */
++-		sfp->module_power_mW = power_mW;
++-		return 0;
++-	}
++-
++ 	if (!supports_a2) {
++ 		/* The module power level is below the host maximum and the
++ 		 * module appears not to implement bus address 0xa2, so assume
++@@ -2782,8 +2782,12 @@ static int sfp_probe(struct platform_dev
++ 
++ 	device_property_read_u32(&pdev->dev, "maximum-power-milliwatt",
++ 				 &sfp->max_power_mW);
++-	if (!sfp->max_power_mW)
+++	if (sfp->max_power_mW < 1000) {
+++		if (sfp->max_power_mW)
+++			dev_warn(sfp->dev,
+++				 "Firmware bug: host maximum power should be at least 1W\n");
++ 		sfp->max_power_mW = 1000;
+++	}
++ 
++ 	dev_info(sfp->dev, "Host maximum power %u.%uW\n",
++ 		 sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
+diff --git a/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch b/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch
+new file mode 100644
+index 0000000000..210cfa76fd
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-2-net-sfp-ignore-power-level-2-prior-to-SFF-8472-Rev-1.patch
+@@ -0,0 +1,27 @@
++From 18cc659e95ab1661254bde815fc9345246d98906 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:09:49 +0100
++Subject: [PATCH] net: sfp: ignore power level 2 prior to SFF-8472 Rev 10.2
++
++Power level 2 was introduced by SFF-8472 revision 10.2. Ignore
++the power declaration bit for modules that are not compliant with
++at least this revision.
++
++This should remove any spurious indication of 1.5W modules.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1817,7 +1817,8 @@ static int sfp_module_parse_power(struct
++ 	u32 power_mW = 1000;
++ 	bool supports_a2;
++ 
++-	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
+++	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
+++	    sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
++ 		power_mW = 1500;
++ 	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
++ 		power_mW = 2000;
+diff --git a/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch b/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch
+new file mode 100644
+index 0000000000..aaefe3d33b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-3-net-sfp-ignore-power-level-3-prior-to-SFF-8472-Rev-1.patch
+@@ -0,0 +1,28 @@
++From f8810ca7582933e436e6c987808bbcc14f5543df Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:09:54 +0100
++Subject: [PATCH] net: sfp: ignore power level 3 prior to SFF-8472 Rev 11.4
++
++Power level 3 was included in SFF-8472 revision 11.9, but this does
++not have a compliance code. Use revision 11.4 as the minimum
++compliance level instead.
++
++This should avoid any spurious indication of 2W modules.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1820,7 +1820,9 @@ static int sfp_module_parse_power(struct
++ 	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
++ 	    sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
++ 		power_mW = 1500;
++-	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
+++	/* Added in Rev 11.9, but there is no compliance code for this */
+++	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV11_4 &&
+++	    sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
++ 		power_mW = 2000;
++ 
++ 	/* Power level 1 modules (max. 1W) are always supported. */
+diff --git a/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch b/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch
+new file mode 100644
+index 0000000000..f20dd12a6a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-4-net-sfp-provide-a-definition-for-the-power-level-sel.patch
+@@ -0,0 +1,42 @@
++From 398900498485fa9465386454681763d81efaad25 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:09:59 +0100
++Subject: [PATCH] net: sfp: provide a definition for the power level select bit
++
++Provide a named definition for the power level select bit in the
++extended status register, rather than using BIT(0) in the code.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1893,13 +1893,13 @@ static int sfp_sm_mod_hpower(struct sfp
++ 	 * all bytes 0xff) at 0x51 but does not accept writes.  In any case,
++ 	 * if the bit is already set, we're already in high power mode.
++ 	 */
++-	if (!!(val & BIT(0)) == enable)
+++	if (!!(val & SFP_EXT_STATUS_PWRLVL_SELECT) == enable)
++ 		return 0;
++ 
++ 	if (enable)
++-		val |= BIT(0);
+++		val |= SFP_EXT_STATUS_PWRLVL_SELECT;
++ 	else
++-		val &= ~BIT(0);
+++		val &= ~SFP_EXT_STATUS_PWRLVL_SELECT;
++ 
++ 	err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
++ 	if (err != sizeof(val)) {
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -489,6 +489,8 @@ enum {
++ 	SFP_WARN1_RXPWR_LOW		= BIT(6),
++ 
++ 	SFP_EXT_STATUS			= 0x76,
+++	SFP_EXT_STATUS_PWRLVL_SELECT	= BIT(0),
+++
++ 	SFP_VSL				= 0x78,
++ 	SFP_PAGE			= 0x7f,
++ };
+diff --git a/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch b/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch
+new file mode 100644
+index 0000000000..b1ece79fc1
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-5-net-sfp-add-sfp_modify_u8-helper.patch
+@@ -0,0 +1,61 @@
++From a3c536fc75803b298fd6ba75af33eecf43d31785 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:10:04 +0100
++Subject: [PATCH] net: sfp: add sfp_modify_u8() helper
++
++Add a helper to modify bits in a single byte in memory space, and use
++it when updating the soft tx-disable flag in the module.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -615,6 +615,22 @@ static int sfp_write(struct sfp *sfp, bo
++ 	return sfp->write(sfp, a2, addr, buf, len);
++ }
++ 
+++static int sfp_modify_u8(struct sfp *sfp, bool a2, u8 addr, u8 mask, u8 val)
+++{
+++	int ret;
+++	u8 old, v;
+++
+++	ret = sfp_read(sfp, a2, addr, &old, sizeof(old));
+++	if (ret != sizeof(old))
+++		return ret;
+++
+++	v = (old & ~mask) | (val & mask);
+++	if (v == old)
+++		return sizeof(v);
+++
+++	return sfp_write(sfp, a2, addr, &v, sizeof(v));
+++}
+++
++ static unsigned int sfp_soft_get_state(struct sfp *sfp)
++ {
++ 	unsigned int state = 0;
++@@ -640,17 +656,14 @@ static unsigned int sfp_soft_get_state(s
++ 
++ static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
++ {
++-	u8 status;
+++	u8 mask = SFP_STATUS_TX_DISABLE_FORCE;
+++	u8 val = 0;
++ 
++-	if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
++-		     sizeof(status)) {
++-		if (state & SFP_F_TX_DISABLE)
++-			status |= SFP_STATUS_TX_DISABLE_FORCE;
++-		else
++-			status &= ~SFP_STATUS_TX_DISABLE_FORCE;
+++	if (state & SFP_F_TX_DISABLE)
+++		val |= SFP_STATUS_TX_DISABLE_FORCE;
++ 
++-		sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status));
++-	}
+++
+++	sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
++ }
++ 
++ static void sfp_soft_start_poll(struct sfp *sfp)
+diff --git a/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch b/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch
+new file mode 100644
+index 0000000000..291fc28a83
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-05-6-net-sfp-get-rid-of-DM7052-hack-when-enabling-high-po.patch
+@@ -0,0 +1,53 @@
++From bd1432f68ddc28bf3ed6e86b16ed29c0b406f91f Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 21 Oct 2022 16:10:09 +0100
++Subject: [PATCH] net: sfp: get rid of DM7052 hack when enabling high power
++
++Since we no longer mis-detect high-power mode with the DM7052 module,
++we no longer need the hack in sfp_module_enable_high_power(), and can
++now switch this to use sfp_modify_u8().
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1893,31 +1893,14 @@ static int sfp_module_parse_power(struct
++ 
++ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
++ {
++-	u8 val;
++ 	int err;
++ 
++-	err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
++-	if (err != sizeof(val)) {
++-		dev_err(sfp->dev, "Failed to read EEPROM: %pe\n", ERR_PTR(err));
++-		return -EAGAIN;
++-	}
++-
++-	/* DM7052 reports as a high power module, responds to reads (with
++-	 * all bytes 0xff) at 0x51 but does not accept writes.  In any case,
++-	 * if the bit is already set, we're already in high power mode.
++-	 */
++-	if (!!(val & SFP_EXT_STATUS_PWRLVL_SELECT) == enable)
++-		return 0;
++-
++-	if (enable)
++-		val |= SFP_EXT_STATUS_PWRLVL_SELECT;
++-	else
++-		val &= ~SFP_EXT_STATUS_PWRLVL_SELECT;
++-
++-	err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
++-	if (err != sizeof(val)) {
++-		dev_err(sfp->dev, "Failed to write EEPROM: %pe\n",
++-			ERR_PTR(err));
+++	err = sfp_modify_u8(sfp, true, SFP_EXT_STATUS,
+++			    SFP_EXT_STATUS_PWRLVL_SELECT,
+++			    enable ? SFP_EXT_STATUS_PWRLVL_SELECT : 0);
+++	if (err != sizeof(u8)) {
+++		dev_err(sfp->dev, "failed to %sable high power: %pe\n",
+++			enable ? "en" : "dis", ERR_PTR(err));
++ 		return -EAGAIN;
++ 	}
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch b/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch
+new file mode 100644
+index 0000000000..6d3f247088
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-06-1-net-sfp-convert-register-indexes-from-hex-to-decimal.patch
+@@ -0,0 +1,234 @@
++From 17dd361119e5bc4cfb85aed660674a846b613817 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Thu, 27 Oct 2022 14:21:16 +0100
++Subject: [PATCH] net: sfp: convert register indexes from hex to decimal
++
++The register indexes in the standards are in decimal rather than hex,
++so lets specify them in decimal in the header file so we can easily
++cross-reference without converting between hex and decimal.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -332,37 +332,37 @@ enum {
++ 
++ /* SFP EEPROM registers */
++ enum {
++-	SFP_PHYS_ID			= 0x00,
++-	SFP_PHYS_EXT_ID			= 0x01,
++-	SFP_CONNECTOR			= 0x02,
++-	SFP_COMPLIANCE			= 0x03,
++-	SFP_ENCODING			= 0x0b,
++-	SFP_BR_NOMINAL			= 0x0c,
++-	SFP_RATE_ID			= 0x0d,
++-	SFP_LINK_LEN_SM_KM		= 0x0e,
++-	SFP_LINK_LEN_SM_100M		= 0x0f,
++-	SFP_LINK_LEN_50UM_OM2_10M	= 0x10,
++-	SFP_LINK_LEN_62_5UM_OM1_10M	= 0x11,
++-	SFP_LINK_LEN_COPPER_1M		= 0x12,
++-	SFP_LINK_LEN_50UM_OM4_10M	= 0x12,
++-	SFP_LINK_LEN_50UM_OM3_10M	= 0x13,
++-	SFP_VENDOR_NAME			= 0x14,
++-	SFP_VENDOR_OUI			= 0x25,
++-	SFP_VENDOR_PN			= 0x28,
++-	SFP_VENDOR_REV			= 0x38,
++-	SFP_OPTICAL_WAVELENGTH_MSB	= 0x3c,
++-	SFP_OPTICAL_WAVELENGTH_LSB	= 0x3d,
++-	SFP_CABLE_SPEC			= 0x3c,
++-	SFP_CC_BASE			= 0x3f,
++-	SFP_OPTIONS			= 0x40,	/* 2 bytes, MSB, LSB */
++-	SFP_BR_MAX			= 0x42,
++-	SFP_BR_MIN			= 0x43,
++-	SFP_VENDOR_SN			= 0x44,
++-	SFP_DATECODE			= 0x54,
++-	SFP_DIAGMON			= 0x5c,
++-	SFP_ENHOPTS			= 0x5d,
++-	SFP_SFF8472_COMPLIANCE		= 0x5e,
++-	SFP_CC_EXT			= 0x5f,
+++	SFP_PHYS_ID			= 0,
+++	SFP_PHYS_EXT_ID			= 1,
+++	SFP_CONNECTOR			= 2,
+++	SFP_COMPLIANCE			= 3,
+++	SFP_ENCODING			= 11,
+++	SFP_BR_NOMINAL			= 12,
+++	SFP_RATE_ID			= 13,
+++	SFP_LINK_LEN_SM_KM		= 14,
+++	SFP_LINK_LEN_SM_100M		= 15,
+++	SFP_LINK_LEN_50UM_OM2_10M	= 16,
+++	SFP_LINK_LEN_62_5UM_OM1_10M	= 17,
+++	SFP_LINK_LEN_COPPER_1M		= 18,
+++	SFP_LINK_LEN_50UM_OM4_10M	= 18,
+++	SFP_LINK_LEN_50UM_OM3_10M	= 19,
+++	SFP_VENDOR_NAME			= 20,
+++	SFP_VENDOR_OUI			= 37,
+++	SFP_VENDOR_PN			= 40,
+++	SFP_VENDOR_REV			= 56,
+++	SFP_OPTICAL_WAVELENGTH_MSB	= 60,
+++	SFP_OPTICAL_WAVELENGTH_LSB	= 61,
+++	SFP_CABLE_SPEC			= 60,
+++	SFP_CC_BASE			= 63,
+++	SFP_OPTIONS			= 64,	/* 2 bytes, MSB, LSB */
+++	SFP_BR_MAX			= 66,
+++	SFP_BR_MIN			= 67,
+++	SFP_VENDOR_SN			= 68,
+++	SFP_DATECODE			= 84,
+++	SFP_DIAGMON			= 92,
+++	SFP_ENHOPTS			= 93,
+++	SFP_SFF8472_COMPLIANCE		= 94,
+++	SFP_CC_EXT			= 95,
++ 
++ 	SFP_PHYS_EXT_ID_SFP		= 0x04,
++ 	SFP_OPTIONS_HIGH_POWER_LEVEL	= BIT(13),
++@@ -404,63 +404,63 @@ enum {
++ /* SFP Diagnostics */
++ enum {
++ 	/* Alarm and warnings stored MSB at lower address then LSB */
++-	SFP_TEMP_HIGH_ALARM		= 0x00,
++-	SFP_TEMP_LOW_ALARM		= 0x02,
++-	SFP_TEMP_HIGH_WARN		= 0x04,
++-	SFP_TEMP_LOW_WARN		= 0x06,
++-	SFP_VOLT_HIGH_ALARM		= 0x08,
++-	SFP_VOLT_LOW_ALARM		= 0x0a,
++-	SFP_VOLT_HIGH_WARN		= 0x0c,
++-	SFP_VOLT_LOW_WARN		= 0x0e,
++-	SFP_BIAS_HIGH_ALARM		= 0x10,
++-	SFP_BIAS_LOW_ALARM		= 0x12,
++-	SFP_BIAS_HIGH_WARN		= 0x14,
++-	SFP_BIAS_LOW_WARN		= 0x16,
++-	SFP_TXPWR_HIGH_ALARM		= 0x18,
++-	SFP_TXPWR_LOW_ALARM		= 0x1a,
++-	SFP_TXPWR_HIGH_WARN		= 0x1c,
++-	SFP_TXPWR_LOW_WARN		= 0x1e,
++-	SFP_RXPWR_HIGH_ALARM		= 0x20,
++-	SFP_RXPWR_LOW_ALARM		= 0x22,
++-	SFP_RXPWR_HIGH_WARN		= 0x24,
++-	SFP_RXPWR_LOW_WARN		= 0x26,
++-	SFP_LASER_TEMP_HIGH_ALARM	= 0x28,
++-	SFP_LASER_TEMP_LOW_ALARM	= 0x2a,
++-	SFP_LASER_TEMP_HIGH_WARN	= 0x2c,
++-	SFP_LASER_TEMP_LOW_WARN		= 0x2e,
++-	SFP_TEC_CUR_HIGH_ALARM		= 0x30,
++-	SFP_TEC_CUR_LOW_ALARM		= 0x32,
++-	SFP_TEC_CUR_HIGH_WARN		= 0x34,
++-	SFP_TEC_CUR_LOW_WARN		= 0x36,
++-	SFP_CAL_RXPWR4			= 0x38,
++-	SFP_CAL_RXPWR3			= 0x3c,
++-	SFP_CAL_RXPWR2			= 0x40,
++-	SFP_CAL_RXPWR1			= 0x44,
++-	SFP_CAL_RXPWR0			= 0x48,
++-	SFP_CAL_TXI_SLOPE		= 0x4c,
++-	SFP_CAL_TXI_OFFSET		= 0x4e,
++-	SFP_CAL_TXPWR_SLOPE		= 0x50,
++-	SFP_CAL_TXPWR_OFFSET		= 0x52,
++-	SFP_CAL_T_SLOPE			= 0x54,
++-	SFP_CAL_T_OFFSET		= 0x56,
++-	SFP_CAL_V_SLOPE			= 0x58,
++-	SFP_CAL_V_OFFSET		= 0x5a,
++-	SFP_CHKSUM			= 0x5f,
++-
++-	SFP_TEMP			= 0x60,
++-	SFP_VCC				= 0x62,
++-	SFP_TX_BIAS			= 0x64,
++-	SFP_TX_POWER			= 0x66,
++-	SFP_RX_POWER			= 0x68,
++-	SFP_LASER_TEMP			= 0x6a,
++-	SFP_TEC_CUR			= 0x6c,
+++	SFP_TEMP_HIGH_ALARM		= 0,
+++	SFP_TEMP_LOW_ALARM		= 2,
+++	SFP_TEMP_HIGH_WARN		= 4,
+++	SFP_TEMP_LOW_WARN		= 6,
+++	SFP_VOLT_HIGH_ALARM		= 8,
+++	SFP_VOLT_LOW_ALARM		= 10,
+++	SFP_VOLT_HIGH_WARN		= 12,
+++	SFP_VOLT_LOW_WARN		= 14,
+++	SFP_BIAS_HIGH_ALARM		= 16,
+++	SFP_BIAS_LOW_ALARM		= 18,
+++	SFP_BIAS_HIGH_WARN		= 20,
+++	SFP_BIAS_LOW_WARN		= 22,
+++	SFP_TXPWR_HIGH_ALARM		= 24,
+++	SFP_TXPWR_LOW_ALARM		= 26,
+++	SFP_TXPWR_HIGH_WARN		= 28,
+++	SFP_TXPWR_LOW_WARN		= 30,
+++	SFP_RXPWR_HIGH_ALARM		= 32,
+++	SFP_RXPWR_LOW_ALARM		= 34,
+++	SFP_RXPWR_HIGH_WARN		= 36,
+++	SFP_RXPWR_LOW_WARN		= 38,
+++	SFP_LASER_TEMP_HIGH_ALARM	= 40,
+++	SFP_LASER_TEMP_LOW_ALARM	= 42,
+++	SFP_LASER_TEMP_HIGH_WARN	= 44,
+++	SFP_LASER_TEMP_LOW_WARN		= 46,
+++	SFP_TEC_CUR_HIGH_ALARM		= 48,
+++	SFP_TEC_CUR_LOW_ALARM		= 50,
+++	SFP_TEC_CUR_HIGH_WARN		= 52,
+++	SFP_TEC_CUR_LOW_WARN		= 54,
+++	SFP_CAL_RXPWR4			= 56,
+++	SFP_CAL_RXPWR3			= 60,
+++	SFP_CAL_RXPWR2			= 64,
+++	SFP_CAL_RXPWR1			= 68,
+++	SFP_CAL_RXPWR0			= 72,
+++	SFP_CAL_TXI_SLOPE		= 76,
+++	SFP_CAL_TXI_OFFSET		= 78,
+++	SFP_CAL_TXPWR_SLOPE		= 80,
+++	SFP_CAL_TXPWR_OFFSET		= 82,
+++	SFP_CAL_T_SLOPE			= 84,
+++	SFP_CAL_T_OFFSET		= 86,
+++	SFP_CAL_V_SLOPE			= 88,
+++	SFP_CAL_V_OFFSET		= 90,
+++	SFP_CHKSUM			= 95,
+++
+++	SFP_TEMP			= 96,
+++	SFP_VCC				= 98,
+++	SFP_TX_BIAS			= 100,
+++	SFP_TX_POWER			= 102,
+++	SFP_RX_POWER			= 104,
+++	SFP_LASER_TEMP			= 106,
+++	SFP_TEC_CUR			= 108,
++ 
++-	SFP_STATUS			= 0x6e,
+++	SFP_STATUS			= 110,
++ 	SFP_STATUS_TX_DISABLE		= BIT(7),
++ 	SFP_STATUS_TX_DISABLE_FORCE	= BIT(6),
++ 	SFP_STATUS_TX_FAULT		= BIT(2),
++ 	SFP_STATUS_RX_LOS		= BIT(1),
++-	SFP_ALARM0			= 0x70,
+++	SFP_ALARM0			= 112,
++ 	SFP_ALARM0_TEMP_HIGH		= BIT(7),
++ 	SFP_ALARM0_TEMP_LOW		= BIT(6),
++ 	SFP_ALARM0_VCC_HIGH		= BIT(5),
++@@ -470,11 +470,11 @@ enum {
++ 	SFP_ALARM0_TXPWR_HIGH		= BIT(1),
++ 	SFP_ALARM0_TXPWR_LOW		= BIT(0),
++ 
++-	SFP_ALARM1			= 0x71,
+++	SFP_ALARM1			= 113,
++ 	SFP_ALARM1_RXPWR_HIGH		= BIT(7),
++ 	SFP_ALARM1_RXPWR_LOW		= BIT(6),
++ 
++-	SFP_WARN0			= 0x74,
+++	SFP_WARN0			= 116,
++ 	SFP_WARN0_TEMP_HIGH		= BIT(7),
++ 	SFP_WARN0_TEMP_LOW		= BIT(6),
++ 	SFP_WARN0_VCC_HIGH		= BIT(5),
++@@ -484,15 +484,15 @@ enum {
++ 	SFP_WARN0_TXPWR_HIGH		= BIT(1),
++ 	SFP_WARN0_TXPWR_LOW		= BIT(0),
++ 
++-	SFP_WARN1			= 0x75,
+++	SFP_WARN1			= 117,
++ 	SFP_WARN1_RXPWR_HIGH		= BIT(7),
++ 	SFP_WARN1_RXPWR_LOW		= BIT(6),
++ 
++-	SFP_EXT_STATUS			= 0x76,
+++	SFP_EXT_STATUS			= 118,
++ 	SFP_EXT_STATUS_PWRLVL_SELECT	= BIT(0),
++ 
++-	SFP_VSL				= 0x78,
++-	SFP_PAGE			= 0x7f,
+++	SFP_VSL				= 120,
+++	SFP_PAGE			= 127,
++ };
++ 
++ struct fwnode_handle;
+diff --git a/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch b/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch
+new file mode 100644
+index 0000000000..88a4548356
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-06-2-net-sfp-move-field-definitions-along-side-register-i.patch
+@@ -0,0 +1,83 @@
++From d83845d224a059165902ecd0e1203015c5713a78 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Thu, 27 Oct 2022 14:21:21 +0100
++Subject: [PATCH] net: sfp: move field definitions along side register index
++
++Just as we do for the A2h enum, arrange the A0h enum to have the
++field definitions next to their corresponding register index.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -333,7 +333,10 @@ enum {
++ /* SFP EEPROM registers */
++ enum {
++ 	SFP_PHYS_ID			= 0,
+++
++ 	SFP_PHYS_EXT_ID			= 1,
+++	SFP_PHYS_EXT_ID_SFP		= 0x04,
+++
++ 	SFP_CONNECTOR			= 2,
++ 	SFP_COMPLIANCE			= 3,
++ 	SFP_ENCODING			= 11,
++@@ -354,17 +357,8 @@ enum {
++ 	SFP_OPTICAL_WAVELENGTH_LSB	= 61,
++ 	SFP_CABLE_SPEC			= 60,
++ 	SFP_CC_BASE			= 63,
++-	SFP_OPTIONS			= 64,	/* 2 bytes, MSB, LSB */
++-	SFP_BR_MAX			= 66,
++-	SFP_BR_MIN			= 67,
++-	SFP_VENDOR_SN			= 68,
++-	SFP_DATECODE			= 84,
++-	SFP_DIAGMON			= 92,
++-	SFP_ENHOPTS			= 93,
++-	SFP_SFF8472_COMPLIANCE		= 94,
++-	SFP_CC_EXT			= 95,
++ 
++-	SFP_PHYS_EXT_ID_SFP		= 0x04,
+++	SFP_OPTIONS			= 64,	/* 2 bytes, MSB, LSB */
++ 	SFP_OPTIONS_HIGH_POWER_LEVEL	= BIT(13),
++ 	SFP_OPTIONS_PAGING_A2		= BIT(12),
++ 	SFP_OPTIONS_RETIMER		= BIT(11),
++@@ -378,11 +372,20 @@ enum {
++ 	SFP_OPTIONS_TX_FAULT		= BIT(3),
++ 	SFP_OPTIONS_LOS_INVERTED	= BIT(2),
++ 	SFP_OPTIONS_LOS_NORMAL		= BIT(1),
+++
+++	SFP_BR_MAX			= 66,
+++	SFP_BR_MIN			= 67,
+++	SFP_VENDOR_SN			= 68,
+++	SFP_DATECODE			= 84,
+++
+++	SFP_DIAGMON			= 92,
++ 	SFP_DIAGMON_DDM			= BIT(6),
++ 	SFP_DIAGMON_INT_CAL		= BIT(5),
++ 	SFP_DIAGMON_EXT_CAL		= BIT(4),
++ 	SFP_DIAGMON_RXPWR_AVG		= BIT(3),
++ 	SFP_DIAGMON_ADDRMODE		= BIT(2),
+++
+++	SFP_ENHOPTS			= 93,
++ 	SFP_ENHOPTS_ALARMWARN		= BIT(7),
++ 	SFP_ENHOPTS_SOFT_TX_DISABLE	= BIT(6),
++ 	SFP_ENHOPTS_SOFT_TX_FAULT	= BIT(5),
++@@ -390,6 +393,8 @@ enum {
++ 	SFP_ENHOPTS_SOFT_RATE_SELECT	= BIT(3),
++ 	SFP_ENHOPTS_APP_SELECT_SFF8079	= BIT(2),
++ 	SFP_ENHOPTS_SOFT_RATE_SFF8431	= BIT(1),
+++
+++	SFP_SFF8472_COMPLIANCE		= 94,
++ 	SFP_SFF8472_COMPLIANCE_NONE	= 0x00,
++ 	SFP_SFF8472_COMPLIANCE_REV9_3	= 0x01,
++ 	SFP_SFF8472_COMPLIANCE_REV9_5	= 0x02,
++@@ -399,6 +404,8 @@ enum {
++ 	SFP_SFF8472_COMPLIANCE_REV11_3	= 0x06,
++ 	SFP_SFF8472_COMPLIANCE_REV11_4	= 0x07,
++ 	SFP_SFF8472_COMPLIANCE_REV12_0	= 0x08,
+++
+++	SFP_CC_EXT			= 95,
++ };
++ 
++ /* SFP Diagnostics */
+diff --git a/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch b/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch
+new file mode 100644
+index 0000000000..515828f0c2
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-07-1-net-sfp-add-A2h-presence-flag.patch
+@@ -0,0 +1,100 @@
++From f94b9bed12e8244717512941494fe83c94773a58 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Thu, 9 Mar 2023 15:57:11 +0000
++Subject: [PATCH] net: sfp: add A2h presence flag
++
++The hwmon code wants to know when it is safe to access the A2h data
++stored in a separate address. We indicate that this is present when
++we have SFF-8472 compliance and the lack of an address-change
++sequence.,
++
++The same conditions are also true if we want to access other controls
++and status in the A2h address. So let's make a flag to indicate whether
++we can access it, instead of repeating the conditions throughout the
++code.
++
++For now, only convert the hwmon code.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -263,6 +263,8 @@ struct sfp {
++ 	unsigned int module_power_mW;
++ 	unsigned int module_t_start_up;
++ 	unsigned int module_t_wait;
+++
+++	bool have_a2;
++ 	bool tx_fault_ignore;
++ 
++ 	const struct sfp_quirk *quirk;
++@@ -1511,20 +1513,10 @@ static void sfp_hwmon_probe(struct work_
++ 
++ static int sfp_hwmon_insert(struct sfp *sfp)
++ {
++-	if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE)
++-		return 0;
++-
++-	if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM))
++-		return 0;
++-
++-	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
++-		/* This driver in general does not support address
++-		 * change.
++-		 */
++-		return 0;
++-
++-	mod_delayed_work(system_wq, &sfp->hwmon_probe, 1);
++-	sfp->hwmon_tries = R_PROBE_RETRY_SLOW;
+++	if (sfp->have_a2 && sfp->id.ext.diagmon & SFP_DIAGMON_DDM) {
+++		mod_delayed_work(system_wq, &sfp->hwmon_probe, 1);
+++		sfp->hwmon_tries = R_PROBE_RETRY_SLOW;
+++	}
++ 
++ 	return 0;
++ }
++@@ -1974,6 +1966,18 @@ static int sfp_cotsworks_fixup_check(str
++ 	return 0;
++ }
++ 
+++static int sfp_module_parse_sff8472(struct sfp *sfp)
+++{
+++	/* If the module requires address swap mode, warn about it */
+++	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
+++		dev_warn(sfp->dev,
+++			 "module address swap to access page 0xA2 is not supported.\n");
+++	else
+++		sfp->have_a2 = true;
+++
+++	return 0;
+++}
+++
++ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
++ {
++ 	/* SFP module inserted - read I2C data */
++@@ -2107,10 +2111,11 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		return -EINVAL;
++ 	}
++ 
++-	/* If the module requires address swap mode, warn about it */
++-	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
++-		dev_warn(sfp->dev,
++-			 "module address swap to access page 0xA2 is not supported.\n");
+++	if (sfp->id.ext.sff8472_compliance != SFP_SFF8472_COMPLIANCE_NONE) {
+++		ret = sfp_module_parse_sff8472(sfp);
+++		if (ret < 0)
+++			return ret;
+++	}
++ 
++ 	/* Parse the module power requirement */
++ 	ret = sfp_module_parse_power(sfp);
++@@ -2157,6 +2162,7 @@ static void sfp_sm_mod_remove(struct sfp
++ 
++ 	memset(&sfp->id, 0, sizeof(sfp->id));
++ 	sfp->module_power_mW = 0;
+++	sfp->have_a2 = false;
++ 
++ 	dev_info(sfp->dev, "module removed\n");
++ }
+diff --git a/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch b/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch
+new file mode 100644
+index 0000000000..2ea6b71b42
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-07-2-net-sfp-only-use-soft-polling-if-we-have-A2h-access.patch
+@@ -0,0 +1,28 @@
++From 5daed426f012a1c0db0048339e359ee98a2c8752 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Thu, 9 Mar 2023 15:57:16 +0000
++Subject: [PATCH] net: sfp: only use soft polling if we have A2h access
++
++The soft state bits are stored in the A2h memory space, and require
++SFF-8472 compliance. This is what our have_a2 flag tells us, so use
++this to indicate whether we should attempt to use the soft signals.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2338,7 +2338,11 @@ static void sfp_sm_main(struct sfp *sfp,
++ 		    sfp->sm_dev_state != SFP_DEV_UP)
++ 			break;
++ 
++-		if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE))
+++		/* Only use the soft state bits if we have access to the A2h
+++		 * memory, which implies that we have some level of SFF-8472
+++		 * compliance.
+++		 */
+++		if (sfp->have_a2)
++ 			sfp_soft_start_poll(sfp);
++ 
++ 		sfp_module_tx_enable(sfp);
+diff --git a/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch b/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch
+new file mode 100644
+index 0000000000..a433a25fdb
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-08-net-sfp-fix-state-loss-when-updating-state_hw_mask.patch
+@@ -0,0 +1,41 @@
++From 04361b8bb81819efb68bf39c276025e2250ac537 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 17 Mar 2023 07:28:00 +0000
++Subject: [PATCH] net: sfp: fix state loss when updating state_hw_mask
++
++Andrew reports that the SFF modules on one of the ZII platforms do not
++indicate link up due to the SFP code believing that LOS indicating that
++there is no signal being received from the remote end, but in fact the
++LOS signal is showing that there is signal.
++
++What makes SFF modules different from SFPs is they typically have an
++inverted LOS, which uncovered this issue. When we read the hardware
++state, we mask it with state_hw_mask so we ignore anything we're not
++interested in. However, we don't re-read when state_hw_mask changes,
++leading to sfp->state being stale.
++
++Arrange for a software poll of the module state after we have parsed
++the EEPROM in sfp_sm_mod_probe() and updated state_*_mask. This will
++generate any necessary events for signal changes for the state
++machine as well as updating sfp->state.
++
++Reported-by: Andrew Lunn <andrew@lunn.ch>
++Tested-by: Andrew Lunn <andrew@lunn.ch>
++Fixes: 8475c4b70b04 ("net: sfp: re-implement soft state polling setup")
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2250,6 +2250,11 @@ static void sfp_sm_module(struct sfp *sf
++ 			break;
++ 		}
++ 
+++		/* Force a poll to re-read the hardware signal state after
+++		 * sfp_sm_mod_probe() changed state_hw_mask.
+++		 */
+++		mod_delayed_work(system_wq, &sfp->poll, 1);
+++
++ 		err = sfp_hwmon_insert(sfp);
++ 		if (err)
++ 			dev_warn(sfp->dev, "hwmon probe failed: %pe\n",
+diff --git a/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch b/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch
+new file mode 100644
+index 0000000000..98499b230e
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-09-1-net-sfp-bus-allow-SFP-quirks-to-override-Autoneg-and.patch
+@@ -0,0 +1,43 @@
++From 8110633db49d7de2e4852f697322e1f3f8e61b04 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 21 Mar 2023 16:58:46 +0000
++Subject: [PATCH] net: sfp-bus: allow SFP quirks to override Autoneg and pause
++ bits
++
++Allow SFP quirks to override the Autoneg, Pause and Asym_Pause bits in
++the support mask.
++
++Some modules have an inaccessible PHY on which is only accessible via
++2500base-X without Autonegotiation. We therefore want to be able to
++clear the Autoneg bit. Rearrange sfp_parse_support() to allow a SFP
++modes quirk to override this bit.
++
++Tested-by: Frank Wunderlich <frank-w@public-files.de>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -151,6 +151,10 @@ void sfp_parse_support(struct sfp_bus *b
++ 	unsigned int br_min, br_nom, br_max;
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
++ 
+++	phylink_set(modes, Autoneg);
+++	phylink_set(modes, Pause);
+++	phylink_set(modes, Asym_Pause);
+++
++ 	/* Decode the bitrate information to MBd */
++ 	br_min = br_nom = br_max = 0;
++ 	if (id->base.br_nominal) {
++@@ -329,10 +333,6 @@ void sfp_parse_support(struct sfp_bus *b
++ 		bus->sfp_quirk->modes(id, modes, interfaces);
++ 
++ 	linkmode_or(support, support, modes);
++-
++-	phylink_set(support, Autoneg);
++-	phylink_set(support, Pause);
++-	phylink_set(support, Asym_Pause);
++ }
++ EXPORT_SYMBOL_GPL(sfp_parse_support);
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch
+new file mode 100644
+index 0000000000..ce3339ceb2
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-09-2-net-sfp-add-quirk-for-2.5G-copper-SFP.patch
+@@ -0,0 +1,51 @@
++From 50e96acbe11667b6fe9d99e1348c6c224b2f11dd Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 21 Mar 2023 16:58:51 +0000
++Subject: [PATCH] net: sfp: add quirk for 2.5G copper SFP
++
++Add a quirk for a copper SFP that identifies itself as "OEM"
++"SFP-2.5G-T". This module's PHY is inaccessible, and can only run
++at 2500base-X with the host without negotiation. Add a quirk to
++enable the 2500base-X interface mode with 2500base-T support, and
++disable autonegotiation.
++
++Reported-by: Frank Wunderlich <frank-w@public-files.de>
++Tested-by: Frank Wunderlich <frank-w@public-files.de>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -368,6 +368,23 @@ static void sfp_quirk_2500basex(const st
++ 	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
++ }
++ 
+++static void sfp_quirk_disable_autoneg(const struct sfp_eeprom_id *id,
+++				      unsigned long *modes,
+++				      unsigned long *interfaces)
+++{
+++	linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, modes);
+++}
+++
+++static void sfp_quirk_oem_2_5g(const struct sfp_eeprom_id *id,
+++			       unsigned long *modes,
+++			       unsigned long *interfaces)
+++{
+++	/* Copper 2.5G SFP */
+++	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, modes);
+++	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
+++	sfp_quirk_disable_autoneg(id, modes, interfaces);
+++}
+++
++ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
++ 				      unsigned long *modes,
++ 				      unsigned long *interfaces)
++@@ -410,6 +427,7 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
++ 
++ 	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
+++	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
+diff --git a/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch b/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch
+new file mode 100644
+index 0000000000..16a88e582e
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-10-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch
+@@ -0,0 +1,34 @@
++From ad651d68cee75e9ac20002254c4e5d09ee67a84b Mon Sep 17 00:00:00 2001
++From: Daniel Golle <daniel@makrotopia.org>
++Date: Sun, 2 Apr 2023 12:44:37 +0100
++Subject: [PATCH] net: sfp: add quirk enabling 2500Base-x for HG MXPD-483II
++
++The HG MXPD-483II 1310nm SFP module is meant to operate with 2500Base-X,
++however, in their EEPROM they incorrectly specify:
++    Transceiver type                          : Ethernet: 1000BASE-LX
++    ...
++    BR, Nominal                               : 2600MBd
++
++Use sfp_quirk_2500basex for this module to allow 2500Base-X mode anyway.
++
++https://forum.banana-pi.org/t/bpi-r3-sfp-module-compatibility/14573/60
++
++Reported-by: chowtom <chowtom@gmail.com>
++Tested-by: chowtom <chowtom@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -415,6 +415,10 @@ static const struct sfp_quirk sfp_quirks
++ 
++ 	SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
++ 
+++	// HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports
+++	// 2600MBd in their EERPOM
+++	SFP_QUIRK_M("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex),
+++
++ 	// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
++ 	// their EEPROM
++ 	SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
+diff --git a/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch b/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch
+new file mode 100644
+index 0000000000..f392e99e26
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-11-net-sfp-avoid-EEPROM-read-of-absent-SFP-module.patch
+@@ -0,0 +1,36 @@
++From bef227c1537cb8005311c0842bc5449e8c7a5973 Mon Sep 17 00:00:00 2001
++From: Ivan Bornyakov <i.bornyakov@metrotek.ru>
++Date: Thu, 6 Apr 2023 16:08:33 +0300
++Subject: [PATCH] net: sfp: avoid EEPROM read of absent SFP module
++
++If SFP module is not present, it is sensible to fail sfp_module_eeprom()
++and sfp_module_eeprom_by_page() early to avoid excessive I2C transfers
++which are garanteed to fail.
++
++Suggested-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Ivan Bornyakov <i.bornyakov@metrotek.ru>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2567,6 +2567,9 @@ static int sfp_module_eeprom(struct sfp
++ 	unsigned int first, last, len;
++ 	int ret;
++ 
+++	if (!(sfp->state & SFP_F_PRESENT))
+++		return -ENODEV;
+++
++ 	if (ee->len == 0)
++ 		return -EINVAL;
++ 
++@@ -2599,6 +2602,9 @@ static int sfp_module_eeprom_by_page(str
++ 				     const struct ethtool_module_eeprom *page,
++ 				     struct netlink_ext_ack *extack)
++ {
+++	if (!(sfp->state & SFP_F_PRESENT))
+++		return -ENODEV;
+++
++ 	if (page->bank) {
++ 		NL_SET_ERR_MSG(extack, "Banks not supported");
++ 		return -EOPNOTSUPP;
+diff --git a/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch b/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch
+new file mode 100644
+index 0000000000..b780ecaa6f
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-1-net-sfp-add-helper-to-modify-signal-states.patch
+@@ -0,0 +1,64 @@
++From 418c1214741cf3ac5e420382a85c4f8a40586024 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:37:47 +0100
++Subject: [PATCH] net: sfp: add helper to modify signal states
++
++There are a couple of locations in the code where we modify
++sfp->state, and then call sfp_set_state(, sfp->state) to update
++the outputs/soft state to control the module. Provide a helper
++which takes a mask and new state so that this is encapsulated in
++one location.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++From 418c1214741cf3ac5e420382a85c4f8a40586024 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:37:47 +0100
++Subject: [PATCH] net: sfp: add helper to modify signal states
++
++There are a couple of locations in the code where we modify
++sfp->state, and then call sfp_set_state(, sfp->state) to update
++the outputs/soft state to control the module. Provide a helper
++which takes a mask and new state so that this is encapsulated in
++one location.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -737,6 +737,12 @@ static void sfp_set_state(struct sfp *sf
++ 		sfp_soft_set_state(sfp, state);
++ }
++ 
+++static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
+++{
+++	sfp->state = (sfp->state & ~mask) | set;
+++	sfp_set_state(sfp, sfp->state);
+++}
+++
++ static unsigned int sfp_check(void *buf, size_t len)
++ {
++ 	u8 *p, check;
++@@ -1589,16 +1595,14 @@ static void sfp_module_tx_disable(struct
++ {
++ 	dev_dbg(sfp->dev, "tx disable %u -> %u\n",
++ 		sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1);
++-	sfp->state |= SFP_F_TX_DISABLE;
++-	sfp_set_state(sfp, sfp->state);
+++	sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE);
++ }
++ 
++ static void sfp_module_tx_enable(struct sfp *sfp)
++ {
++ 	dev_dbg(sfp->dev, "tx disable %u -> %u\n",
++ 		sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0);
++-	sfp->state &= ~SFP_F_TX_DISABLE;
++-	sfp_set_state(sfp, sfp->state);
+++	sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0);
++ }
++ 
++ #if IS_ENABLED(CONFIG_DEBUG_FS)
+diff --git a/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch b/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch
+new file mode 100644
+index 0000000000..22c5c390ab
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-2-net-sfp-move-rtnl-lock-to-cover-reading-state.patch
+@@ -0,0 +1,42 @@
++From d47e5a430dfd8b15739a118e4a2add5fa90347fd Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:37:52 +0100
++Subject: [PATCH] net: sfp: move rtnl lock to cover reading state
++
++As preparation to moving st_mutex inside rtnl_lock, we need to first
++move the rtnl lock to cover reading the state.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++From d47e5a430dfd8b15739a118e4a2add5fa90347fd Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:37:52 +0100
++Subject: [PATCH] net: sfp: move rtnl lock to cover reading state
++
++As preparation to moving st_mutex inside rtnl_lock, we need to first
++move the rtnl lock to cover reading the state.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2653,6 +2653,7 @@ static void sfp_check_state(struct sfp *
++ 	unsigned int state, i, changed;
++ 
++ 	mutex_lock(&sfp->st_mutex);
+++	rtnl_lock();
++ 	state = sfp_get_state(sfp);
++ 	changed = state ^ sfp->state;
++ 	if (sfp->tx_fault_ignore)
++@@ -2668,7 +2669,6 @@ static void sfp_check_state(struct sfp *
++ 	state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
++ 	sfp->state = state;
++ 
++-	rtnl_lock();
++ 	if (changed & SFP_F_PRESENT)
++ 		sfp_sm_event(sfp, state & SFP_F_PRESENT ?
++ 				SFP_E_INSERT : SFP_E_REMOVE);
+diff --git a/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch b/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch
+new file mode 100644
+index 0000000000..a3b861253a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-3-net-sfp-swap-order-of-rtnl-and-st_mutex-locks.patch
+@@ -0,0 +1,36 @@
++From a9fe964e7aaeb3fc06a91c21269d0ac8b5afcea8 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:37:57 +0100
++Subject: [PATCH] net: sfp: swap order of rtnl and st_mutex locks
++
++Swap the order of the rtnl and st_mutex locks - st_mutex is now nested
++beneath rtnl lock instead of rtnl being beneath st_mutex. This will
++allow us to hold st_mutex only while manipulating the module's hardware
++or software control state.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2652,8 +2652,8 @@ static void sfp_check_state(struct sfp *
++ {
++ 	unsigned int state, i, changed;
++ 
++-	mutex_lock(&sfp->st_mutex);
++ 	rtnl_lock();
+++	mutex_lock(&sfp->st_mutex);
++ 	state = sfp_get_state(sfp);
++ 	changed = state ^ sfp->state;
++ 	if (sfp->tx_fault_ignore)
++@@ -2680,8 +2680,8 @@ static void sfp_check_state(struct sfp *
++ 	if (changed & SFP_F_LOS)
++ 		sfp_sm_event(sfp, state & SFP_F_LOS ?
++ 				SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
++-	rtnl_unlock();
++ 	mutex_unlock(&sfp->st_mutex);
+++	rtnl_unlock();
++ }
++ 
++ static irqreturn_t sfp_irq(int irq, void *data)
+diff --git a/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch b/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch
+new file mode 100644
+index 0000000000..fa678484cc
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-4-net-sfp-move-sm_mutex-into-sfp_check_state.patch
+@@ -0,0 +1,66 @@
++From 97a492050aa5e15507fd7b8774e7adaf8d6e4bb5 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:38:02 +0100
++Subject: [PATCH] net: sfp: move sm_mutex into sfp_check_state()
++
++Provide an unlocked version of sfp_sm_event() which can be used by
++sfp_check_state() to avoid having to keep re-taking the lock if
++several signals have changed state.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2508,10 +2508,8 @@ static void sfp_sm_main(struct sfp *sfp,
++ 	}
++ }
++ 
++-static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+++static void __sfp_sm_event(struct sfp *sfp, unsigned int event)
++ {
++-	mutex_lock(&sfp->sm_mutex);
++-
++ 	dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
++ 		mod_state_to_str(sfp->sm_mod_state),
++ 		dev_state_to_str(sfp->sm_dev_state),
++@@ -2526,7 +2524,12 @@ static void sfp_sm_event(struct sfp *sfp
++ 		mod_state_to_str(sfp->sm_mod_state),
++ 		dev_state_to_str(sfp->sm_dev_state),
++ 		sm_state_to_str(sfp->sm_state));
+++}
++ 
+++static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+++{
+++	mutex_lock(&sfp->sm_mutex);
+++	__sfp_sm_event(sfp, event);
++ 	mutex_unlock(&sfp->sm_mutex);
++ }
++ 
++@@ -2669,17 +2672,19 @@ static void sfp_check_state(struct sfp *
++ 	state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
++ 	sfp->state = state;
++ 
+++	mutex_lock(&sfp->sm_mutex);
++ 	if (changed & SFP_F_PRESENT)
++-		sfp_sm_event(sfp, state & SFP_F_PRESENT ?
++-				SFP_E_INSERT : SFP_E_REMOVE);
+++		__sfp_sm_event(sfp, state & SFP_F_PRESENT ?
+++				    SFP_E_INSERT : SFP_E_REMOVE);
++ 
++ 	if (changed & SFP_F_TX_FAULT)
++-		sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
++-				SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
+++		__sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
+++				    SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
++ 
++ 	if (changed & SFP_F_LOS)
++-		sfp_sm_event(sfp, state & SFP_F_LOS ?
++-				SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
+++		__sfp_sm_event(sfp, state & SFP_F_LOS ?
+++				    SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
+++	mutex_unlock(&sfp->sm_mutex);
++ 	mutex_unlock(&sfp->st_mutex);
++ 	rtnl_unlock();
++ }
+diff --git a/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch b/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch
+new file mode 100644
+index 0000000000..f618e4c17c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-5-net-sfp-change-st_mutex-locking.patch
+@@ -0,0 +1,182 @@
++From 1974fd3bf0f04589dea1a4a76273bbc8fd5760f6 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:38:07 +0100
++Subject: [PATCH] net: sfp: change st_mutex locking
++
++Change st_mutex's use within SFP such that it only protects the various
++state members, as it was originally supposed to, and isn't held while
++making various calls outside the driver.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -244,10 +244,17 @@ struct sfp {
++ 
++ 	bool need_poll;
++ 
+++	/* Access rules:
+++	 * state_hw_drive: st_mutex held
+++	 * state_hw_mask: st_mutex held
+++	 * state_soft_mask: st_mutex held
+++	 * state: st_mutex held unless reading input bits
+++	 */
++ 	struct mutex st_mutex;			/* Protects state */
++ 	unsigned int state_hw_mask;
++ 	unsigned int state_soft_mask;
++ 	unsigned int state;
+++
++ 	struct delayed_work poll;
++ 	struct delayed_work timeout;
++ 	struct mutex sm_mutex;			/* Protects state machine */
++@@ -695,7 +702,6 @@ static void sfp_soft_start_poll(struct s
++ 	const struct sfp_eeprom_id *id = &sfp->id;
++ 	unsigned int mask = 0;
++ 
++-	sfp->state_soft_mask = 0;
++ 	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE)
++ 		mask |= SFP_F_TX_DISABLE;
++ 	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT)
++@@ -703,19 +709,26 @@ static void sfp_soft_start_poll(struct s
++ 	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
++ 		mask |= SFP_F_LOS;
++ 
+++	mutex_lock(&sfp->st_mutex);
++ 	// Poll the soft state for hardware pins we want to ignore
++ 	sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
++ 
++ 	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
++ 	    !sfp->need_poll)
++ 		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+++	mutex_unlock(&sfp->st_mutex);
++ }
++ 
++ static void sfp_soft_stop_poll(struct sfp *sfp)
++ {
+++	mutex_lock(&sfp->st_mutex);
++ 	sfp->state_soft_mask = 0;
+++	mutex_unlock(&sfp->st_mutex);
++ }
++ 
+++/* sfp_get_state() - must be called with st_mutex held, or in the
+++ * initialisation path.
+++ */
++ static unsigned int sfp_get_state(struct sfp *sfp)
++ {
++ 	unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT);
++@@ -728,6 +741,9 @@ static unsigned int sfp_get_state(struct
++ 	return state;
++ }
++ 
+++/* sfp_set_state() - must be called with st_mutex held, or in the
+++ * initialisation path.
+++ */
++ static void sfp_set_state(struct sfp *sfp, unsigned int state)
++ {
++ 	sfp->set_state(sfp, state);
++@@ -739,8 +755,10 @@ static void sfp_set_state(struct sfp *sf
++ 
++ static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
++ {
+++	mutex_lock(&sfp->st_mutex);
++ 	sfp->state = (sfp->state & ~mask) | set;
++ 	sfp_set_state(sfp, sfp->state);
+++	mutex_unlock(&sfp->st_mutex);
++ }
++ 
++ static unsigned int sfp_check(void *buf, size_t len)
++@@ -1655,16 +1673,18 @@ static void sfp_debugfs_exit(struct sfp
++ 
++ static void sfp_module_tx_fault_reset(struct sfp *sfp)
++ {
++-	unsigned int state = sfp->state;
++-
++-	if (state & SFP_F_TX_DISABLE)
++-		return;
+++	unsigned int state;
++ 
++-	sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
+++	mutex_lock(&sfp->st_mutex);
+++	state = sfp->state;
+++	if (!(state & SFP_F_TX_DISABLE)) {
+++		sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
++ 
++-	udelay(T_RESET_US);
+++		udelay(T_RESET_US);
++ 
++-	sfp_set_state(sfp, state);
+++		sfp_set_state(sfp, state);
+++	}
+++	mutex_unlock(&sfp->st_mutex);
++ }
++ 
++ /* SFP state machine */
++@@ -2009,6 +2029,7 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	/* SFP module inserted - read I2C data */
++ 	struct sfp_eeprom_id id;
++ 	bool cotsworks_sfbg;
+++	unsigned int mask;
++ 	bool cotsworks;
++ 	u8 check;
++ 	int ret;
++@@ -2148,14 +2169,13 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	if (ret < 0)
++ 		return ret;
++ 
++-	/* Initialise state bits to use from hardware */
++-	sfp->state_hw_mask = SFP_F_PRESENT;
+++	mask = SFP_F_PRESENT;
++ 	if (sfp->gpio[GPIO_TX_DISABLE])
++-		sfp->state_hw_mask |= SFP_F_TX_DISABLE;
+++		mask |= SFP_F_TX_DISABLE;
++ 	if (sfp->gpio[GPIO_TX_FAULT])
++-		sfp->state_hw_mask |= SFP_F_TX_FAULT;
+++		mask |= SFP_F_TX_FAULT;
++ 	if (sfp->gpio[GPIO_LOS])
++-		sfp->state_hw_mask |= SFP_F_LOS;
+++		mask |= SFP_F_LOS;
++ 
++ 	sfp->module_t_start_up = T_START_UP;
++ 	sfp->module_t_wait = T_WAIT;
++@@ -2173,8 +2193,14 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		sfp->mdio_protocol = MDIO_I2C_NONE;
++ 
++ 	sfp->quirk = sfp_lookup_quirk(&id);
+++
+++	mutex_lock(&sfp->st_mutex);
+++	/* Initialise state bits to use from hardware */
+++	sfp->state_hw_mask = mask;
+++
++ 	if (sfp->quirk && sfp->quirk->fixup)
++ 		sfp->quirk->fixup(sfp);
+++	mutex_unlock(&sfp->st_mutex);
++ 
++ 	return 0;
++ }
++@@ -2671,6 +2697,7 @@ static void sfp_check_state(struct sfp *
++ 
++ 	state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
++ 	sfp->state = state;
+++	mutex_unlock(&sfp->st_mutex);
++ 
++ 	mutex_lock(&sfp->sm_mutex);
++ 	if (changed & SFP_F_PRESENT)
++@@ -2685,7 +2712,6 @@ static void sfp_check_state(struct sfp *
++ 		__sfp_sm_event(sfp, state & SFP_F_LOS ?
++ 				    SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
++ 	mutex_unlock(&sfp->sm_mutex);
++-	mutex_unlock(&sfp->st_mutex);
++ 	rtnl_unlock();
++ }
++ 
++@@ -2704,6 +2730,8 @@ static void sfp_poll(struct work_struct
++ 
++ 	sfp_check_state(sfp);
++ 
+++	// st_mutex doesn't need to be held here for state_soft_mask,
+++	// it's unimportant if we race while reading this.
++ 	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
++ 	    sfp->need_poll)
++ 		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+diff --git a/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch b/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch
+new file mode 100644
+index 0000000000..cd79d03af9
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-6-net-sfp-add-support-for-setting-signalling-rate.patch
+@@ -0,0 +1,142 @@
++From dc18582211b34bce8250ddf3cac2a2230e192120 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:38:12 +0100
++Subject: [PATCH] net: sfp: add support for setting signalling rate
++
++Add support to the SFP layer to allow phylink to set the signalling
++rate for a SFP module. The rate given will be in units of kilo-baud
++(1000 baud).
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -116,6 +116,23 @@ do {									\
++ })
++ #endif
++ 
+++static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
+++{
+++	switch (interface) {
+++	case PHY_INTERFACE_MODE_SGMII:
+++	case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */
+++		return 1250;
+++	case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */
+++		return 3125;
+++	case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */
+++		return 5156;
+++	case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */
+++		return 10313;
+++	default:
+++		return 0;
+++	}
+++}
+++
++ /**
++  * phylink_set_port_modes() - set the port type modes in the ethtool mask
++  * @mask: ethtool link mode mask
++@@ -802,6 +819,7 @@ static void phylink_major_config(struct
++ 				  const struct phylink_link_state *state)
++ {
++ 	struct phylink_pcs *pcs = NULL;
+++	unsigned int rate_kbd;
++ 	int err;
++ 
++ 	phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
++@@ -856,6 +874,12 @@ static void phylink_major_config(struct
++ 			phylink_err(pl, "mac_finish failed: %pe\n",
++ 				    ERR_PTR(err));
++ 	}
+++
+++	if (pl->sfp_bus) {
+++		rate_kbd = phylink_interface_signal_rate(state->interface);
+++		if (rate_kbd)
+++			sfp_upstream_set_signal_rate(pl->sfp_bus, rate_kbd);
+++	}
++ }
++ 
++ /*
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -576,6 +576,26 @@ static void sfp_upstream_clear(struct sf
++ }
++ 
++ /**
+++ * sfp_upstream_set_signal_rate() - set data signalling rate
+++ * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+++ * @rate_kbd: signalling rate in units of 1000 baud
+++ *
+++ * Configure the rate select settings on the SFP module for the signalling
+++ * rate (not the same as the data rate).
+++ *
+++ * Locks that may be held:
+++ *  Phylink's state_mutex
+++ *  rtnl lock
+++ *  SFP's sm_mutex
+++ */
+++void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd)
+++{
+++	if (bus->registered)
+++		bus->socket_ops->set_signal_rate(bus->sfp, rate_kbd);
+++}
+++EXPORT_SYMBOL_GPL(sfp_upstream_set_signal_rate);
+++
+++/**
++  * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
++  * @fwnode: firmware node for the parent device (MAC or PHY)
++  *
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -2579,6 +2579,10 @@ static void sfp_stop(struct sfp *sfp)
++ 	sfp_sm_event(sfp, SFP_E_DEV_DOWN);
++ }
++ 
+++static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
+++{
+++}
+++
++ static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
++ {
++ 	/* locking... and check module is present */
++@@ -2663,6 +2667,7 @@ static const struct sfp_socket_ops sfp_m
++ 	.detach = sfp_detach,
++ 	.start = sfp_start,
++ 	.stop = sfp_stop,
+++	.set_signal_rate = sfp_set_signal_rate,
++ 	.module_info = sfp_module_info,
++ 	.module_eeprom = sfp_module_eeprom,
++ 	.module_eeprom_by_page = sfp_module_eeprom_by_page,
++--- a/drivers/net/phy/sfp.h
+++++ b/drivers/net/phy/sfp.h
++@@ -19,6 +19,7 @@ struct sfp_socket_ops {
++ 	void (*detach)(struct sfp *sfp);
++ 	void (*start)(struct sfp *sfp);
++ 	void (*stop)(struct sfp *sfp);
+++	void (*set_signal_rate)(struct sfp *sfp, unsigned int rate_kbd);
++ 	int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo);
++ 	int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee,
++ 			     u8 *data);
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -556,6 +556,7 @@ int sfp_get_module_eeprom_by_page(struct
++ 				  struct netlink_ext_ack *extack);
++ void sfp_upstream_start(struct sfp_bus *bus);
++ void sfp_upstream_stop(struct sfp_bus *bus);
+++void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd);
++ void sfp_bus_put(struct sfp_bus *bus);
++ struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
++ int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++@@ -615,6 +616,11 @@ static inline void sfp_upstream_stop(str
++ {
++ }
++ 
+++static inline void sfp_upstream_set_signal_rate(struct sfp_bus *bus,
+++						unsigned int rate_kbd)
+++{
+++}
+++
++ static inline void sfp_bus_put(struct sfp_bus *bus)
++ {
++ }
+diff --git a/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch b/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch
+new file mode 100644
+index 0000000000..2aa6f6e54b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-12-7-net-sfp-add-support-for-rate-selection.patch
+@@ -0,0 +1,422 @@
++From fc082b39d0a29891ab4b54c88a40f42385103f71 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 17 May 2023 11:38:17 +0100
++Subject: [PATCH] net: sfp: add support for rate selection
++
++Add support for parsing the rate select thresholds and switching of the
++RS0 and RS1 signals to the transceiver. This is complicated by various
++revisions of SFF-8472 and interaction of SFF-8431, SFF-8079 and
++INF-8074.
++
++Reviewed-by: Simon Horman <simon.horman@corigine.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -26,14 +26,18 @@ enum {
++ 	GPIO_LOS,
++ 	GPIO_TX_FAULT,
++ 	GPIO_TX_DISABLE,
++-	GPIO_RATE_SELECT,
+++	GPIO_RS0,
+++	GPIO_RS1,
++ 	GPIO_MAX,
++ 
++ 	SFP_F_PRESENT = BIT(GPIO_MODDEF0),
++ 	SFP_F_LOS = BIT(GPIO_LOS),
++ 	SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT),
++ 	SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE),
++-	SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT),
+++	SFP_F_RS0 = BIT(GPIO_RS0),
+++	SFP_F_RS1 = BIT(GPIO_RS1),
+++
+++	SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
++ 
++ 	SFP_E_INSERT = 0,
++ 	SFP_E_REMOVE,
++@@ -150,6 +154,7 @@ static const char *gpio_of_names[] = {
++ 	"tx-fault",
++ 	"tx-disable",
++ 	"rate-select0",
+++	"rate-select1",
++ };
++ 
++ static const enum gpiod_flags gpio_flags[] = {
++@@ -158,6 +163,7 @@ static const enum gpiod_flags gpio_flags
++ 	GPIOD_IN,
++ 	GPIOD_ASIS,
++ 	GPIOD_ASIS,
+++	GPIOD_ASIS,
++ };
++ 
++ /* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
++@@ -251,6 +257,7 @@ struct sfp {
++ 	 * state: st_mutex held unless reading input bits
++ 	 */
++ 	struct mutex st_mutex;			/* Protects state */
+++	unsigned int state_hw_drive;
++ 	unsigned int state_hw_mask;
++ 	unsigned int state_soft_mask;
++ 	unsigned int state;
++@@ -271,6 +278,10 @@ struct sfp {
++ 	unsigned int module_t_start_up;
++ 	unsigned int module_t_wait;
++ 
+++	unsigned int rate_kbd;
+++	unsigned int rs_threshold_kbd;
+++	unsigned int rs_state_mask;
+++
++ 	bool have_a2;
++ 	bool tx_fault_ignore;
++ 
++@@ -321,7 +332,7 @@ static bool sfp_module_supported(const s
++ 
++ static const struct sff_data sfp_data = {
++ 	.gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT |
++-		 SFP_F_TX_DISABLE | SFP_F_RATE_SELECT,
+++		 SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
++ 	.module_supported = sfp_module_supported,
++ };
++ 
++@@ -510,20 +521,37 @@ static unsigned int sff_gpio_get_state(s
++ 
++ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
++ {
++-	if (state & SFP_F_PRESENT) {
++-		/* If the module is present, drive the signals */
++-		if (sfp->gpio[GPIO_TX_DISABLE])
+++	unsigned int drive;
+++
+++	if (state & SFP_F_PRESENT)
+++		/* If the module is present, drive the requested signals */
+++		drive = sfp->state_hw_drive;
+++	else
+++		/* Otherwise, let them float to the pull-ups */
+++		drive = 0;
+++
+++	if (sfp->gpio[GPIO_TX_DISABLE]) {
+++		if (drive & SFP_F_TX_DISABLE)
++ 			gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE],
++ 					       state & SFP_F_TX_DISABLE);
++-		if (state & SFP_F_RATE_SELECT)
++-			gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT],
++-					       state & SFP_F_RATE_SELECT);
++-	} else {
++-		/* Otherwise, let them float to the pull-ups */
++-		if (sfp->gpio[GPIO_TX_DISABLE])
+++		else
++ 			gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]);
++-		if (state & SFP_F_RATE_SELECT)
++-			gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]);
+++	}
+++
+++	if (sfp->gpio[GPIO_RS0]) {
+++		if (drive & SFP_F_RS0)
+++			gpiod_direction_output(sfp->gpio[GPIO_RS0],
+++					       state & SFP_F_RS0);
+++		else
+++			gpiod_direction_input(sfp->gpio[GPIO_RS0]);
+++	}
+++
+++	if (sfp->gpio[GPIO_RS1]) {
+++		if (drive & SFP_F_RS1)
+++			gpiod_direction_output(sfp->gpio[GPIO_RS1],
+++					       state & SFP_F_RS1);
+++		else
+++			gpiod_direction_input(sfp->gpio[GPIO_RS1]);
++ 	}
++ }
++ 
++@@ -685,16 +713,33 @@ static unsigned int sfp_soft_get_state(s
++ 	return state & sfp->state_soft_mask;
++ }
++ 
++-static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
+++static void sfp_soft_set_state(struct sfp *sfp, unsigned int state,
+++			       unsigned int soft)
++ {
++-	u8 mask = SFP_STATUS_TX_DISABLE_FORCE;
+++	u8 mask = 0;
++ 	u8 val = 0;
++ 
+++	if (soft & SFP_F_TX_DISABLE)
+++		mask |= SFP_STATUS_TX_DISABLE_FORCE;
++ 	if (state & SFP_F_TX_DISABLE)
++ 		val |= SFP_STATUS_TX_DISABLE_FORCE;
++ 
+++	if (soft & SFP_F_RS0)
+++		mask |= SFP_STATUS_RS0_SELECT;
+++	if (state & SFP_F_RS0)
+++		val |= SFP_STATUS_RS0_SELECT;
+++
+++	if (mask)
+++		sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
+++
+++	val = mask = 0;
+++	if (soft & SFP_F_RS1)
+++		mask |= SFP_EXT_STATUS_RS1_SELECT;
+++	if (state & SFP_F_RS1)
+++		val |= SFP_EXT_STATUS_RS1_SELECT;
++ 
++-	sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
+++	if (mask)
+++		sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val);
++ }
++ 
++ static void sfp_soft_start_poll(struct sfp *sfp)
++@@ -708,6 +753,8 @@ static void sfp_soft_start_poll(struct s
++ 		mask |= SFP_F_TX_FAULT;
++ 	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
++ 		mask |= SFP_F_LOS;
+++	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT)
+++		mask |= sfp->rs_state_mask;
++ 
++ 	mutex_lock(&sfp->st_mutex);
++ 	// Poll the soft state for hardware pins we want to ignore
++@@ -746,11 +793,13 @@ static unsigned int sfp_get_state(struct
++  */
++ static void sfp_set_state(struct sfp *sfp, unsigned int state)
++ {
+++	unsigned int soft;
+++
++ 	sfp->set_state(sfp, state);
++ 
++-	if (state & SFP_F_PRESENT &&
++-	    sfp->state_soft_mask & SFP_F_TX_DISABLE)
++-		sfp_soft_set_state(sfp, state);
+++	soft = sfp->state_soft_mask & SFP_F_OUTPUTS;
+++	if (state & SFP_F_PRESENT && soft)
+++		sfp_soft_set_state(sfp, state, soft);
++ }
++ 
++ static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
++@@ -1641,10 +1690,15 @@ static int sfp_debug_state_show(struct s
++ 		   sfp->sm_fault_retries);
++ 	seq_printf(s, "PHY probe remaining retries: %d\n",
++ 		   sfp->sm_phy_retries);
+++	seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd);
+++	seq_printf(s, "Rate select threshold: %u kBd\n",
+++		   sfp->rs_threshold_kbd);
++ 	seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT));
++ 	seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS));
++ 	seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT));
++ 	seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE));
+++	seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0));
+++	seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1));
++ 	return 0;
++ }
++ DEFINE_SHOW_ATTRIBUTE(sfp_debug_state);
++@@ -1950,6 +2004,95 @@ static int sfp_sm_mod_hpower(struct sfp
++ 	return 0;
++ }
++ 
+++static void sfp_module_parse_rate_select(struct sfp *sfp)
+++{
+++	u8 rate_id;
+++
+++	sfp->rs_threshold_kbd = 0;
+++	sfp->rs_state_mask = 0;
+++
+++	if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT)))
+++		/* No support for RateSelect */
+++		return;
+++
+++	/* Default to INF-8074 RateSelect operation. The signalling threshold
+++	 * rate is not well specified, so always select "Full Bandwidth", but
+++	 * SFF-8079 reveals that it is understood that RS0 will be low for
+++	 * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between.
+++	 * This method exists prior to SFF-8472.
+++	 */
+++	sfp->rs_state_mask = SFP_F_RS0;
+++	sfp->rs_threshold_kbd = 1594;
+++
+++	/* Parse the rate identifier, which is complicated due to history:
+++	 * SFF-8472 rev 9.5 marks this field as reserved.
+++	 * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472
+++	 *  compliance is not required.
+++	 * SFF-8472 rev 10.2 defines this field using values 0..4
+++	 * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079
+++	 * and even values.
+++	 */
+++	rate_id = sfp->id.base.rate_id;
+++	if (rate_id == 0)
+++		/* Unspecified */
+++		return;
+++
+++	/* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0,
+++	 * and allocated value 3 to SFF-8431 independent tx/rx rate select.
+++	 * Convert this to a SFF-8472 rev 11.0 rate identifier.
+++	 */
+++	if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
+++	    sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 &&
+++	    rate_id == 3)
+++		rate_id = SFF_RID_8431;
+++
+++	if (rate_id & SFF_RID_8079) {
+++		/* SFF-8079 RateSelect / Application Select in conjunction with
+++		 * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield
+++		 * with only bit 0 used, which takes precedence over SFF-8472.
+++		 */
+++		if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) {
+++			/* SFF-8079 Part 1 - rate selection between Fibre
+++			 * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0
+++			 * is high for 2125, so we have to subtract 1 to
+++			 * include it.
+++			 */
+++			sfp->rs_threshold_kbd = 2125 - 1;
+++			sfp->rs_state_mask = SFP_F_RS0;
+++		}
+++		return;
+++	}
+++
+++	/* SFF-8472 rev 9.5 does not define the rate identifier */
+++	if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5)
+++		return;
+++
+++	/* SFF-8472 rev 11.0 defines rate_id as a numerical value which will
+++	 * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id.
+++	 */
+++	switch (rate_id) {
+++	case SFF_RID_8431_RX_ONLY:
+++		sfp->rs_threshold_kbd = 4250;
+++		sfp->rs_state_mask = SFP_F_RS0;
+++		break;
+++
+++	case SFF_RID_8431_TX_ONLY:
+++		sfp->rs_threshold_kbd = 4250;
+++		sfp->rs_state_mask = SFP_F_RS1;
+++		break;
+++
+++	case SFF_RID_8431:
+++		sfp->rs_threshold_kbd = 4250;
+++		sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
+++		break;
+++
+++	case SFF_RID_10G8G:
+++		sfp->rs_threshold_kbd = 9000;
+++		sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
+++		break;
+++	}
+++}
+++
++ /* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL
++  * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do
++  * not support multibyte reads from the EEPROM. Each multi-byte read
++@@ -2169,6 +2312,8 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	if (ret < 0)
++ 		return ret;
++ 
+++	sfp_module_parse_rate_select(sfp);
+++
++ 	mask = SFP_F_PRESENT;
++ 	if (sfp->gpio[GPIO_TX_DISABLE])
++ 		mask |= SFP_F_TX_DISABLE;
++@@ -2176,6 +2321,10 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		mask |= SFP_F_TX_FAULT;
++ 	if (sfp->gpio[GPIO_LOS])
++ 		mask |= SFP_F_LOS;
+++	if (sfp->gpio[GPIO_RS0])
+++		mask |= SFP_F_RS0;
+++	if (sfp->gpio[GPIO_RS1])
+++		mask |= SFP_F_RS1;
++ 
++ 	sfp->module_t_start_up = T_START_UP;
++ 	sfp->module_t_wait = T_WAIT;
++@@ -2198,6 +2347,9 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	/* Initialise state bits to use from hardware */
++ 	sfp->state_hw_mask = mask;
++ 
+++	/* We want to drive the rate select pins that the module is using */
+++	sfp->state_hw_drive |= sfp->rs_state_mask;
+++
++ 	if (sfp->quirk && sfp->quirk->fixup)
++ 		sfp->quirk->fixup(sfp);
++ 	mutex_unlock(&sfp->st_mutex);
++@@ -2214,6 +2366,7 @@ static void sfp_sm_mod_remove(struct sfp
++ 
++ 	memset(&sfp->id, 0, sizeof(sfp->id));
++ 	sfp->module_power_mW = 0;
+++	sfp->state_hw_drive = SFP_F_TX_DISABLE;
++ 	sfp->have_a2 = false;
++ 
++ 	dev_info(sfp->dev, "module removed\n");
++@@ -2581,6 +2734,16 @@ static void sfp_stop(struct sfp *sfp)
++ 
++ static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
++ {
+++	unsigned int set;
+++
+++	sfp->rate_kbd = rate_kbd;
+++
+++	if (rate_kbd > sfp->rs_threshold_kbd)
+++		set = sfp->rs_state_mask;
+++	else
+++		set = 0;
+++
+++	sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set);
++ }
++ 
++ static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
++@@ -2700,7 +2863,7 @@ static void sfp_check_state(struct sfp *
++ 			dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_of_names[i],
++ 				!!(sfp->state & BIT(i)), !!(state & BIT(i)));
++ 
++-	state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
+++	state |= sfp->state & SFP_F_OUTPUTS;
++ 	sfp->state = state;
++ 	mutex_unlock(&sfp->st_mutex);
++ 
++@@ -2856,6 +3019,7 @@ static int sfp_probe(struct platform_dev
++ 		}
++ 
++ 	sfp->state_hw_mask = SFP_F_PRESENT;
+++	sfp->state_hw_drive = SFP_F_TX_DISABLE;
++ 
++ 	sfp->get_state = sfp_gpio_get_state;
++ 	sfp->set_state = sfp_gpio_set_state;
++@@ -2881,9 +3045,9 @@ static int sfp_probe(struct platform_dev
++ 	 */
++ 	sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE;
++ 
++-	if (sfp->gpio[GPIO_RATE_SELECT] &&
++-	    gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT]))
++-		sfp->state |= SFP_F_RATE_SELECT;
+++	if (sfp->gpio[GPIO_RS0] &&
+++	    gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0]))
+++		sfp->state |= SFP_F_RS0;
++ 	sfp_set_state(sfp, sfp->state);
++ 	sfp_module_tx_disable(sfp);
++ 	if (sfp->state & SFP_F_PRESENT) {
++--- a/include/linux/sfp.h
+++++ b/include/linux/sfp.h
++@@ -342,6 +342,12 @@ enum {
++ 	SFP_ENCODING			= 11,
++ 	SFP_BR_NOMINAL			= 12,
++ 	SFP_RATE_ID			= 13,
+++	SFF_RID_8079			= 0x01,
+++	SFF_RID_8431_RX_ONLY		= 0x02,
+++	SFF_RID_8431_TX_ONLY		= 0x04,
+++	SFF_RID_8431			= 0x06,
+++	SFF_RID_10G8G			= 0x0e,
+++
++ 	SFP_LINK_LEN_SM_KM		= 14,
++ 	SFP_LINK_LEN_SM_100M		= 15,
++ 	SFP_LINK_LEN_50UM_OM2_10M	= 16,
++@@ -465,6 +471,7 @@ enum {
++ 	SFP_STATUS			= 110,
++ 	SFP_STATUS_TX_DISABLE		= BIT(7),
++ 	SFP_STATUS_TX_DISABLE_FORCE	= BIT(6),
+++	SFP_STATUS_RS0_SELECT		= BIT(3),
++ 	SFP_STATUS_TX_FAULT		= BIT(2),
++ 	SFP_STATUS_RX_LOS		= BIT(1),
++ 	SFP_ALARM0			= 112,
++@@ -496,6 +503,7 @@ enum {
++ 	SFP_WARN1_RXPWR_LOW		= BIT(6),
++ 
++ 	SFP_EXT_STATUS			= 118,
+++	SFP_EXT_STATUS_RS1_SELECT	= BIT(3),
++ 	SFP_EXT_STATUS_PWRLVL_SELECT	= BIT(0),
++ 
++ 	SFP_VSL				= 120,
+diff --git a/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch b/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch
+new file mode 100644
+index 0000000000..938e14627a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-13-net-sfp-add-support-for-a-couple-of-copper-multi-rat.patch
+@@ -0,0 +1,93 @@
++From 5859a99b52254be356d3cca2e40f7f371ef24b0a Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Sat, 20 May 2023 11:18:30 +0100
++Subject: [PATCH] net: sfp: add support for a couple of copper multi-rate
++ modules
++
++Add support for the Fiberstore SFP-10G-T and Walsun HXSX-ATRC-1
++modules. Internally, the PCB silkscreen has what seems to be a part
++number of WT_502. Fiberstore use v2.2 whereas Walsun use v2.6.
++
++These modules contain a Marvell AQrate AQR113C PHY, accessible through
++I2C 0x51 using the "rollball" protocol. In both cases, the PHY is
++programmed to use 10GBASE-R with pause-mode rate adaption.
++
++Unlike the other rollball modules, these only need a four second delay
++before we can talk to the PHY.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1q0JfS-006Dqc-8t@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -172,7 +172,6 @@ static const enum gpiod_flags gpio_flags
++  * on board (for a copper SFP) time to initialise.
++  */
++ #define T_WAIT			msecs_to_jiffies(50)
++-#define T_WAIT_ROLLBALL		msecs_to_jiffies(25000)
++ #define T_START_UP		msecs_to_jiffies(300)
++ #define T_START_UP_BAD_GPON	msecs_to_jiffies(60000)
++ 
++@@ -353,6 +352,27 @@ static void sfp_fixup_ignore_tx_fault(st
++ 	sfp->tx_fault_ignore = true;
++ }
++ 
+++// For 10GBASE-T short-reach modules
+++static void sfp_fixup_10gbaset_30m(struct sfp *sfp)
+++{
+++	sfp->id.base.connector = SFF8024_CONNECTOR_RJ45;
+++	sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
+++}
+++
+++static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs)
+++{
+++	sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
+++	sfp->module_t_wait = msecs_to_jiffies(secs * 1000);
+++}
+++
+++static void sfp_fixup_fs_10gt(struct sfp *sfp)
+++{
+++	sfp_fixup_10gbaset_30m(sfp);
+++
+++	// These SFPs need 4 seconds before the PHY can be accessed
+++	sfp_fixup_rollball_proto(sfp, 4);
+++}
+++
++ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
++ {
++ 	/* Ignore the TX_FAULT and LOS signals on this module.
++@@ -364,8 +384,8 @@ static void sfp_fixup_halny_gsfp(struct
++ 
++ static void sfp_fixup_rollball(struct sfp *sfp)
++ {
++-	sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
++-	sfp->module_t_wait = T_WAIT_ROLLBALL;
+++	// Rollball SFPs need 25 seconds before the PHY can be accessed
+++	sfp_fixup_rollball_proto(sfp, 25);
++ }
++ 
++ static void sfp_fixup_rollball_cc(struct sfp *sfp)
++@@ -431,6 +451,10 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
++ 		  sfp_fixup_long_startup),
++ 
+++	// Fiberstore SFP-10G-T doesn't identify as copper, and uses the
+++	// Rollball protocol to talk to the PHY.
+++	SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
+++
++ 	SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
++ 
++ 	// HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports
++@@ -448,6 +472,10 @@ static const struct sfp_quirk sfp_quirks
++ 
++ 	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
++ 
+++	// Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the
+++	// Rollball protocol to talk to the PHY.
+++	SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt),
+++
++ 	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
+diff --git a/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch b/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch
+new file mode 100644
+index 0000000000..c6512692c8
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-14-net-sfp-add-support-for-HXSX-ATRI-1-copper-SFP-modul.patch
+@@ -0,0 +1,30 @@
++From ac2e8e3cfe48439a2403b3d616fb654db313e362 Mon Sep 17 00:00:00 2001
++From: Josua Mayer <josua@solid-run.com>
++Date: Mon, 22 May 2023 17:52:42 +0300
++Subject: [PATCH] net: sfp: add support for HXSX-ATRI-1 copper SFP+ module
++
++Walsun offers commercial ("C") and industrial ("I") variants of
++multi-rate copper SFP+ modules.
++
++Add quirk for HXSX-ATRI-1 using same parameters as the already supported
++commercial variant HXSX-ATRC-1.
++
++Signed-off-by: Josua Mayer <josua@solid-run.com>
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Link: https://lore.kernel.org/r/20230522145242.30192-2-josua@solid-run.com/
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -472,9 +472,10 @@ static const struct sfp_quirk sfp_quirks
++ 
++ 	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
++ 
++-	// Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the
+++	// Walsun HXSX-ATR[CI]-1 don't identify as copper, and use the
++ 	// Rollball protocol to talk to the PHY.
++ 	SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt),
+++	SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt),
++ 
++ 	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
+diff --git a/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch b/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch
+new file mode 100644
+index 0000000000..45587fad0c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-15-net-phy-move-marking-PHY-on-SFP-module-into-SFP-code.patch
+@@ -0,0 +1,39 @@
++From f4bf467883f210d0bfbe784fffca52887de147fb Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Thu, 3 Aug 2023 16:56:24 +0100
++Subject: [PATCH] net: phy: move marking PHY on SFP module into SFP code
++
++Move marking the PHY as being on a SFP module into the SFP code between
++getting the PHY device (and thus initialising the phy_device structure)
++and registering the discovered device.
++
++This means that PHY drivers can use phy_on_sfp() in their match and
++get_features methods.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Link: https://lore.kernel.org/r/E1qRaga-001vKt-8X@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/phy_device.c
+++++ b/drivers/net/phy/phy_device.c
++@@ -1452,8 +1452,6 @@ int phy_attach_direct(struct net_device
++ 
++ 		if (phydev->sfp_bus_attached)
++ 			dev->sfp_bus = phydev->sfp_bus;
++-		else if (dev->sfp_bus)
++-			phydev->is_on_sfp_module = true;
++ 	}
++ 
++ 	/* Some Ethernet drivers try to connect to a PHY device before
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -1815,6 +1815,9 @@ static int sfp_sm_probe_phy(struct sfp *
++ 		return PTR_ERR(phy);
++ 	}
++ 
+++	/* Mark this PHY as being on a SFP module */
+++	phy->is_on_sfp_module = true;
+++
++ 	err = phy_device_register(phy);
++ 	if (err) {
++ 		phy_device_free(phy);
+diff --git a/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch b/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch
+new file mode 100644
+index 0000000000..ce17622591
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-16-net-sfp-add-quirk-for-Fiberstone-GPON-ONU-34-20BI.patch
+@@ -0,0 +1,29 @@
++From d387e34fec407f881fdf165b5d7ec128ebff362f Mon Sep 17 00:00:00 2001
++From: Christian Marangi <ansuelsmth@gmail.com>
++Date: Tue, 19 Sep 2023 14:47:20 +0200
++Subject: [PATCH] net: sfp: add quirk for Fiberstone GPON-ONU-34-20BI
++
++Fiberstone GPON-ONU-34-20B can operate at 2500base-X, but report 1.2GBd
++NRZ in their EEPROM.
++
++The module also require the ignore tx fault fixup similar to Huawei MA5671A
++as it gets disabled on error messages with serial redirection enabled.
++
++Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
++Link: https://lore.kernel.org/r/20230919124720.8210-1-ansuelsmth@gmail.com
++Signed-off-by: Paolo Abeni <pabeni@redhat.com>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -455,6 +455,11 @@ static const struct sfp_quirk sfp_quirks
++ 	// Rollball protocol to talk to the PHY.
++ 	SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
++ 
+++	// Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
+++	// NRZ in their EEPROM
+++	SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex,
+++		  sfp_fixup_ignore_tx_fault),
+++
++ 	SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
++ 
++ 	// HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports
+diff --git a/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch
+new file mode 100644
+index 0000000000..7da5a924c5
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-17-net-sfp-add-quirk-for-FS-s-2.5G-copper-SFP.patch
+@@ -0,0 +1,26 @@
++From e27aca3760c08b7b05aea71068bd609aa93e7b35 Mon Sep 17 00:00:00 2001
++From: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
++Date: Mon, 25 Sep 2023 13:30:59 +0530
++Subject: [PATCH] net: sfp: add quirk for FS's 2.5G copper SFP
++
++Add a quirk for a copper SFP that identifies itself as "FS" "SFP-2.5G-T".
++This module's PHY is inaccessible, and can only run at 2500base-X with the
++host without negotiation. Add a quirk to enable the 2500base-X interface mode
++with 2500base-T support and disable auto negotiation.
++
++Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
++Link: https://lore.kernel.org/r/20230925080059.266240-1-Raju.Lakkaraju@microchip.com
++Signed-off-by: Paolo Abeni <pabeni@redhat.com>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -471,6 +471,9 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
++ 		  sfp_fixup_ignore_tx_fault),
++ 
+++	// FS 2.5G Base-T
+++	SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
+++
++ 	// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
++ 	// 2500MBd NRZ in their EEPROM
++ 	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
+diff --git a/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch b/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch
+new file mode 100644
+index 0000000000..434210cd87
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-18-1-net-sfp-re-implement-ignoring-the-hardware-TX_FAULT-.patch
+@@ -0,0 +1,82 @@
++From e184e8609f8c1cd9fef703f667245b6ebd89c2ed Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 3 Oct 2023 14:34:24 +0100
++Subject: [PATCH] net: sfp: re-implement ignoring the hardware TX_FAULT signal
++
++Re-implement how we ignore the hardware TX_FAULT signal. Rather than
++having a separate boolean for this, use a bitmask of the hardware
++signals that we wish to ignore. This gives more flexibility in the
++future to ignore other signals such as RX_LOS.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Tested-by: Christian Marangi <ansuelsmth@gmail.com>
++Link: https://lore.kernel.org/r/E1qnfXc-008UDY-91@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -259,6 +259,7 @@ struct sfp {
++ 	unsigned int state_hw_drive;
++ 	unsigned int state_hw_mask;
++ 	unsigned int state_soft_mask;
+++	unsigned int state_ignore_mask;
++ 	unsigned int state;
++ 
++ 	struct delayed_work poll;
++@@ -282,7 +283,6 @@ struct sfp {
++ 	unsigned int rs_state_mask;
++ 
++ 	bool have_a2;
++-	bool tx_fault_ignore;
++ 
++ 	const struct sfp_quirk *quirk;
++ 
++@@ -349,7 +349,7 @@ static void sfp_fixup_long_startup(struc
++ 
++ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
++ {
++-	sfp->tx_fault_ignore = true;
+++	sfp->state_ignore_mask |= SFP_F_TX_FAULT;
++ }
++ 
++ // For 10GBASE-T short-reach modules
++@@ -795,7 +795,8 @@ static void sfp_soft_start_poll(struct s
++ 
++ 	mutex_lock(&sfp->st_mutex);
++ 	// Poll the soft state for hardware pins we want to ignore
++-	sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
+++	sfp->state_soft_mask = ~sfp->state_hw_mask & ~sfp->state_ignore_mask &
+++			       mask;
++ 
++ 	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
++ 	    !sfp->need_poll)
++@@ -2369,7 +2370,7 @@ static int sfp_sm_mod_probe(struct sfp *
++ 	sfp->module_t_start_up = T_START_UP;
++ 	sfp->module_t_wait = T_WAIT;
++ 
++-	sfp->tx_fault_ignore = false;
+++	sfp->state_ignore_mask = 0;
++ 
++ 	if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
++ 	    sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
++@@ -2392,6 +2393,8 @@ static int sfp_sm_mod_probe(struct sfp *
++ 
++ 	if (sfp->quirk && sfp->quirk->fixup)
++ 		sfp->quirk->fixup(sfp);
+++
+++	sfp->state_hw_mask &= ~sfp->state_ignore_mask;
++ 	mutex_unlock(&sfp->st_mutex);
++ 
++ 	return 0;
++@@ -2893,10 +2896,7 @@ static void sfp_check_state(struct sfp *
++ 	mutex_lock(&sfp->st_mutex);
++ 	state = sfp_get_state(sfp);
++ 	changed = state ^ sfp->state;
++-	if (sfp->tx_fault_ignore)
++-		changed &= SFP_F_PRESENT | SFP_F_LOS;
++-	else
++-		changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
+++	changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
++ 
++ 	for (i = 0; i < GPIO_MAX; i++)
++ 		if (changed & BIT(i))
+diff --git a/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch b/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch
+new file mode 100644
+index 0000000000..37afcd1c7b
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-18-2-net-sfp-improve-Nokia-GPON-sfp-fixup.patch
+@@ -0,0 +1,54 @@
++From 5ffe330e40bdfad9c49a615c54d2d89343b2f08a Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Tue, 3 Oct 2023 14:34:29 +0100
++Subject: [PATCH] net: sfp: improve Nokia GPON sfp fixup
++
++Improve the Nokia GPON fixup - we need to ignore not only the hardware
++LOS signal, but also the software implementation as well. Do this by
++using the new state_ignore_mask to indicate that we should ignore not
++only the hardware RX_LOS signal, and also clear the LOS bits in the
++option field.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Tested-by: Christian Marangi <ansuelsmth@gmail.com>
++Link: https://lore.kernel.org/r/E1qnfXh-008UDe-F9@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -347,11 +347,26 @@ static void sfp_fixup_long_startup(struc
++ 	sfp->module_t_start_up = T_START_UP_BAD_GPON;
++ }
++ 
+++static void sfp_fixup_ignore_los(struct sfp *sfp)
+++{
+++	/* This forces LOS to zero, so we ignore transitions */
+++	sfp->state_ignore_mask |= SFP_F_LOS;
+++	/* Make sure that LOS options are clear */
+++	sfp->id.ext.options &= ~cpu_to_be16(SFP_OPTIONS_LOS_INVERTED |
+++					    SFP_OPTIONS_LOS_NORMAL);
+++}
+++
++ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
++ {
++ 	sfp->state_ignore_mask |= SFP_F_TX_FAULT;
++ }
++ 
+++static void sfp_fixup_nokia(struct sfp *sfp)
+++{
+++	sfp_fixup_long_startup(sfp);
+++	sfp_fixup_ignore_los(sfp);
+++}
+++
++ // For 10GBASE-T short-reach modules
++ static void sfp_fixup_10gbaset_30m(struct sfp *sfp)
++ {
++@@ -449,7 +464,7 @@ static const struct sfp_quirk sfp_quirks
++ 	// Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd
++ 	// NRZ in their EEPROM
++ 	SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
++-		  sfp_fixup_long_startup),
+++		  sfp_fixup_nokia),
++ 
++ 	// Fiberstore SFP-10G-T doesn't identify as copper, and uses the
++ 	// Rollball protocol to talk to the PHY.
+diff --git a/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch b/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch
+new file mode 100644
+index 0000000000..892edde0e2
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-19-1-net-linkmode-add-linkmode_fill-helper.patch
+@@ -0,0 +1,26 @@
++From 96fa96e198f9707285003075fbbce7db6a485112 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 15 Nov 2023 11:39:18 +0000
++Subject: [PATCH] net: linkmode: add linkmode_fill() helper
++
++Add a linkmode_fill() helper, which will allow us to convert phylink's
++open coded bitmap_fill() operations.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/include/linux/linkmode.h
+++++ b/include/linux/linkmode.h
++@@ -10,6 +10,11 @@ static inline void linkmode_zero(unsigne
++ 	bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
++ }
++ 
+++static inline void linkmode_fill(unsigned long *dst)
+++{
+++	bitmap_fill(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
+++}
+++
++ static inline void linkmode_copy(unsigned long *dst, const unsigned long *src)
++ {
++ 	bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS);
+diff --git a/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch b/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch
+new file mode 100644
+index 0000000000..bf32262638
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-19-2-net-phylink-use-linkmode_fill.patch
+@@ -0,0 +1,31 @@
++From ba50a8d40258081325db15f5a86cbb301867a3ba Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 15 Nov 2023 11:39:23 +0000
++Subject: [PATCH] net: phylink: use linkmode_fill()
++
++Use linkmode_fill() rather than open coding the bitmap operation.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -603,7 +603,7 @@ static int phylink_parse_fixedlink(struc
++ 		phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n",
++ 			     pl->link_config.speed);
++ 
++-	bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+++	linkmode_fill(pl->supported);
++ 	linkmode_copy(pl->link_config.advertising, pl->supported);
++ 	phylink_validate(pl, pl->supported, &pl->link_config);
++ 
++@@ -1288,7 +1288,7 @@ struct phylink *phylink_create(struct ph
++ 	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
++ 	timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
++ 
++-	bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+++	linkmode_fill(pl->supported);
++ 	linkmode_copy(pl->link_config.advertising, pl->supported);
++ 	phylink_validate(pl, pl->supported, &pl->link_config);
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch b/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch
+new file mode 100644
+index 0000000000..fa8b1a6536
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-19-3-net-sfp-use-linkmode_-rather-than-open-coding.patch
+@@ -0,0 +1,23 @@
++From 466b97b1871a49c272757f7527db2f85ea6338b4 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Wed, 15 Nov 2023 11:39:28 +0000
++Subject: [PATCH] net: sfp: use linkmode_*() rather than open coding
++
++Use the linkmode_*() helpers rather than open coding the calls to the
++bitmap operators.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -318,7 +318,7 @@ void sfp_parse_support(struct sfp_bus *b
++ 	 * modules use 2500Mbaud rather than 3100 or 3200Mbaud for
++ 	 * 2500BASE-X, so we allow some slack here.
++ 	 */
++-	if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) {
+++	if (linkmode_empty(modes) && br_nom) {
++ 		if (br_min <= 1300 && br_max >= 1200) {
++ 			phylink_set(modes, 1000baseX_Full);
++ 			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
+diff --git a/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch b/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch
+new file mode 100644
+index 0000000000..088ae6c1ba
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-20-net-sfp-rework-the-RollBall-PHY-waiting-code.patch
+@@ -0,0 +1,131 @@
++From 2f3ce7a56c6e02bc0b258507f3a82b7511f62f9e Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Tue, 21 Nov 2023 18:20:24 +0100
++Subject: [PATCH] net: sfp: rework the RollBall PHY waiting code
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++RollBall SFP modules allow the access to PHY registers only after a
++certain time has passed. Until then, the registers read 0xffff.
++
++Currently we have quirks for modules where we need to wait either 25
++seconds or 4 seconds, but recently I got hands on another module where
++the wait is even shorter.
++
++Instead of hardcoding different wait times, lets rework the code:
++- increase the PHY retry count to 25
++- when RollBall module is detected, increase the PHY retry time from
++  50ms to 1s
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -193,7 +193,7 @@ static const enum gpiod_flags gpio_flags
++  * R_PHY_RETRY is the number of attempts.
++  */
++ #define T_PHY_RETRY		msecs_to_jiffies(50)
++-#define R_PHY_RETRY		12
+++#define R_PHY_RETRY		25
++ 
++ /* SFP module presence detection is poor: the three MOD DEF signals are
++  * the same length on the PCB, which means it's possible for MOD DEF 0 to
++@@ -276,7 +276,7 @@ struct sfp {
++ 	struct sfp_eeprom_id id;
++ 	unsigned int module_power_mW;
++ 	unsigned int module_t_start_up;
++-	unsigned int module_t_wait;
+++	unsigned int phy_t_retry;
++ 
++ 	unsigned int rate_kbd;
++ 	unsigned int rs_threshold_kbd;
++@@ -374,18 +374,22 @@ static void sfp_fixup_10gbaset_30m(struc
++ 	sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
++ }
++ 
++-static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs)
+++static void sfp_fixup_rollball(struct sfp *sfp)
++ {
++ 	sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
++-	sfp->module_t_wait = msecs_to_jiffies(secs * 1000);
+++
+++	/* RollBall modules may disallow access to PHY registers for up to 25
+++	 * seconds, and the reads return 0xffff before that. Increase the time
+++	 * between PHY probe retries from 50ms to 1s so that we will wait for
+++	 * the PHY for a sufficient amount of time.
+++	 */
+++	sfp->phy_t_retry = msecs_to_jiffies(1000);
++ }
++ 
++ static void sfp_fixup_fs_10gt(struct sfp *sfp)
++ {
++ 	sfp_fixup_10gbaset_30m(sfp);
++-
++-	// These SFPs need 4 seconds before the PHY can be accessed
++-	sfp_fixup_rollball_proto(sfp, 4);
+++	sfp_fixup_rollball(sfp);
++ }
++ 
++ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
++@@ -397,12 +401,6 @@ static void sfp_fixup_halny_gsfp(struct
++ 	sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
++ }
++ 
++-static void sfp_fixup_rollball(struct sfp *sfp)
++-{
++-	// Rollball SFPs need 25 seconds before the PHY can be accessed
++-	sfp_fixup_rollball_proto(sfp, 25);
++-}
++-
++ static void sfp_fixup_rollball_cc(struct sfp *sfp)
++ {
++ 	sfp_fixup_rollball(sfp);
++@@ -2383,7 +2381,7 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		mask |= SFP_F_RS1;
++ 
++ 	sfp->module_t_start_up = T_START_UP;
++-	sfp->module_t_wait = T_WAIT;
+++	sfp->phy_t_retry = T_PHY_RETRY;
++ 
++ 	sfp->state_ignore_mask = 0;
++ 
++@@ -2620,10 +2618,9 @@ static void sfp_sm_main(struct sfp *sfp,
++ 
++ 		/* We need to check the TX_FAULT state, which is not defined
++ 		 * while TX_DISABLE is asserted. The earliest we want to do
++-		 * anything (such as probe for a PHY) is 50ms (or more on
++-		 * specific modules).
+++		 * anything (such as probe for a PHY) is 50ms.
++ 		 */
++-		sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
+++		sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
++ 		break;
++ 
++ 	case SFP_S_WAIT:
++@@ -2637,8 +2634,8 @@ static void sfp_sm_main(struct sfp *sfp,
++ 			 * deasserting.
++ 			 */
++ 			timeout = sfp->module_t_start_up;
++-			if (timeout > sfp->module_t_wait)
++-				timeout -= sfp->module_t_wait;
+++			if (timeout > T_WAIT)
+++				timeout -= T_WAIT;
++ 			else
++ 				timeout = 1;
++ 
++@@ -2681,7 +2678,11 @@ static void sfp_sm_main(struct sfp *sfp,
++ 		ret = sfp_sm_probe_for_phy(sfp);
++ 		if (ret == -ENODEV) {
++ 			if (--sfp->sm_phy_retries) {
++-				sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
+++				sfp_sm_next(sfp, SFP_S_INIT_PHY,
+++					    sfp->phy_t_retry);
+++				dev_dbg(sfp->dev,
+++					"no PHY detected, %u tries left\n",
+++					sfp->sm_phy_retries);
++ 				break;
++ 			} else {
++ 				dev_info(sfp->dev, "no PHY detected\n");
+diff --git a/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch b/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch
+new file mode 100644
+index 0000000000..6fd406742a
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-21-net-sfp-fix-PHY-discovery-for-FS-SFP-10G-T-module.patch
+@@ -0,0 +1,82 @@
++From e9301af385e7864dea353f5e58cad7339dd6c718 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Tue, 19 Dec 2023 17:24:15 +0100
++Subject: [PATCH] net: sfp: fix PHY discovery for FS SFP-10G-T module
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Commit 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code")
++changed the long wait before accessing RollBall / FS modules into
++probing for PHY every 1 second, and trying 25 times.
++
++Wei Lei reports that this does not work correctly on FS modules: when
++initializing, they may report values different from 0xffff in PHY ID
++registers for some MMDs, causing get_phy_c45_ids() to find some bogus
++MMD.
++
++Fix this by adding the module_t_wait member back, and setting it to 4
++seconds for FS modules.
++
++Fixes: 2f3ce7a56c6e ("net: sfp: rework the RollBall PHY waiting code")
++Reported-by: Wei Lei <quic_leiwei@quicinc.com>
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Tested-by: Lei Wei <quic_leiwei@quicinc.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -276,6 +276,7 @@ struct sfp {
++ 	struct sfp_eeprom_id id;
++ 	unsigned int module_power_mW;
++ 	unsigned int module_t_start_up;
+++	unsigned int module_t_wait;
++ 	unsigned int phy_t_retry;
++ 
++ 	unsigned int rate_kbd;
++@@ -390,6 +391,12 @@ static void sfp_fixup_fs_10gt(struct sfp
++ {
++ 	sfp_fixup_10gbaset_30m(sfp);
++ 	sfp_fixup_rollball(sfp);
+++
+++	/* The RollBall fixup is not enough for FS modules, the AQR chip inside
+++	 * them does not return 0xffff for PHY ID registers in all MMDs for the
+++	 * while initializing. They need a 4 second wait before accessing PHY.
+++	 */
+++	sfp->module_t_wait = msecs_to_jiffies(4000);
++ }
++ 
++ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
++@@ -2381,6 +2388,7 @@ static int sfp_sm_mod_probe(struct sfp *
++ 		mask |= SFP_F_RS1;
++ 
++ 	sfp->module_t_start_up = T_START_UP;
+++	sfp->module_t_wait = T_WAIT;
++ 	sfp->phy_t_retry = T_PHY_RETRY;
++ 
++ 	sfp->state_ignore_mask = 0;
++@@ -2618,9 +2626,10 @@ static void sfp_sm_main(struct sfp *sfp,
++ 
++ 		/* We need to check the TX_FAULT state, which is not defined
++ 		 * while TX_DISABLE is asserted. The earliest we want to do
++-		 * anything (such as probe for a PHY) is 50ms.
+++		 * anything (such as probe for a PHY) is 50ms (or more on
+++		 * specific modules).
++ 		 */
++-		sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
+++		sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
++ 		break;
++ 
++ 	case SFP_S_WAIT:
++@@ -2634,8 +2643,8 @@ static void sfp_sm_main(struct sfp *sfp,
++ 			 * deasserting.
++ 			 */
++ 			timeout = sfp->module_t_start_up;
++-			if (timeout > T_WAIT)
++-				timeout -= T_WAIT;
+++			if (timeout > sfp->module_t_wait)
+++				timeout -= sfp->module_t_wait;
++ 			else
++ 				timeout = 1;
++ 
+diff --git a/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch b/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch
+new file mode 100644
+index 0000000000..7d3210d341
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/706-22-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch
+@@ -0,0 +1,43 @@
++From 97eb5d51b4a584a60e5d096bdb6b33edc9f50d8d Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Mon, 15 Jan 2024 12:43:38 +0000
++Subject: [PATCH] net: sfp-bus: fix SFP mode detect from bitrate
++
++The referenced commit moved the setting of the Autoneg and pause bits
++early in sfp_parse_support(). However, we check whether the modes are
++empty before using the bitrate to set some modes. Setting these bits
++so early causes that test to always be false, preventing this working,
++and thus some modules that used to work no longer do.
++
++Move them just before the call to the quirk.
++
++Fixes: 8110633db49d ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits")
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Link: https://lore.kernel.org/r/E1rPMJW-001Ahf-L0@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/sfp-bus.c
+++++ b/drivers/net/phy/sfp-bus.c
++@@ -151,10 +151,6 @@ void sfp_parse_support(struct sfp_bus *b
++ 	unsigned int br_min, br_nom, br_max;
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
++ 
++-	phylink_set(modes, Autoneg);
++-	phylink_set(modes, Pause);
++-	phylink_set(modes, Asym_Pause);
++-
++ 	/* Decode the bitrate information to MBd */
++ 	br_min = br_nom = br_max = 0;
++ 	if (id->base.br_nominal) {
++@@ -329,6 +325,10 @@ void sfp_parse_support(struct sfp_bus *b
++ 		}
++ 	}
++ 
+++	phylink_set(modes, Autoneg);
+++	phylink_set(modes, Pause);
+++	phylink_set(modes, Asym_Pause);
+++
++ 	if (bus->sfp_quirk && bus->sfp_quirk->modes)
++ 		bus->sfp_quirk->modes(id, modes, interfaces);
++ 
+diff --git a/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch b/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch
+new file mode 100644
+index 0000000000..e00b1a406c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-01-net-phy-marvell10g-add-downshift-tunable-support.patch
+@@ -0,0 +1,212 @@
++From 4075a6a047bbb4c67a0670f4ad981cfc5ffb5c76 Mon Sep 17 00:00:00 2001
++From: Russell King <rmk+kernel@armlinux.org.uk>
++Date: Wed, 29 Sep 2021 16:28:53 +0100
++Subject: [PATCH] net: phy: marvell10g: add downshift tunable support
++
++Add support for the downshift tunable for the Marvell 88x3310 PHY.
++Downshift is only usable with firmware 0.3.5.0 and later.
++
++Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -22,6 +22,7 @@
++  * If both the fiber and copper ports are connected, the first to gain
++  * link takes priority and the other port is completely locked out.
++  */
+++#include <linux/bitfield.h>
++ #include <linux/ctype.h>
++ #include <linux/delay.h>
++ #include <linux/hwmon.h>
++@@ -33,6 +34,8 @@
++ #define MV_PHY_ALASKA_NBT_QUIRK_MASK	0xfffffffe
++ #define MV_PHY_ALASKA_NBT_QUIRK_REV	(MARVELL_PHY_ID_88X3310 | 0xa)
++ 
+++#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+++
++ enum {
++ 	MV_PMA_FW_VER0		= 0xc011,
++ 	MV_PMA_FW_VER1		= 0xc012,
++@@ -62,6 +65,15 @@ enum {
++ 	MV_PCS_CSCR1_MDIX_MDIX	= 0x0020,
++ 	MV_PCS_CSCR1_MDIX_AUTO	= 0x0060,
++ 
+++	MV_PCS_DSC1		= 0x8003,
+++	MV_PCS_DSC1_ENABLE	= BIT(9),
+++	MV_PCS_DSC1_10GBT	= 0x01c0,
+++	MV_PCS_DSC1_1GBR	= 0x0038,
+++	MV_PCS_DSC1_100BTX	= 0x0007,
+++	MV_PCS_DSC2		= 0x8004,
+++	MV_PCS_DSC2_2P5G	= 0xf000,
+++	MV_PCS_DSC2_5G		= 0x0f00,
+++
++ 	MV_PCS_CSSR1		= 0x8008,
++ 	MV_PCS_CSSR1_SPD1_MASK	= 0xc000,
++ 	MV_PCS_CSSR1_SPD1_SPD2	= 0xc000,
++@@ -130,6 +142,7 @@ enum {
++ };
++ 
++ struct mv3310_chip {
+++	bool (*has_downshift)(struct phy_device *phydev);
++ 	void (*init_supported_interfaces)(unsigned long *mask);
++ 	int (*get_mactype)(struct phy_device *phydev);
++ 	int (*set_mactype)(struct phy_device *phydev, int mactype);
++@@ -145,6 +158,7 @@ struct mv3310_priv {
++ 	DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
++ 
++ 	u32 firmware_ver;
+++	bool has_downshift;
++ 	bool rate_match;
++ 	phy_interface_t const_interface;
++ 
++@@ -344,6 +358,71 @@ static int mv3310_reset(struct phy_devic
++ 					 5000, 100000, true);
++ }
++ 
+++static int mv3310_get_downshift(struct phy_device *phydev, u8 *ds)
+++{
+++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+++	int val;
+++
+++	if (!priv->has_downshift)
+++		return -EOPNOTSUPP;
+++
+++	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1);
+++	if (val < 0)
+++		return val;
+++
+++	if (val & MV_PCS_DSC1_ENABLE)
+++		/* assume that all fields are the same */
+++		*ds = 1 + FIELD_GET(MV_PCS_DSC1_10GBT, (u16)val);
+++	else
+++		*ds = DOWNSHIFT_DEV_DISABLE;
+++
+++	return 0;
+++}
+++
+++static int mv3310_set_downshift(struct phy_device *phydev, u8 ds)
+++{
+++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+++	u16 val;
+++	int err;
+++
+++	if (!priv->has_downshift)
+++		return -EOPNOTSUPP;
+++
+++	if (ds == DOWNSHIFT_DEV_DISABLE)
+++		return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
+++					  MV_PCS_DSC1_ENABLE);
+++
+++	/* DOWNSHIFT_DEV_DEFAULT_COUNT is confusing. It looks like it should
+++	 * set the default settings for the PHY. However, it is used for
+++	 * "ethtool --set-phy-tunable ethN downshift on". The intention is
+++	 * to enable downshift at a default number of retries. The default
+++	 * settings for 88x3310 are for two retries with downshift disabled.
+++	 * So let's use two retries with downshift enabled.
+++	 */
+++	if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT)
+++		ds = 2;
+++
+++	if (ds > 8)
+++		return -E2BIG;
+++
+++	ds -= 1;
+++	val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds);
+++	val |= FIELD_PREP(MV_PCS_DSC2_5G, ds);
+++	err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2,
+++			     MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val);
+++	if (err < 0)
+++		return err;
+++
+++	val = MV_PCS_DSC1_ENABLE;
+++	val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds);
+++	val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds);
+++	val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds);
+++
+++	return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
+++			      MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT |
+++			      MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val);
+++}
+++
++ static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd)
++ {
++ 	int val;
++@@ -463,6 +542,9 @@ static int mv3310_probe(struct phy_devic
++ 		    priv->firmware_ver >> 24, (priv->firmware_ver >> 16) & 255,
++ 		    (priv->firmware_ver >> 8) & 255, priv->firmware_ver & 255);
++ 
+++	if (chip->has_downshift)
+++		priv->has_downshift = chip->has_downshift(phydev);
+++
++ 	/* Powering down the port when not in use saves about 600mW */
++ 	ret = mv3310_power_down(phydev);
++ 	if (ret)
++@@ -728,7 +810,16 @@ static int mv3310_config_init(struct phy
++ 	}
++ 
++ 	/* Enable EDPD mode - saving 600mW */
++-	return mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
+++	err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
+++	if (err)
+++		return err;
+++
+++	/* Allow downshift */
+++	err = mv3310_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT);
+++	if (err && err != -EOPNOTSUPP)
+++		return err;
+++
+++	return 0;
++ }
++ 
++ static int mv3310_get_features(struct phy_device *phydev)
++@@ -998,6 +1089,8 @@ static int mv3310_get_tunable(struct phy
++ 			      struct ethtool_tunable *tuna, void *data)
++ {
++ 	switch (tuna->id) {
+++	case ETHTOOL_PHY_DOWNSHIFT:
+++		return mv3310_get_downshift(phydev, data);
++ 	case ETHTOOL_PHY_EDPD:
++ 		return mv3310_get_edpd(phydev, data);
++ 	default:
++@@ -1009,6 +1102,8 @@ static int mv3310_set_tunable(struct phy
++ 			      struct ethtool_tunable *tuna, const void *data)
++ {
++ 	switch (tuna->id) {
+++	case ETHTOOL_PHY_DOWNSHIFT:
+++		return mv3310_set_downshift(phydev, *(u8 *)data);
++ 	case ETHTOOL_PHY_EDPD:
++ 		return mv3310_set_edpd(phydev, *(u16 *)data);
++ 	default:
++@@ -1016,6 +1111,14 @@ static int mv3310_set_tunable(struct phy
++ 	}
++ }
++ 
+++static bool mv3310_has_downshift(struct phy_device *phydev)
+++{
+++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+++
+++	/* Fails to downshift with firmware older than v0.3.5.0 */
+++	return priv->firmware_ver >= MV_VERSION(0,3,5,0);
+++}
+++
++ static void mv3310_init_supported_interfaces(unsigned long *mask)
++ {
++ 	__set_bit(PHY_INTERFACE_MODE_SGMII, mask);
++@@ -1055,6 +1158,7 @@ static void mv2111_init_supported_interf
++ }
++ 
++ static const struct mv3310_chip mv3310_type = {
+++	.has_downshift = mv3310_has_downshift,
++ 	.init_supported_interfaces = mv3310_init_supported_interfaces,
++ 	.get_mactype = mv3310_get_mactype,
++ 	.set_mactype = mv3310_set_mactype,
++@@ -1067,6 +1171,7 @@ static const struct mv3310_chip mv3310_t
++ };
++ 
++ static const struct mv3310_chip mv3340_type = {
+++	.has_downshift = mv3310_has_downshift,
++ 	.init_supported_interfaces = mv3340_init_supported_interfaces,
++ 	.get_mactype = mv3310_get_mactype,
++ 	.set_mactype = mv3310_set_mactype,
+diff --git a/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch b/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch
+new file mode 100644
+index 0000000000..77a47a9930
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-02-net-phylink-use-for_each_set_bit.patch
+@@ -0,0 +1,43 @@
++From 335662889f5a5f4d5668ed6c8b5fd58913d91d15 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Sun, 19 Nov 2023 21:07:43 +0000
++Subject: [PATCH] net: phylink: use for_each_set_bit()
++
++Use for_each_set_bit() rather than open coding the for() test_bit()
++loop.
++
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
++Link: https://lore.kernel.org/r/E1r4p15-00Cpxe-C7@rmk-PC.armlinux.org.uk
++Signed-off-by: Paolo Abeni <pabeni@redhat.com>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -493,18 +493,16 @@ static int phylink_validate_mask(struct
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(s);
++ 	struct phylink_link_state t;
++-	int intf;
+++	int interface;
++ 
++-	for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
++-		if (test_bit(intf, interfaces)) {
++-			linkmode_copy(s, supported);
+++	for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) {
+++		linkmode_copy(s, supported);
++ 
++-			t = *state;
++-			t.interface = intf;
++-			if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
++-				linkmode_or(all_s, all_s, s);
++-				linkmode_or(all_adv, all_adv, t.advertising);
++-			}
+++		t = *state;
+++		t.interface = interface;
+++		if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
+++			linkmode_or(all_s, all_s, s);
+++			linkmode_or(all_adv, all_adv, t.advertising);
++ 		}
++ 	}
++ 
+diff --git a/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch b/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch
+new file mode 100644
+index 0000000000..4e8cf853b4
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-03-net-phylink-Support-disabling-autonegotiation-for-PC.patch
+@@ -0,0 +1,79 @@
++From 92817dad7dcb781561dcebbf1b19a177774d84c2 Mon Sep 17 00:00:00 2001
++From: Robert Hancock <robert.hancock@calian.com>
++Date: Tue, 19 Oct 2021 11:24:50 +0100
++Subject: [PATCH] net: phylink: Support disabling autonegotiation for PCS
++
++The auto-negotiation state in the PCS as set by
++phylink_mii_c22_pcs_config was previously always enabled when the
++driver is configured for in-band autonegotiation, even if
++autonegotiation was disabled on the interface with ethtool. Update the
++code to set the BMCR_ANENABLE bit based on the interface's
++autonegotiation enabled state.
++
++Update phylink_mii_c22_pcs_get_state to not check
++autonegotiation-related fields when autonegotiation is disabled.
++
++Update phylink_mac_pcs_get_state to initialize the state based on the
++interface's configured speed, duplex and pause parameters rather than
++to unknown when autonegotiation is disabled, before calling the
++driver's pcs_get_state functions, as they are not likely to provide
++meaningful data for these fields when autonegotiation is disabled. In
++this case the driver is really just filling in the link state field.
++
++Note that in cases where there is a downstream PHY connected, such as
++with SGMII and a copper PHY, the configuration set by ethtool is
++handled by phy_ethtool_ksettings_set and not propagated to the PCS.
++This is correct since SGMII or 1000Base-X autonegotiation with the PCS
++should normally still be used even if the copper side has disabled it.
++
++Signed-off-by: Robert Hancock <robert.hancock@calian.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -930,9 +930,15 @@ static void phylink_mac_pcs_get_state(st
++ 	linkmode_zero(state->lp_advertising);
++ 	state->interface = pl->link_config.interface;
++ 	state->an_enabled = pl->link_config.an_enabled;
++-	state->speed = SPEED_UNKNOWN;
++-	state->duplex = DUPLEX_UNKNOWN;
++-	state->pause = MLO_PAUSE_NONE;
+++	if  (state->an_enabled) {
+++		state->speed = SPEED_UNKNOWN;
+++		state->duplex = DUPLEX_UNKNOWN;
+++		state->pause = MLO_PAUSE_NONE;
+++	} else {
+++		state->speed =  pl->link_config.speed;
+++		state->duplex = pl->link_config.duplex;
+++		state->pause = pl->link_config.pause;
+++	}
++ 	state->an_complete = 0;
++ 	state->link = 1;
++ 
++@@ -3091,7 +3097,10 @@ void phylink_mii_c22_pcs_get_state(struc
++ 
++ 	state->link = !!(bmsr & BMSR_LSTATUS);
++ 	state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
++-	if (!state->link)
+++	/* If there is no link or autonegotiation is disabled, the LP advertisement
+++	 * data is not meaningful, so don't go any further.
+++	 */
+++	if (!state->link || !state->an_enabled)
++ 		return;
++ 
++ 	switch (state->interface) {
++@@ -3214,7 +3223,12 @@ int phylink_mii_c22_pcs_config(struct md
++ 	changed = ret > 0;
++ 
++ 	/* Ensure ISOLATE bit is disabled */
++-	bmcr = mode == MLO_AN_INBAND ? BMCR_ANENABLE : 0;
+++	if (mode == MLO_AN_INBAND &&
+++	    linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising))
+++		bmcr = BMCR_ANENABLE;
+++	else
+++		bmcr = 0;
+++
++ 	ret = mdiobus_modify(pcs->bus, pcs->addr, MII_BMCR,
++ 			     BMCR_ANENABLE | BMCR_ISOLATE, bmcr);
++ 	if (ret < 0)
+diff --git a/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch b/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch
+new file mode 100644
+index 0000000000..cfccdb4636
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-04-net-phy-Introduce-QUSGMII-PHY-mode.patch
+@@ -0,0 +1,117 @@
++From 5e61fe157a27afc7c0d4f7bcbceefdca536c015f Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Wed, 17 Aug 2022 14:32:52 +0200
++Subject: [PATCH] net: phy: Introduce QUSGMII PHY mode
++
++The QUSGMII mode is a derivative of Cisco's USXGMII standard. This
++standard is pretty similar to SGMII, but allows for faster speeds, and
++has the build-in bits for Quad and Octa variants (like QSGMII).
++
++The main difference with SGMII/QSGMII is that USXGMII/QUSGMII re-uses
++the preamble to carry various information, named 'Extensions'.
++
++As of today, the USXGMII standard only mentions the "PCH" extension,
++which is used to convey timestamps, allowing in-band signaling of PTP
++timestamps without having to modify the frame itself.
++
++This commit adds support for that mode. When no extension is in use, it
++behaves exactly like QSGMII, although it's not compatible with QSGMII.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From 5e61fe157a27afc7c0d4f7bcbceefdca536c015f Mon Sep 17 00:00:00 2001
++From: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Date: Wed, 17 Aug 2022 14:32:52 +0200
++Subject: [PATCH] net: phy: Introduce QUSGMII PHY mode
++
++The QUSGMII mode is a derivative of Cisco's USXGMII standard. This
++standard is pretty similar to SGMII, but allows for faster speeds, and
++has the build-in bits for Quad and Octa variants (like QSGMII).
++
++The main difference with SGMII/QSGMII is that USXGMII/QUSGMII re-uses
++the preamble to carry various information, named 'Extensions'.
++
++As of today, the USXGMII standard only mentions the "PCH" extension,
++which is used to convey timestamps, allowing in-band signaling of PTP
++timestamps without having to modify the frame itself.
++
++This commit adds support for that mode. When no extension is in use, it
++behaves exactly like QSGMII, although it's not compatible with QSGMII.
++
++Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/Documentation/networking/phy.rst
+++++ b/Documentation/networking/phy.rst
++@@ -303,6 +303,15 @@ Some of the interface modes are describe
++     rate of 125Mpbs using a 4B/5B encoding scheme, resulting in an underlying
++     data rate of 100Mpbs.
++ 
+++``PHY_INTERFACE_MODE_QUSGMII``
+++    This defines the Cisco the Quad USGMII mode, which is the Quad variant of
+++    the USGMII (Universal SGMII) link. It's very similar to QSGMII, but uses
+++    a Packet Control Header (PCH) instead of the 7 bytes preamble to carry not
+++    only the port id, but also so-called "extensions". The only documented
+++    extension so-far in the specification is the inclusion of timestamps, for
+++    PTP-enabled PHYs. This mode isn't compatible with QSGMII, but offers the
+++    same capabilities in terms of link speed and negociation.
+++
++ Pause frames / flow control
++ ===========================
++ 
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -396,6 +396,7 @@ void phylink_get_linkmodes(unsigned long
++ 	case PHY_INTERFACE_MODE_RGMII_ID:
++ 	case PHY_INTERFACE_MODE_RGMII:
++ 	case PHY_INTERFACE_MODE_QSGMII:
+++	case PHY_INTERFACE_MODE_QUSGMII:
++ 	case PHY_INTERFACE_MODE_SGMII:
++ 	case PHY_INTERFACE_MODE_GMII:
++ 		caps |= MAC_1000HD | MAC_1000FD;
++@@ -660,6 +661,7 @@ static int phylink_parse_mode(struct phy
++ 		switch (pl->link_config.interface) {
++ 		case PHY_INTERFACE_MODE_SGMII:
++ 		case PHY_INTERFACE_MODE_QSGMII:
+++		case PHY_INTERFACE_MODE_QUSGMII:
++ 			phylink_set(pl->supported, 10baseT_Half);
++ 			phylink_set(pl->supported, 10baseT_Full);
++ 			phylink_set(pl->supported, 100baseT_Half);
++@@ -3114,6 +3116,7 @@ void phylink_mii_c22_pcs_get_state(struc
++ 
++ 	case PHY_INTERFACE_MODE_SGMII:
++ 	case PHY_INTERFACE_MODE_QSGMII:
+++	case PHY_INTERFACE_MODE_QUSGMII:
++ 		phylink_decode_sgmii_word(state, lpa);
++ 		break;
++ 
++--- a/include/linux/phy.h
+++++ b/include/linux/phy.h
++@@ -115,6 +115,7 @@ extern const int phy_10gbit_features_arr
++  * @PHY_INTERFACE_MODE_25GBASER: 25G BaseR
++  * @PHY_INTERFACE_MODE_USXGMII:  Universal Serial 10GE MII
++  * @PHY_INTERFACE_MODE_10GKR: 10GBASE-KR - with Clause 73 AN
+++ * @PHY_INTERFACE_MODE_QUSGMII: Quad Universal SGMII
++  * @PHY_INTERFACE_MODE_MAX: Book keeping
++  *
++  * Describes the interface between the MAC and PHY.
++@@ -152,6 +153,7 @@ typedef enum {
++ 	PHY_INTERFACE_MODE_USXGMII,
++ 	/* 10GBASE-KR - with Clause 73 AN */
++ 	PHY_INTERFACE_MODE_10GKR,
+++	PHY_INTERFACE_MODE_QUSGMII,
++ 	PHY_INTERFACE_MODE_MAX,
++ } phy_interface_t;
++ 
++@@ -267,6 +269,8 @@ static inline const char *phy_modes(phy_
++ 		return "10gbase-kr";
++ 	case PHY_INTERFACE_MODE_100BASEX:
++ 		return "100base-x";
+++	case PHY_INTERFACE_MODE_QUSGMII:
+++		return "qusgmii";
++ 	default:
++ 		return "unknown";
++ 	}
+diff --git a/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch b/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch
+new file mode 100644
+index 0000000000..69b824a4a6
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-05-net-phy-Add-1000BASE-KX-interface-mode.patch
+@@ -0,0 +1,80 @@
++From 05ad5d4581c3c1cc724fe50d4652833fb9f3037b Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Fri, 2 Sep 2022 18:02:39 -0400
++Subject: [PATCH] net: phy: Add 1000BASE-KX interface mode
++
++Add 1000BASE-KX interface mode. This 1G backplane ethernet as described in
++clause 70. Clause 73 autonegotiation is mandatory, and only full duplex
++operation is supported.
++
++Although at the PMA level this interface mode is identical to
++1000BASE-X, it uses a different form of in-band autonegation. This
++justifies a separate interface mode, since the interface mode (along
++with the MLO_AN_* autonegotiation mode) sets the type of autonegotiation
++which will be used on a link. This results in more than just electrical
++differences between the link modes.
++
++With regard to 1000BASE-X, 1000BASE-KX holds a similar position to
++SGMII: same signaling, but different autonegotiation. PCS drivers
++(which typically handle in-band autonegotiation) may only support
++1000BASE-X, and not 1000BASE-KX. Similarly, the phy mode is used to
++configure serdes phys with phy_set_mode_ext. Due to the different
++electrical standards (SFI or XFI vs Clause 70), they will likely want to
++use different configuration. Adding a phy interface mode for
++1000BASE-KX helps simplify configuration in these areas.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/Documentation/networking/phy.rst
+++++ b/Documentation/networking/phy.rst
++@@ -312,6 +312,12 @@ Some of the interface modes are describe
++     PTP-enabled PHYs. This mode isn't compatible with QSGMII, but offers the
++     same capabilities in terms of link speed and negociation.
++ 
+++``PHY_INTERFACE_MODE_1000BASEKX``
+++    This is 1000BASE-X as defined by IEEE 802.3 Clause 36 with Clause 73
+++    autonegotiation. Generally, it will be used with a Clause 70 PMD. To
+++    contrast with the 1000BASE-X phy mode used for Clause 38 and 39 PMDs, this
+++    interface mode has different autonegotiation and only supports full duplex.
+++
++ Pause frames / flow control
++ ===========================
++ 
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -419,6 +419,7 @@ void phylink_get_linkmodes(unsigned long
++ 	case PHY_INTERFACE_MODE_1000BASEX:
++ 		caps |= MAC_1000HD;
++ 		fallthrough;
+++	case PHY_INTERFACE_MODE_1000BASEKX:
++ 	case PHY_INTERFACE_MODE_TRGMII:
++ 		caps |= MAC_1000FD;
++ 		break;
++--- a/include/linux/phy.h
+++++ b/include/linux/phy.h
++@@ -116,6 +116,7 @@ extern const int phy_10gbit_features_arr
++  * @PHY_INTERFACE_MODE_USXGMII:  Universal Serial 10GE MII
++  * @PHY_INTERFACE_MODE_10GKR: 10GBASE-KR - with Clause 73 AN
++  * @PHY_INTERFACE_MODE_QUSGMII: Quad Universal SGMII
+++ * @PHY_INTERFACE_MODE_1000BASEKX: 1000Base-KX - with Clause 73 AN
++  * @PHY_INTERFACE_MODE_MAX: Book keeping
++  *
++  * Describes the interface between the MAC and PHY.
++@@ -154,6 +155,7 @@ typedef enum {
++ 	/* 10GBASE-KR - with Clause 73 AN */
++ 	PHY_INTERFACE_MODE_10GKR,
++ 	PHY_INTERFACE_MODE_QUSGMII,
+++	PHY_INTERFACE_MODE_1000BASEKX,
++ 	PHY_INTERFACE_MODE_MAX,
++ } phy_interface_t;
++ 
++@@ -251,6 +253,8 @@ static inline const char *phy_modes(phy_
++ 		return "trgmii";
++ 	case PHY_INTERFACE_MODE_1000BASEX:
++ 		return "1000base-x";
+++	case PHY_INTERFACE_MODE_1000BASEKX:
+++		return "1000base-kx";
++ 	case PHY_INTERFACE_MODE_2500BASEX:
++ 		return "2500base-x";
++ 	case PHY_INTERFACE_MODE_5GBASER:
+diff --git a/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch b/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch
+new file mode 100644
+index 0000000000..7fa798f2bc
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-1-net-phylink-Document-MAC_-A-SYM_PAUSE.patch
+@@ -0,0 +1,66 @@
++From 72bc36956f73ac54f19a7ac7302fb274069bec18 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:28 -0400
++Subject: [PATCH] net: phylink: Document MAC_(A)SYM_PAUSE
++
++This documents the possible MLO_PAUSE_* settings which can result from
++different combinations of MAC_(A)SYM_PAUSE. Special note is paid to
++settings which can result from user configuration (MLO_PAUSE_AN). The
++autonegotiation results are more-or-less a direct consequence of IEEE
++802.3 Table 28B-2.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From 72bc36956f73ac54f19a7ac7302fb274069bec18 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:28 -0400
++Subject: [PATCH] net: phylink: Document MAC_(A)SYM_PAUSE
++
++This documents the possible MLO_PAUSE_* settings which can result from
++different combinations of MAC_(A)SYM_PAUSE. Special note is paid to
++settings which can result from user configuration (MLO_PAUSE_AN). The
++autonegotiation results are more-or-less a direct consequence of IEEE
++802.3 Table 28B-2.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/include/linux/phylink.h
+++++ b/include/linux/phylink.h
++@@ -21,6 +21,35 @@ enum {
++ 	MLO_AN_FIXED,	/* Fixed-link mode */
++ 	MLO_AN_INBAND,	/* In-band protocol */
++ 
+++	/* MAC_SYM_PAUSE and MAC_ASYM_PAUSE are used when configuring our
+++	 * autonegotiation advertisement. They correspond to the PAUSE and
+++	 * ASM_DIR bits defined by 802.3, respectively.
+++	 *
+++	 * The following table lists the values of tx_pause and rx_pause which
+++	 * might be requested in mac_link_up. The exact values depend on either
+++	 * the results of autonegotation (if MLO_PAUSE_AN is set) or user
+++	 * configuration (if MLO_PAUSE_AN is not set).
+++	 *
+++	 * MAC_SYM_PAUSE MAC_ASYM_PAUSE MLO_PAUSE_AN tx_pause/rx_pause
+++	 * ============= ============== ============ ==================
+++	 *             0              0            0 0/0
+++	 *             0              0            1 0/0
+++	 *             0              1            0 0/0, 0/1, 1/0, 1/1
+++	 *             0              1            1 0/0,      1/0
+++	 *             1              0            0 0/0,           1/1
+++	 *             1              0            1 0/0,           1/1
+++	 *             1              1            0 0/0, 0/1, 1/0, 1/1
+++	 *             1              1            1 0/0, 0/1,      1/1
+++	 *
+++	 * If you set MAC_ASYM_PAUSE, the user may request any combination of
+++	 * tx_pause and rx_pause. You do not have to support these
+++	 * combinations.
+++	 *
+++	 * However, you should support combinations of tx_pause and rx_pause
+++	 * which might be the result of autonegotation. For example, don't set
+++	 * MAC_SYM_PAUSE unless your device can support tx_pause and rx_pause
+++	 * at the same time.
+++	 */
++ 	MAC_SYM_PAUSE	= BIT(0),
++ 	MAC_ASYM_PAUSE	= BIT(1),
++ 	MAC_10HD	= BIT(2),
+diff --git a/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch b/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch
+new file mode 100644
+index 0000000000..5a34f22b34
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-2-net-phylink-Export-phylink_caps_to_linkmodes.patch
+@@ -0,0 +1,62 @@
++From 606116529ab2d12e93bf751f74ed50a621b46846 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:29 -0400
++Subject: [PATCH] net: phylink: Export phylink_caps_to_linkmodes
++
++This function is convenient for MAC drivers. They can use it to add or
++remove particular link modes based on capabilities (such as if half
++duplex is not supported for a particular interface mode).
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From 606116529ab2d12e93bf751f74ed50a621b46846 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:29 -0400
++Subject: [PATCH] net: phylink: Export phylink_caps_to_linkmodes
++
++This function is convenient for MAC drivers. They can use it to add or
++remove particular link modes based on capabilities (such as if half
++duplex is not supported for a particular interface mode).
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -233,8 +233,15 @@ static int phylink_validate_mac_and_pcs(
++ 	return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
++ }
++ 
++-static void phylink_caps_to_linkmodes(unsigned long *linkmodes,
++-				      unsigned long caps)
+++/**
+++ * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes
+++ * @linkmodes: ethtool linkmode mask (must be already initialised)
+++ * @caps: bitmask of MAC capabilities
+++ *
+++ * Set all possible pause, speed and duplex linkmodes in @linkmodes that are
+++ * supported by the @caps. @linkmodes must have been initialised previously.
+++ */
+++void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps)
++ {
++ 	if (caps & MAC_SYM_PAUSE)
++ 		__set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes);
++@@ -370,6 +377,7 @@ static void phylink_caps_to_linkmodes(un
++ 		__set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes);
++ 	}
++ }
+++EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes);
++ 
++ /**
++  * phylink_get_linkmodes() - get acceptable link modes
++--- a/include/linux/phylink.h
+++++ b/include/linux/phylink.h
++@@ -556,6 +556,7 @@ void pcs_link_up(struct phylink_pcs *pcs
++ 		 phy_interface_t interface, int speed, int duplex);
++ #endif
++ 
+++void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps);
++ void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
++ 			   unsigned long mac_capabilities);
++ void phylink_generic_validate(struct phylink_config *config,
+diff --git a/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch b/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch
+new file mode 100644
+index 0000000000..d453e5da3d
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-3-net-phylink-Generate-caps-and-convert-to-linkmodes-s.patch
+@@ -0,0 +1,113 @@
++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:30 -0400
++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes
++ separately
++
++If we call phylink_caps_to_linkmodes directly from
++phylink_get_linkmodes, it is difficult to re-use this functionality in
++MAC drivers. This is because MAC drivers must then work with an ethtool
++linkmode bitmap, instead of with mac capabilities. Instead, let the
++caller of phylink_get_linkmodes do the conversion. To reflect this
++change, rename the function to phylink_get_capabilities.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:30 -0400
++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes
++ separately
++
++If we call phylink_caps_to_linkmodes directly from
++phylink_get_linkmodes, it is difficult to re-use this functionality in
++MAC drivers. This is because MAC drivers must then work with an ethtool
++linkmode bitmap, instead of with mac capabilities. Instead, let the
++caller of phylink_get_linkmodes do the conversion. To reflect this
++change, rename the function to phylink_get_capabilities.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From 3e6eab8f3ef93cd78cd4b67f497ef6035eb073ad Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:30 -0400
++Subject: [PATCH] net: phylink: Generate caps and convert to linkmodes
++ separately
++
++If we call phylink_caps_to_linkmodes directly from
++phylink_get_linkmodes, it is difficult to re-use this functionality in
++MAC drivers. This is because MAC drivers must then work with an ethtool
++linkmode bitmap, instead of with mac capabilities. Instead, let the
++caller of phylink_get_linkmodes do the conversion. To reflect this
++change, rename the function to phylink_get_capabilities.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -380,17 +380,15 @@ void phylink_caps_to_linkmodes(unsigned
++ EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes);
++ 
++ /**
++- * phylink_get_linkmodes() - get acceptable link modes
++- * @linkmodes: ethtool linkmode mask (must be already initialised)
+++ * phylink_get_capabilities() - get capabilities for a given MAC
++  * @interface: phy interface mode defined by &typedef phy_interface_t
++  * @mac_capabilities: bitmask of MAC capabilities
++  *
++- * Set all possible pause, speed and duplex linkmodes in @linkmodes that
++- * are supported by the @interface mode and @mac_capabilities. @linkmodes
++- * must have been initialised previously.
+++ * Get the MAC capabilities that are supported by the @interface mode and
+++ * @mac_capabilities.
++  */
++-void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
++-			   unsigned long mac_capabilities)
+++unsigned long phylink_get_capabilities(phy_interface_t interface,
+++				       unsigned long mac_capabilities)
++ {
++ 	unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
++ 
++@@ -466,9 +464,9 @@ void phylink_get_linkmodes(unsigned long
++ 		break;
++ 	}
++ 
++-	phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities);
+++	return caps & mac_capabilities;
++ }
++-EXPORT_SYMBOL_GPL(phylink_get_linkmodes);
+++EXPORT_SYMBOL_GPL(phylink_get_capabilities);
++ 
++ /**
++  * phylink_generic_validate() - generic validate() callback implementation
++@@ -485,10 +483,13 @@ void phylink_generic_validate(struct phy
++ 			      struct phylink_link_state *state)
++ {
++ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+++	unsigned long caps;
++ 
++ 	phylink_set_port_modes(mask);
++ 	phylink_set(mask, Autoneg);
++-	phylink_get_linkmodes(mask, state->interface, config->mac_capabilities);
+++	caps = phylink_get_capabilities(state->interface,
+++					config->mac_capabilities);
+++	phylink_caps_to_linkmodes(mask, caps);
++ 
++ 	linkmode_and(supported, supported, mask);
++ 	linkmode_and(state->advertising, state->advertising, mask);
++--- a/include/linux/phylink.h
+++++ b/include/linux/phylink.h
++@@ -557,8 +557,8 @@ void pcs_link_up(struct phylink_pcs *pcs
++ #endif
++ 
++ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps);
++-void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
++-			   unsigned long mac_capabilities);
+++unsigned long phylink_get_capabilities(phy_interface_t interface,
+++				       unsigned long mac_capabilities);
++ void phylink_generic_validate(struct phylink_config *config,
++ 			      unsigned long *supported,
++ 			      struct phylink_link_state *state);
+diff --git a/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch b/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch
+new file mode 100644
+index 0000000000..902431a69c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-4-net-phy-Add-support-for-rate-matching.patch
+@@ -0,0 +1,284 @@
++From 0c3e10cb44232833a50cb8e3e784c432906a60c1 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:31 -0400
++Subject: [PATCH] net: phy: Add support for rate matching
++
++This adds support for rate matching (also known as rate adaptation) to
++the phy subsystem. The general idea is that the phy interface runs at
++one speed, and the MAC throttles the rate at which it sends packets to
++the link speed. There's a good overview of several techniques for
++achieving this at [1]. This patch adds support for three: pause-frame
++based (such as in Aquantia phys), CRS-based (such as in 10PASS-TS and
++2BASE-TL), and open-loop-based (such as in 10GBASE-W).
++
++This patch makes a few assumptions and a few non assumptions about the
++types of rate matching available. First, it assumes that different phys
++may use different forms of rate matching. Second, it assumes that phys
++can use rate matching for any of their supported link speeds (e.g. if a
++phy supports 10BASE-T and XGMII, then it can adapt XGMII to 10BASE-T).
++Third, it does not assume that all interface modes will use the same
++form of rate matching. Fourth, it does not assume that all phy devices
++will support rate matching (even if some do). Relaxing or strengthening
++these (non-)assumptions could result in a different API. For example, if
++all interface modes were assumed to use the same form of rate matching,
++then a bitmask of interface modes supportting rate matching would
++suffice.
++
++For some better visibility into the process, the current rate matching
++mode is exposed as part of the ethtool ksettings. For the moment, only
++read access is supported. I'm not sure what userspace might want to
++configure yet (disable it altogether, disable just one mode, specify the
++mode to use, etc.). For the moment, since only pause-based rate
++adaptation support is added in the next few commits, rate matching can
++be disabled altogether by adjusting the advertisement.
++
++802.3 calls this feature "rate adaptation" in clause 49 (10GBASE-R) and
++"rate matching" in clause 61 (10PASS-TL and 2BASE-TS). Aquantia also calls
++this feature "rate adaptation". I chose "rate matching" because it is
++shorter, and because Russell doesn't think "adaptation" is correct in this
++context.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/Documentation/networking/ethtool-netlink.rst
+++++ b/Documentation/networking/ethtool-netlink.rst
++@@ -418,6 +418,7 @@ Kernel response contents:
++   ``ETHTOOL_A_LINKMODES_DUPLEX``              u8      duplex mode
++   ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG``    u8      Master/slave port mode
++   ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE``  u8      Master/slave port state
+++  ``ETHTOOL_A_LINKMODES_RATE_MATCHING``       u8      PHY rate matching
++   ==========================================  ======  ==========================
++ 
++ For ``ETHTOOL_A_LINKMODES_OURS``, value represents advertised modes and mask
++@@ -441,6 +442,7 @@ Request contents:
++   ``ETHTOOL_A_LINKMODES_SPEED``               u32     link speed (Mb/s)
++   ``ETHTOOL_A_LINKMODES_DUPLEX``              u8      duplex mode
++   ``ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG``    u8      Master/slave port mode
+++  ``ETHTOOL_A_LINKMODES_RATE_MATCHING``       u8      PHY rate matching
++   ``ETHTOOL_A_LINKMODES_LANES``               u32     lanes
++   ==========================================  ======  ==========================
++ 
++--- a/drivers/net/phy/phy-core.c
+++++ b/drivers/net/phy/phy-core.c
++@@ -58,6 +58,27 @@ const char *phy_speed_to_str(int speed)
++ EXPORT_SYMBOL_GPL(phy_speed_to_str);
++ 
++ /**
+++ * phy_rate_matching_to_str - Return a string describing the rate matching
+++ *
+++ * @rate_matching: Type of rate matching to describe
+++ */
+++const char *phy_rate_matching_to_str(int rate_matching)
+++{
+++	switch (rate_matching) {
+++	case RATE_MATCH_NONE:
+++		return "none";
+++	case RATE_MATCH_PAUSE:
+++		return "pause";
+++	case RATE_MATCH_CRS:
+++		return "crs";
+++	case RATE_MATCH_OPEN_LOOP:
+++		return "open-loop";
+++	}
+++	return "Unsupported (update phy-core.c)";
+++}
+++EXPORT_SYMBOL_GPL(phy_rate_matching_to_str);
+++
+++/**
++  * phy_duplex_to_str - Return string describing the duplex
++  *
++  * @duplex: Duplex setting to describe
++--- a/drivers/net/phy/phy.c
+++++ b/drivers/net/phy/phy.c
++@@ -127,6 +127,33 @@ void phy_print_status(struct phy_device
++ EXPORT_SYMBOL(phy_print_status);
++ 
++ /**
+++ * phy_get_rate_matching - determine if rate matching is supported
+++ * @phydev: The phy device to return rate matching for
+++ * @iface: The interface mode to use
+++ *
+++ * This determines the type of rate matching (if any) that @phy supports
+++ * using @iface. @iface may be %PHY_INTERFACE_MODE_NA to determine if any
+++ * interface supports rate matching.
+++ *
+++ * Return: The type of rate matching @phy supports for @iface, or
+++ *         %RATE_MATCH_NONE.
+++ */
+++int phy_get_rate_matching(struct phy_device *phydev,
+++			  phy_interface_t iface)
+++{
+++	int ret = RATE_MATCH_NONE;
+++
+++	if (phydev->drv->get_rate_matching) {
+++		mutex_lock(&phydev->lock);
+++		ret = phydev->drv->get_rate_matching(phydev, iface);
+++		mutex_unlock(&phydev->lock);
+++	}
+++
+++	return ret;
+++}
+++EXPORT_SYMBOL_GPL(phy_get_rate_matching);
+++
+++/**
++  * phy_config_interrupt - configure the PHY device for the requested interrupts
++  * @phydev: the phy_device struct
++  * @interrupts: interrupt flags to configure for this @phydev
++@@ -268,6 +295,7 @@ void phy_ethtool_ksettings_get(struct ph
++ 	cmd->base.duplex = phydev->duplex;
++ 	cmd->base.master_slave_cfg = phydev->master_slave_get;
++ 	cmd->base.master_slave_state = phydev->master_slave_state;
+++	cmd->base.rate_matching = phydev->rate_matching;
++ 	if (phydev->interface == PHY_INTERFACE_MODE_MOCA)
++ 		cmd->base.port = PORT_BNC;
++ 	else
++--- a/include/linux/phy.h
+++++ b/include/linux/phy.h
++@@ -280,7 +280,6 @@ static inline const char *phy_modes(phy_
++ 	}
++ }
++ 
++-
++ #define PHY_INIT_TIMEOUT	100000
++ #define PHY_FORCE_TIMEOUT	10
++ 
++@@ -574,6 +573,7 @@ struct macsec_ops;
++  * @host_interfaces: PHY interface modes supported by host
++  * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
++  * @autoneg: Flag autoneg being used
+++ * @rate_matching: Current rate matching mode
++  * @link: Current link state
++  * @autoneg_complete: Flag auto negotiation of the link has completed
++  * @mdix: Current crossover
++@@ -640,6 +640,8 @@ struct phy_device {
++ 	unsigned irq_suspended:1;
++ 	unsigned irq_rerun:1;
++ 
+++	int rate_matching;
+++
++ 	enum phy_state state;
++ 
++ 	u32 dev_flags;
++@@ -805,6 +807,21 @@ struct phy_driver {
++ 	 */
++ 	int (*get_features)(struct phy_device *phydev);
++ 
+++	/**
+++	 * @get_rate_matching: Get the supported type of rate matching for a
+++	 * particular phy interface. This is used by phy consumers to determine
+++	 * whether to advertise lower-speed modes for that interface. It is
+++	 * assumed that if a rate matching mode is supported on an interface,
+++	 * then that interface's rate can be adapted to all slower link speeds
+++	 * supported by the phy. If iface is %PHY_INTERFACE_MODE_NA, and the phy
+++	 * supports any kind of rate matching for any interface, then it must
+++	 * return that rate matching mode (preferring %RATE_MATCH_PAUSE to
+++	 * %RATE_MATCH_CRS). If the interface is not supported, this should
+++	 * return %RATE_MATCH_NONE.
+++	 */
+++	int (*get_rate_matching)(struct phy_device *phydev,
+++				   phy_interface_t iface);
+++
++ 	/* PHY Power Management */
++ 	/** @suspend: Suspend the hardware, saving state if needed */
++ 	int (*suspend)(struct phy_device *phydev);
++@@ -977,6 +994,7 @@ struct phy_fixup {
++ 
++ const char *phy_speed_to_str(int speed);
++ const char *phy_duplex_to_str(unsigned int duplex);
+++const char *phy_rate_matching_to_str(int rate_matching);
++ 
++ /* A structure for mapping a particular speed and duplex
++  * combination to a particular SUPPORTED and ADVERTISED value
++@@ -1683,6 +1701,8 @@ int phy_disable_interrupts(struct phy_de
++ void phy_request_interrupt(struct phy_device *phydev);
++ void phy_free_interrupt(struct phy_device *phydev);
++ void phy_print_status(struct phy_device *phydev);
+++int phy_get_rate_matching(struct phy_device *phydev,
+++			   phy_interface_t iface);
++ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
++ void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode);
++ void phy_advertise_supported(struct phy_device *phydev);
++--- a/include/uapi/linux/ethtool.h
+++++ b/include/uapi/linux/ethtool.h
++@@ -1809,6 +1809,20 @@ static inline int ethtool_validate_duple
++ #define MASTER_SLAVE_STATE_SLAVE		3
++ #define MASTER_SLAVE_STATE_ERR			4
++ 
+++/* These are used to throttle the rate of data on the phy interface when the
+++ * native speed of the interface is higher than the link speed. These should
+++ * not be used for phy interfaces which natively support multiple speeds (e.g.
+++ * MII or SGMII).
+++ */
+++/* No rate matching performed. */
+++#define RATE_MATCH_NONE		0
+++/* The phy sends pause frames to throttle the MAC. */
+++#define RATE_MATCH_PAUSE	1
+++/* The phy asserts CRS to prevent the MAC from transmitting. */
+++#define RATE_MATCH_CRS		2
+++/* The MAC is programmed with a sufficiently-large IPG. */
+++#define RATE_MATCH_OPEN_LOOP	3
+++
++ /* Which connector port. */
++ #define PORT_TP			0x00
++ #define PORT_AUI		0x01
++@@ -2002,8 +2016,8 @@ enum ethtool_reset_flags {
++  *	reported consistently by PHYLIB.  Read-only.
++  * @master_slave_cfg: Master/slave port mode.
++  * @master_slave_state: Master/slave port state.
+++ * @rate_matching: Rate adaptation performed by the PHY
++  * @reserved: Reserved for future use; see the note on reserved space.
++- * @reserved1: Reserved for future use; see the note on reserved space.
++  * @link_mode_masks: Variable length bitmaps.
++  *
++  * If autonegotiation is disabled, the speed and @duplex represent the
++@@ -2054,7 +2068,7 @@ struct ethtool_link_settings {
++ 	__u8	transceiver;
++ 	__u8	master_slave_cfg;
++ 	__u8	master_slave_state;
++-	__u8	reserved1[1];
+++	__u8	rate_matching;
++ 	__u32	reserved[7];
++ 	__u32	link_mode_masks[0];
++ 	/* layout of link_mode_masks fields:
++--- a/include/uapi/linux/ethtool_netlink.h
+++++ b/include/uapi/linux/ethtool_netlink.h
++@@ -238,6 +238,7 @@ enum {
++ 	ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,	/* u8 */
++ 	ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE,	/* u8 */
++ 	ETHTOOL_A_LINKMODES_LANES,		/* u32 */
+++	ETHTOOL_A_LINKMODES_RATE_MATCHING,	/* u8 */
++ 
++ 	/* add new constants above here */
++ 	__ETHTOOL_A_LINKMODES_CNT,
++--- a/net/ethtool/ioctl.c
+++++ b/net/ethtool/ioctl.c
++@@ -559,6 +559,7 @@ static int ethtool_get_link_ksettings(st
++ 		= __ETHTOOL_LINK_MODE_MASK_NU32;
++ 	link_ksettings.base.master_slave_cfg = MASTER_SLAVE_CFG_UNSUPPORTED;
++ 	link_ksettings.base.master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
+++	link_ksettings.base.rate_matching = RATE_MATCH_NONE;
++ 
++ 	return store_link_ksettings_for_user(useraddr, &link_ksettings);
++ }
++--- a/net/ethtool/linkmodes.c
+++++ b/net/ethtool/linkmodes.c
++@@ -70,6 +70,7 @@ static int linkmodes_reply_size(const st
++ 		+ nla_total_size(sizeof(u32)) /* LINKMODES_SPEED */
++ 		+ nla_total_size(sizeof(u32)) /* LINKMODES_LANES */
++ 		+ nla_total_size(sizeof(u8)) /* LINKMODES_DUPLEX */
+++		+ nla_total_size(sizeof(u8)) /* LINKMODES_RATE_MATCHING */
++ 		+ 0;
++ 	ret = ethnl_bitset_size(ksettings->link_modes.advertising,
++ 				ksettings->link_modes.supported,
++@@ -143,6 +144,10 @@ static int linkmodes_fill_reply(struct s
++ 		       lsettings->master_slave_state))
++ 		return -EMSGSIZE;
++ 
+++	if (nla_put_u8(skb, ETHTOOL_A_LINKMODES_RATE_MATCHING,
+++		       lsettings->rate_matching))
+++		return -EMSGSIZE;
+++
++ 	return 0;
++ }
++ 
+diff --git a/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch b/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch
+new file mode 100644
+index 0000000000..3bde950c49
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-5-net-phylink-Adjust-link-settings-based-on-rate-match.patch
+@@ -0,0 +1,256 @@
++From ae0e4bb2a0e0e434e9f98fb4994093ec2ee71997 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:32 -0400
++Subject: [PATCH] net: phylink: Adjust link settings based on rate matching
++
++If the phy is configured to use pause-based rate matching, ensure that
++the link is full duplex with pause frame reception enabled. As
++suggested, if pause-based rate matching is enabled by the phy, then
++pause reception is unconditionally enabled.
++
++The interface duplex is determined based on the rate matching type.
++When rate matching is enabled, so is the speed. We assume the maximum
++interface speed is used. This is only relevant for MLO_AN_PHY. For
++MLO_AN_INBAND, the MAC/PCS's view of the interface speed will be used.
++
++Although there are no RATE_ADAPT_CRS phys in-tree, it has been added for
++comparison (and the implementation is quite simple).
++
++Co-developed-by: Russell King <linux@armlinux.org.uk>
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -234,6 +234,75 @@ static int phylink_validate_mac_and_pcs(
++ }
++ 
++ /**
+++ * phylink_interface_max_speed() - get the maximum speed of a phy interface
+++ * @interface: phy interface mode defined by &typedef phy_interface_t
+++ *
+++ * Determine the maximum speed of a phy interface. This is intended to help
+++ * determine the correct speed to pass to the MAC when the phy is performing
+++ * rate matching.
+++ *
+++ * Return: The maximum speed of @interface
+++ */
+++static int phylink_interface_max_speed(phy_interface_t interface)
+++{
+++	switch (interface) {
+++	case PHY_INTERFACE_MODE_100BASEX:
+++	case PHY_INTERFACE_MODE_REVRMII:
+++	case PHY_INTERFACE_MODE_RMII:
+++	case PHY_INTERFACE_MODE_SMII:
+++	case PHY_INTERFACE_MODE_REVMII:
+++	case PHY_INTERFACE_MODE_MII:
+++		return SPEED_100;
+++
+++	case PHY_INTERFACE_MODE_TBI:
+++	case PHY_INTERFACE_MODE_MOCA:
+++	case PHY_INTERFACE_MODE_RTBI:
+++	case PHY_INTERFACE_MODE_1000BASEX:
+++	case PHY_INTERFACE_MODE_1000BASEKX:
+++	case PHY_INTERFACE_MODE_TRGMII:
+++	case PHY_INTERFACE_MODE_RGMII_TXID:
+++	case PHY_INTERFACE_MODE_RGMII_RXID:
+++	case PHY_INTERFACE_MODE_RGMII_ID:
+++	case PHY_INTERFACE_MODE_RGMII:
+++	case PHY_INTERFACE_MODE_QSGMII:
+++	case PHY_INTERFACE_MODE_SGMII:
+++	case PHY_INTERFACE_MODE_GMII:
+++		return SPEED_1000;
+++
+++	case PHY_INTERFACE_MODE_2500BASEX:
+++		return SPEED_2500;
+++
+++	case PHY_INTERFACE_MODE_5GBASER:
+++		return SPEED_5000;
+++
+++	case PHY_INTERFACE_MODE_XGMII:
+++	case PHY_INTERFACE_MODE_RXAUI:
+++	case PHY_INTERFACE_MODE_XAUI:
+++	case PHY_INTERFACE_MODE_10GBASER:
+++	case PHY_INTERFACE_MODE_10GKR:
+++	case PHY_INTERFACE_MODE_USXGMII:
+++	case PHY_INTERFACE_MODE_QUSGMII:
+++		return SPEED_10000;
+++
+++	case PHY_INTERFACE_MODE_25GBASER:
+++		return SPEED_25000;
+++
+++	case PHY_INTERFACE_MODE_XLGMII:
+++		return SPEED_40000;
+++
+++	case PHY_INTERFACE_MODE_INTERNAL:
+++	case PHY_INTERFACE_MODE_NA:
+++	case PHY_INTERFACE_MODE_MAX:
+++		/* No idea! Garbage in, unknown out */
+++		return SPEED_UNKNOWN;
+++	}
+++
+++	/* If we get here, someone forgot to add an interface mode above */
+++	WARN_ON_ONCE(1);
+++	return SPEED_UNKNOWN;
+++}
+++
+++/**
++  * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes
++  * @linkmodes: ethtool linkmode mask (must be already initialised)
++  * @caps: bitmask of MAC capabilities
++@@ -802,11 +871,12 @@ static void phylink_mac_config(struct ph
++ 			       const struct phylink_link_state *state)
++ {
++ 	phylink_dbg(pl,
++-		    "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
+++		    "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
++ 		    __func__, phylink_an_mode_str(pl->cur_link_an_mode),
++ 		    phy_modes(state->interface),
++ 		    phy_speed_to_str(state->speed),
++ 		    phy_duplex_to_str(state->duplex),
+++		    phy_rate_matching_to_str(state->rate_matching),
++ 		    __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
++ 		    state->pause, state->link, state->an_enabled);
++ 
++@@ -942,7 +1012,8 @@ static void phylink_mac_pcs_get_state(st
++ 	linkmode_zero(state->lp_advertising);
++ 	state->interface = pl->link_config.interface;
++ 	state->an_enabled = pl->link_config.an_enabled;
++-	if  (state->an_enabled) {
+++	state->rate_matching = pl->link_config.rate_matching;
+++	if (state->an_enabled) {
++ 		state->speed = SPEED_UNKNOWN;
++ 		state->duplex = DUPLEX_UNKNOWN;
++ 		state->pause = MLO_PAUSE_NONE;
++@@ -1025,19 +1096,43 @@ static void phylink_link_up(struct phyli
++ 			    struct phylink_link_state link_state)
++ {
++ 	struct net_device *ndev = pl->netdev;
+++	int speed, duplex;
+++	bool rx_pause;
+++
+++	speed = link_state.speed;
+++	duplex = link_state.duplex;
+++	rx_pause = !!(link_state.pause & MLO_PAUSE_RX);
+++
+++	switch (link_state.rate_matching) {
+++	case RATE_MATCH_PAUSE:
+++		/* The PHY is doing rate matchion from the media rate (in
+++		 * the link_state) to the interface speed, and will send
+++		 * pause frames to the MAC to limit its transmission speed.
+++		 */
+++		speed = phylink_interface_max_speed(link_state.interface);
+++		duplex = DUPLEX_FULL;
+++		rx_pause = true;
+++		break;
+++
+++	case RATE_MATCH_CRS:
+++		/* The PHY is doing rate matchion from the media rate (in
+++		 * the link_state) to the interface speed, and will cause
+++		 * collisions to the MAC to limit its transmission speed.
+++		 */
+++		speed = phylink_interface_max_speed(link_state.interface);
+++		duplex = DUPLEX_HALF;
+++		break;
+++	}
++ 
++ 	pl->cur_interface = link_state.interface;
++ 
++ 	if (pl->pcs_ops && pl->pcs_ops->pcs_link_up)
++ 		pl->pcs_ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode,
++-					 pl->cur_interface,
++-					 link_state.speed, link_state.duplex);
+++					 pl->cur_interface, speed, duplex);
++ 
++-	pl->mac_ops->mac_link_up(pl->config, pl->phydev,
++-				 pl->cur_link_an_mode, pl->cur_interface,
++-				 link_state.speed, link_state.duplex,
++-				 !!(link_state.pause & MLO_PAUSE_TX),
++-				 !!(link_state.pause & MLO_PAUSE_RX));
+++	pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
+++				 pl->cur_interface, speed, duplex,
+++				 !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
++ 
++ 	if (ndev)
++ 		netif_carrier_on(ndev);
++@@ -1129,6 +1224,17 @@ static void phylink_resolve(struct work_
++ 				}
++ 				link_state.interface = pl->phy_state.interface;
++ 
+++				/* If we are doing rate matching, then the
+++				 * link speed/duplex comes from the PHY
+++				 */
+++				if (pl->phy_state.rate_matching) {
+++					link_state.rate_matching =
+++						pl->phy_state.rate_matching;
+++					link_state.speed = pl->phy_state.speed;
+++					link_state.duplex =
+++						pl->phy_state.duplex;
+++				}
+++
++ 				/* If we have a PHY, we need to update with
++ 				 * the PHY flow control bits.
++ 				 */
++@@ -1394,6 +1500,7 @@ static void phylink_phy_change(struct ph
++ 	mutex_lock(&pl->state_mutex);
++ 	pl->phy_state.speed = phydev->speed;
++ 	pl->phy_state.duplex = phydev->duplex;
+++	pl->phy_state.rate_matching = phydev->rate_matching;
++ 	pl->phy_state.pause = MLO_PAUSE_NONE;
++ 	if (tx_pause)
++ 		pl->phy_state.pause |= MLO_PAUSE_TX;
++@@ -1405,10 +1512,11 @@ static void phylink_phy_change(struct ph
++ 
++ 	phylink_run_resolve(pl);
++ 
++-	phylink_dbg(pl, "phy link %s %s/%s/%s/%s\n", up ? "up" : "down",
+++	phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s\n", up ? "up" : "down",
++ 		    phy_modes(phydev->interface),
++ 		    phy_speed_to_str(phydev->speed),
++ 		    phy_duplex_to_str(phydev->duplex),
+++		    phy_rate_matching_to_str(phydev->rate_matching),
++ 		    phylink_pause_to_str(pl->phy_state.pause));
++ }
++ 
++@@ -1472,6 +1580,7 @@ static int phylink_bringup_phy(struct ph
++ 	pl->phy_state.pause = MLO_PAUSE_NONE;
++ 	pl->phy_state.speed = SPEED_UNKNOWN;
++ 	pl->phy_state.duplex = DUPLEX_UNKNOWN;
+++	pl->phy_state.rate_matching = RATE_MATCH_NONE;
++ 	linkmode_copy(pl->supported, supported);
++ 	linkmode_copy(pl->link_config.advertising, config.advertising);
++ 
++@@ -1909,8 +2018,10 @@ static void phylink_get_ksettings(const
++ {
++ 	phylink_merge_link_mode(kset->link_modes.advertising, state->advertising);
++ 	linkmode_copy(kset->link_modes.lp_advertising, state->lp_advertising);
++-	kset->base.speed = state->speed;
++-	kset->base.duplex = state->duplex;
+++	if (kset->base.rate_matching == RATE_MATCH_NONE) {
+++		kset->base.speed = state->speed;
+++		kset->base.duplex = state->duplex;
+++	}
++ 	kset->base.autoneg = state->an_enabled ? AUTONEG_ENABLE :
++ 				AUTONEG_DISABLE;
++ }
++--- a/include/linux/phylink.h
+++++ b/include/linux/phylink.h
++@@ -88,6 +88,10 @@ static inline bool phylink_autoneg_inban
++  * @speed: link speed, one of the SPEED_* constants.
++  * @duplex: link duplex mode, one of DUPLEX_* constants.
++  * @pause: link pause state, described by MLO_PAUSE_* constants.
+++ * @rate_matching: rate matching being performed, one of the RATE_MATCH_*
+++ *   constants. If rate matching is taking place, then the speed/duplex of
+++ *   the medium link mode (@speed and @duplex) and the speed/duplex of the phy
+++ *   interface mode (@interface) are different.
++  * @link: true if the link is up.
++  * @an_enabled: true if autonegotiation is enabled/desired.
++  * @an_complete: true if autonegotiation has completed.
++@@ -99,6 +103,7 @@ struct phylink_link_state {
++ 	int speed;
++ 	int duplex;
++ 	int pause;
+++	int rate_matching;
++ 	unsigned int link:1;
++ 	unsigned int an_enabled:1;
++ 	unsigned int an_complete:1;
+diff --git a/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch b/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch
+new file mode 100644
+index 0000000000..29344604f1
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-06-6-net-phylink-Adjust-advertisement-based-on-rate-match.patch
+@@ -0,0 +1,187 @@
++From b7e9294885b610791fcebc799bf2a9e219446fd6 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:33 -0400
++Subject: [PATCH] net: phylink: Adjust advertisement based on rate matching
++
++This adds support for adjusting the advertisement for pause-based rate
++matching. This may result in a lossy link, since the final link settings
++are not adjusted. Asymmetric pause support is necessary. It would be
++possible for a MAC supporting only symmetric pause to use pause-based rate
++adaptation, but only if pause reception was enabled as well.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++From b7e9294885b610791fcebc799bf2a9e219446fd6 Mon Sep 17 00:00:00 2001
++From: Sean Anderson <sean.anderson@seco.com>
++Date: Tue, 20 Sep 2022 18:12:33 -0400
++Subject: [PATCH] net: phylink: Adjust advertisement based on rate matching
++
++This adds support for adjusting the advertisement for pause-based rate
++matching. This may result in a lossy link, since the final link settings
++are not adjusted. Asymmetric pause support is necessary. It would be
++possible for a MAC supporting only symmetric pause to use pause-based rate
++adaptation, but only if pause reception was enabled as well.
++
++Signed-off-by: Sean Anderson <sean.anderson@seco.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/phylink.c
+++++ b/drivers/net/phy/phylink.c
++@@ -448,18 +448,70 @@ void phylink_caps_to_linkmodes(unsigned
++ }
++ EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes);
++ 
+++static struct {
+++	unsigned long mask;
+++	int speed;
+++	unsigned int duplex;
+++} phylink_caps_params[] = {
+++	{ MAC_400000FD, SPEED_400000, DUPLEX_FULL },
+++	{ MAC_200000FD, SPEED_200000, DUPLEX_FULL },
+++	{ MAC_100000FD, SPEED_100000, DUPLEX_FULL },
+++	{ MAC_56000FD,  SPEED_56000,  DUPLEX_FULL },
+++	{ MAC_50000FD,  SPEED_50000,  DUPLEX_FULL },
+++	{ MAC_40000FD,  SPEED_40000,  DUPLEX_FULL },
+++	{ MAC_25000FD,  SPEED_25000,  DUPLEX_FULL },
+++	{ MAC_20000FD,  SPEED_20000,  DUPLEX_FULL },
+++	{ MAC_10000FD,  SPEED_10000,  DUPLEX_FULL },
+++	{ MAC_5000FD,   SPEED_5000,   DUPLEX_FULL },
+++	{ MAC_2500FD,   SPEED_2500,   DUPLEX_FULL },
+++	{ MAC_1000FD,   SPEED_1000,   DUPLEX_FULL },
+++	{ MAC_1000HD,   SPEED_1000,   DUPLEX_HALF },
+++	{ MAC_100FD,    SPEED_100,    DUPLEX_FULL },
+++	{ MAC_100HD,    SPEED_100,    DUPLEX_HALF },
+++	{ MAC_10FD,     SPEED_10,     DUPLEX_FULL },
+++	{ MAC_10HD,     SPEED_10,     DUPLEX_HALF },
+++};
+++
+++/**
+++ * phylink_cap_from_speed_duplex - Get mac capability from speed/duplex
+++ * @speed: the speed to search for
+++ * @duplex: the duplex to search for
+++ *
+++ * Find the mac capability for a given speed and duplex.
+++ *
+++ * Return: A mask with the mac capability patching @speed and @duplex, or 0 if
+++ *         there were no matches.
+++ */
+++static unsigned long phylink_cap_from_speed_duplex(int speed,
+++						   unsigned int duplex)
+++{
+++	int i;
+++
+++	for (i = 0; i < ARRAY_SIZE(phylink_caps_params); i++) {
+++		if (speed == phylink_caps_params[i].speed &&
+++		    duplex == phylink_caps_params[i].duplex)
+++			return phylink_caps_params[i].mask;
+++	}
+++
+++	return 0;
+++}
+++
++ /**
++  * phylink_get_capabilities() - get capabilities for a given MAC
++  * @interface: phy interface mode defined by &typedef phy_interface_t
++  * @mac_capabilities: bitmask of MAC capabilities
+++ * @rate_matching: type of rate matching being performed
++  *
++  * Get the MAC capabilities that are supported by the @interface mode and
++  * @mac_capabilities.
++  */
++ unsigned long phylink_get_capabilities(phy_interface_t interface,
++-				       unsigned long mac_capabilities)
+++				       unsigned long mac_capabilities,
+++				       int rate_matching)
++ {
+++	int max_speed = phylink_interface_max_speed(interface);
++ 	unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+++	unsigned long matched_caps = 0;
++ 
++ 	switch (interface) {
++ 	case PHY_INTERFACE_MODE_USXGMII:
++@@ -533,7 +585,53 @@ unsigned long phylink_get_capabilities(p
++ 		break;
++ 	}
++ 
++-	return caps & mac_capabilities;
+++	switch (rate_matching) {
+++	case RATE_MATCH_OPEN_LOOP:
+++		/* TODO */
+++		fallthrough;
+++	case RATE_MATCH_NONE:
+++		matched_caps = 0;
+++		break;
+++	case RATE_MATCH_PAUSE: {
+++		/* The MAC must support asymmetric pause towards the local
+++		 * device for this. We could allow just symmetric pause, but
+++		 * then we might have to renegotiate if the link partner
+++		 * doesn't support pause. This is because there's no way to
+++		 * accept pause frames without transmitting them if we only
+++		 * support symmetric pause.
+++		 */
+++		if (!(mac_capabilities & MAC_SYM_PAUSE) ||
+++		    !(mac_capabilities & MAC_ASYM_PAUSE))
+++			break;
+++
+++		/* We can't adapt if the MAC doesn't support the interface's
+++		 * max speed at full duplex.
+++		 */
+++		if (mac_capabilities &
+++		    phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) {
+++			/* Although a duplex-matching phy might exist, we
+++			 * conservatively remove these modes because the MAC
+++			 * will not be aware of the half-duplex nature of the
+++			 * link.
+++			 */
+++			matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD));
+++			matched_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD);
+++		}
+++		break;
+++	}
+++	case RATE_MATCH_CRS:
+++		/* The MAC must support half duplex at the interface's max
+++		 * speed.
+++		 */
+++		if (mac_capabilities &
+++		    phylink_cap_from_speed_duplex(max_speed, DUPLEX_HALF)) {
+++			matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD));
+++			matched_caps &= mac_capabilities;
+++		}
+++		break;
+++	}
+++
+++	return (caps & mac_capabilities) | matched_caps;
++ }
++ EXPORT_SYMBOL_GPL(phylink_get_capabilities);
++ 
++@@ -557,7 +655,8 @@ void phylink_generic_validate(struct phy
++ 	phylink_set_port_modes(mask);
++ 	phylink_set(mask, Autoneg);
++ 	caps = phylink_get_capabilities(state->interface,
++-					config->mac_capabilities);
+++					config->mac_capabilities,
+++					state->rate_matching);
++ 	phylink_caps_to_linkmodes(mask, caps);
++ 
++ 	linkmode_and(supported, supported, mask);
++@@ -1553,6 +1652,7 @@ static int phylink_bringup_phy(struct ph
++ 		config.interface = PHY_INTERFACE_MODE_NA;
++ 	else
++ 		config.interface = interface;
+++	config.rate_matching = phy_get_rate_matching(phy, config.interface);
++ 
++ 	ret = phylink_validate(pl, supported, &config);
++ 	if (ret) {
++--- a/include/linux/phylink.h
+++++ b/include/linux/phylink.h
++@@ -563,7 +563,8 @@ void pcs_link_up(struct phylink_pcs *pcs
++ 
++ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps);
++ unsigned long phylink_get_capabilities(phy_interface_t interface,
++-				       unsigned long mac_capabilities);
+++				       unsigned long mac_capabilities,
+++				       int rate_matching);
++ void phylink_generic_validate(struct phylink_config *config,
++ 			      unsigned long *supported,
++ 			      struct phylink_link_state *state);
+diff --git a/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch
+new file mode 100644
+index 0000000000..db8e5f2fdc
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-07-1-net-phy-add-possible-interfaces.patch
+@@ -0,0 +1,56 @@
++From 243ad8df7a1bd24c2e01bd99d9f0bb88844dae91 Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 24 Nov 2023 12:27:52 +0000
++Subject: [PATCH] net: phy: add possible interfaces
++
++Add a possible_interfaces member to struct phy_device to indicate which
++interfaces a clause 45 PHY may switch between depending on the media.
++This must be populated by the PHY driver by the time the .config_init()
++method completes according to the PHYs host-side configuration.
++
++For example, the Marvell 88x3310 PHY can switch between 10GBASE-R,
++5GBASE-R, 2500BASE-X, and SGMII on the host side depending on the media
++side speed, so all these interface modes are set in the
++possible_interfaces member.
++
++This allows phylib users (such as phylink) to know in advance which
++interface modes to expect, which allows them to appropriately restrict
++the advertised link modes according to the capabilities of other parts
++of the link.
++
++Tested-by: Luo Jie <quic_luoj@quicinc.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1r6VHk-00DDLN-I7@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/phy_device.c
+++++ b/drivers/net/phy/phy_device.c
++@@ -1210,6 +1210,8 @@ int phy_init_hw(struct phy_device *phyde
++ 	if (ret < 0)
++ 		return ret;
++ 
+++	phy_interface_zero(phydev->possible_interfaces);
+++
++ 	if (phydev->drv->config_init) {
++ 		ret = phydev->drv->config_init(phydev);
++ 		if (ret < 0)
++--- a/include/linux/phy.h
+++++ b/include/linux/phy.h
++@@ -584,6 +584,8 @@ struct macsec_ops;
++  * @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
++  *             requiring a rerun of the interrupt handler after resume
++  * @interface: enum phy_interface_t value
+++ * @possible_interfaces: bitmap if interface modes that the attached PHY
+++ *			 will switch between depending on media speed.
++  * @skb: Netlink message for cable diagnostics
++  * @nest: Netlink nest used for cable diagnostics
++  * @ehdr: nNtlink header for cable diagnostics
++@@ -647,6 +649,7 @@ struct phy_device {
++ 	u32 dev_flags;
++ 
++ 	phy_interface_t interface;
+++	DECLARE_PHY_INTERFACE_MASK(possible_interfaces);
++ 
++ 	/*
++ 	 * forced speed & duplex (no autoneg)
+diff --git a/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch b/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch
+new file mode 100644
+index 0000000000..044cad8264
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-07-2-net-phy-marvell10g-table-driven-mactype-decode.patch
+@@ -0,0 +1,295 @@
++From 2cb6d63b30c6fbc7cf5f671279be4a94049e141f Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 24 Nov 2023 12:27:58 +0000
++Subject: [PATCH] net: phy: marvell10g: table driven mactype decode
++
++Replace the code-based mactype decode with a table driven approach.
++This will allow us to fill in the possible_interfaces cleanly.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Link: https://lore.kernel.org/r/E1r6VHq-00DDLT-In@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -141,13 +141,21 @@ enum {
++ 	MV_V2_TEMP_UNKNOWN	= 0x9600, /* unknown function */
++ };
++ 
+++struct mv3310_mactype {
+++	bool valid;
+++	bool fixed_interface;
+++	phy_interface_t interface_10g;
+++};
+++
++ struct mv3310_chip {
++ 	bool (*has_downshift)(struct phy_device *phydev);
++ 	void (*init_supported_interfaces)(unsigned long *mask);
++ 	int (*get_mactype)(struct phy_device *phydev);
++ 	int (*set_mactype)(struct phy_device *phydev, int mactype);
++ 	int (*select_mactype)(unsigned long *interfaces);
++-	int (*init_interface)(struct phy_device *phydev, int mactype);
+++
+++	const struct mv3310_mactype *mactypes;
+++	size_t n_mactypes;
++ 
++ #ifdef CONFIG_HWMON
++ 	int (*hwmon_read_temp_reg)(struct phy_device *phydev);
++@@ -156,11 +164,10 @@ struct mv3310_chip {
++ 
++ struct mv3310_priv {
++ 	DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
+++	const struct mv3310_mactype *mactype;
++ 
++ 	u32 firmware_ver;
++ 	bool has_downshift;
++-	bool rate_match;
++-	phy_interface_t const_interface;
++ 
++ 	struct device *hwmon_dev;
++ 	char *hwmon_name;
++@@ -702,71 +709,99 @@ static int mv3310_select_mactype(unsigne
++ 		return -1;
++ }
++ 
++-static int mv2110_init_interface(struct phy_device *phydev, int mactype)
++-{
++-	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++-
++-	priv->rate_match = false;
++-
++-	if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH)
++-		priv->rate_match = true;
++-
++-	if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII)
++-		priv->const_interface = PHY_INTERFACE_MODE_USXGMII;
++-	else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH)
++-		priv->const_interface = PHY_INTERFACE_MODE_10GBASER;
++-	else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER ||
++-		 mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN)
++-		priv->const_interface = PHY_INTERFACE_MODE_NA;
++-	else
++-		return -EINVAL;
++-
++-	return 0;
++-}
++-
++-static int mv3310_init_interface(struct phy_device *phydev, int mactype)
++-{
++-	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++-
++-	priv->rate_match = false;
++-
++-	if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH ||
++-	    mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH ||
++-	    mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH)
++-		priv->rate_match = true;
++-
++-	if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII)
++-		priv->const_interface = PHY_INTERFACE_MODE_USXGMII;
++-	else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH ||
++-		 mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN ||
++-		 mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER)
++-		priv->const_interface = PHY_INTERFACE_MODE_10GBASER;
++-	else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH ||
++-		 mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI)
++-		priv->const_interface = PHY_INTERFACE_MODE_RXAUI;
++-	else if (mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH ||
++-		 mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI)
++-		priv->const_interface = PHY_INTERFACE_MODE_XAUI;
++-	else
++-		return -EINVAL;
++-
++-	return 0;
++-}
++-
++-static int mv3340_init_interface(struct phy_device *phydev, int mactype)
++-{
++-	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++-	int err = 0;
++-
++-	priv->rate_match = false;
+++static const struct mv3310_mactype mv2110_mactypes[] = {
+++	[MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_USXGMII,
+++	},
+++	[MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_NA,
+++	},
+++	[MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_NA,
+++	},
+++	[MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++};
++ 
++-	if (mactype == MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN)
++-		priv->const_interface = PHY_INTERFACE_MODE_RXAUI;
++-	else
++-		err = mv3310_init_interface(phydev, mactype);
+++static const struct mv3310_mactype mv3310_mactypes[] = {
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_RXAUI,
+++	},
+++	[MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_XAUI,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_RXAUI,
+++	},
+++	[MV_V2_3310_PORT_CTRL_MACTYPE_XAUI] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_XAUI,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_USXGMII,
+++	},
+++};
++ 
++-	return err;
++-}
+++static const struct mv3310_mactype mv3340_mactypes[] = {
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_RXAUI,
+++	},
+++	[MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_RXAUI,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_RXAUI,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = {
+++		.valid = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_10GBASER,
+++	},
+++	[MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = {
+++		.valid = true,
+++		.fixed_interface = true,
+++		.interface_10g = PHY_INTERFACE_MODE_USXGMII,
+++	},
+++};
++ 
++ static int mv3310_config_init(struct phy_device *phydev)
++ {
++@@ -803,12 +838,13 @@ static int mv3310_config_init(struct phy
++ 	if (mactype < 0)
++ 		return mactype;
++ 
++-	err = chip->init_interface(phydev, mactype);
++-	if (err) {
+++	if (mactype >= chip->n_mactypes || !chip->mactypes[mactype].valid) {
++ 		phydev_err(phydev, "MACTYPE configuration invalid\n");
++-		return err;
+++		return -EINVAL;
++ 	}
++ 
+++	priv->mactype = &chip->mactypes[mactype];
+++
++ 	/* Enable EDPD mode - saving 600mW */
++ 	err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
++ 	if (err)
++@@ -935,9 +971,8 @@ static void mv3310_update_interface(stru
++ 	 *
++ 	 * In USXGMII mode the PHY interface mode is also fixed.
++ 	 */
++-	if (priv->rate_match ||
++-	    priv->const_interface == PHY_INTERFACE_MODE_USXGMII) {
++-		phydev->interface = priv->const_interface;
+++	if (priv->mactype->fixed_interface) {
+++		phydev->interface = priv->mactype->interface_10g;
++ 		return;
++ 	}
++ 
++@@ -949,7 +984,7 @@ static void mv3310_update_interface(stru
++ 	 */
++ 	switch (phydev->speed) {
++ 	case SPEED_10000:
++-		phydev->interface = priv->const_interface;
+++		phydev->interface = priv->mactype->interface_10g;
++ 		break;
++ 	case SPEED_5000:
++ 		phydev->interface = PHY_INTERFACE_MODE_5GBASER;
++@@ -1163,7 +1198,9 @@ static const struct mv3310_chip mv3310_t
++ 	.get_mactype = mv3310_get_mactype,
++ 	.set_mactype = mv3310_set_mactype,
++ 	.select_mactype = mv3310_select_mactype,
++-	.init_interface = mv3310_init_interface,
+++
+++	.mactypes = mv3310_mactypes,
+++	.n_mactypes = ARRAY_SIZE(mv3310_mactypes),
++ 
++ #ifdef CONFIG_HWMON
++ 	.hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg,
++@@ -1176,7 +1213,9 @@ static const struct mv3310_chip mv3340_t
++ 	.get_mactype = mv3310_get_mactype,
++ 	.set_mactype = mv3310_set_mactype,
++ 	.select_mactype = mv3310_select_mactype,
++-	.init_interface = mv3340_init_interface,
+++
+++	.mactypes = mv3340_mactypes,
+++	.n_mactypes = ARRAY_SIZE(mv3340_mactypes),
++ 
++ #ifdef CONFIG_HWMON
++ 	.hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg,
++@@ -1188,7 +1227,9 @@ static const struct mv3310_chip mv2110_t
++ 	.get_mactype = mv2110_get_mactype,
++ 	.set_mactype = mv2110_set_mactype,
++ 	.select_mactype = mv2110_select_mactype,
++-	.init_interface = mv2110_init_interface,
+++
+++	.mactypes = mv2110_mactypes,
+++	.n_mactypes = ARRAY_SIZE(mv2110_mactypes),
++ 
++ #ifdef CONFIG_HWMON
++ 	.hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg,
++@@ -1200,7 +1241,9 @@ static const struct mv3310_chip mv2111_t
++ 	.get_mactype = mv2110_get_mactype,
++ 	.set_mactype = mv2110_set_mactype,
++ 	.select_mactype = mv2110_select_mactype,
++-	.init_interface = mv2110_init_interface,
+++
+++	.mactypes = mv2110_mactypes,
+++	.n_mactypes = ARRAY_SIZE(mv2110_mactypes),
++ 
++ #ifdef CONFIG_HWMON
++ 	.hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg,
+diff --git a/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch
+new file mode 100644
+index 0000000000..092f561dec
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-07-3-net-phy-marvell10g-fill-in-possible_interfaces.patch
+@@ -0,0 +1,47 @@
++From 82f2e76b660a490ae226db80d495b7c785e00d7a Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 24 Nov 2023 12:28:03 +0000
++Subject: [PATCH] net: phy: marvell10g: fill in possible_interfaces
++
++Fill in the possible_interfaces member according to the selected
++mactype mode.
++
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1r6VHv-00DDLZ-OL@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/marvell10g.c
+++++ b/drivers/net/phy/marvell10g.c
++@@ -803,6 +803,22 @@ static const struct mv3310_mactype mv334
++ 	},
++ };
++ 
+++static void mv3310_fill_possible_interfaces(struct phy_device *phydev)
+++{
+++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+++	unsigned long *possible = phydev->possible_interfaces;
+++	const struct mv3310_mactype *mactype = priv->mactype;
+++
+++	if (mactype->interface_10g != PHY_INTERFACE_MODE_NA)
+++		__set_bit(priv->mactype->interface_10g, possible);
+++
+++	if (!mactype->fixed_interface) {
+++		__set_bit(PHY_INTERFACE_MODE_5GBASER, possible);
+++		__set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
+++		__set_bit(PHY_INTERFACE_MODE_SGMII, possible);
+++	}
+++}
+++
++ static int mv3310_config_init(struct phy_device *phydev)
++ {
++ 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
++@@ -845,6 +861,8 @@ static int mv3310_config_init(struct phy
++ 
++ 	priv->mactype = &chip->mactypes[mactype];
++ 
+++	mv3310_fill_possible_interfaces(phydev);
+++
++ 	/* Enable EDPD mode - saving 600mW */
++ 	err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
++ 	if (err)
+diff --git a/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch b/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch
+new file mode 100644
+index 0000000000..482ea97eb5
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-07-4-net-phy-bcm84881-fill-in-possible_interfaces.patch
+@@ -0,0 +1,44 @@
++From a22583338e535ba2512283da4aee893163a4b78d Mon Sep 17 00:00:00 2001
++From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
++Date: Fri, 24 Nov 2023 12:28:08 +0000
++Subject: [PATCH] net: phy: bcm84881: fill in possible_interfaces
++
++Fill in the possible_interfaces member. This PHY driver only supports
++a single configuration found on SFPs.
++
++Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
++Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/E1r6VI0-00DDLf-Tb@rmk-PC.armlinux.org.uk
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/bcm84881.c
+++++ b/drivers/net/phy/bcm84881.c
++@@ -29,8 +29,19 @@ static int bcm84881_wait_init(struct phy
++ 					 100000, 2000000, false);
++ }
++ 
+++static void bcm84881_fill_possible_interfaces(struct phy_device *phydev)
+++{
+++	unsigned long *possible = phydev->possible_interfaces;
+++
+++	__set_bit(PHY_INTERFACE_MODE_SGMII, possible);
+++	__set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
+++	__set_bit(PHY_INTERFACE_MODE_10GBASER, possible);
+++}
+++
++ static int bcm84881_config_init(struct phy_device *phydev)
++ {
+++	bcm84881_fill_possible_interfaces(phydev);
+++
++ 	switch (phydev->interface) {
++ 	case PHY_INTERFACE_MODE_SGMII:
++ 	case PHY_INTERFACE_MODE_2500BASEX:
++@@ -39,6 +50,7 @@ static int bcm84881_config_init(struct p
++ 	default:
++ 		return -ENODEV;
++ 	}
+++
++ 	return 0;
++ }
++ 
+diff --git a/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch b/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch
+new file mode 100644
+index 0000000000..6cb63c9577
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-08-1-net-mdio-add-2.5g-and-5g-related-PMA-speed-constants.patch
+@@ -0,0 +1,27 @@
++From 6c06c88fa838fcc1b7e5380facd086f57fd9d1c4 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Sun, 4 Feb 2024 15:16:46 +0100
++Subject: [PATCH] net: mdio: add 2.5g and 5g related PMA speed constants
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Add constants indicating 2.5g and 5g ability in the MMD PMA speed
++register.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
++Link: https://lore.kernel.org/r/98e15038-d96c-442f-93e4-410100d27866@gmail.com
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/include/uapi/linux/mdio.h
+++++ b/include/uapi/linux/mdio.h
++@@ -119,6 +119,8 @@
++ #define MDIO_PMA_SPEED_1000		0x0010	/* 1000M capable */
++ #define MDIO_PMA_SPEED_100		0x0020	/* 100M capable */
++ #define MDIO_PMA_SPEED_10		0x0040	/* 10M capable */
+++#define MDIO_PMA_SPEED_2_5G		0x2000	/* 2.5G capable */
+++#define MDIO_PMA_SPEED_5G		0x4000	/* 5G capable */
++ #define MDIO_PCS_SPEED_10P2B		0x0002	/* 10PASS-TS/2BASE-TL capable */
++ #define MDIO_PCS_SPEED_2_5G		0x0040	/* 2.5G capable */
++ #define MDIO_PCS_SPEED_5G		0x0080	/* 5G capable */
+diff --git a/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch b/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch
+new file mode 100644
+index 0000000000..55ca8ace53
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-08-2-net-phy-realtek-use-generic-MDIO-constants.patch
+@@ -0,0 +1,90 @@
++From 2b9ec5dfb8255656ca731ab9d9bf59d94566d377 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Sun, 4 Feb 2024 15:17:53 +0100
++Subject: [PATCH] net: phy: realtek: use generic MDIO constants
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Drop the ad-hoc MDIO constants used in the driver and use generic
++constants instead.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/732a70d6-4191-4aae-8862-3716b062aa9e@gmail.com
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -56,14 +56,6 @@
++ #define RTL8366RB_POWER_SAVE			0x15
++ #define RTL8366RB_POWER_SAVE_ON			BIT(12)
++ 
++-#define RTL_SUPPORTS_5000FULL			BIT(14)
++-#define RTL_SUPPORTS_2500FULL			BIT(13)
++-#define RTL_SUPPORTS_10000FULL			BIT(0)
++-#define RTL_ADV_2500FULL			BIT(7)
++-#define RTL_LPADV_10000FULL			BIT(11)
++-#define RTL_LPADV_5000FULL			BIT(6)
++-#define RTL_LPADV_2500FULL			BIT(5)
++-
++ #define RTL9000A_GINMR				0x14
++ #define RTL9000A_GINMR_LINK_STATUS		BIT(4)
++ 
++@@ -638,11 +630,11 @@ static int rtl822x_get_features(struct p
++ 		return val;
++ 
++ 	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++-			 phydev->supported, val & RTL_SUPPORTS_2500FULL);
+++			 phydev->supported, val & MDIO_PMA_SPEED_2_5G);
++ 	linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
++-			 phydev->supported, val & RTL_SUPPORTS_5000FULL);
+++			 phydev->supported, val & MDIO_PMA_SPEED_5G);
++ 	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
++-			 phydev->supported, val & RTL_SUPPORTS_10000FULL);
+++			 phydev->supported, val & MDIO_SPEED_10G);
++ 
++ 	return genphy_read_abilities(phydev);
++ }
++@@ -656,10 +648,11 @@ static int rtl822x_config_aneg(struct ph
++ 
++ 		if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++ 				      phydev->advertising))
++-			adv2500 = RTL_ADV_2500FULL;
+++			adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G;
++ 
++ 		ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
++-					       RTL_ADV_2500FULL, adv2500);
+++					       MDIO_AN_10GBT_CTRL_ADV2_5G,
+++					       adv2500);
++ 		if (ret < 0)
++ 			return ret;
++ 	}
++@@ -678,11 +671,14 @@ static int rtl822x_read_status(struct ph
++ 			return lpadv;
++ 
++ 		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
++-			phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
+++				 phydev->lp_advertising,
+++				 lpadv & MDIO_AN_10GBT_STAT_LP10G);
++ 		linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
++-			phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
+++				 phydev->lp_advertising,
+++				 lpadv & MDIO_AN_10GBT_STAT_LP5G);
++ 		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++-			phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
+++				 phydev->lp_advertising,
+++				 lpadv & MDIO_AN_10GBT_STAT_LP2_5G);
++ 	}
++ 
++ 	ret = genphy_read_status(phydev);
++@@ -700,7 +696,7 @@ static bool rtlgen_supports_2_5gbps(stru
++ 	val = phy_read(phydev, 0x13);
++ 	phy_write(phydev, RTL821x_PAGE_SELECT, 0);
++ 
++-	return val >= 0 && val & RTL_SUPPORTS_2500FULL;
+++	return val >= 0 && val & MDIO_PMA_SPEED_2_5G;
++ }
++ 
++ static int rtlgen_match_phy_device(struct phy_device *phydev)
+diff --git a/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch b/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch
+new file mode 100644
+index 0000000000..290ca699a8
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-08-3-net-phy-realtek-add-5Gbps-support-to-rtl822x_config_.patch
+@@ -0,0 +1,39 @@
++From db1bb7741ff29bf2cefcbc0ca567644e9ed1caa9 Mon Sep 17 00:00:00 2001
++From: Heiner Kallweit <hkallweit1@gmail.com>
++Date: Sun, 4 Feb 2024 15:18:50 +0100
++Subject: [PATCH] net: phy: realtek: add 5Gbps support to rtl822x_config_aneg()
++
++RTL8126 as an evolution of RTL8125 supports 5Gbps. rtl822x_config_aneg()
++is used by the PHY driver for the integrated PHY, therefore add 5Gbps
++support to it.
++
++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
++Link: https://lore.kernel.org/r/5644ab50-e3e9-477c-96db-05cd5bdc2563@gmail.com
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -644,15 +644,19 @@ static int rtl822x_config_aneg(struct ph
++ 	int ret = 0;
++ 
++ 	if (phydev->autoneg == AUTONEG_ENABLE) {
++-		u16 adv2500 = 0;
+++		u16 adv = 0;
++ 
++ 		if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++ 				      phydev->advertising))
++-			adv2500 = MDIO_AN_10GBT_CTRL_ADV2_5G;
+++			adv |= MDIO_AN_10GBT_CTRL_ADV2_5G;
+++		if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+++				      phydev->advertising))
+++			adv |= MDIO_AN_10GBT_CTRL_ADV5G;
++ 
++ 		ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
++-					       MDIO_AN_10GBT_CTRL_ADV2_5G,
++-					       adv2500);
+++					       MDIO_AN_10GBT_CTRL_ADV2_5G |
+++					       MDIO_AN_10GBT_CTRL_ADV5G,
+++					       adv);
++ 		if (ret < 0)
++ 			return ret;
++ 	}
+diff --git a/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch b/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch
+new file mode 100644
+index 0000000000..8409275336
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-09-net-phy-realtek-use-generic-MDIO-helpers-to-simplify.patch
+@@ -0,0 +1,49 @@
++From b63cc73341e076961d564a74cc3d29b2fd444079 Mon Sep 17 00:00:00 2001
++From: Heiner Kallweit <hkallweit1@gmail.com>
++Date: Thu, 8 Feb 2024 07:59:18 +0100
++Subject: [PATCH] net: phy: realtek: use generic MDIO helpers to simplify the
++ code
++
++Use generic MDIO helpers to simplify the code.
++
++Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Link: https://lore.kernel.org/r/422ae70f-7305-45fd-ab3e-0dd604b9fd6c@gmail.com
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -644,14 +644,7 @@ static int rtl822x_config_aneg(struct ph
++ 	int ret = 0;
++ 
++ 	if (phydev->autoneg == AUTONEG_ENABLE) {
++-		u16 adv = 0;
++-
++-		if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++-				      phydev->advertising))
++-			adv |= MDIO_AN_10GBT_CTRL_ADV2_5G;
++-		if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
++-				      phydev->advertising))
++-			adv |= MDIO_AN_10GBT_CTRL_ADV5G;
+++		u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
++ 
++ 		ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
++ 					       MDIO_AN_10GBT_CTRL_ADV2_5G |
++@@ -674,15 +667,8 @@ static int rtl822x_read_status(struct ph
++ 		if (lpadv < 0)
++ 			return lpadv;
++ 
++-		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
++-				 phydev->lp_advertising,
++-				 lpadv & MDIO_AN_10GBT_STAT_LP10G);
++-		linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
++-				 phydev->lp_advertising,
++-				 lpadv & MDIO_AN_10GBT_STAT_LP5G);
++-		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++-				 phydev->lp_advertising,
++-				 lpadv & MDIO_AN_10GBT_STAT_LP2_5G);
+++		mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising,
+++						  lpadv);
++ 	}
++ 
++ 	ret = genphy_read_status(phydev);
+diff --git a/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch b/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch
+new file mode 100644
+index 0000000000..bf95e8ff1e
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-1-net-phy-realtek-configure-SerDes-mode-for-rtl822xb-P.patch
+@@ -0,0 +1,206 @@
++From deb8af5243504e379878ae3f9a091b21422d65b2 Mon Sep 17 00:00:00 2001
++From: Alexander Couzens <lynxis@fe80.eu>
++Date: Tue, 9 Apr 2024 09:30:11 +0200
++Subject: [PATCH] net: phy: realtek: configure SerDes mode for rtl822xb PHYs
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++The rtl8221b and rtl8226b series support switching SerDes mode between
++2500base-x and sgmii based on the negotiated copper speed.
++
++Configure this switching mode according to SerDes modes supported by
++host.
++
++There is an additional datasheet for RTL8226B/RTL8221B called
++"SERDES MODE SETTING FLOW APPLICATION NOTE" where a sequence is
++described to setup interface and rate adapter mode.
++
++However, there is no documentation about the meaning of registers
++and bits, it's literally just magic numbers and pseudo-code.
++
++Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
++[ refactored, dropped HiSGMII mode and changed commit message ]
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++[ changed rtl822x_update_interface() to use vendor register ]
++[ always fill in possible interfaces ]
++[ only apply to rtl8221b and rtl8226b phy's ]
++[ set phydev->rate_matching in .config_init() ]
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Reviewed-by: should come before them, without any blank lines. As the
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -53,6 +53,16 @@
++ 						 RTL8201F_ISR_LINK)
++ #define RTL8201F_IER				0x13
++ 
+++#define RTL822X_VND1_SERDES_OPTION			0x697a
+++#define RTL822X_VND1_SERDES_OPTION_MODE_MASK		GENMASK(5, 0)
+++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII		0
+++#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX		2
+++
+++#define RTL822X_VND1_SERDES_CTRL3			0x7580
+++#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK		GENMASK(5, 0)
+++#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII			0x02
+++#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX		0x16
+++
++ #define RTL8366RB_POWER_SAVE			0x15
++ #define RTL8366RB_POWER_SAVE_ON			BIT(12)
++ 
++@@ -621,6 +631,63 @@ static int rtl822x_write_mmd(struct phy_
++ 	return ret;
++ }
++ 
+++static int rtl822xb_config_init(struct phy_device *phydev)
+++{
+++	bool has_2500, has_sgmii;
+++	u16 mode;
+++	int ret;
+++
+++	has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX,
+++			    phydev->host_interfaces) ||
+++		   phydev->interface == PHY_INTERFACE_MODE_2500BASEX;
+++
+++	has_sgmii = test_bit(PHY_INTERFACE_MODE_SGMII,
+++			     phydev->host_interfaces) ||
+++		    phydev->interface == PHY_INTERFACE_MODE_SGMII;
+++
+++	/* fill in possible interfaces */
+++	__assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces,
+++		     has_2500);
+++	__assign_bit(PHY_INTERFACE_MODE_SGMII, phydev->possible_interfaces,
+++		     has_sgmii);
+++
+++	if (!has_2500 && !has_sgmii)
+++		return 0;
+++
+++	/* determine SerDes option mode */
+++	if (has_2500 && !has_sgmii) {
+++		mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
+++		phydev->rate_matching = RATE_MATCH_PAUSE;
+++	} else {
+++		mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
+++		phydev->rate_matching = RATE_MATCH_NONE;
+++	}
+++
+++	/* the following sequence with magic numbers sets up the SerDes
+++	 * option mode
+++	 */
+++	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
+++	if (ret < 0)
+++		return ret;
+++
+++	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
+++				     RTL822X_VND1_SERDES_OPTION,
+++				     RTL822X_VND1_SERDES_OPTION_MODE_MASK,
+++				     mode);
+++	if (ret < 0)
+++		return ret;
+++
+++	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
+++	if (ret < 0)
+++		return ret;
+++
+++	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
+++	if (ret < 0)
+++		return ret;
+++
+++	return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
+++}
+++
++ static int rtl822x_get_features(struct phy_device *phydev)
++ {
++ 	int val;
++@@ -657,6 +724,28 @@ static int rtl822x_config_aneg(struct ph
++ 	return __genphy_config_aneg(phydev, ret);
++ }
++ 
+++static void rtl822xb_update_interface(struct phy_device *phydev)
+++{
+++	int val;
+++
+++	if (!phydev->link)
+++		return;
+++
+++	/* Change interface according to serdes mode */
+++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
+++	if (val < 0)
+++		return;
+++
+++	switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
+++	case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
+++		phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+++		break;
+++	case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
+++		phydev->interface = PHY_INTERFACE_MODE_SGMII;
+++		break;
+++	}
+++}
+++
++ static int rtl822x_read_status(struct phy_device *phydev)
++ {
++ 	int ret;
++@@ -678,6 +767,19 @@ static int rtl822x_read_status(struct ph
++ 	return rtlgen_get_speed(phydev);
++ }
++ 
+++static int rtl822xb_read_status(struct phy_device *phydev)
+++{
+++	int ret;
+++
+++	ret = rtl822x_read_status(phydev);
+++	if (ret < 0)
+++		return ret;
+++
+++	rtl822xb_update_interface(phydev);
+++
+++	return 0;
+++}
+++
++ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
++ {
++ 	int val;
++@@ -936,7 +1038,8 @@ static struct phy_driver realtek_drvs[]
++ 		.name		= "RTL8226B_RTL8221B 2.5Gbps PHY",
++ 		.get_features	= rtl822x_get_features,
++ 		.config_aneg	= rtl822x_config_aneg,
++-		.read_status	= rtl822x_read_status,
+++		.config_init    = rtl822xb_config_init,
+++		.read_status	= rtl822xb_read_status,
++ 		.suspend	= genphy_suspend,
++ 		.resume		= rtlgen_resume,
++ 		.read_page	= rtl821x_read_page,
++@@ -958,7 +1061,8 @@ static struct phy_driver realtek_drvs[]
++ 		.name           = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++-		.read_status    = rtl822x_read_status,
+++		.config_init    = rtl822xb_config_init,
+++		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
++ 		.read_page      = rtl821x_read_page,
++@@ -968,7 +1072,8 @@ static struct phy_driver realtek_drvs[]
++ 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY",
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++-		.read_status    = rtl822x_read_status,
+++		.config_init    = rtl822xb_config_init,
+++		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
++ 		.read_page      = rtl821x_read_page,
++@@ -978,7 +1083,8 @@ static struct phy_driver realtek_drvs[]
++ 		.name           = "RTL8221B-VM-CG 2.5Gbps PHY",
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++-		.read_status    = rtl822x_read_status,
+++		.config_init    = rtl822xb_config_init,
+++		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
++ 		.read_page      = rtl821x_read_page,
+diff --git a/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch b/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch
+new file mode 100644
+index 0000000000..5eddd6cc18
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-2-net-phy-realtek-add-get_rate_matching-for-rtl822xb-P.patch
+@@ -0,0 +1,74 @@
++From c189dbd738243be6775bb6878366bf63e27bfd05 Mon Sep 17 00:00:00 2001
++From: Eric Woudstra <ericwouds@gmail.com>
++Date: Tue, 9 Apr 2024 09:30:12 +0200
++Subject: [PATCH] net: phy: realtek: add get_rate_matching() for rtl822xb PHYs
++
++Uses vendor register to determine if SerDes is setup in rate-matching mode.
++
++Rate-matching only supported when SerDes is set to 2500base-x.
++
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -688,6 +688,27 @@ static int rtl822xb_config_init(struct p
++ 	return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
++ }
++ 
+++static int rtl822xb_get_rate_matching(struct phy_device *phydev,
+++				      phy_interface_t iface)
+++{
+++	int val;
+++
+++	/* Only rate matching at 2500base-x */
+++	if (iface != PHY_INTERFACE_MODE_2500BASEX)
+++		return RATE_MATCH_NONE;
+++
+++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION);
+++	if (val < 0)
+++		return val;
+++
+++	if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) ==
+++	    RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX)
+++		return RATE_MATCH_PAUSE;
+++
+++	/* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */
+++	return RATE_MATCH_NONE;
+++}
+++
++ static int rtl822x_get_features(struct phy_device *phydev)
++ {
++ 	int val;
++@@ -1039,6 +1060,7 @@ static struct phy_driver realtek_drvs[]
++ 		.get_features	= rtl822x_get_features,
++ 		.config_aneg	= rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
++ 		.read_status	= rtl822xb_read_status,
++ 		.suspend	= genphy_suspend,
++ 		.resume		= rtlgen_resume,
++@@ -1062,6 +1084,7 @@ static struct phy_driver realtek_drvs[]
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
++ 		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
++@@ -1073,6 +1096,7 @@ static struct phy_driver realtek_drvs[]
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
++ 		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
++@@ -1084,6 +1108,7 @@ static struct phy_driver realtek_drvs[]
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
++ 		.read_status    = rtl822xb_read_status,
++ 		.suspend        = genphy_suspend,
++ 		.resume         = rtlgen_resume,
+diff --git a/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch b/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch
+new file mode 100644
+index 0000000000..ff80be2370
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-3-net-phy-realtek-Add-driver-instances-for-rtl8221b-vi.patch
+@@ -0,0 +1,215 @@
++From ad5ce743a6b0329f642d80be50ef7b534e908fba Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Tue, 9 Apr 2024 09:30:13 +0200
++Subject: [PATCH] net: phy: realtek: Add driver instances for rtl8221b via
++ Clause 45
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Collected from several commits in [PATCH net-next]
++"Realtek RTL822x PHY rework to c45 and SerDes interface switching"
++
++The instances are used by Clause 45 only accessible PHY's on several sfp
++modules, which are using RollBall protocol.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++[ Added matching functions to differentiate C45 instances ]
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -63,6 +63,13 @@
++ #define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII			0x02
++ #define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX		0x16
++ 
+++/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
+++ * is set, they cannot be accessed by C45-over-C22.
+++ */
+++#define RTL822X_VND2_GBCR				0xa412
+++
+++#define RTL822X_VND2_GANLPAR				0xa414
+++
++ #define RTL8366RB_POWER_SAVE			0x15
++ #define RTL8366RB_POWER_SAVE_ON			BIT(12)
++ 
++@@ -72,6 +79,9 @@
++ #define RTLGEN_SPEED_MASK			0x0630
++ 
++ #define RTL_GENERIC_PHYID			0x001cc800
+++#define RTL_8221B_VB_CG				0x001cc849
+++#define RTL_8221B_VN_CG				0x001cc84a
+++#define RTL_8251B				0x001cc862
++ 
++ MODULE_DESCRIPTION("Realtek PHY driver");
++ MODULE_AUTHOR("Johnson Leung");
++@@ -801,6 +811,67 @@ static int rtl822xb_read_status(struct p
++ 	return 0;
++ }
++ 
+++static int rtl822x_c45_config_aneg(struct phy_device *phydev)
+++{
+++	bool changed = false;
+++	int ret, val;
+++
+++	if (phydev->autoneg == AUTONEG_DISABLE)
+++		return genphy_c45_pma_setup_forced(phydev);
+++
+++	ret = genphy_c45_an_config_aneg(phydev);
+++	if (ret < 0)
+++		return ret;
+++	if (ret > 0)
+++		changed = true;
+++
+++	val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
+++
+++	/* Vendor register as C45 has no standardized support for 1000BaseT */
+++	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
+++				     ADVERTISE_1000FULL, val);
+++	if (ret < 0)
+++		return ret;
+++	if (ret > 0)
+++		changed = true;
+++
+++	return genphy_c45_check_and_restart_aneg(phydev, changed);
+++}
+++
+++static int rtl822x_c45_read_status(struct phy_device *phydev)
+++{
+++	int ret, val;
+++
+++	ret = genphy_c45_read_status(phydev);
+++	if (ret < 0)
+++		return ret;
+++
+++	/* Vendor register as C45 has no standardized support for 1000BaseT */
+++	if (phydev->autoneg == AUTONEG_ENABLE) {
+++		val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+++				   RTL822X_VND2_GANLPAR);
+++		if (val < 0)
+++			return val;
+++
+++		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
+++	}
+++
+++	return 0;
+++}
+++
+++static int rtl822xb_c45_read_status(struct phy_device *phydev)
+++{
+++	int ret;
+++
+++	ret = rtl822x_c45_read_status(phydev);
+++	if (ret < 0)
+++		return ret;
+++
+++	rtl822xb_update_interface(phydev);
+++
+++	return 0;
+++}
+++
++ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
++ {
++ 	int val;
++@@ -824,6 +895,35 @@ static int rtl8226_match_phy_device(stru
++ 	       rtlgen_supports_2_5gbps(phydev);
++ }
++ 
+++static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
+++			       bool is_c45)
+++{
+++	if (phydev->is_c45)
+++		return is_c45 && (id == phydev->c45_ids.device_ids[1]);
+++	else
+++		return !is_c45 && (id == phydev->phy_id);
+++}
+++
+++static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
+++{
+++	return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
+++}
+++
+++static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
+++{
+++	return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
+++}
+++
+++static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
+++{
+++	return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
+++}
+++
+++static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
+++{
+++	return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
+++}
+++
++ static int rtlgen_resume(struct phy_device *phydev)
++ {
++ 	int ret = genphy_resume(phydev);
++@@ -834,6 +934,15 @@ static int rtlgen_resume(struct phy_devi
++ 	return ret;
++ }
++ 
+++static int rtlgen_c45_resume(struct phy_device *phydev)
+++{
+++	int ret = genphy_c45_pma_resume(phydev);
+++
+++	msleep(20);
+++
+++	return ret;
+++}
+++
++ static int rtl9000a_config_init(struct phy_device *phydev)
++ {
++ 	phydev->autoneg = AUTONEG_DISABLE;
++@@ -1091,8 +1200,8 @@ static struct phy_driver realtek_drvs[]
++ 		.read_page      = rtl821x_read_page,
++ 		.write_page     = rtl821x_write_page,
++ 	}, {
++-		PHY_ID_MATCH_EXACT(0x001cc849),
++-		.name           = "RTL8221B-VB-CG 2.5Gbps PHY",
+++		.match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
+++		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
++@@ -1103,8 +1212,17 @@ static struct phy_driver realtek_drvs[]
++ 		.read_page      = rtl821x_read_page,
++ 		.write_page     = rtl821x_write_page,
++ 	}, {
++-		PHY_ID_MATCH_EXACT(0x001cc84a),
++-		.name           = "RTL8221B-VM-CG 2.5Gbps PHY",
+++		.match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
+++		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+++		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
+++		.config_aneg    = rtl822x_c45_config_aneg,
+++		.read_status    = rtl822xb_c45_read_status,
+++		.suspend        = genphy_c45_pma_suspend,
+++		.resume         = rtlgen_c45_resume,
+++	}, {
+++		.match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
+++		.name           = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
++ 		.get_features   = rtl822x_get_features,
++ 		.config_aneg    = rtl822x_config_aneg,
++ 		.config_init    = rtl822xb_config_init,
++@@ -1115,6 +1233,15 @@ static struct phy_driver realtek_drvs[]
++ 		.read_page      = rtl821x_read_page,
++ 		.write_page     = rtl821x_write_page,
++ 	}, {
+++		.match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
+++		.name           = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+++		.config_init    = rtl822xb_config_init,
+++		.get_rate_matching = rtl822xb_get_rate_matching,
+++		.config_aneg    = rtl822x_c45_config_aneg,
+++		.read_status    = rtl822xb_c45_read_status,
+++		.suspend        = genphy_c45_pma_suspend,
+++		.resume         = rtlgen_c45_resume,
+++	}, {
++ 		PHY_ID_MATCH_EXACT(0x001cc961),
++ 		.name		= "RTL8366RB Gigabit Ethernet",
++ 		.config_init	= &rtl8366rb_config_init,
+diff --git a/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch b/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch
+new file mode 100644
+index 0000000000..b832de6feb
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-4-net-phy-realtek-Change-rtlgen_get_speed-to-rtlgen_de.patch
+@@ -0,0 +1,122 @@
++From 2e4ea707c7e04eb83e58c43e0e744bbdf6b23ff2 Mon Sep 17 00:00:00 2001
++From: Eric Woudstra <ericwouds@gmail.com>
++Date: Tue, 9 Apr 2024 09:30:14 +0200
++Subject: [PATCH] net: phy: realtek: Change rtlgen_get_speed() to
++ rtlgen_decode_speed()
++
++The value of the register to determine the speed, is retrieved
++differently when using Clause 45 only. To use the rtlgen_get_speed()
++function in this case, pass the value of the register as argument to
++rtlgen_get_speed(). The function would then always return 0, so change it
++to void. A better name for this function now is rtlgen_decode_speed().
++
++Replace a call to genphy_read_status() followed by rtlgen_get_speed()
++with a call to rtlgen_read_status() in rtl822x_read_status().
++
++Add reading speed to rtl822x_c45_read_status().
++
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -70,6 +70,8 @@
++ 
++ #define RTL822X_VND2_GANLPAR				0xa414
++ 
+++#define RTL822X_VND2_PHYSR				0xa434
+++
++ #define RTL8366RB_POWER_SAVE			0x15
++ #define RTL8366RB_POWER_SAVE_ON			BIT(12)
++ 
++@@ -513,17 +515,8 @@ static int rtl8366rb_config_init(struct
++ }
++ 
++ /* get actual speed to cover the downshift case */
++-static int rtlgen_get_speed(struct phy_device *phydev)
+++static void rtlgen_decode_speed(struct phy_device *phydev, int val)
++ {
++-	int val;
++-
++-	if (!phydev->link)
++-		return 0;
++-
++-	val = phy_read_paged(phydev, 0xa43, 0x12);
++-	if (val < 0)
++-		return val;
++-
++ 	switch (val & RTLGEN_SPEED_MASK) {
++ 	case 0x0000:
++ 		phydev->speed = SPEED_10;
++@@ -546,19 +539,26 @@ static int rtlgen_get_speed(struct phy_d
++ 	default:
++ 		break;
++ 	}
++-
++-	return 0;
++ }
++ 
++ static int rtlgen_read_status(struct phy_device *phydev)
++ {
++-	int ret;
+++	int ret, val;
++ 
++ 	ret = genphy_read_status(phydev);
++ 	if (ret < 0)
++ 		return ret;
++ 
++-	return rtlgen_get_speed(phydev);
+++	if (!phydev->link)
+++		return 0;
+++
+++	val = phy_read_paged(phydev, 0xa43, 0x12);
+++	if (val < 0)
+++		return val;
+++
+++	rtlgen_decode_speed(phydev, val);
+++
+++	return 0;
++ }
++ 
++ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
++@@ -779,8 +779,6 @@ static void rtl822xb_update_interface(st
++ 
++ static int rtl822x_read_status(struct phy_device *phydev)
++ {
++-	int ret;
++-
++ 	if (phydev->autoneg == AUTONEG_ENABLE) {
++ 		int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
++ 
++@@ -791,11 +789,7 @@ static int rtl822x_read_status(struct ph
++ 						  lpadv);
++ 	}
++ 
++-	ret = genphy_read_status(phydev);
++-	if (ret < 0)
++-		return ret;
++-
++-	return rtlgen_get_speed(phydev);
+++	return rtlgen_read_status(phydev);
++ }
++ 
++ static int rtl822xb_read_status(struct phy_device *phydev)
++@@ -856,6 +850,16 @@ static int rtl822x_c45_read_status(struc
++ 		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
++ 	}
++ 
+++	if (!phydev->link)
+++		return 0;
+++
+++	/* Read actual speed from vendor register. */
+++	val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR);
+++	if (val < 0)
+++		return val;
+++
+++	rtlgen_decode_speed(phydev, val);
+++
++ 	return 0;
++ }
++ 
+diff --git a/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch b/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch
+new file mode 100644
+index 0000000000..21fefd8d21
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-5-net-phy-realtek-add-rtl822x_c45_get_features-to-set-.patch
+@@ -0,0 +1,45 @@
++From 2d9ce64862705b33397d54dafecc5f51d8b1bb06 Mon Sep 17 00:00:00 2001
++From: Eric Woudstra <ericwouds@gmail.com>
++Date: Tue, 9 Apr 2024 09:30:15 +0200
++Subject: [PATCH] net: phy: realtek: add rtl822x_c45_get_features() to set
++ supported port
++
++Sets ETHTOOL_LINK_MODE_TP_BIT in phydev->supported.
++
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/realtek.c
+++++ b/drivers/net/phy/realtek.c
++@@ -805,6 +805,14 @@ static int rtl822xb_read_status(struct p
++ 	return 0;
++ }
++ 
+++static int rtl822x_c45_get_features(struct phy_device *phydev)
+++{
+++	linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
+++			 phydev->supported);
+++
+++	return genphy_c45_pma_read_abilities(phydev);
+++}
+++
++ static int rtl822x_c45_config_aneg(struct phy_device *phydev)
++ {
++ 	bool changed = false;
++@@ -1220,6 +1228,7 @@ static struct phy_driver realtek_drvs[]
++ 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
++ 		.config_init    = rtl822xb_config_init,
++ 		.get_rate_matching = rtl822xb_get_rate_matching,
+++		.get_features   = rtl822x_c45_get_features,
++ 		.config_aneg    = rtl822x_c45_config_aneg,
++ 		.read_status    = rtl822xb_c45_read_status,
++ 		.suspend        = genphy_c45_pma_suspend,
++@@ -1241,6 +1250,7 @@ static struct phy_driver realtek_drvs[]
++ 		.name           = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
++ 		.config_init    = rtl822xb_config_init,
++ 		.get_rate_matching = rtl822xb_get_rate_matching,
+++		.get_features   = rtl822x_c45_get_features,
++ 		.config_aneg    = rtl822x_c45_config_aneg,
++ 		.read_status    = rtl822xb_c45_read_status,
++ 		.suspend        = genphy_c45_pma_suspend,
+diff --git a/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch b/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch
+new file mode 100644
+index 0000000000..f85443bdc6
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-10-6-net-sfp-add-quirk-for-another-multigig-RollBall-tran.patch
+@@ -0,0 +1,27 @@
++From 1c77c721916ae108c2c5865986735bfe92000908 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Tue, 9 Apr 2024 09:30:16 +0200
++Subject: [PATCH] net: sfp: add quirk for another multigig RollBall transceiver
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Add quirk for another RollBall copper transceiver: Turris RTSFP-2.5G,
++containing 2.5g capable RTL8221B PHY.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
++
++Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
++Signed-off-by: David S. Miller <davem@davemloft.net>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -509,6 +509,7 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
+++	SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball),
++ 	SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
++ 	SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball),
++ };
+diff --git a/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch b/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch
+new file mode 100644
+index 0000000000..0b96cfa5bb
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-11-1-net-sfp-update-comment-for-FS-SFP-10G-T-quirk.patch
+@@ -0,0 +1,30 @@
++From 92fadf3c4ef9a3d1b5bdc75d89366d2138e0ef12 Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Mon, 22 Apr 2024 11:19:09 +0200
++Subject: [PATCH] net: sfp: update comment for FS SFP-10G-T quirk
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Update the comment for the Fibrestore SFP-10G-T module: since commit
++e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module")
++we also do a 4 second wait before probing the PHY.
++
++Fixes: e9301af385e7 ("net: sfp: fix PHY discovery for FS SFP-10G-T module")
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++Reviewed-by: Andrew Lunn <andrew@lunn.ch>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -471,8 +471,9 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex,
++ 		  sfp_fixup_nokia),
++ 
++-	// Fiberstore SFP-10G-T doesn't identify as copper, and uses the
++-	// Rollball protocol to talk to the PHY.
+++	// Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball
+++	// protocol to talk to the PHY and needs 4 sec wait before probing the
+++	// PHY.
++ 	SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
++ 
++ 	// Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
+diff --git a/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch b/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch
+new file mode 100644
+index 0000000000..622f883baa
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-11-2-net-sfp-enhance-quirk-for-Fibrestore-2.5G-copper-SFP.patch
+@@ -0,0 +1,71 @@
++From dda80a7dd0819a758cf2ab0b20e40fbcb88091ca Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
++Date: Mon, 22 Apr 2024 11:09:29 +0200
++Subject: [PATCH] net: sfp: enhance quirk for Fibrestore 2.5G copper SFP module
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Enhance the quirk for Fibrestore 2.5G copper SFP module. The original
++commit e27aca3760c0 ("net: sfp: add quirk for FS's 2.5G copper SFP")
++introducing the quirk says that the PHY is inaccessible, but that is
++not true.
++
++The module uses Rollball protocol to talk to the PHY, and needs a 4
++second wait before probing it, same as FS 10G module.
++
++The PHY inside the module is Realtek RTL8221B-VB-CG PHY. The realtek
++driver recently gained support to set it up via clause 45 accesses.
++
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -387,18 +387,23 @@ static void sfp_fixup_rollball(struct sf
++ 	sfp->phy_t_retry = msecs_to_jiffies(1000);
++ }
++ 
++-static void sfp_fixup_fs_10gt(struct sfp *sfp)
+++static void sfp_fixup_fs_2_5gt(struct sfp *sfp)
++ {
++-	sfp_fixup_10gbaset_30m(sfp);
++ 	sfp_fixup_rollball(sfp);
++ 
++-	/* The RollBall fixup is not enough for FS modules, the AQR chip inside
+++	/* The RollBall fixup is not enough for FS modules, the PHY chip inside
++ 	 * them does not return 0xffff for PHY ID registers in all MMDs for the
++ 	 * while initializing. They need a 4 second wait before accessing PHY.
++ 	 */
++ 	sfp->module_t_wait = msecs_to_jiffies(4000);
++ }
++ 
+++static void sfp_fixup_fs_10gt(struct sfp *sfp)
+++{
+++	sfp_fixup_10gbaset_30m(sfp);
+++	sfp_fixup_fs_2_5gt(sfp);
+++}
+++
++ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
++ {
++ 	/* Ignore the TX_FAULT and LOS signals on this module.
++@@ -476,6 +481,10 @@ static const struct sfp_quirk sfp_quirks
++ 	// PHY.
++ 	SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt),
++ 
+++	// Fiberstore SFP-2.5G-T uses Rollball protocol to talk to the PHY and
+++	// needs 4 sec wait before probing the PHY.
+++	SFP_QUIRK_F("FS", "SFP-2.5G-T", sfp_fixup_fs_2_5gt),
+++
++ 	// Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
++ 	// NRZ in their EEPROM
++ 	SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex,
++@@ -492,9 +501,6 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
++ 		  sfp_fixup_ignore_tx_fault),
++ 
++-	// FS 2.5G Base-T
++-	SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
++-
++ 	// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
++ 	// 2500MBd NRZ in their EEPROM
++ 	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
+diff --git a/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch b/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch
+new file mode 100644
+index 0000000000..24e901413c
+--- /dev/null
++++ b/target/linux/mvebu/patches-5.15/707-12-net-sfp-add-quirk-for-ATS-SFP-GE-T-1000Base-TX-modul.patch
+@@ -0,0 +1,30 @@
++From e0237a52ec29fe07ef2c83d8e97dca91d9a270ce Mon Sep 17 00:00:00 2001
++From: Daniel Golle <daniel@makrotopia.org>
++Date: Tue, 23 Apr 2024 10:58:12 +0200
++Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Add quirk for ATS SFP-GE-T 1000Base-TX module.
++
++This copper module comes with broken TX_FAULT indicator which must be
++ignored for it to work.
++
++Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++[ rebased on top of net-next ]
++Signed-off-by: Marek BehĂşn <kabel@kernel.org>
++
++--- a/drivers/net/phy/sfp.c
+++++ b/drivers/net/phy/sfp.c
++@@ -512,6 +512,9 @@ static const struct sfp_quirk sfp_quirks
++ 	SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt),
++ 	SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt),
++ 
+++	// OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator
+++	SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault),
+++
++ 	SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
++ 	SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
++ 	SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
+-- 
+2.43.2
+
diff --git a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch b/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch
deleted file mode 100644
index 7c9221d24..000000000
--- a/patches/openwrt/wip/0012-TurrisSFP-9-mvebu-add-support-for-Turris-SFP-module.patch
+++ /dev/null
@@ -1,2297 +0,0 @@
-From 5c7fed78547688817c24ceac4f341e30830bcd26 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
-Date: Thu, 24 Sep 2020 00:28:51 +0200
-Subject: [PATCH 9/9] mvebu: add support for Turris SFP module
-
----
- target/linux/mvebu/config-5.15                |   1 +
- ...te-supported_interfaces-with-lower-m.patch | 144 ++++++
- ...-supported-PHY-interface-modes-to-ph.patch | 123 +++++
- ...ell10g-add-downshift-tunable-support.patch | 220 +++++++++
- ...0g-Use-generic-macro-for-supported-i.patch |  35 ++
- ...0g-Use-tabs-instead-of-spaces-for-in.patch |  51 ++
- ...0g-select-host-interface-configurati.patch | 242 ++++++++++
- ...w-attaching-phy-for-SFP-modules-on-8.patch |  48 ++
- ...estroy-I2C-mdiobus-before-PHY-probe-.patch | 181 ++++++++
- ...-support-I2C-MDIO-protocol-for-RollB.patch | 434 ++++++++++++++++++
- ...ort-for-multigig-RollBall-transceive.patch | 156 +++++++
- ...SFP-parsing-with-phy_interface_t-bit.patch | 340 ++++++++++++++
- ...phy_interface_t-bitmaps-for-optical-.patch | 203 ++++++++
- 13 files changed, 2178 insertions(+)
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
- create mode 100644 target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
-
-diff --git a/target/linux/mvebu/config-5.15 b/target/linux/mvebu/config-5.15
-index 0811ee6d4c..f3548c94b7 100644
---- a/target/linux/mvebu/config-5.15
-+++ b/target/linux/mvebu/config-5.15
-@@ -241,6 +241,7 @@ CONFIG_MACH_MVEBU_V7=y
- CONFIG_MAGIC_SYSRQ=y
- CONFIG_MANGLE_BOOTARGS=y
- CONFIG_MARVELL_PHY=y
-+CONFIG_MARVELL_10G_PHY=y
- CONFIG_MDIO_BUS=y
- CONFIG_MDIO_DEVICE=y
- CONFIG_MDIO_DEVRES=y
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch
-new file mode 100644
-index 0000000000..c0c274d278
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-01-net-phylink-update-supported_interfaces-with-lower-m.patch
-@@ -0,0 +1,144 @@
-+From e6ad7e8ac63cf2190a94af5e4d88f19c4353c1ba Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Thu, 4 Nov 2021 20:57:33 +0100
-+Subject: [PATCH 01/12] net: phylink: update supported_interfaces with lower
-+ modes
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Update the bitmap of interfaces supported by the MAC with lower modes
-+that should be supported if upper are.
-+
-+As Russell King says,
-+  conventionally phy-mode has meant "this is the mode we want to operate
-+  the PHY interface in" which was fine when PHYs didn't change their
-+  mode depending on the media speed
-+
-+An example is DT defining
-+  phy-mode = "sgmii";
-+but the board supporting also 1000base-x and 2500base-x.
-+
-+Add the following logic to keep this backwards compatiblity:
-+- if one PHY mode is defined:
-+  - if it is sgmii, 1000base-x or 2500base-x, add all three and then do
-+    the intersection
-+  - if it is 10gbase-r or usxgmii, add both, and also 5gbase-r,
-+    2500base-x, 1000base-x and sgmii, and then do the intersection
-+
-+This is simple enough and should work for all boards.
-+
-+Nonetheless it is possible (although extremely unlikely, in my opinion)
-+that a board will be found that (for example) defines
-+  phy-mode = "sgmii";
-+and the MAC drivers supports sgmii, 1000base-x and 2500base-x, but the
-+board DOESN'T support 2500base-x, because of electrical reasons (since
-+the frequency is 2.5x of sgmii).
-+Our code will in this case incorrectly infer also support for
-+2500base-x. To avoid this, the board maintainer should add a fix into
-+the function we are introducing in this commit.
-+
-+Another example would be a board with device-tree defining
-+  phy-mode = "10gbase-r";
-+We infer from this all other modes (sgmii, 1000base-x, 2500base-x,
-+5gbase-r, usxgmii), and these then get filtered by those supported by
-+the driver. But it is possible that a driver supports all of these
-+modes, and yet not all are supported because the board has an older
-+version of the TF-A firmware, which implements changing of PHY modes via
-+SMC calls. For this case, the board maintainer should add a fix into
-+this function that somehow checks for this situation. But this is a
-+really improbable scenario, in my opinion.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+---
-+ drivers/net/phy/phylink.c | 67 +++++++++++++++++++++++++++++++++++++++
-+ 1 file changed, 67 insertions(+)
-+
-+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
-+index 49eb7fd4ed51..fbcab015ff7d 100644
-+--- a/drivers/net/phy/phylink.c
-++++ b/drivers/net/phy/phylink.c
-+@@ -300,6 +300,71 @@ static int phylink_parse_fixedlink(struct phylink *pl,
-+ 	return 0;
-+ }
-+
-++static void phylink_update_phy_modes(struct phylink *pl,
-++				     struct fwnode_handle *fwnode)
-++{
-++	unsigned long *supported = pl->config->supported_interfaces;
-++	DECLARE_PHY_INTERFACE_MASK(modes);
-++
-++	/* FIXME: If supported is empty, leave it as it is. This happens for
-++	 * unconverted drivers that don't fill up supported_interfaces. Once all
-++	 * such drivers are converted, we can drop this.
-++	 */
-++	if (phy_interface_empty(supported))
-++		return;
-++
-++	/* If no modes are defined in fwnode, interpret it as all modes
-++	 * supported by the MAC are supported by the board.
-++	 */
-++	if (phy_interface_empty(modes))
-++		return;
-++
-++	/* We want the intersection of given supported modes with those defined
-++	 * in DT.
-++	 *
-++	 * Some older device-trees mention only one of `sgmii`, `1000base-x` or
-++	 * `2500base-x`, while supporting all three. Other mention `10gbase-r`
-++	 * or `usxgmii`, while supporting both, and also `sgmii`, `1000base-x`,
-++	 * `2500base-x` and `5gbase-r`.
-++	 * For backwards compatibility with these older DTs, make it so that if
-++	 * one of these modes is mentioned in DT and MAC supports more of them,
-++	 * keep all that are supported according to the logic above.
-++	 *
-++	 * Nonetheless it is possible that a device may support only one mode,
-++	 * for example 1000base-x, due to strapping pins or some other reasons.
-++	 * If a specific device supports only the mode mentioned in DT, the
-++	 * exception should be made here with of_machine_is_compatible().
-++	 */
-++	if (bitmap_weight(modes, PHY_INTERFACE_MODE_MAX) == 1) {
-++		DECLARE_PHY_INTERFACE_MASK(mask);
-++		bool lower = false;
-++
-++		if (test_bit(PHY_INTERFACE_MODE_10GBASER, modes) ||
-++		    test_bit(PHY_INTERFACE_MODE_USXGMII, modes)) {
-++			phy_interface_zero(mask);
-++			__set_bit(PHY_INTERFACE_MODE_5GBASER, mask);
-++			__set_bit(PHY_INTERFACE_MODE_10GBASER, mask);
-++			__set_bit(PHY_INTERFACE_MODE_USXGMII, mask);
-++			phy_interface_and(mask, supported, mask);
-++			phy_interface_or(modes, modes, mask);
-++			lower = true;
-++		}
-++
-++		if (lower || (test_bit(PHY_INTERFACE_MODE_SGMII, modes) ||
-++			      test_bit(PHY_INTERFACE_MODE_1000BASEX, modes) ||
-++			      test_bit(PHY_INTERFACE_MODE_2500BASEX, modes))) {
-++			phy_interface_zero(mask);
-++			__set_bit(PHY_INTERFACE_MODE_SGMII, mask);
-++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, mask);
-++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, mask);
-++			phy_interface_and(mask, supported, mask);
-++			phy_interface_or(modes, modes, mask);
-++		}
-++	}
-++
-++	phy_interface_and(supported, supported, modes);
-++}
-++
-+ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
-+ {
-+ 	struct fwnode_handle *dn;
-+@@ -911,6 +976,8 @@ struct phylink *phylink_create(struct phylink_config *config,
-+ 	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
-+ 	timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
-+
-++	phylink_update_phy_modes(pl, fwnode);
-++
-+ 	bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
-+ 	linkmode_copy(pl->link_config.advertising, pl->supported);
-+ 	phylink_validate(pl, pl->supported, &pl->link_config);
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch
-new file mode 100644
-index 0000000000..a528045987
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-02-net-phylink-pass-supported-PHY-interface-modes-to-ph.patch
-@@ -0,0 +1,123 @@
-+From 3b7db3ec50d7ccc39ab98b592a2f0bdeee632cc1 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Mon, 22 Nov 2021 21:39:41 +0100
-+Subject: [PATCH 02/12] net: phylink: pass supported PHY interface modes to
-+ phylib
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Pass the supported PHY interface types to phylib so that PHY drivers
-+can select an appropriate host configuration mode for their interface
-+according to the host capabilities.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-+---
-+ drivers/net/phy/phylink.c | 28 ++++++++++++++++++++++++++++
-+ include/linux/phy.h       | 10 ++++++++++
-+ 2 files changed, 38 insertions(+)
-+
-+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
-+index fbcab015ff7d..9d248802253a 100644
-+--- a/drivers/net/phy/phylink.c
-++++ b/drivers/net/phy/phylink.c
-+@@ -1195,6 +1195,10 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
-+ 		pl->link_config.interface = pl->link_interface;
-+ 	}
-+
-++	/* Set the PHY's host supported interfaces */
-++	phy_interface_copy(phy->host_interfaces,
-++			   pl->config->supported_interfaces);
-++
-+ 	ret = phylink_attach_phy(pl, phy, pl->link_interface);
-+ 	if (ret < 0)
-+ 		return ret;
-+@@ -1264,6 +1268,10 @@ int phylink_fwnode_phy_connect(struct phylink *pl,
-+ 	if (!phy_dev)
-+ 		return -ENODEV;
-+
-++	/* Set the PHY's host supported interfaces */
-++	phy_interface_copy(phy_dev->host_interfaces,
-++			   pl->config->supported_interfaces);
-++
-+ 	ret = phy_attach_direct(pl->netdev, phy_dev, flags,
-+ 				pl->link_interface);
-+ 	if (ret) {
-+@@ -2448,6 +2456,8 @@ static bool phylink_phy_no_inband(struct phy_device *phy)
-+ 		(phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
-+ }
-+
-++static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
-++
-+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
-+ {
-+ 	struct phylink *pl = upstream;
-+@@ -2469,6 +2479,10 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
-+ 	else
-+ 		mode = MLO_AN_INBAND;
-+
-++	/* Set the PHY's host supported interfaces */
-++	phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
-++			  pl->config->supported_interfaces);
-++
-+ 	/* Do the initial configuration */
-+ 	ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising);
-+ 	if (ret < 0)
-+@@ -2852,4 +2866,18 @@ void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs,
-+ }
-+ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
-+
-++static int __init phylink_init(void)
-++{
-++	__set_bit(PHY_INTERFACE_MODE_USXGMII, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_10GBASER, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_5GBASER, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_2500BASEX, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_SGMII, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_1000BASEX, phylink_sfp_interfaces);
-++	__set_bit(PHY_INTERFACE_MODE_100BASEX, phylink_sfp_interfaces);
-++
-++	return 0;
-++}
-++module_init(phylink_init);
-++
-+ MODULE_LICENSE("GPL v2");
-+diff --git a/include/linux/phy.h b/include/linux/phy.h
-+index c270e6b3c3f6..4262f49c1eae 100644
-+--- a/include/linux/phy.h
-++++ b/include/linux/phy.h
-+@@ -169,6 +169,12 @@ static inline bool phy_interface_empty(const unsigned long *intf)
-+ 	return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX);
-+ }
-+
-++static inline void phy_interface_copy(unsigned long *dst,
-++				      const unsigned long *src)
-++{
-++	bitmap_copy(dst, src, PHY_INTERFACE_MODE_MAX);
-++}
-++
-+ static inline void phy_interface_and(unsigned long *dst, const unsigned long *a,
-+ 				     const unsigned long *b)
-+ {
-+@@ -563,6 +569,7 @@ struct macsec_ops;
-+  * @advertising: Currently advertised linkmodes
-+  * @adv_old: Saved advertised while power saving for WoL
-+  * @lp_advertising: Current link partner advertised linkmodes
-++ * @host_interfaces: PHY interface modes supported by host
-+  * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
-+  * @autoneg: Flag autoneg being used
-+  * @link: Current link state
-+@@ -658,6 +665,9 @@ struct phy_device {
-+ 	/* used with phy_speed_down */
-+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
-+
-++	/* host supported PHY interface types */
-++	DECLARE_PHY_INTERFACE_MASK(host_interfaces);
-++
-+ 	/* Energy efficient ethernet modes which should be prohibited */
-+ 	u32 eee_broken_modes;
-+
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch
-new file mode 100644
-index 0000000000..4ccb537861
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-03-net-phy-marvell10g-add-downshift-tunable-support.patch
-@@ -0,0 +1,220 @@
-+From b09b1757932fb02420dcb29933bc8d15f9797403 Mon Sep 17 00:00:00 2001
-+From: Russell King <rmk+kernel@armlinux.org.uk>
-+Date: Wed, 29 Sep 2021 16:28:53 +0100
-+Subject: [PATCH 03/12] net: phy: marvell10g: add downshift tunable support
-+
-+Add support for the downshift tunable for the Marvell 88x3310 PHY.
-+Downshift is only usable with firmware 0.3.5.0 and later.
-+
-+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ drivers/net/phy/marvell10g.c | 107 ++++++++++++++++++++++++++++++++++-
-+ 1 file changed, 106 insertions(+), 1 deletion(-)
-+
-+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
-+index df33637c5269..2b7d0720720b 100644
-+--- a/drivers/net/phy/marvell10g.c
-++++ b/drivers/net/phy/marvell10g.c
-+@@ -22,6 +22,7 @@
-+  * If both the fiber and copper ports are connected, the first to gain
-+  * link takes priority and the other port is completely locked out.
-+  */
-++#include <linux/bitfield.h>
-+ #include <linux/ctype.h>
-+ #include <linux/delay.h>
-+ #include <linux/hwmon.h>
-+@@ -33,6 +34,8 @@
-+ #define MV_PHY_ALASKA_NBT_QUIRK_MASK	0xfffffffe
-+ #define MV_PHY_ALASKA_NBT_QUIRK_REV	(MARVELL_PHY_ID_88X3310 | 0xa)
-+
-++#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
-++
-+ enum {
-+ 	MV_PMA_FW_VER0		= 0xc011,
-+ 	MV_PMA_FW_VER1		= 0xc012,
-+@@ -62,6 +65,15 @@ enum {
-+ 	MV_PCS_CSCR1_MDIX_MDIX	= 0x0020,
-+ 	MV_PCS_CSCR1_MDIX_AUTO	= 0x0060,
-+
-++	MV_PCS_DSC1		= 0x8003,
-++	MV_PCS_DSC1_ENABLE	= BIT(9),
-++	MV_PCS_DSC1_10GBT	= 0x01c0,
-++	MV_PCS_DSC1_1GBR	= 0x0038,
-++	MV_PCS_DSC1_100BTX	= 0x0007,
-++	MV_PCS_DSC2		= 0x8004,
-++	MV_PCS_DSC2_2P5G	= 0xf000,
-++	MV_PCS_DSC2_5G		= 0x0f00,
-++
-+ 	MV_PCS_CSSR1		= 0x8008,
-+ 	MV_PCS_CSSR1_SPD1_MASK	= 0xc000,
-+ 	MV_PCS_CSSR1_SPD1_SPD2	= 0xc000,
-+@@ -125,6 +137,7 @@ enum {
-+ };
-+
-+ struct mv3310_chip {
-++	bool (*has_downshift)(struct phy_device *phydev);
-+ 	void (*init_supported_interfaces)(unsigned long *mask);
-+ 	int (*get_mactype)(struct phy_device *phydev);
-+ 	int (*init_interface)(struct phy_device *phydev, int mactype);
-+@@ -138,6 +151,7 @@ struct mv3310_priv {
-+ 	DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
-+
-+ 	u32 firmware_ver;
-++	bool has_downshift;
-+ 	bool rate_match;
-+ 	phy_interface_t const_interface;
-+
-+@@ -330,6 +344,71 @@ static int mv3310_reset(struct phy_device *phydev, u32 unit)
-+ 					 5000, 100000, true);
-+ }
-+
-++static int mv3310_get_downshift(struct phy_device *phydev, u8 *ds)
-++{
-++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-++	int val;
-++
-++	if (!priv->has_downshift)
-++		return -EOPNOTSUPP;
-++
-++	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1);
-++	if (val < 0)
-++		return val;
-++
-++	if (val & MV_PCS_DSC1_ENABLE)
-++		/* assume that all fields are the same */
-++		*ds = 1 + FIELD_GET(MV_PCS_DSC1_10GBT, (u16)val);
-++	else
-++		*ds = DOWNSHIFT_DEV_DISABLE;
-++
-++	return 0;
-++}
-++
-++static int mv3310_set_downshift(struct phy_device *phydev, u8 ds)
-++{
-++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-++	u16 val;
-++	int err;
-++
-++	if (!priv->has_downshift)
-++		return -EOPNOTSUPP;
-++
-++	if (ds == DOWNSHIFT_DEV_DISABLE)
-++		return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
-++					  MV_PCS_DSC1_ENABLE);
-++
-++	/* DOWNSHIFT_DEV_DEFAULT_COUNT is confusing. It looks like it should
-++	 * set the default settings for the PHY. However, it is used for
-++	 * "ethtool --set-phy-tunable ethN downshift on". The intention is
-++	 * to enable downshift at a default number of retries. The default
-++	 * settings for 88x3310 are for two retries with downshift disabled.
-++	 * So let's use two retries with downshift enabled.
-++	 */
-++	if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT)
-++		ds = 2;
-++
-++	if (ds > 8)
-++		return -E2BIG;
-++
-++	ds -= 1;
-++	val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds);
-++	val |= FIELD_PREP(MV_PCS_DSC2_5G, ds);
-++	err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2,
-++			     MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val);
-++	if (err < 0)
-++		return err;
-++
-++	val = MV_PCS_DSC1_ENABLE;
-++	val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds);
-++	val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds);
-++	val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds);
-++
-++	return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
-++			      MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT |
-++			      MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val);
-++}
-++
-+ static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd)
-+ {
-+ 	int val;
-+@@ -448,6 +527,9 @@ static int mv3310_probe(struct phy_device *phydev)
-+ 		    priv->firmware_ver >> 24, (priv->firmware_ver >> 16) & 255,
-+ 		    (priv->firmware_ver >> 8) & 255, priv->firmware_ver & 255);
-+
-++	if (chip->has_downshift)
-++		priv->has_downshift = chip->has_downshift(phydev);
-++
-+ 	/* Powering down the port when not in use saves about 600mW */
-+ 	ret = mv3310_power_down(phydev);
-+ 	if (ret)
-+@@ -616,7 +698,16 @@ static int mv3310_config_init(struct phy_device *phydev)
-+ 	}
-+
-+ 	/* Enable EDPD mode - saving 600mW */
-+-	return mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
-++	err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
-++	if (err)
-++		return err;
-++
-++	/* Allow downshift */
-++	err = mv3310_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT);
-++	if (err && err != -EOPNOTSUPP)
-++		return err;
-++
-++	return 0;
-+ }
-+
-+ static int mv3310_get_features(struct phy_device *phydev)
-+@@ -886,6 +977,8 @@ static int mv3310_get_tunable(struct phy_device *phydev,
-+ 			      struct ethtool_tunable *tuna, void *data)
-+ {
-+ 	switch (tuna->id) {
-++	case ETHTOOL_PHY_DOWNSHIFT:
-++		return mv3310_get_downshift(phydev, data);
-+ 	case ETHTOOL_PHY_EDPD:
-+ 		return mv3310_get_edpd(phydev, data);
-+ 	default:
-+@@ -897,6 +990,8 @@ static int mv3310_set_tunable(struct phy_device *phydev,
-+ 			      struct ethtool_tunable *tuna, const void *data)
-+ {
-+ 	switch (tuna->id) {
-++	case ETHTOOL_PHY_DOWNSHIFT:
-++		return mv3310_set_downshift(phydev, *(u8 *)data);
-+ 	case ETHTOOL_PHY_EDPD:
-+ 		return mv3310_set_edpd(phydev, *(u16 *)data);
-+ 	default:
-+@@ -904,6 +999,14 @@ static int mv3310_set_tunable(struct phy_device *phydev,
-+ 	}
-+ }
-+
-++static bool mv3310_has_downshift(struct phy_device *phydev)
-++{
-++	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-++
-++	/* Fails to downshift with firmware older than v0.3.5.0 */
-++	return priv->firmware_ver >= MV_VERSION(0,3,5,0);
-++}
-++
-+ static void mv3310_init_supported_interfaces(unsigned long *mask)
-+ {
-+ 	__set_bit(PHY_INTERFACE_MODE_SGMII, mask);
-+@@ -943,6 +1046,7 @@ static void mv2111_init_supported_interfaces(unsigned long *mask)
-+ }
-+
-+ static const struct mv3310_chip mv3310_type = {
-++	.has_downshift = mv3310_has_downshift,
-+ 	.init_supported_interfaces = mv3310_init_supported_interfaces,
-+ 	.get_mactype = mv3310_get_mactype,
-+ 	.init_interface = mv3310_init_interface,
-+@@ -953,6 +1057,7 @@ static const struct mv3310_chip mv3310_type = {
-+ };
-+
-+ static const struct mv3310_chip mv3340_type = {
-++	.has_downshift = mv3310_has_downshift,
-+ 	.init_supported_interfaces = mv3340_init_supported_interfaces,
-+ 	.get_mactype = mv3310_get_mactype,
-+ 	.init_interface = mv3340_init_interface,
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch
-new file mode 100644
-index 0000000000..76f3479f3a
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-04-net-phy-marvell10g-Use-generic-macro-for-supported-i.patch
-@@ -0,0 +1,35 @@
-+From 9a4f26cb3e71400555c0c3a7edbcbd0d29fd4464 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Thu, 4 Nov 2021 17:25:25 +0100
-+Subject: [PATCH 04/12] net: phy: marvell10g: Use generic macro for supported
-+ interfaces
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Now that phy.h defines macro DECLARE_PHY_INTERFACE_MASK(), use it
-+instead of DECLARE_BITMAP().
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-+---
-+ drivers/net/phy/marvell10g.c | 2 +-
-+ 1 file changed, 1 insertion(+), 1 deletion(-)
-+
-+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
-+index 2b7d0720720b..6e8de692c0f5 100644
-+--- a/drivers/net/phy/marvell10g.c
-++++ b/drivers/net/phy/marvell10g.c
-+@@ -148,7 +148,7 @@ struct mv3310_chip {
-+ };
-+
-+ struct mv3310_priv {
-+-	DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
-++	DECLARE_PHY_INTERFACE_MASK(supported_interfaces);
-+
-+ 	u32 firmware_ver;
-+ 	bool has_downshift;
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
-new file mode 100644
-index 0000000000..2d931ba43e
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-05-net-phy-marvell10g-Use-tabs-instead-of-spaces-for-in.patch
-@@ -0,0 +1,51 @@
-+From fe4dc078a329618d3a14bec90d365942953e9a47 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Thu, 4 Nov 2021 17:26:35 +0100
-+Subject: [PATCH 05/12] net: phy: marvell10g: Use tabs instead of spaces for
-+ indentation
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Some register definitions were defined with spaces used for indentation.
-+Change them to tabs.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-+---
-+ drivers/net/phy/marvell10g.c | 18 +++++++++---------
-+ 1 file changed, 9 insertions(+), 9 deletions(-)
-+
-+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
-+index 6e8de692c0f5..2249f737beaf 100644
-+--- a/drivers/net/phy/marvell10g.c
-++++ b/drivers/net/phy/marvell10g.c
-+@@ -117,16 +117,16 @@ enum {
-+ 	MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN	= 0x5,
-+ 	MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH	= 0x6,
-+ 	MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII			= 0x7,
-+-	MV_V2_PORT_INTR_STS     = 0xf040,
-+-	MV_V2_PORT_INTR_MASK    = 0xf043,
-+-	MV_V2_PORT_INTR_STS_WOL_EN      = BIT(8),
-+-	MV_V2_MAGIC_PKT_WORD0   = 0xf06b,
-+-	MV_V2_MAGIC_PKT_WORD1   = 0xf06c,
-+-	MV_V2_MAGIC_PKT_WORD2   = 0xf06d,
-++	MV_V2_PORT_INTR_STS		= 0xf040,
-++	MV_V2_PORT_INTR_MASK		= 0xf043,
-++	MV_V2_PORT_INTR_STS_WOL_EN	= BIT(8),
-++	MV_V2_MAGIC_PKT_WORD0		= 0xf06b,
-++	MV_V2_MAGIC_PKT_WORD1		= 0xf06c,
-++	MV_V2_MAGIC_PKT_WORD2		= 0xf06d,
-+ 	/* Wake on LAN registers */
-+-	MV_V2_WOL_CTRL          = 0xf06e,
-+-	MV_V2_WOL_CTRL_CLEAR_STS        = BIT(15),
-+-	MV_V2_WOL_CTRL_MAGIC_PKT_EN     = BIT(0),
-++	MV_V2_WOL_CTRL			= 0xf06e,
-++	MV_V2_WOL_CTRL_CLEAR_STS	= BIT(15),
-++	MV_V2_WOL_CTRL_MAGIC_PKT_EN	= BIT(0),
-+ 	/* Temperature control/read registers (88X3310 only) */
-+ 	MV_V2_TEMP_CTRL		= 0xf08a,
-+ 	MV_V2_TEMP_CTRL_MASK	= 0xc000,
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch
-new file mode 100644
-index 0000000000..b40e361036
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-06-net-phy-marvell10g-select-host-interface-configurati.patch
-@@ -0,0 +1,242 @@
-+From 18cdeb60b63e4362df32da136ece815b38c3031e Mon Sep 17 00:00:00 2001
-+From: Russell King <rmk+kernel@armlinux.org.uk>
-+Date: Thu, 4 Nov 2021 23:23:38 +0100
-+Subject: [PATCH 06/12] net: phy: marvell10g: select host interface
-+ configuration
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Select the host interface configuration according to the capabilities of
-+the host.
-+
-+The PHY supports several configurations of host communication:
-+- always communicate with host in 10gbase-r, even if copper speed is
-+  lower (rate matching mode),
-+- the same as above but use xaui/rxaui instead of 10gbase-r,
-+- switch host SerDes mode between 10gbase-r, 5gbase-r, 2500base-x and
-+  sgmii according to copper speed,
-+- the same as above but use xaui/rxaui instead of 10gbase-r.
-+
-+This mode of host communication, called MACTYPE, is by default selected
-+by strapping pins, but it can be changed in software.
-+
-+This adds support for selecting this mode according to which modes are
-+supported by the host.
-+
-+This allows the kernel to:
-+- support SFP modules with 88X33X0 or 88E21X0 inside them
-+- switch interface modes when the PHY is used with the mvpp2 MAC
-+  (e.g. on MacchiatoBIN)
-+
-+Note: we use mv3310_select_mactype() for both 88X3310 and 88X3340,
-+although 88X3340 does not support XAUI. This is not a problem because
-+88X3340 does not declare XAUI in it's supported_interfaces, and so this
-+function will never choose that MACTYPE.
-+
-+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-+[ rebase, updated, also added support for 88E21X0 ]
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+---
-+ drivers/net/phy/marvell10g.c | 120 +++++++++++++++++++++++++++++++++--
-+ 1 file changed, 115 insertions(+), 5 deletions(-)
-+
-+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
-+index 2249f737beaf..b16e67b352bf 100644
-+--- a/drivers/net/phy/marvell10g.c
-++++ b/drivers/net/phy/marvell10g.c
-+@@ -96,6 +96,11 @@ enum {
-+ 	MV_PCS_PORT_INFO_NPORTS_MASK	= 0x0380,
-+ 	MV_PCS_PORT_INFO_NPORTS_SHIFT	= 7,
-+
-++	/* SerDes reinitialization 88E21X0 */
-++	MV_AN_21X0_SERDES_CTRL2	= 0x800f,
-++	MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS	= BIT(13),
-++	MV_AN_21X0_SERDES_CTRL2_RUN_INIT	= BIT(15),
-++
-+ 	/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
-+ 	 * registers appear to set themselves to the 0x800X when AN is
-+ 	 * restarted, but status registers appear readable from either.
-+@@ -140,6 +145,8 @@ struct mv3310_chip {
-+ 	bool (*has_downshift)(struct phy_device *phydev);
-+ 	void (*init_supported_interfaces)(unsigned long *mask);
-+ 	int (*get_mactype)(struct phy_device *phydev);
-++	int (*set_mactype)(struct phy_device *phydev, int mactype);
-++	int (*select_mactype)(unsigned long *interfaces);
-+ 	int (*init_interface)(struct phy_device *phydev, int mactype);
-+
-+ #ifdef CONFIG_HWMON
-+@@ -593,6 +600,49 @@ static int mv2110_get_mactype(struct phy_device *phydev)
-+ 	return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
-+ }
-+
-++static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
-++{
-++	int err, val;
-++
-++	mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
-++	err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
-++			     MV_PMA_21X0_PORT_CTRL_SWRST |
-++			     MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
-++			     MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
-++	if (err)
-++		return err;
-++
-++	err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
-++			       MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
-++			       MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
-++	if (err)
-++		return err;
-++
-++	err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
-++					MV_AN_21X0_SERDES_CTRL2, val,
-++					!(val &
-++					  MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
-++					5000, 100000, true);
-++	if (err)
-++		return err;
-++
-++	return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
-++				  MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
-++}
-++
-++static int mv2110_select_mactype(unsigned long *interfaces)
-++{
-++	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
-++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
-++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
-++		 !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
-++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
-++	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
-++		return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
-++	else
-++		return -1;
-++}
-++
-+ static int mv3310_get_mactype(struct phy_device *phydev)
-+ {
-+ 	int mactype;
-+@@ -604,6 +654,46 @@ static int mv3310_get_mactype(struct phy_device *phydev)
-+ 	return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
-+ }
-+
-++static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
-++{
-++	int ret;
-++
-++	mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
-++	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
-++				     MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
-++				     mactype);
-++	if (ret <= 0)
-++		return ret;
-++
-++	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
-++				MV_V2_33X0_PORT_CTRL_SWRST);
-++}
-++
-++static int mv3310_select_mactype(unsigned long *interfaces)
-++{
-++	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
-++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
-++		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
-++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
-++		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
-++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
-++		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
-++		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
-++	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
-++	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
-++	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
-++		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
-++	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
-++		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
-++	else
-++		return -1;
-++}
-++
-+ static int mv2110_init_interface(struct phy_device *phydev, int mactype)
-+ {
-+ 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-+@@ -674,10 +764,16 @@ static int mv3310_config_init(struct phy_device *phydev)
-+ {
-+ 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-+ 	const struct mv3310_chip *chip = to_mv3310_chip(phydev);
-++	DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ 	int err, mactype;
-+
-+-	/* Check that the PHY interface type is compatible */
-+-	if (!test_bit(phydev->interface, priv->supported_interfaces))
-++	/* In case host didn't provide supported interfaces */
-++	__set_bit(phydev->interface, phydev->host_interfaces);
-++
-++	/* Check that there is at least one compatible PHY interface type */
-++	phy_interface_and(interfaces, phydev->host_interfaces,
-++			  priv->supported_interfaces);
-++	if (phy_interface_empty(interfaces))
-+ 		return -ENODEV;
-+
-+ 	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
-+@@ -687,9 +783,15 @@ static int mv3310_config_init(struct phy_device *phydev)
-+ 	if (err)
-+ 		return err;
-+
-+-	mactype = chip->get_mactype(phydev);
-+-	if (mactype < 0)
-+-		return mactype;
-++	mactype = chip->select_mactype(interfaces);
-++	if (mactype < 0) {
-++		mactype = chip->get_mactype(phydev);
-++	} else {
-++		phydev_info(phydev, "Changing MACTYPE to %i\n", mactype);
-++		err = chip->set_mactype(phydev, mactype);
-++		if (err)
-++			return err;
-++	}
-+
-+ 	err = chip->init_interface(phydev, mactype);
-+ 	if (err) {
-+@@ -1049,6 +1151,8 @@ static const struct mv3310_chip mv3310_type = {
-+ 	.has_downshift = mv3310_has_downshift,
-+ 	.init_supported_interfaces = mv3310_init_supported_interfaces,
-+ 	.get_mactype = mv3310_get_mactype,
-++	.set_mactype = mv3310_set_mactype,
-++	.select_mactype = mv3310_select_mactype,
-+ 	.init_interface = mv3310_init_interface,
-+
-+ #ifdef CONFIG_HWMON
-+@@ -1060,6 +1164,8 @@ static const struct mv3310_chip mv3340_type = {
-+ 	.has_downshift = mv3310_has_downshift,
-+ 	.init_supported_interfaces = mv3340_init_supported_interfaces,
-+ 	.get_mactype = mv3310_get_mactype,
-++	.set_mactype = mv3310_set_mactype,
-++	.select_mactype = mv3310_select_mactype,
-+ 	.init_interface = mv3340_init_interface,
-+
-+ #ifdef CONFIG_HWMON
-+@@ -1070,6 +1176,8 @@ static const struct mv3310_chip mv3340_type = {
-+ static const struct mv3310_chip mv2110_type = {
-+ 	.init_supported_interfaces = mv2110_init_supported_interfaces,
-+ 	.get_mactype = mv2110_get_mactype,
-++	.set_mactype = mv2110_set_mactype,
-++	.select_mactype = mv2110_select_mactype,
-+ 	.init_interface = mv2110_init_interface,
-+
-+ #ifdef CONFIG_HWMON
-+@@ -1080,6 +1188,8 @@ static const struct mv3310_chip mv2110_type = {
-+ static const struct mv3310_chip mv2111_type = {
-+ 	.init_supported_interfaces = mv2111_init_supported_interfaces,
-+ 	.get_mactype = mv2110_get_mactype,
-++	.set_mactype = mv2110_set_mactype,
-++	.select_mactype = mv2110_select_mactype,
-+ 	.init_interface = mv2110_init_interface,
-+
-+ #ifdef CONFIG_HWMON
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
-new file mode 100644
-index 0000000000..bd9f2b6ae0
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-07-net-phylink-allow-attaching-phy-for-SFP-modules-on-8.patch
-@@ -0,0 +1,48 @@
-+From 3f8b2734f1df8dc6f4f619d8f165d70fdea25232 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Sun, 10 Jan 2021 00:29:41 +0100
-+Subject: [PATCH 07/12] net: phylink: allow attaching phy for SFP modules on
-+ 802.3z mode
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Some SFPs may contain an internal PHY which may in some cases want to
-+connect with the host interface in 1000base-x/2500base-x mode.
-+Do not fail if such PHY is being attached in one of these PHY interface
-+modes.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk>
-+Reviewed-by: Pali Rohár <pali@kernel.org>
-+Cc: Andrew Lunn <andrew@lunn.ch>
-+---
-+ drivers/net/phy/phylink.c | 5 +----
-+ 1 file changed, 1 insertion(+), 4 deletions(-)
-+
-+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
-+index 9d248802253a..f1fad9e18d03 100644
-+--- a/drivers/net/phy/phylink.c
-++++ b/drivers/net/phy/phylink.c
-+@@ -1161,7 +1161,7 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
-+ {
-+ 	if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
-+ 		    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
-+-		     phy_interface_mode_is_8023z(interface))))
-++		     phy_interface_mode_is_8023z(interface) && !pl->sfp_bus)))
-+ 		return -EINVAL;
-+
-+ 	if (pl->phydev)
-+@@ -2347,9 +2347,6 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
-+ 		    phylink_an_mode_str(mode), phy_modes(config.interface),
-+ 		    __ETHTOOL_LINK_MODE_MASK_NBITS, support);
-+
-+-	if (phy_interface_mode_is_8023z(iface) && pl->phydev)
-+-		return -EINVAL;
-+-
-+ 	changed = !linkmode_equal(pl->supported, support) ||
-+ 		  !linkmode_equal(pl->link_config.advertising,
-+ 				  config.advertising);
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
-new file mode 100644
-index 0000000000..8ce0a3fcd0
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-08-net-sfp-create-destroy-I2C-mdiobus-before-PHY-probe-.patch
-@@ -0,0 +1,181 @@
-+From 36941751c1ebc9b8d755c49688e7e4637cbc25ea Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Thu, 4 Nov 2021 23:58:53 +0100
-+Subject: [PATCH 08/12] net: sfp: create/destroy I2C mdiobus before PHY
-+ probe/after PHY release
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Instead of configuring the I2C mdiobus when SFP driver is probed,
-+create/destroy the mdiobus before the PHY is probed for/after it is
-+released.
-+
-+This way we can tell the mdio-i2c code which protocol to use for each
-+SFP transceiver.
-+
-+Move the code that determines MDIO I2C protocol from
-+sfp_sm_probe_for_phy() to sfp_sm_mod_probe(), where most of the SFP ID
-+parsing is done. Don't allocate I2C bus if no PHY is expected.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+---
-+ drivers/net/phy/sfp.c         | 64 ++++++++++++++++++++++++++++-------
-+ include/linux/mdio/mdio-i2c.h |  6 ++++
-+ 2 files changed, 57 insertions(+), 13 deletions(-)
-+
-+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
-+index 1df5d5008ab2..5932addfc5d9 100644
-+--- a/drivers/net/phy/sfp.c
-++++ b/drivers/net/phy/sfp.c
-+@@ -218,6 +218,7 @@ struct sfp {
-+ 	struct i2c_adapter *i2c;
-+ 	struct mii_bus *i2c_mii;
-+ 	struct sfp_bus *sfp_bus;
-++	enum mdio_i2c_proto mdio_protocol;
-+ 	struct phy_device *mod_phy;
-+ 	const struct sff_data *type;
-+ 	size_t i2c_block_size;
-+@@ -532,9 +533,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
-+
-+ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
-+ {
-+-	struct mii_bus *i2c_mii;
-+-	int ret;
-+-
-+ 	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
-+ 		return -EINVAL;
-+
-+@@ -542,7 +540,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
-+ 	sfp->read = sfp_i2c_read;
-+ 	sfp->write = sfp_i2c_write;
-+
-+-	i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
-++	return 0;
-++}
-++
-++static int sfp_i2c_mdiobus_create(struct sfp *sfp)
-++{
-++	struct mii_bus *i2c_mii;
-++	int ret;
-++
-++	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c);
-+ 	if (IS_ERR(i2c_mii))
-+ 		return PTR_ERR(i2c_mii);
-+
-+@@ -560,6 +566,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
-+ 	return 0;
-+ }
-+
-++static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
-++{
-++	mdiobus_unregister(sfp->i2c_mii);
-++	sfp->i2c_mii = NULL;
-++}
-++
-+ /* Interface */
-+ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
-+ {
-+@@ -1724,6 +1736,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
-+ 	}
-+ }
-+
-++static int sfp_sm_add_mdio_bus(struct sfp *sfp)
-++{
-++	if (sfp->mdio_protocol != MDIO_I2C_NONE)
-++		return sfp_i2c_mdiobus_create(sfp);
-++
-++	return 0;
-++}
-++
-+ /* Probe a SFP for a PHY device if the module supports copper - the PHY
-+  * normally sits at I2C bus address 0x56, and may either be a clause 22
-+  * or clause 45 PHY.
-+@@ -1739,19 +1759,19 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
-+ {
-+ 	int err = 0;
-+
-+-	switch (sfp->id.base.extended_cc) {
-+-	case SFF8024_ECC_10GBASE_T_SFI:
-+-	case SFF8024_ECC_10GBASE_T_SR:
-+-	case SFF8024_ECC_5GBASE_T:
-+-	case SFF8024_ECC_2_5GBASE_T:
-+-		err = sfp_sm_probe_phy(sfp, true);
-++	switch (sfp->mdio_protocol) {
-++	case MDIO_I2C_NONE:
-+ 		break;
-+
-+-	default:
-+-		if (sfp->id.base.e1000_base_t)
-+-			err = sfp_sm_probe_phy(sfp, false);
-++	case MDIO_I2C_MARVELL_C22:
-++		err = sfp_sm_probe_phy(sfp, false);
-++		break;
-++
-++	case MDIO_I2C_C45:
-++		err = sfp_sm_probe_phy(sfp, true);
-+ 		break;
-+ 	}
-++
-+ 	return err;
-+ }
-+
-+@@ -2073,6 +2093,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
-+ 	if (sfp->quirk && sfp->quirk->fixup)
-+ 		sfp->quirk->fixup(sfp);
-+
-++	if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
-++	    sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
-++	    sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T ||
-++	    sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T)
-++		sfp->mdio_protocol = MDIO_I2C_C45;
-++	else if (sfp->id.base.e1000_base_t)
-++		sfp->mdio_protocol = MDIO_I2C_MARVELL_C22;
-++	else
-++		sfp->mdio_protocol = MDIO_I2C_NONE;
-++
-+ 	return 0;
-+ }
-+
-+@@ -2244,6 +2274,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
-+ 			sfp_module_stop(sfp->sfp_bus);
-+ 		if (sfp->mod_phy)
-+ 			sfp_sm_phy_detach(sfp);
-++		if (sfp->i2c_mii)
-++			sfp_i2c_mdiobus_destroy(sfp);
-+ 		sfp_module_tx_disable(sfp);
-+ 		sfp_soft_stop_poll(sfp);
-+ 		sfp_sm_next(sfp, SFP_S_DOWN, 0);
-+@@ -2306,6 +2338,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
-+ 				     sfp->sm_fault_retries == N_FAULT_INIT);
-+ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
-+ 	init_done:
-++			/* Create mdiobus and start trying for PHY */
-++			ret = sfp_sm_add_mdio_bus(sfp);
-++			if (ret < 0) {
-++				sfp_sm_next(sfp, SFP_S_FAIL, 0);
-++				break;
-++			}
-+ 			sfp->sm_phy_retries = R_PHY_RETRY;
-+ 			goto phy_probe;
-+ 		}
-+diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h
-+index b1d27f7cd23f..3bde1a555a49 100644
-+--- a/include/linux/mdio/mdio-i2c.h
-++++ b/include/linux/mdio/mdio-i2c.h
-+@@ -11,6 +11,12 @@ struct device;
-+ struct i2c_adapter;
-+ struct mii_bus;
-+
-++enum mdio_i2c_proto {
-++	MDIO_I2C_NONE,
-++	MDIO_I2C_MARVELL_C22,
-++	MDIO_I2C_C45,
-++};
-++
-+ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
-+
-+ #endif
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
-new file mode 100644
-index 0000000000..2806501dd0
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-09-net-phy-mdio-i2c-support-I2C-MDIO-protocol-for-RollB.patch
-@@ -0,0 +1,434 @@
-+From afa187b54a94c9a2de7873c2c78accd195bcb60c Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Mon, 11 Jan 2021 05:36:26 +0100
-+Subject: [PATCH 09/12] net: phy: mdio-i2c: support I2C MDIO protocol for
-+ RollBall SFP modules
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Some multigig SFPs from RollBall and Hilink do not expose functional
-+MDIO access to the internal PHY of the SFP via I2C address 0x56
-+(although there seems to be read-only clause 22 access on this address).
-+
-+Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced
-+Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be
-+selected to 3 and the password must be filled with 0xff bytes for this
-+PHY communication to work.
-+
-+This extends the mdio-i2c driver to support this protocol by adding a
-+special parameter to mdio_i2c_alloc function via which this RollBall
-+protocol can be selected.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Cc: Andrew Lunn <andrew@lunn.ch>
-+Cc: Russell King <rmk+kernel@armlinux.org.uk>
-+---
-+ drivers/net/mdio/mdio-i2c.c   | 310 +++++++++++++++++++++++++++++++++-
-+ drivers/net/phy/sfp.c         |   6 +-
-+ include/linux/mdio/mdio-i2c.h |   4 +-
-+ 3 files changed, 313 insertions(+), 7 deletions(-)
-+
-+diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c
-+index 09200a70b315..bf8bf5e20faf 100644
-+--- a/drivers/net/mdio/mdio-i2c.c
-++++ b/drivers/net/mdio/mdio-i2c.c
-+@@ -3,6 +3,7 @@
-+  * MDIO I2C bridge
-+  *
-+  * Copyright (C) 2015-2016 Russell King
-++ * Copyright (C) 2021 Marek Behun
-+  *
-+  * Network PHYs can appear on I2C buses when they are part of SFP module.
-+  * This driver exposes these PHYs to the networking PHY code, allowing
-+@@ -12,6 +13,7 @@
-+ #include <linux/i2c.h>
-+ #include <linux/mdio/mdio-i2c.h>
-+ #include <linux/phy.h>
-++#include <linux/sfp.h>
-+
-+ /*
-+  * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
-+@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id)
-+ 	return phy_id + 0x40;
-+ }
-+
-+-static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
-++static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg)
-+ {
-+ 	struct i2c_adapter *i2c = bus->priv;
-+ 	struct i2c_msg msgs[2];
-+@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
-+ 	return data[0] << 8 | data[1];
-+ }
-+
-+-static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
-++static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg,
-++				 u16 val)
-+ {
-+ 	struct i2c_adapter *i2c = bus->priv;
-+ 	struct i2c_msg msg;
-+@@ -91,9 +94,288 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
-+ 	return ret < 0 ? ret : 0;
-+ }
-+
-+-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
-++/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
-++ * instead via address 0x51, when SFP page is set to 0x03 and password to
-++ * 0xffffffff.
-++ *
-++ * address  size  contents  description
-++ * -------  ----  --------  -----------
-++ * 0x80     1     CMD       0x01/0x02/0x04 for write/read/done
-++ * 0x81     1     DEV       Clause 45 device
-++ * 0x82     2     REG       Clause 45 register
-++ * 0x84     2     VAL       Register value
-++ */
-++#define ROLLBALL_PHY_I2C_ADDR		0x51
-++
-++#define ROLLBALL_PASSWORD		(SFP_VSL + 3)
-++
-++#define ROLLBALL_CMD_ADDR		0x80
-++#define ROLLBALL_DATA_ADDR		0x81
-++
-++#define ROLLBALL_CMD_WRITE		0x01
-++#define ROLLBALL_CMD_READ		0x02
-++#define ROLLBALL_CMD_DONE		0x04
-++
-++#define SFP_PAGE_ROLLBALL_MDIO		3
-++
-++static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs,
-++			      int num)
-++{
-++	int ret;
-++
-++	ret = __i2c_transfer(i2c, msgs, num);
-++	if (ret < 0)
-++		return ret;
-++	else if (ret != num)
-++		return -EIO;
-++	else
-++		return 0;
-++}
-++
-++static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr,
-++				   u8 *page)
-++{
-++	struct i2c_msg msgs[2];
-++	u8 addr = SFP_PAGE;
-++
-++	msgs[0].addr = bus_addr;
-++	msgs[0].flags = 0;
-++	msgs[0].len = 1;
-++	msgs[0].buf = &addr;
-++
-++	msgs[1].addr = bus_addr;
-++	msgs[1].flags = I2C_M_RD;
-++	msgs[1].len = 1;
-++	msgs[1].buf = page;
-++
-++	return __i2c_transfer_err(i2c, msgs, 2);
-++}
-++
-++static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr,
-++				   u8 page)
-++{
-++	struct i2c_msg msg;
-++	u8 buf[2];
-++
-++	buf[0] = SFP_PAGE;
-++	buf[1] = page;
-++
-++	msg.addr = bus_addr;
-++	msg.flags = 0;
-++	msg.len = 2;
-++	msg.buf = buf;
-++
-++	return __i2c_transfer_err(i2c, &msg, 1);
-++}
-++
-++/* In order to not interfere with other SFP code (which possibly may manipulate
-++ * SFP_PAGE), for every transfer we do this:
-++ *   1. lock the bus
-++ *   2. save content of SFP_PAGE
-++ *   3. set SFP_PAGE to 3
-++ *   4. do the transfer
-++ *   5. restore original SFP_PAGE
-++ *   6. unlock the bus
-++ * Note that one might think that steps 2 to 5 could be theoretically done all
-++ * in one call to i2c_transfer (by constructing msgs array in such a way), but
-++ * unfortunately tests show that this does not work :-( Changed SFP_PAGE does
-++ * not take into account until i2c_transfer() is done.
-++ */
-++static int i2c_transfer_rollball(struct i2c_adapter *i2c,
-++				 struct i2c_msg *msgs, int num)
-++{
-++	int ret, main_err = 0;
-++	u8 saved_page;
-++
-++	i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
-++
-++	/* save original page */
-++	ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
-++	if (ret)
-++		goto unlock;
-++
-++	/* change to RollBall MDIO page */
-++	ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
-++	if (ret)
-++		goto unlock;
-++
-++	/* do the transfer; we try to restore original page if this fails */
-++	ret = __i2c_transfer_err(i2c, msgs, num);
-++	if (ret)
-++		main_err = ret;
-++
-++	/* restore original page */
-++	ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page);
-++
-++unlock:
-++	i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
-++
-++	return main_err ? : ret;
-++}
-++
-++static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
-++				 size_t len)
-++{
-++	struct i2c_adapter *i2c = bus->priv;
-++	struct i2c_msg msgs[2];
-++	u8 cmd_addr, tmp, *res;
-++	int i, ret;
-++
-++	cmd_addr = ROLLBALL_CMD_ADDR;
-++
-++	res = buf ? buf : &tmp;
-++	len = buf ? len : 1;
-++
-++	msgs[0].addr = bus_addr;
-++	msgs[0].flags = 0;
-++	msgs[0].len = 1;
-++	msgs[0].buf = &cmd_addr;
-++
-++	msgs[1].addr = bus_addr;
-++	msgs[1].flags = I2C_M_RD;
-++	msgs[1].len = len;
-++	msgs[1].buf = res;
-++
-++	/* By experiment it takes up to 70 ms to access a register for these
-++	 * SFPs. Sleep 20ms between iterations and try 10 times.
-++	 */
-++	i = 10;
-++	do {
-++		msleep(20);
-++
-++		ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
-++		if (ret)
-++			return ret;
-++
-++		if (*res == ROLLBALL_CMD_DONE)
-++			return 0;
-++	} while (i-- > 0);
-++
-++	dev_dbg(&bus->dev, "poll timed out\n");
-++
-++	return -ETIMEDOUT;
-++}
-++
-++static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd,
-++				u8 *data, size_t len)
-++{
-++	struct i2c_adapter *i2c = bus->priv;
-++	struct i2c_msg msgs[2];
-++	u8 cmdbuf[2];
-++
-++	cmdbuf[0] = ROLLBALL_CMD_ADDR;
-++	cmdbuf[1] = cmd;
-++
-++	msgs[0].addr = bus_addr;
-++	msgs[0].flags = 0;
-++	msgs[0].len = len;
-++	msgs[0].buf = data;
-++
-++	msgs[1].addr = bus_addr;
-++	msgs[1].flags = 0;
-++	msgs[1].len = sizeof(cmdbuf);
-++	msgs[1].buf = cmdbuf;
-++
-++	return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
-++}
-++
-++static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg)
-++{
-++	u8 buf[4], res[6];
-++	int bus_addr, ret;
-++	u16 val;
-++
-++	if (!(reg & MII_ADDR_C45))
-++		return -EOPNOTSUPP;
-++
-++	bus_addr = i2c_mii_phy_addr(phy_id);
-++	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
-++		return 0xffff;
-++
-++	buf[0] = ROLLBALL_DATA_ADDR;
-++	buf[1] = (reg >> 16) & 0x1f;
-++	buf[2] = (reg >> 8) & 0xff;
-++	buf[3] = reg & 0xff;
-++
-++	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf,
-++				   sizeof(buf));
-++	if (ret < 0)
-++		return ret;
-++
-++	ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res));
-++	if (ret == -ETIMEDOUT)
-++		return 0xffff;
-++	else if (ret < 0)
-++		return ret;
-++
-++	val = res[4] << 8 | res[5];
-++
-++	return val;
-++}
-++
-++static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg,
-++				  u16 val)
-++{
-++	int bus_addr, ret;
-++	u8 buf[6];
-++
-++	if (!(reg & MII_ADDR_C45))
-++		return -EOPNOTSUPP;
-++
-++	bus_addr = i2c_mii_phy_addr(phy_id);
-++	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
-++		return 0;
-++
-++	buf[0] = ROLLBALL_DATA_ADDR;
-++	buf[1] = (reg >> 16) & 0x1f;
-++	buf[2] = (reg >> 8) & 0xff;
-++	buf[3] = reg & 0xff;
-++	buf[4] = val >> 8;
-++	buf[5] = val & 0xff;
-++
-++	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf,
-++				   sizeof(buf));
-++	if (ret < 0)
-++		return ret;
-++
-++	ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0);
-++	if (ret < 0)
-++		return ret;
-++
-++	return 0;
-++}
-++
-++static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
-++{
-++	struct i2c_msg msg;
-++	u8 pw[5];
-++	int ret;
-++
-++	pw[0] = ROLLBALL_PASSWORD;
-++	pw[1] = 0xff;
-++	pw[2] = 0xff;
-++	pw[3] = 0xff;
-++	pw[4] = 0xff;
-++
-++	msg.addr = ROLLBALL_PHY_I2C_ADDR;
-++	msg.flags = 0;
-++	msg.len = sizeof(pw);
-++	msg.buf = pw;
-++
-++	ret = i2c_transfer(i2c, &msg, 1);
-++	if (ret < 0)
-++		return ret;
-++	else if (ret != 1)
-++		return -EIO;
-++	else
-++		return 0;
-++}
-++
-++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
-++			       enum mdio_i2c_proto protocol)
-+ {
-+ 	struct mii_bus *mii;
-++	int ret;
-+
-+ 	if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
-+ 		return ERR_PTR(-EINVAL);
-+@@ -104,10 +386,28 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
-+
-+ 	snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
-+ 	mii->parent = parent;
-+-	mii->read = i2c_mii_read;
-+-	mii->write = i2c_mii_write;
-+ 	mii->priv = i2c;
-+
-++	switch (protocol) {
-++	case MDIO_I2C_ROLLBALL:
-++		ret = i2c_mii_init_rollball(i2c);
-++		if (ret < 0) {
-++			dev_err(parent,
-++				"Cannot initialize RollBall MDIO I2C protocol: %d\n",
-++				ret);
-++			mdiobus_free(mii);
-++			return ERR_PTR(ret);
-++		}
-++
-++		mii->read = i2c_mii_read_rollball;
-++		mii->write = i2c_mii_write_rollball;
-++		break;
-++	default:
-++		mii->read = i2c_mii_read_default;
-++		mii->write = i2c_mii_write_default;
-++		break;
-++	}
-++
-+ 	return mii;
-+ }
-+ EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
-+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
-+index 5932addfc5d9..b2c8c640ac96 100644
-+--- a/drivers/net/phy/sfp.c
-++++ b/drivers/net/phy/sfp.c
-+@@ -548,7 +548,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp)
-+ 	struct mii_bus *i2c_mii;
-+ 	int ret;
-+
-+-	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c);
-++	i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
-+ 	if (IS_ERR(i2c_mii))
-+ 		return PTR_ERR(i2c_mii);
-+
-+@@ -1770,6 +1770,10 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
-+ 	case MDIO_I2C_C45:
-+ 		err = sfp_sm_probe_phy(sfp, true);
-+ 		break;
-++
-++	case MDIO_I2C_ROLLBALL:
-++		err = -EOPNOTSUPP;
-++		break;
-+ 	}
-+
-+ 	return err;
-+diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h
-+index 3bde1a555a49..65b550a6fc32 100644
-+--- a/include/linux/mdio/mdio-i2c.h
-++++ b/include/linux/mdio/mdio-i2c.h
-+@@ -15,8 +15,10 @@ enum mdio_i2c_proto {
-+ 	MDIO_I2C_NONE,
-+ 	MDIO_I2C_MARVELL_C22,
-+ 	MDIO_I2C_C45,
-++	MDIO_I2C_ROLLBALL,
-+ };
-+
-+-struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
-++struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
-++			       enum mdio_i2c_proto protocol);
-+
-+ #endif
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch
-new file mode 100644
-index 0000000000..1d775870a1
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-10-net-sfp-add-support-for-multigig-RollBall-transceive.patch
-@@ -0,0 +1,156 @@
-+From 4997e61943215ab7940ca633def47f743edc8970 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
-+Date: Fri, 5 Nov 2021 00:21:19 +0100
-+Subject: [PATCH 10/12] net: sfp: add support for multigig RollBall
-+ transceivers
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+This adds support for multigig copper SFP modules from RollBall/Hilink.
-+These modules have a specific way to access clause 45 registers of the
-+internal PHY.
-+
-+We also need to wait at least 22 seconds after deasserting TX disable
-+before accessing the PHY. The code waits for 25 seconds just to be sure.
-+
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk>
-+---
-+ drivers/net/phy/sfp-bus.c |  6 ++++++
-+ drivers/net/phy/sfp.c     | 41 ++++++++++++++++++++++++++++-----------
-+ 2 files changed, 36 insertions(+), 11 deletions(-)
-+
-+diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
-+index 0a9099c77694..22dba5895ef6 100644
-+--- a/drivers/net/phy/sfp-bus.c
-++++ b/drivers/net/phy/sfp-bus.c
-+@@ -130,6 +130,12 @@ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
-+ 		}
-+ 	}
-+
-++	if (((!memcmp(id->base.vendor_name, "OEM             ", 16) ||
-++	      !memcmp(id->base.vendor_name, "Turris          ", 16)) &&
-++	     (!memcmp(id->base.vendor_pn, "SFP-10G-T       ", 16) ||
-++	      !memcmp(id->base.vendor_pn, "RTSFP-10", 8))))
-++		return true;
-++
-+ 	return false;
-+ }
-+ EXPORT_SYMBOL_GPL(sfp_may_have_phy);
-+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
-+index b2c8c640ac96..49e69f1d9b1b 100644
-+--- a/drivers/net/phy/sfp.c
-++++ b/drivers/net/phy/sfp.c
-+@@ -166,6 +166,7 @@ static const enum gpiod_flags gpio_flags[] = {
-+  * on board (for a copper SFP) time to initialise.
-+  */
-+ #define T_WAIT			msecs_to_jiffies(50)
-++#define T_WAIT_ROLLBALL		msecs_to_jiffies(25000)
-+ #define T_START_UP		msecs_to_jiffies(300)
-+ #define T_START_UP_BAD_GPON	msecs_to_jiffies(60000)
-+
-+@@ -205,8 +206,11 @@ static const enum gpiod_flags gpio_flags[] = {
-+
-+ /* SFP modules appear to always have their PHY configured for bus address
-+  * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
-++ * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface
-++ * via address 0x51 (mdio-i2c will use RollBall protocol on this address).
-+  */
-+-#define SFP_PHY_ADDR	22
-++#define SFP_PHY_ADDR		22
-++#define SFP_PHY_ADDR_ROLLBALL	17
-+
-+ struct sff_data {
-+ 	unsigned int gpios;
-+@@ -252,6 +256,7 @@ struct sfp {
-+ 	struct sfp_eeprom_id id;
-+ 	unsigned int module_power_mW;
-+ 	unsigned int module_t_start_up;
-++	unsigned int module_t_wait;
-+ 	bool tx_fault_ignore;
-+
-+ 	const struct sfp_quirk *quirk;
-+@@ -1636,12 +1641,12 @@ static void sfp_sm_phy_detach(struct sfp *sfp)
-+ 	sfp->mod_phy = NULL;
-+ }
-+
-+-static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
-++static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
-+ {
-+ 	struct phy_device *phy;
-+ 	int err;
-+
-+-	phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
-++	phy = get_phy_device(sfp->i2c_mii, addr, is_c45);
-+ 	if (phy == ERR_PTR(-ENODEV))
-+ 		return PTR_ERR(phy);
-+ 	if (IS_ERR(phy)) {
-+@@ -1764,15 +1769,15 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
-+ 		break;
-+
-+ 	case MDIO_I2C_MARVELL_C22:
-+-		err = sfp_sm_probe_phy(sfp, false);
-++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, false);
-+ 		break;
-+
-+ 	case MDIO_I2C_C45:
-+-		err = sfp_sm_probe_phy(sfp, true);
-++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR, true);
-+ 		break;
-+
-+ 	case MDIO_I2C_ROLLBALL:
-+-		err = -EOPNOTSUPP;
-++		err = sfp_sm_probe_phy(sfp, SFP_PHY_ADDR_ROLLBALL, true);
-+ 		break;
-+ 	}
-+
-+@@ -2097,7 +2102,20 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
-+ 	if (sfp->quirk && sfp->quirk->fixup)
-+ 		sfp->quirk->fixup(sfp);
-+
-+-	if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
-++	sfp->module_t_wait = T_WAIT;
-++
-++	if (((!memcmp(id.base.vendor_name, "OEM             ", 16) ||
-++	      !memcmp(id.base.vendor_name, "Turris          ", 16)) &&
-++	     (!memcmp(id.base.vendor_pn, "SFP-10G-T       ", 16) ||
-++	      !memcmp(id.base.vendor_pn, "RTSFP-10", 8)))) {
-++		sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
-++		sfp->module_t_wait = T_WAIT_ROLLBALL;
-++
-++		/* RollBall SFPs may have wrong (zero) extended compliance code
-++		 * burned in EEPROM. For PHY probing we need the correct one.
-++		 */
-++		id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI;
-++	} else if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
-+ 	    sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
-+ 	    sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T ||
-+ 	    sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T)
-+@@ -2303,9 +2321,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
-+
-+ 		/* We need to check the TX_FAULT state, which is not defined
-+ 		 * while TX_DISABLE is asserted. The earliest we want to do
-+-		 * anything (such as probe for a PHY) is 50ms.
-++		 * anything (such as probe for a PHY) is 50ms (or more on
-++		 * specific modules).
-+ 		 */
-+-		sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
-++		sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait);
-+ 		break;
-+
-+ 	case SFP_S_WAIT:
-+@@ -2319,8 +2338,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
-+ 			 * deasserting.
-+ 			 */
-+ 			timeout = sfp->module_t_start_up;
-+-			if (timeout > T_WAIT)
-+-				timeout -= T_WAIT;
-++			if (timeout > sfp->module_t_wait)
-++				timeout -= sfp->module_t_wait;
-+ 			else
-+ 				timeout = 1;
-+
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
-new file mode 100644
-index 0000000000..bda0114281
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-11-net-sfp-augment-SFP-parsing-with-phy_interface_t-bit.patch
-@@ -0,0 +1,340 @@
-+From abdd0ad38b4e970f98600cdde9de37e2dbbcad5f Mon Sep 17 00:00:00 2001
-+From: Russell King <rmk+kernel@armlinux.org.uk>
-+Date: Tue, 3 Mar 2020 11:57:39 +0000
-+Subject: [PATCH 11/12] net: sfp: augment SFP parsing with phy_interface_t
-+ bitmap
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+We currently parse the SFP EEPROM to a bitmap of ethtool link modes,
-+and then attempt to convert the link modes to a PHY interface mode.
-+While this works at present, there are cases where this is sub-optimal.
-+For example, where a module can operate with several different PHY
-+interface modes.
-+
-+To start addressing this, arrange for the SFP EEPROM parsing to also
-+provide a bitmap of the possible PHY interface modes.
-+
-+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-+[ added 5gbase-r interface ]
-+Signed-off-by: Marek BehĂşn <kabel@kernel.org>
-+---
-+ drivers/net/phy/marvell-88x2222.c |  3 +-
-+ drivers/net/phy/marvell.c         |  3 +-
-+ drivers/net/phy/marvell10g.c      |  3 +-
-+ drivers/net/phy/phylink.c         |  4 +-
-+ drivers/net/phy/sfp-bus.c         | 68 +++++++++++++++++++++++--------
-+ drivers/net/phy/sfp.c             |  7 +++-
-+ drivers/net/phy/sfp.h             |  3 +-
-+ include/linux/sfp.h               |  5 ++-
-+ 8 files changed, 71 insertions(+), 25 deletions(-)
-+
-+diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c
-+index d8b31d4d2a73..ae285e4225d6 100644
-+--- a/drivers/net/phy/marvell-88x2222.c
-++++ b/drivers/net/phy/marvell-88x2222.c
-+@@ -478,6 +478,7 @@ static int mv2222_config_init(struct phy_device *phydev)
-+
-+ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+ {
-++	DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ 	struct phy_device *phydev = upstream;
-+ 	phy_interface_t sfp_interface;
-+ 	struct mv2222_data *priv;
-+@@ -489,7 +490,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+ 	priv = (struct mv2222_data *)phydev->priv;
-+ 	dev = &phydev->mdio.dev;
-+
-+-	sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
-++	sfp_parse_support(phydev->sfp_bus, id, sfp_supported, interfaces);
-+ 	sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
-+
-+ 	dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
-+diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
-+index 4d726ee03ce2..288befc9f44b 100644
-+--- a/drivers/net/phy/marvell.c
-++++ b/drivers/net/phy/marvell.c
-+@@ -2806,6 +2806,7 @@ static int marvell_probe(struct phy_device *phydev)
-+
-+ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+ {
-++	DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ 	struct phy_device *phydev = upstream;
-+ 	phy_interface_t interface;
-+ 	struct device *dev;
-+@@ -2817,7 +2818,7 @@ static int m88e1510_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+
-+ 	dev = &phydev->mdio.dev;
-+
-+-	sfp_parse_support(phydev->sfp_bus, id, supported);
-++	sfp_parse_support(phydev->sfp_bus, id, supported, interfaces);
-+ 	interface = sfp_select_interface(phydev->sfp_bus, supported);
-+
-+ 	dev_info(dev, "%s SFP module inserted\n", phy_modes(interface));
-+diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
-+index b16e67b352bf..c07d51907418 100644
-+--- a/drivers/net/phy/marvell10g.c
-++++ b/drivers/net/phy/marvell10g.c
-+@@ -473,9 +473,10 @@ static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+ {
-+ 	struct phy_device *phydev = upstream;
-+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
-++	DECLARE_PHY_INTERFACE_MASK(interfaces);
-+ 	phy_interface_t iface;
-+
-+-	sfp_parse_support(phydev->sfp_bus, id, support);
-++	sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
-+ 	iface = sfp_select_interface(phydev->sfp_bus, support);
-+
-+ 	if (iface != PHY_INTERFACE_MODE_10GBASER) {
-+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
-+index f1fad9e18d03..7d0b7a2e69d8 100644
-+--- a/drivers/net/phy/phylink.c
-++++ b/drivers/net/phy/phylink.c
-+@@ -77,6 +77,7 @@ struct phylink {
-+
-+ 	struct sfp_bus *sfp_bus;
-+ 	bool sfp_may_have_phy;
-++	DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
-+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
-+ 	u8 sfp_port;
-+ };
-+@@ -2385,7 +2386,8 @@ static int phylink_sfp_module_insert(void *upstream,
-+ 	ASSERT_RTNL();
-+
-+ 	linkmode_zero(support);
-+-	sfp_parse_support(pl->sfp_bus, id, support);
-++	phy_interface_zero(pl->sfp_interfaces);
-++	sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces);
-+ 	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
-+
-+ 	/* If this module may have a PHY connecting later, defer until later */
-+diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
-+index 22dba5895ef6..98af41843cce 100644
-+--- a/drivers/net/phy/sfp-bus.c
-++++ b/drivers/net/phy/sfp-bus.c
-+@@ -145,12 +145,14 @@ EXPORT_SYMBOL_GPL(sfp_may_have_phy);
-+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
-+  * @id: a pointer to the module's &struct sfp_eeprom_id
-+  * @support: pointer to an array of unsigned long for the ethtool support mask
-++ * @interfaces: pointer to an array of unsigned long for phy interface modes
-++ *		mask
-+  *
-+  * Parse the EEPROM identification information and derive the supported
-+  * ethtool link modes for the module.
-+  */
-+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+-		       unsigned long *support)
-++		       unsigned long *support, unsigned long *interfaces)
-+ {
-+ 	unsigned int br_min, br_nom, br_max;
-+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
-+@@ -177,27 +179,41 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 	}
-+
-+ 	/* Set ethtool support from the compliance fields. */
-+-	if (id->base.e10g_base_sr)
-++	if (id->base.e10g_base_sr) {
-+ 		phylink_set(modes, 10000baseSR_Full);
-+-	if (id->base.e10g_base_lr)
-++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++	}
-++	if (id->base.e10g_base_lr) {
-+ 		phylink_set(modes, 10000baseLR_Full);
-+-	if (id->base.e10g_base_lrm)
-++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++	}
-++	if (id->base.e10g_base_lrm) {
-+ 		phylink_set(modes, 10000baseLRM_Full);
-+-	if (id->base.e10g_base_er)
-++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++	}
-++	if (id->base.e10g_base_er) {
-+ 		phylink_set(modes, 10000baseER_Full);
-++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++	}
-+ 	if (id->base.e1000_base_sx ||
-+ 	    id->base.e1000_base_lx ||
-+-	    id->base.e1000_base_cx)
-++	    id->base.e1000_base_cx) {
-+ 		phylink_set(modes, 1000baseX_Full);
-++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++	}
-+ 	if (id->base.e1000_base_t) {
-+ 		phylink_set(modes, 1000baseT_Half);
-+ 		phylink_set(modes, 1000baseT_Full);
-++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++		__set_bit(PHY_INTERFACE_MODE_SGMII, interfaces);
-+ 	}
-+
-+ 	/* 1000Base-PX or 1000Base-BX10 */
-+ 	if ((id->base.e_base_px || id->base.e_base_bx10) &&
-+-	    br_min <= 1300 && br_max >= 1200)
-++	    br_min <= 1300 && br_max >= 1200) {
-+ 		phylink_set(modes, 1000baseX_Full);
-++		__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++	}
-+
-+ 	/* 100Base-FX, 100Base-LX, 100Base-PX, 100Base-BX10 */
-+ 	if (id->base.e100_base_fx || id->base.e100_base_lx)
-+@@ -210,21 +226,30 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 	 */
-+ 	if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
-+ 		/* This may look odd, but some manufacturers use 12000MBd */
-+-		if (br_min <= 12000 && br_max >= 10300)
-++		if (br_min <= 12000 && br_max >= 10300) {
-+ 			phylink_set(modes, 10000baseCR_Full);
-+-		if (br_min <= 3200 && br_max >= 3100)
-++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++		}
-++		if (br_min <= 3200 && br_max >= 3100) {
-+ 			phylink_set(modes, 2500baseX_Full);
-+-		if (br_min <= 1300 && br_max >= 1200)
-++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
-++		}
-++		if (br_min <= 1300 && br_max >= 1200) {
-+ 			phylink_set(modes, 1000baseX_Full);
-++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++		}
-+ 	}
-+ 	if (id->base.sfp_ct_passive) {
-+-		if (id->base.passive.sff8431_app_e)
-++		if (id->base.passive.sff8431_app_e) {
-+ 			phylink_set(modes, 10000baseCR_Full);
-++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-++		}
-+ 	}
-+ 	if (id->base.sfp_ct_active) {
-+ 		if (id->base.active.sff8431_app_e ||
-+ 		    id->base.active.sff8431_lim) {
-+ 			phylink_set(modes, 10000baseCR_Full);
-++			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-+ 		}
-+ 	}
-+
-+@@ -249,12 +274,15 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 	case SFF8024_ECC_10GBASE_T_SFI:
-+ 	case SFF8024_ECC_10GBASE_T_SR:
-+ 		phylink_set(modes, 10000baseT_Full);
-++		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
-+ 		break;
-+ 	case SFF8024_ECC_5GBASE_T:
-+ 		phylink_set(modes, 5000baseT_Full);
-++		__set_bit(PHY_INTERFACE_MODE_5GBASER, interfaces);
-+ 		break;
-+ 	case SFF8024_ECC_2_5GBASE_T:
-+ 		phylink_set(modes, 2500baseT_Full);
-++		__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
-+ 		break;
-+ 	default:
-+ 		dev_warn(bus->sfp_dev,
-+@@ -267,10 +295,14 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 	if (id->base.fc_speed_100 ||
-+ 	    id->base.fc_speed_200 ||
-+ 	    id->base.fc_speed_400) {
-+-		if (id->base.br_nominal >= 31)
-++		if (id->base.br_nominal >= 31) {
-+ 			phylink_set(modes, 2500baseX_Full);
-+-		if (id->base.br_nominal >= 12)
-++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
-++		}
-++		if (id->base.br_nominal >= 12) {
-+ 			phylink_set(modes, 1000baseX_Full);
-++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++		}
-+ 	}
-+
-+ 	/* If we haven't discovered any modes that this module supports, try
-+@@ -283,14 +315,18 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 	 * 2500BASE-X, so we allow some slack here.
-+ 	 */
-+ 	if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) {
-+-		if (br_min <= 1300 && br_max >= 1200)
-++		if (br_min <= 1300 && br_max >= 1200) {
-+ 			phylink_set(modes, 1000baseX_Full);
-+-		if (br_min <= 3200 && br_max >= 2500)
-++			__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-++		}
-++		if (br_min <= 3200 && br_max >= 2500) {
-+ 			phylink_set(modes, 2500baseX_Full);
-++			__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
-++		}
-+ 	}
-+
-+ 	if (bus->sfp_quirk && bus->sfp_quirk->modes)
-+-		bus->sfp_quirk->modes(id, modes);
-++		bus->sfp_quirk->modes(id, modes, interfaces);
-+
-+ 	linkmode_or(support, support, modes);
-+
-+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
-+index 49e69f1d9b1b..02c55fdae8be 100644
-+--- a/drivers/net/phy/sfp.c
-++++ b/drivers/net/phy/sfp.c
-+@@ -333,13 +333,15 @@ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
-+ }
-+
-+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
-+-				unsigned long *modes)
-++				unsigned long *modes, unsigned long *interfaces)
-+ {
-+ 	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
-++	__set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
-+ }
-+
-+ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
-+-				      unsigned long *modes)
-++				      unsigned long *modes,
-++				      unsigned long *interfaces)
-+ {
-+ 	/* Ubiquiti U-Fiber Instant module claims that support all transceiver
-+ 	 * types including 10G Ethernet which is not truth. So clear all claimed
-+@@ -347,6 +349,7 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
-+ 	 */
-+ 	linkmode_zero(modes);
-+ 	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes);
-++	__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
-+ }
-+
-+ static const struct sfp_quirk sfp_quirks[] = {
-+diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h
-+index 7ad06deae76c..6cf1643214d3 100644
-+--- a/drivers/net/phy/sfp.h
-++++ b/drivers/net/phy/sfp.h
-+@@ -9,7 +9,8 @@ struct sfp;
-+ struct sfp_quirk {
-+ 	const char *vendor;
-+ 	const char *part;
-+-	void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
-++	void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes,
-++		      unsigned long *interfaces);
-+ 	void (*fixup)(struct sfp *sfp);
-+ };
-+
-+diff --git a/include/linux/sfp.h b/include/linux/sfp.h
-+index 302094b855fb..d1f343853b6c 100644
-+--- a/include/linux/sfp.h
-++++ b/include/linux/sfp.h
-+@@ -535,7 +535,7 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+ 		   unsigned long *support);
-+ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
-+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
-+-		       unsigned long *support);
-++		       unsigned long *support, unsigned long *interfaces);
-+ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
-+ 				     unsigned long *link_modes);
-+
-+@@ -568,7 +568,8 @@ static inline bool sfp_may_have_phy(struct sfp_bus *bus,
-+
-+ static inline void sfp_parse_support(struct sfp_bus *bus,
-+ 				     const struct sfp_eeprom_id *id,
-+-				     unsigned long *support)
-++				     unsigned long *support,
-++				     unsigned long *interfaces)
-+ {
-+ }
-+
-+--
-+2.35.1
-+
-diff --git a/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch b/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
-new file mode 100644
-index 0000000000..c1adcacf27
---- /dev/null
-+++ b/target/linux/mvebu/patches-5.15/706-TurrisSFP-12-net-phylink-use-phy_interface_t-bitmaps-for-optical-.patch
-@@ -0,0 +1,203 @@
-+From c069d5a6e0a41c84d49f870340757910c652cf21 Mon Sep 17 00:00:00 2001
-+From: Russell King <rmk+kernel@armlinux.org.uk>
-+Date: Tue, 3 Mar 2020 12:12:43 +0000
-+Subject: [PATCH 12/12] net: phylink: use phy_interface_t bitmaps for optical
-+ modules
-+
-+Where a MAC provides a phy_interface_t bitmap, use these bitmaps to
-+select the operating interface mode for optical SFP modules, rather
-+than using the linkmode bitmaps.
-+
-+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-+[ rebased, added 5GBASER into preference array ]
-+---
-+ drivers/net/phy/phylink.c | 138 ++++++++++++++++++++++++++++++++++----
-+ 1 file changed, 124 insertions(+), 14 deletions(-)
-+
-+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
-+index 7d0b7a2e69d8..4861924303ee 100644
-+--- a/drivers/net/phy/phylink.c
-++++ b/drivers/net/phy/phylink.c
-+@@ -2296,6 +2296,42 @@ static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
-+ 	pl->netdev->sfp_bus = NULL;
-+ }
-+
-++static const phy_interface_t phylink_sfp_interface_preference[] = {
-++	PHY_INTERFACE_MODE_USXGMII,
-++	PHY_INTERFACE_MODE_10GBASER,
-++	PHY_INTERFACE_MODE_5GBASER,
-++	PHY_INTERFACE_MODE_2500BASEX,
-++	PHY_INTERFACE_MODE_SGMII,
-++	PHY_INTERFACE_MODE_1000BASEX,
-++	PHY_INTERFACE_MODE_100BASEX,
-++};
-++
-++static phy_interface_t phylink_select_interface(struct phylink *pl,
-++						const unsigned long *intf,
-++						const char *intf_name)
-++{
-++	DECLARE_PHY_INTERFACE_MASK(u);
-++	phy_interface_t interface;
-++	size_t i;
-++
-++	phy_interface_and(u, intf, pl->config->supported_interfaces);
-++
-++	interface = PHY_INTERFACE_MODE_NA;
-++	for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++)
-++		if (test_bit(phylink_sfp_interface_preference[i], u)) {
-++			interface = phylink_sfp_interface_preference[i];
-++			break;
-++		}
-++
-++	phylink_dbg(pl, "interfaces=[mac=%*pbl %s=%*pbl] selected %d (%s)\n",
-++		    (int)PHY_INTERFACE_MODE_MAX,
-++		    pl->config->supported_interfaces,
-++		    intf_name, (int)PHY_INTERFACE_MODE_MAX, intf,
-++		    interface, phy_modes(interface));
-++
-++	return interface;
-++}
-++
-+ static int phylink_sfp_config(struct phylink *pl, u8 mode,
-+ 			      const unsigned long *supported,
-+ 			      const unsigned long *advertising)
-+@@ -2377,25 +2413,102 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
-+ 	return ret;
-+ }
-+
-++static int phylink_sfp_config_nophy(struct phylink *pl)
-++{
-++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
-++	struct phylink_link_state config;
-++	phy_interface_t interface;
-++	bool changed;
-++	int ret;
-++
-++	if (phy_interface_empty(pl->config->supported_interfaces))
-++		return phylink_sfp_config(pl, MLO_AN_INBAND,
-++					  pl->sfp_support, pl->sfp_support);
-++
-++	memset(&config, 0, sizeof(config));
-++	linkmode_copy(config.advertising, pl->sfp_support);
-++	config.interface = PHY_INTERFACE_MODE_NA;
-++	config.speed = SPEED_UNKNOWN;
-++	config.duplex = DUPLEX_UNKNOWN;
-++	config.pause = MLO_PAUSE_AN;
-++	config.an_enabled = true;
-++
-++	/* Get the full range of supported link modes */
-++	ret = phylink_validate(pl, pl->sfp_support, &config);
-++	if (ret) {
-++		phylink_err(pl,
-++			    "initial validation with support %*pb failed: %d\n",
-++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
-++		return ret;
-++	}
-++
-++	interface = phylink_select_interface(pl, pl->sfp_interfaces, "sfp");
-++	if (interface == PHY_INTERFACE_MODE_NA)
-++		return -EINVAL;
-++
-++	linkmode_copy(support, pl->sfp_support);
-++	config.interface = interface;
-++
-++	/* Ignore errors if we're expecting a PHY to attach later */
-++	ret = phylink_validate(pl, support, &config);
-++	if (ret) {
-++		phylink_err(pl, "validation with support %*pb failed: %d\n",
-++			    __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
-++		return ret;
-++	}
-++
-++	phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
-++		    phylink_an_mode_str(MLO_AN_INBAND),
-++		    phy_modes(config.interface),
-++		    __ETHTOOL_LINK_MODE_MASK_NBITS, pl->sfp_support);
-++
-++	changed = !linkmode_equal(pl->supported, pl->sfp_support) ||
-++		  !linkmode_equal(pl->link_config.advertising,
-++				  config.advertising);
-++	if (changed) {
-++		linkmode_copy(pl->supported, pl->sfp_support);
-++		linkmode_copy(pl->link_config.advertising, config.advertising);
-++	}
-++
-++	if (pl->cur_link_an_mode != MLO_AN_INBAND ||
-++	    pl->link_config.interface != config.interface) {
-++		pl->link_config.interface = config.interface;
-++		pl->cur_link_an_mode = MLO_AN_INBAND;
-++
-++		changed = true;
-++
-++		phylink_info(pl, "switched to %s/%s link mode\n",
-++			     phylink_an_mode_str(MLO_AN_INBAND),
-++			     phy_modes(config.interface));
-++	}
-++
-++	pl->link_port = pl->sfp_port;
-++
-++	if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
-++				 &pl->phylink_disable_state))
-++		phylink_mac_initial_config(pl, false);
-++
-++	return 0;
-++}
-++
-+ static int phylink_sfp_module_insert(void *upstream,
-+ 				     const struct sfp_eeprom_id *id)
-+ {
-+ 	struct phylink *pl = upstream;
-+-	unsigned long *support = pl->sfp_support;
-+
-+ 	ASSERT_RTNL();
-+
-+-	linkmode_zero(support);
-++	linkmode_zero(pl->sfp_support);
-+ 	phy_interface_zero(pl->sfp_interfaces);
-+-	sfp_parse_support(pl->sfp_bus, id, support, pl->sfp_interfaces);
-+-	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
-++	sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces);
-++	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support);
-+
-+ 	/* If this module may have a PHY connecting later, defer until later */
-+ 	pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
-+ 	if (pl->sfp_may_have_phy)
-+ 		return 0;
-+
-+-	return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
-++	return phylink_sfp_config_nophy(pl);
-+ }
-+
-+ static int phylink_sfp_module_start(void *upstream)
-+@@ -2414,8 +2527,7 @@ static int phylink_sfp_module_start(void *upstream)
-+ 	if (!pl->sfp_may_have_phy)
-+ 		return 0;
-+
-+-	return phylink_sfp_config(pl, MLO_AN_INBAND,
-+-				  pl->sfp_support, pl->sfp_support);
-++	return phylink_sfp_config_nophy(pl);
-+ }
-+
-+ static void phylink_sfp_module_stop(void *upstream)
-+@@ -2867,13 +2979,11 @@ EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
-+
-+ static int __init phylink_init(void)
-+ {
-+-	__set_bit(PHY_INTERFACE_MODE_USXGMII, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_10GBASER, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_5GBASER, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_2500BASEX, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_SGMII, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_1000BASEX, phylink_sfp_interfaces);
-+-	__set_bit(PHY_INTERFACE_MODE_100BASEX, phylink_sfp_interfaces);
-++	int i;
-++
-++	for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i)
-++		__set_bit(phylink_sfp_interface_preference[i],
-++			  phylink_sfp_interfaces);
-+
-+ 	return 0;
-+ }
-+--
-+2.35.1
-+
---
-2.35.1
-
-- 
GitLab