mirror of
https://github.com/FUjr/gl-infra-builder.git
synced 2025-12-16 17:15:08 +00:00
``` python3 setup.py -c configs/config-mt798x.yml cd mt798x ./scripts/gen_config.py target_mt7986_gl-mt6000 glinet_mt7986_wifi glinet_mt6000 make -j $(nproc) ``` Signed-off-by: Jianhui Zhao <jianhui.zhao@gl-inet.com>
924 lines
27 KiB
Diff
924 lines
27 KiB
Diff
From d3356e2dc7a28d315bf950f7c691766acc2b37f8 Mon Sep 17 00:00:00 2001
|
|
From: Jianhui Zhao <jianhui.zhao@gl-inet.com>
|
|
Date: Fri, 19 May 2023 11:04:29 +0800
|
|
Subject: [PATCH] kernel: backport rtl8221b from openwrt master
|
|
|
|
Signed-off-by: Jianhui Zhao <jianhui.zhao@gl-inet.com>
|
|
---
|
|
.../hack-5.4/961-backport-rtl8221b.patch | 903 ++++++++++++++++++
|
|
1 file changed, 903 insertions(+)
|
|
create mode 100644 target/linux/generic/hack-5.4/961-backport-rtl8221b.patch
|
|
|
|
diff --git a/target/linux/generic/hack-5.4/961-backport-rtl8221b.patch b/target/linux/generic/hack-5.4/961-backport-rtl8221b.patch
|
|
new file mode 100644
|
|
index 0000000000..0b53a146cf
|
|
--- /dev/null
|
|
+++ b/target/linux/generic/hack-5.4/961-backport-rtl8221b.patch
|
|
@@ -0,0 +1,903 @@
|
|
+--- a/drivers/net/phy/realtek.c
|
|
++++ b/drivers/net/phy/realtek.c
|
|
+@@ -1,6 +1,5 @@
|
|
+ // SPDX-License-Identifier: GPL-2.0+
|
|
+-/*
|
|
+- * drivers/net/phy/realtek.c
|
|
++/* drivers/net/phy/realtek.c
|
|
+ *
|
|
+ * Driver for Realtek PHYs
|
|
+ *
|
|
+@@ -9,8 +8,10 @@
|
|
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
|
|
+ */
|
|
+ #include <linux/bitops.h>
|
|
++#include <linux/of.h>
|
|
+ #include <linux/phy.h>
|
|
+ #include <linux/module.h>
|
|
++#include <linux/delay.h>
|
|
+
|
|
+ #define RTL821x_PHYSR 0x11
|
|
+ #define RTL821x_PHYSR_DUPLEX BIT(13)
|
|
+@@ -26,26 +27,56 @@
|
|
+ #define RTL821x_EXT_PAGE_SELECT 0x1e
|
|
+ #define RTL821x_PAGE_SELECT 0x1f
|
|
+
|
|
++#define RTL8211F_PHYCR1 0x18
|
|
++#define RTL8211F_PHYCR2 0x19
|
|
+ #define RTL8211F_INSR 0x1d
|
|
+
|
|
+ #define RTL8211F_TX_DELAY BIT(8)
|
|
+-#define RTL8211E_TX_DELAY BIT(1)
|
|
+-#define RTL8211E_RX_DELAY BIT(2)
|
|
+-#define RTL8211E_MODE_MII_GMII BIT(3)
|
|
++#define RTL8211F_RX_DELAY BIT(3)
|
|
++
|
|
++#define RTL8211F_ALDPS_PLL_OFF BIT(1)
|
|
++#define RTL8211F_ALDPS_ENABLE BIT(2)
|
|
++#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
|
|
++
|
|
++#define RTL8211E_CTRL_DELAY BIT(13)
|
|
++#define RTL8211E_TX_DELAY BIT(12)
|
|
++#define RTL8211E_RX_DELAY BIT(11)
|
|
++
|
|
++#define RTL8211F_CLKOUT_EN BIT(0)
|
|
+
|
|
+ #define RTL8201F_ISR 0x1e
|
|
++#define RTL8201F_ISR_ANERR BIT(15)
|
|
++#define RTL8201F_ISR_DUPLEX BIT(13)
|
|
++#define RTL8201F_ISR_LINK BIT(11)
|
|
++#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \
|
|
++ RTL8201F_ISR_DUPLEX | \
|
|
++ 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 RTL8221B_PHYCR1 0xa430
|
|
++#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
|
|
++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12)
|
|
++
|
|
+ #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)
|
|
++
|
|
++#define RTLGEN_SPEED_MASK 0x0630
|
|
+
|
|
+ #define RTL_GENERIC_PHYID 0x001cc800
|
|
+
|
|
+@@ -53,6 +84,11 @@ MODULE_DESCRIPTION("Realtek PHY driver")
|
|
+ MODULE_AUTHOR("Johnson Leung");
|
|
+ MODULE_LICENSE("GPL");
|
|
+
|
|
++struct rtl821x_priv {
|
|
++ u16 phycr1;
|
|
++ u16 phycr2;
|
|
++};
|
|
++
|
|
+ static int rtl821x_read_page(struct phy_device *phydev)
|
|
+ {
|
|
+ return __phy_read(phydev, RTL821x_PAGE_SELECT);
|
|
+@@ -63,6 +99,37 @@ static int rtl821x_write_page(struct phy
|
|
+ return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
|
|
+ }
|
|
+
|
|
++static int rtl821x_probe(struct phy_device *phydev)
|
|
++{
|
|
++ struct device *dev = &phydev->mdio.dev;
|
|
++ struct rtl821x_priv *priv;
|
|
++ int ret;
|
|
++
|
|
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
++ if (!priv)
|
|
++ return -ENOMEM;
|
|
++
|
|
++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
|
|
++ if (ret < 0)
|
|
++ return ret;
|
|
++
|
|
++ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
|
|
++ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
|
|
++ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
|
|
++
|
|
++ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
|
|
++ if (ret < 0)
|
|
++ return ret;
|
|
++
|
|
++ priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
|
|
++ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
|
|
++ priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
|
|
++
|
|
++ phydev->priv = priv;
|
|
++
|
|
++ return 0;
|
|
++}
|
|
++
|
|
+ static int rtl8201_ack_interrupt(struct phy_device *phydev)
|
|
+ {
|
|
+ int err;
|
|
+@@ -93,24 +160,45 @@ static int rtl8211f_ack_interrupt(struct
|
|
+ static int rtl8201_config_intr(struct phy_device *phydev)
|
|
+ {
|
|
+ u16 val;
|
|
++ int err;
|
|
++
|
|
++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
|
++ err = rtl8201_ack_interrupt(phydev);
|
|
++ if (err)
|
|
++ return err;
|
|
+
|
|
+- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
|
+ val = BIT(13) | BIT(12) | BIT(11);
|
|
+- else
|
|
++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
|
|
++ } else {
|
|
+ val = 0;
|
|
++ err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
|
|
++ if (err)
|
|
++ return err;
|
|
+
|
|
+- return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
|
|
++ err = rtl8201_ack_interrupt(phydev);
|
|
++ }
|
|
++
|
|
++ return err;
|
|
+ }
|
|
+
|
|
+ static int rtl8211b_config_intr(struct phy_device *phydev)
|
|
+ {
|
|
+ int err;
|
|
+
|
|
+- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
|
++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
|
++ err = rtl821x_ack_interrupt(phydev);
|
|
++ if (err)
|
|
++ return err;
|
|
++
|
|
+ err = phy_write(phydev, RTL821x_INER,
|
|
+ RTL8211B_INER_INIT);
|
|
+- else
|
|
++ } else {
|
|
+ err = phy_write(phydev, RTL821x_INER, 0);
|
|
++ if (err)
|
|
++ return err;
|
|
++
|
|
++ err = rtl821x_ack_interrupt(phydev);
|
|
++ }
|
|
+
|
|
+ return err;
|
|
+ }
|
|
+@@ -119,11 +207,20 @@ static int rtl8211e_config_intr(struct p
|
|
+ {
|
|
+ int err;
|
|
+
|
|
+- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
|
++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
|
++ err = rtl821x_ack_interrupt(phydev);
|
|
++ if (err)
|
|
++ return err;
|
|
++
|
|
+ err = phy_write(phydev, RTL821x_INER,
|
|
+ RTL8211E_INER_LINK_STATUS);
|
|
+- else
|
|
++ } else {
|
|
+ err = phy_write(phydev, RTL821x_INER, 0);
|
|
++ if (err)
|
|
++ return err;
|
|
++
|
|
++ err = rtl821x_ack_interrupt(phydev);
|
|
++ }
|
|
+
|
|
+ return err;
|
|
+ }
|
|
+@@ -131,13 +228,85 @@ static int rtl8211e_config_intr(struct p
|
|
+ static int rtl8211f_config_intr(struct phy_device *phydev)
|
|
+ {
|
|
+ u16 val;
|
|
++ int err;
|
|
++
|
|
++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
|
|
++ err = rtl8211f_ack_interrupt(phydev);
|
|
++ if (err)
|
|
++ return err;
|
|
+
|
|
+- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
|
+ val = RTL8211F_INER_LINK_STATUS;
|
|
+- else
|
|
++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
|
|
++ } else {
|
|
+ val = 0;
|
|
++ err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
|
|
++ if (err)
|
|
++ return err;
|
|
++
|
|
++ err = rtl8211f_ack_interrupt(phydev);
|
|
++ }
|
|
+
|
|
+- return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
|
|
++ return err;
|
|
++}
|
|
++
|
|
++static int rtl8201_handle_interrupt(struct phy_device *phydev)
|
|
++{
|
|
++ int irq_status;
|
|
++
|
|
++ irq_status = phy_read(phydev, RTL8201F_ISR);
|
|
++ if (irq_status < 0) {
|
|
++ phydev_err(phydev, "Err: read RTL8201F_ISR: %d\n", irq_status);
|
|
++ return -1;
|
|
++ }
|
|
++
|
|
++ if (!(irq_status & RTL8201F_ISR_MASK))
|
|
++ return -1;
|
|
++
|
|
++ phy_queue_state_machine(phydev, 0);
|
|
++
|
|
++ return 0;
|
|
++}
|
|
++
|
|
++static int rtl821x_handle_interrupt(struct phy_device *phydev)
|
|
++{
|
|
++ int irq_status, irq_enabled;
|
|
++
|
|
++ irq_status = phy_read(phydev, RTL821x_INSR);
|
|
++ if (irq_status < 0) {
|
|
++ phydev_err(phydev, "Err: read RTL821x_INSR: %d\n", irq_status);
|
|
++ return -1;
|
|
++ }
|
|
++
|
|
++ irq_enabled = phy_read(phydev, RTL821x_INER);
|
|
++ if (irq_enabled < 0) {
|
|
++ phydev_err(phydev, "Err: read RTL821x_INER: %d\n", irq_enabled);
|
|
++ return -1;
|
|
++ }
|
|
++
|
|
++ if (!(irq_status & irq_enabled))
|
|
++ return -1;
|
|
++
|
|
++ phy_queue_state_machine(phydev, 0);
|
|
++
|
|
++ return 0;
|
|
++}
|
|
++
|
|
++static int rtl8211f_handle_interrupt(struct phy_device *phydev)
|
|
++{
|
|
++ int irq_status;
|
|
++
|
|
++ irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
|
|
++ if (irq_status < 0) {
|
|
++ phydev_err(phydev, "Err: read RTL8211F_INSR: %d\n", irq_status);
|
|
++ return -1;
|
|
++ }
|
|
++
|
|
++ if (!(irq_status & RTL8211F_INER_LINK_STATUS))
|
|
++ return -1;
|
|
++
|
|
++ phy_queue_state_machine(phydev, 0);
|
|
++
|
|
++ return 0;
|
|
+ }
|
|
+
|
|
+ static int rtl8211_config_aneg(struct phy_device *phydev)
|
|
+@@ -171,41 +340,96 @@ static int rtl8211c_config_init(struct p
|
|
+
|
|
+ static int rtl8211f_config_init(struct phy_device *phydev)
|
|
+ {
|
|
++ struct rtl821x_priv *priv = phydev->priv;
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
+- u16 val;
|
|
++ u16 val_txdly, val_rxdly;
|
|
+ int ret;
|
|
+
|
|
+- /* enable TX-delay for rgmii-{id,txid}, and disable it for rgmii and
|
|
+- * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin.
|
|
+- */
|
|
++ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
|
|
++ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
|
|
++ priv->phycr1);
|
|
++ if (ret < 0) {
|
|
++ dev_err(dev, "aldps mode configuration failed: %pe\n",
|
|
++ ERR_PTR(ret));
|
|
++ return ret;
|
|
++ }
|
|
++
|
|
+ switch (phydev->interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
++ val_txdly = 0;
|
|
++ val_rxdly = 0;
|
|
++ break;
|
|
++
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+- val = 0;
|
|
++ val_txdly = 0;
|
|
++ val_rxdly = RTL8211F_RX_DELAY;
|
|
+ break;
|
|
+- case PHY_INTERFACE_MODE_RGMII_ID:
|
|
++
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+- val = RTL8211F_TX_DELAY;
|
|
++ val_txdly = RTL8211F_TX_DELAY;
|
|
++ val_rxdly = 0;
|
|
+ break;
|
|
++
|
|
++ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
++ val_txdly = RTL8211F_TX_DELAY;
|
|
++ val_rxdly = RTL8211F_RX_DELAY;
|
|
++ break;
|
|
++
|
|
+ default: /* the rest of the modes imply leaving delay as is. */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
|
|
+- val);
|
|
++ val_txdly);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed to update the TX delay register\n");
|
|
+ return ret;
|
|
+ } else if (ret) {
|
|
+ dev_dbg(dev,
|
|
+ "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
|
|
+- val ? "Enabling" : "Disabling");
|
|
++ val_txdly ? "Enabling" : "Disabling");
|
|
+ } else {
|
|
+ dev_dbg(dev,
|
|
+ "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
|
|
+- val ? "enabled" : "disabled");
|
|
++ val_txdly ? "enabled" : "disabled");
|
|
++ }
|
|
++
|
|
++ ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
|
|
++ val_rxdly);
|
|
++ if (ret < 0) {
|
|
++ dev_err(dev, "Failed to update the RX delay register\n");
|
|
++ return ret;
|
|
++ } else if (ret) {
|
|
++ dev_dbg(dev,
|
|
++ "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
|
|
++ val_rxdly ? "Enabling" : "Disabling");
|
|
++ } else {
|
|
++ dev_dbg(dev,
|
|
++ "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
|
|
++ val_rxdly ? "enabled" : "disabled");
|
|
+ }
|
|
+
|
|
++ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
|
|
++ RTL8211F_CLKOUT_EN, priv->phycr2);
|
|
++ if (ret < 0) {
|
|
++ dev_err(dev, "clkout configuration failed: %pe\n",
|
|
++ ERR_PTR(ret));
|
|
++ return ret;
|
|
++ }
|
|
++
|
|
++ return genphy_soft_reset(phydev);
|
|
++}
|
|
++
|
|
++static int rtl821x_resume(struct phy_device *phydev)
|
|
++{
|
|
++ int ret;
|
|
++
|
|
++ ret = genphy_resume(phydev);
|
|
++ if (ret < 0)
|
|
++ return ret;
|
|
++
|
|
++ msleep(20);
|
|
++
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+@@ -217,16 +441,16 @@ static int rtl8211e_config_init(struct p
|
|
+ /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
|
|
+ switch (phydev->interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+- val = 0;
|
|
++ val = RTL8211E_CTRL_DELAY | 0;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+- val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
|
|
++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+- val = RTL8211E_RX_DELAY;
|
|
++ val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+- val = RTL8211E_TX_DELAY;
|
|
++ val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
|
|
+ break;
|
|
+ default: /* the rest of the modes imply leaving delays as is. */
|
|
+ return 0;
|
|
+@@ -234,11 +458,12 @@ static int rtl8211e_config_init(struct p
|
|
+
|
|
+ /* According to a sample driver there is a 0x1c config register on the
|
|
+ * 0xa4 extension page (0x7) layout. It can be used to disable/enable
|
|
+- * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can
|
|
+- * also be used to customize the whole configuration register:
|
|
+- * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select,
|
|
+- * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet
|
|
+- * for details).
|
|
++ * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
|
|
++ * The configuration register definition:
|
|
++ * 14 = reserved
|
|
++ * 13 = Force Tx RX Delay controlled by bit12 bit11,
|
|
++ * 12 = RX Delay, 11 = TX Delay
|
|
++ * 10:0 = Test && debug settings reserved by realtek
|
|
+ */
|
|
+ oldpage = phy_select_page(phydev, 0x7);
|
|
+ if (oldpage < 0)
|
|
+@@ -248,7 +473,8 @@ static int rtl8211e_config_init(struct p
|
|
+ if (ret)
|
|
+ goto err_restore_page;
|
|
+
|
|
+- ret = __phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
|
|
++ ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
|
|
++ | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
|
|
+ val);
|
|
+
|
|
+ err_restore_page:
|
|
+@@ -269,18 +495,53 @@ static int rtl8211b_resume(struct phy_de
|
|
+ return genphy_resume(phydev);
|
|
+ }
|
|
+
|
|
+-static int rtl8366rb_config_init(struct phy_device *phydev)
|
|
++/* get actual speed to cover the downshift case */
|
|
++static int rtlgen_get_speed(struct phy_device *phydev)
|
|
+ {
|
|
+- int ret;
|
|
++ int val;
|
|
+
|
|
+- ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
|
|
+- RTL8366RB_POWER_SAVE_ON);
|
|
+- if (ret) {
|
|
+- dev_err(&phydev->mdio.dev,
|
|
+- "error enabling power management\n");
|
|
++ 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;
|
|
++ break;
|
|
++ case 0x0010:
|
|
++ phydev->speed = SPEED_100;
|
|
++ break;
|
|
++ case 0x0020:
|
|
++ phydev->speed = SPEED_1000;
|
|
++ break;
|
|
++ case 0x0200:
|
|
++ phydev->speed = SPEED_10000;
|
|
++ break;
|
|
++ case 0x0210:
|
|
++ phydev->speed = SPEED_2500;
|
|
++ break;
|
|
++ case 0x0220:
|
|
++ phydev->speed = SPEED_5000;
|
|
++ break;
|
|
++ default:
|
|
++ break;
|
|
+ }
|
|
+
|
|
+- return ret;
|
|
++ return 0;
|
|
++}
|
|
++
|
|
++static int rtlgen_read_status(struct phy_device *phydev)
|
|
++{
|
|
++ int ret;
|
|
++
|
|
++ ret = genphy_read_status(phydev);
|
|
++ if (ret < 0)
|
|
++ return ret;
|
|
++
|
|
++ return rtlgen_get_speed(phydev);
|
|
+ }
|
|
+
|
|
+ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|
+@@ -322,7 +583,7 @@ static int rtlgen_write_mmd(struct phy_d
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+-static int rtl8125_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|
++static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|
+ {
|
|
+ int ret = rtlgen_read_mmd(phydev, devnum, regnum);
|
|
+
|
|
+@@ -346,7 +607,7 @@ static int rtl8125_read_mmd(struct phy_d
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+-static int rtl8125_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
|
|
++static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
|
|
+ u16 val)
|
|
+ {
|
|
+ int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
|
|
+@@ -363,7 +624,7 @@ static int rtl8125_write_mmd(struct phy_
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+-static int rtl8125_get_features(struct phy_device *phydev)
|
|
++static int rtl822x_get_features(struct phy_device *phydev)
|
|
+ {
|
|
+ int val;
|
|
+
|
|
+@@ -381,19 +642,16 @@ static int rtl8125_get_features(struct p
|
|
+ return genphy_read_abilities(phydev);
|
|
+ }
|
|
+
|
|
+-static int rtl8125_config_aneg(struct phy_device *phydev)
|
|
++static int rtl822x_config_aneg(struct phy_device *phydev)
|
|
+ {
|
|
+ int ret = 0;
|
|
+
|
|
+ if (phydev->autoneg == AUTONEG_ENABLE) {
|
|
+- u16 adv2500 = 0;
|
|
+-
|
|
+- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
|
+- phydev->advertising))
|
|
+- adv2500 = RTL_ADV_2500FULL;
|
|
+-
|
|
+ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
|
|
+- RTL_ADV_2500FULL, adv2500);
|
|
++ MDIO_AN_10GBT_CTRL_ADV10G |
|
|
++ MDIO_AN_10GBT_CTRL_ADV5G |
|
|
++ MDIO_AN_10GBT_CTRL_ADV2_5G,
|
|
++ linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising));
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+@@ -401,32 +659,61 @@ static int rtl8125_config_aneg(struct ph
|
|
+ return __genphy_config_aneg(phydev, ret);
|
|
+ }
|
|
+
|
|
+-static int rtl8125_read_status(struct phy_device *phydev)
|
|
++static void rtl822x_update_interface(struct phy_device *phydev)
|
|
++{
|
|
++ /* Automatically switch SERDES interface between
|
|
++ * SGMII and 2500-BaseX according to speed.
|
|
++ */
|
|
++ switch (phydev->speed) {
|
|
++ case SPEED_2500:
|
|
++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
|
|
++ break;
|
|
++ case SPEED_1000:
|
|
++ case SPEED_100:
|
|
++ case SPEED_10:
|
|
++ phydev->interface = PHY_INTERFACE_MODE_SGMII;
|
|
++ break;
|
|
++ default:
|
|
++ break;
|
|
++ }
|
|
++}
|
|
++
|
|
++static int rtl822x_read_status(struct phy_device *phydev)
|
|
+ {
|
|
++ int ret;
|
|
++
|
|
+ if (phydev->autoneg == AUTONEG_ENABLE) {
|
|
+ int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
|
|
+
|
|
+ if (lpadv < 0)
|
|
+ return lpadv;
|
|
+
|
|
+- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
|
+- phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
|
|
+- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
|
|
+- phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
|
|
+- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
|
+- phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
|
|
++ if (!(lpadv & MDIO_AN_10GBT_STAT_REMOK) ||
|
|
++ !(lpadv & MDIO_AN_10GBT_STAT_LOCOK))
|
|
++ lpadv = 0;
|
|
++
|
|
++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
|
|
+ }
|
|
+
|
|
+- return genphy_read_status(phydev);
|
|
++ ret = rtlgen_read_status(phydev);
|
|
++ if (ret < 0)
|
|
++ return ret;
|
|
++
|
|
++ if (phydev->is_c45 && phydev->link)
|
|
++ rtl822x_update_interface(phydev);
|
|
++
|
|
++ return 0;
|
|
+ }
|
|
+
|
|
+ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
|
|
+ {
|
|
+ int val;
|
|
+
|
|
+- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
|
|
+- val = phy_read(phydev, 0x13);
|
|
+- phy_write(phydev, RTL821x_PAGE_SELECT, 0);
|
|
++ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
|
++ rtl821x_write_page(phydev, 0xa61);
|
|
++ val = __phy_read(phydev, 0x13);
|
|
++ rtl821x_write_page(phydev, 0);
|
|
++ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
|
+
|
|
+ return val >= 0 && val & RTL_SUPPORTS_2500FULL;
|
|
+ }
|
|
+@@ -437,21 +724,102 @@ static int rtlgen_match_phy_device(struc
|
|
+ !rtlgen_supports_2_5gbps(phydev);
|
|
+ }
|
|
+
|
|
+-static int rtl8125_match_phy_device(struct phy_device *phydev)
|
|
++static int rtl8226_match_phy_device(struct phy_device *phydev)
|
|
+ {
|
|
+ return phydev->phy_id == RTL_GENERIC_PHYID &&
|
|
+ rtlgen_supports_2_5gbps(phydev);
|
|
+ }
|
|
+
|
|
++static int rtl822x_probe(struct phy_device *phydev)
|
|
++{
|
|
++ struct device *dev = &phydev->mdio.dev;
|
|
++ int val;
|
|
++
|
|
++ val = phy_read_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, RTL8221B_PHYCR1);
|
|
++ if (val < 0)
|
|
++ return val;
|
|
++
|
|
++ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
|
|
++ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
|
|
++ else
|
|
++ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
|
|
++
|
|
++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, RTL8221B_PHYCR1, val);
|
|
++
|
|
++ return 0;
|
|
++}
|
|
++
|
|
++static int rtlgen_resume(struct phy_device *phydev)
|
|
++{
|
|
++ int ret = genphy_resume(phydev);
|
|
++
|
|
++ /* Internal PHY's from RTL8168h up may not be instantly ready */
|
|
++ msleep(20);
|
|
++
|
|
++ return ret;
|
|
++}
|
|
++
|
|
++static int rtl8221b_config_init(struct phy_device *phydev)
|
|
++{
|
|
++ u16 option_mode;
|
|
++ int val;
|
|
++
|
|
++ switch (phydev->interface) {
|
|
++ case PHY_INTERFACE_MODE_2500BASEX:
|
|
++ if (!phydev->is_c45) {
|
|
++ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX;
|
|
++ break;
|
|
++ }
|
|
++ fallthrough;
|
|
++ case PHY_INTERFACE_MODE_SGMII:
|
|
++ 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;
|
|
++ }
|
|
++
|
|
++ /* Disable SGMII AN */
|
|
++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7588, 0x2);
|
|
++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7589, 0x71d0);
|
|
++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587, 0x3);
|
|
++ phy_read_mmd_poll_timeout(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587,
|
|
++ val, !(val & BIT(0)), 500, 100000, false);
|
|
++
|
|
++ return 0;
|
|
++}
|
|
++
|
|
+ static struct phy_driver realtek_drvs[] = {
|
|
+ {
|
|
+ PHY_ID_MATCH_EXACT(0x00008201),
|
|
+ .name = "RTL8201CP Ethernet",
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
+ }, {
|
|
+ PHY_ID_MATCH_EXACT(0x001cc816),
|
|
+ .name = "RTL8201F Fast Ethernet",
|
|
+- .ack_interrupt = &rtl8201_ack_interrupt,
|
|
+ .config_intr = &rtl8201_config_intr,
|
|
++ .handle_interrupt = rtl8201_handle_interrupt,
|
|
+ .suspend = genphy_suspend,
|
|
+ .resume = genphy_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+@@ -476,8 +844,8 @@ static struct phy_driver realtek_drvs[]
|
|
+ }, {
|
|
+ PHY_ID_MATCH_EXACT(0x001cc912),
|
|
+ .name = "RTL8211B Gigabit Ethernet",
|
|
+- .ack_interrupt = &rtl821x_ack_interrupt,
|
|
+ .config_intr = &rtl8211b_config_intr,
|
|
++ .handle_interrupt = rtl821x_handle_interrupt,
|
|
+ .read_mmd = &genphy_read_mmd_unsupported,
|
|
+ .write_mmd = &genphy_write_mmd_unsupported,
|
|
+ .suspend = rtl8211b_suspend,
|
|
+@@ -495,8 +863,8 @@ static struct phy_driver realtek_drvs[]
|
|
+ }, {
|
|
+ PHY_ID_MATCH_EXACT(0x001cc914),
|
|
+ .name = "RTL8211DN Gigabit Ethernet",
|
|
+- .ack_interrupt = rtl821x_ack_interrupt,
|
|
+ .config_intr = rtl8211e_config_intr,
|
|
++ .handle_interrupt = rtl821x_handle_interrupt,
|
|
+ .suspend = genphy_suspend,
|
|
+ .resume = genphy_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+@@ -505,8 +873,8 @@ static struct phy_driver realtek_drvs[]
|
|
+ PHY_ID_MATCH_EXACT(0x001cc915),
|
|
+ .name = "RTL8211E Gigabit Ethernet",
|
|
+ .config_init = &rtl8211e_config_init,
|
|
+- .ack_interrupt = &rtl821x_ack_interrupt,
|
|
+ .config_intr = &rtl8211e_config_intr,
|
|
++ .handle_interrupt = rtl821x_handle_interrupt,
|
|
+ .suspend = genphy_suspend,
|
|
+ .resume = genphy_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+@@ -514,47 +882,103 @@ static struct phy_driver realtek_drvs[]
|
|
+ }, {
|
|
+ PHY_ID_MATCH_EXACT(0x001cc916),
|
|
+ .name = "RTL8211F Gigabit Ethernet",
|
|
++ .probe = rtl821x_probe,
|
|
+ .config_init = &rtl8211f_config_init,
|
|
+- .ack_interrupt = &rtl8211f_ack_interrupt,
|
|
++ .read_status = rtlgen_read_status,
|
|
+ .config_intr = &rtl8211f_config_intr,
|
|
++ .handle_interrupt = rtl8211f_handle_interrupt,
|
|
+ .suspend = genphy_suspend,
|
|
+- .resume = genphy_resume,
|
|
++ .resume = rtl821x_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+ .write_page = rtl821x_write_page,
|
|
+ }, {
|
|
+ .name = "Generic FE-GE Realtek PHY",
|
|
+ .match_phy_device = rtlgen_match_phy_device,
|
|
++ .read_status = rtlgen_read_status,
|
|
+ .suspend = genphy_suspend,
|
|
+- .resume = genphy_resume,
|
|
++ .resume = rtlgen_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+ .write_page = rtl821x_write_page,
|
|
+ .read_mmd = rtlgen_read_mmd,
|
|
+ .write_mmd = rtlgen_write_mmd,
|
|
+ }, {
|
|
+- .name = "RTL8125 2.5Gbps internal",
|
|
+- .match_phy_device = rtl8125_match_phy_device,
|
|
+- .get_features = rtl8125_get_features,
|
|
+- .config_aneg = rtl8125_config_aneg,
|
|
+- .read_status = rtl8125_read_status,
|
|
++ .name = "RTL8226 2.5Gbps PHY",
|
|
++ .match_phy_device = rtl8226_match_phy_device,
|
|
++ .get_features = rtl822x_get_features,
|
|
++ .config_aneg = rtl822x_config_aneg,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
+ .suspend = genphy_suspend,
|
|
+- .resume = genphy_resume,
|
|
++ .resume = rtlgen_resume,
|
|
+ .read_page = rtl821x_read_page,
|
|
+ .write_page = rtl821x_write_page,
|
|
+- .read_mmd = rtl8125_read_mmd,
|
|
+- .write_mmd = rtl8125_write_mmd,
|
|
+- }, {
|
|
+- PHY_ID_MATCH_EXACT(0x001cc961),
|
|
+- .name = "RTL8366RB Gigabit Ethernet",
|
|
+- .config_init = &rtl8366rb_config_init,
|
|
+- /* These interrupts are handled by the irq controller
|
|
+- * embedded inside the RTL8366RB, they get unmasked when the
|
|
+- * irq is requested and ACKed by reading the status register,
|
|
+- * which is done by the irqchip code.
|
|
+- */
|
|
+- .ack_interrupt = genphy_no_ack_interrupt,
|
|
+- .config_intr = genphy_no_config_intr,
|
|
++ .read_mmd = rtl822x_read_mmd,
|
|
++ .write_mmd = rtl822x_write_mmd,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
++ }, {
|
|
++ PHY_ID_MATCH_EXACT(0x001cc840),
|
|
++ .name = "RTL8226B_RTL8221B 2.5Gbps PHY",
|
|
++ .get_features = rtl822x_get_features,
|
|
++ .config_aneg = rtl822x_config_aneg,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
+ .suspend = genphy_suspend,
|
|
+- .resume = genphy_resume,
|
|
++ .resume = rtlgen_resume,
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
++ .read_mmd = rtl822x_read_mmd,
|
|
++ .write_mmd = rtl822x_write_mmd,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
++ }, {
|
|
++ PHY_ID_MATCH_EXACT(0x001cc838),
|
|
++ .name = "RTL8226-CG 2.5Gbps PHY",
|
|
++ .get_features = rtl822x_get_features,
|
|
++ .config_aneg = rtl822x_config_aneg,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
++ .suspend = genphy_suspend,
|
|
++ .resume = rtlgen_resume,
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
++ }, {
|
|
++ PHY_ID_MATCH_EXACT(0x001cc848),
|
|
++ .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
|
|
++ .get_features = rtl822x_get_features,
|
|
++ .config_aneg = rtl822x_config_aneg,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
++ .suspend = genphy_suspend,
|
|
++ .resume = rtlgen_resume,
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
++ }, {
|
|
++ 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,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
++ .suspend = genphy_suspend,
|
|
++ .resume = rtlgen_resume,
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
++ }, {
|
|
++ PHY_ID_MATCH_EXACT(0x001cc84a),
|
|
++ .name = "RTL8221B-VM-CG 2.5Gbps PHY",
|
|
++ .get_features = rtl822x_get_features,
|
|
++ .config_aneg = rtl822x_config_aneg,
|
|
++ .config_init = rtl8221b_config_init,
|
|
++ .probe = rtl822x_probe,
|
|
++ .read_status = rtl822x_read_status,
|
|
++ .suspend = genphy_suspend,
|
|
++ .resume = rtlgen_resume,
|
|
++ .read_page = rtl821x_read_page,
|
|
++ .write_page = rtl821x_write_page,
|
|
++ .soft_reset = genphy_soft_reset,
|
|
+ },
|
|
+ };
|
|
+
|
|
--
|
|
2.34.1
|
|
|