generic: backport at803x fixes

As patches for the AR8031/AR8033 copper page selection were merged
upstream, we can backport these patches.

This also fixes a PHY capabilities detection issue on the Ubiquiti
ER-X-SFP.

Signed-off-by: David Bauer <mail@david-bauer.net>
This commit is contained in:
David Bauer 2021-06-04 15:12:14 +02:00
parent 1412424fc5
commit 15167671b0
12 changed files with 361 additions and 208 deletions

View File

@ -0,0 +1,108 @@
From c329e5afb42ff0a88285eb4d8a391a18793e4777 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Thu, 15 Apr 2021 03:26:50 +0200
Subject: [PATCH] net: phy: at803x: select correct page on config init
The Atheros AR8031 and AR8033 expose different registers for SGMII/Fiber
as well as the copper side of the PHY depending on the BT_BX_REG_SEL bit
in the chip configure register.
The driver assumes the copper side is selected on probe, but this might
not be the case depending which page was last selected by the
bootloader. Notably, Ubiquiti UniFi bootloaders show this behavior.
Select the copper page when probing to circumvent this.
Signed-off-by: David Bauer <mail@david-bauer.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 50 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -139,6 +139,9 @@
#define ATH8035_PHY_ID 0x004dd072
#define AT8030_PHY_ID_MASK 0xffffffef
+#define AT803X_PAGE_FIBER 0
+#define AT803X_PAGE_COPPER 1
+
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
@@ -190,6 +193,35 @@ static int at803x_debug_reg_mask(struct
return phy_write(phydev, AT803X_DEBUG_DATA, val);
}
+static int at803x_write_page(struct phy_device *phydev, int page)
+{
+ int mask;
+ int set;
+
+ if (page == AT803X_PAGE_COPPER) {
+ set = AT803X_BT_BX_REG_SEL;
+ mask = 0;
+ } else {
+ set = 0;
+ mask = AT803X_BT_BX_REG_SEL;
+ }
+
+ return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
+}
+
+static int at803x_read_page(struct phy_device *phydev)
+{
+ int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+
+ if (ccr < 0)
+ return ccr;
+
+ if (ccr & AT803X_BT_BX_REG_SEL)
+ return AT803X_PAGE_COPPER;
+
+ return AT803X_PAGE_FIBER;
+}
+
static int at803x_enable_rx_delay(struct phy_device *phydev)
{
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
@@ -508,6 +540,7 @@ static int at803x_probe(struct phy_devic
{
struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -515,7 +548,20 @@ static int at803x_probe(struct phy_devic
phydev->priv = priv;
- return at803x_parse_dt(phydev);
+ ret = at803x_parse_dt(phydev);
+ if (ret)
+ return ret;
+
+ /* Some bootloaders leave the fiber page selected.
+ * Switch to the copper page, as otherwise we read
+ * the PHY capabilities from the fiber side.
+ */
+ if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) {
+ ret = phy_select_page(phydev, AT803X_PAGE_COPPER);
+ ret = phy_restore_page(phydev, AT803X_PAGE_COPPER, ret);
+ }
+
+ return ret;
}
static void at803x_remove(struct phy_device *phydev)
@@ -1097,6 +1143,8 @@ static struct phy_driver at803x_driver[]
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
+ .read_page = at803x_read_page,
+ .write_page = at803x_write_page,
/* PHY_GBIT_FEATURES */
.read_status = at803x_read_status,
.aneg_done = at803x_aneg_done,

View File

@ -0,0 +1,73 @@
From 8f7e876273e294b732b42af2e5e6bba91d798954 Mon Sep 17 00:00:00 2001
From: Michael Walle <michael@walle.cc>
Date: Tue, 20 Apr 2021 12:29:29 +0200
Subject: [PATCH] net: phy: at803x: fix probe error if copper page is selected
The commit c329e5afb42f ("net: phy: at803x: select correct page on
config init") selects the copper page during probe. This fails if the
copper page was already selected. In this case, the value of the copper
page (which is 1) is propagated through phy_restore_page() and is
finally returned for at803x_probe(). Fix it, by just using the
at803x_page_write() directly.
Also in case of an error, the regulator is not disabled and leads to a
WARN_ON() when the probe fails. This couldn't happen before, because
at803x_parse_dt() was the last call in at803x_probe(). It is hard to
see, that the parse_dt() actually enables the regulator. Thus move the
regulator_enable() to the probe function and undo it in case of an
error.
Fixes: c329e5afb42f ("net: phy: at803x: select correct page on config init")
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: David Bauer <mail@david-bauer.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -527,10 +527,6 @@ static int at803x_parse_dt(struct phy_de
phydev_err(phydev, "failed to get VDDIO regulator\n");
return PTR_ERR(priv->vddio);
}
-
- ret = regulator_enable(priv->vddio);
- if (ret < 0)
- return ret;
}
return 0;
@@ -552,15 +548,30 @@ static int at803x_probe(struct phy_devic
if (ret)
return ret;
+ if (priv->vddio) {
+ ret = regulator_enable(priv->vddio);
+ if (ret < 0)
+ return ret;
+ }
+
/* Some bootloaders leave the fiber page selected.
* Switch to the copper page, as otherwise we read
* the PHY capabilities from the fiber side.
*/
if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) {
- ret = phy_select_page(phydev, AT803X_PAGE_COPPER);
- ret = phy_restore_page(phydev, AT803X_PAGE_COPPER, ret);
+ phy_lock_mdio_bus(phydev);
+ ret = at803x_write_page(phydev, AT803X_PAGE_COPPER);
+ phy_unlock_mdio_bus(phydev);
+ if (ret)
+ goto err;
}
+ return 0;
+
+err:
+ if (priv->vddio)
+ regulator_disable(priv->vddio);
+
return ret;
}

View File

@ -0,0 +1,104 @@
From c329e5afb42ff0a88285eb4d8a391a18793e4777 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Thu, 15 Apr 2021 03:26:50 +0200
Subject: [PATCH] net: phy: at803x: select correct page on config init
The Atheros AR8031 and AR8033 expose different registers for SGMII/Fiber
as well as the copper side of the PHY depending on the BT_BX_REG_SEL bit
in the chip configure register.
The driver assumes the copper side is selected on probe, but this might
not be the case depending which page was last selected by the
bootloader. Notably, Ubiquiti UniFi bootloaders show this behavior.
Select the copper page when probing to circumvent this.
Signed-off-by: David Bauer <mail@david-bauer.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 50 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -67,6 +67,9 @@
#define ATH8035_PHY_ID 0x004dd072
#define AT803X_PHY_ID_MASK 0xffffffef
+#define AT803X_PAGE_FIBER 0
+#define AT803X_PAGE_COPPER 1
+
MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
@@ -112,6 +115,35 @@ static int at803x_debug_reg_mask(struct
return phy_write(phydev, AT803X_DEBUG_DATA, val);
}
+static int at803x_write_page(struct phy_device *phydev, int page)
+{
+ int mask;
+ int set;
+
+ if (page == AT803X_PAGE_COPPER) {
+ set = AT803X_BT_BX_REG_SEL;
+ mask = 0;
+ } else {
+ set = 0;
+ mask = AT803X_BT_BX_REG_SEL;
+ }
+
+ return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
+}
+
+static int at803x_read_page(struct phy_device *phydev)
+{
+ int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+
+ if (ccr < 0)
+ return ccr;
+
+ if (ccr & AT803X_BT_BX_REG_SEL)
+ return AT803X_PAGE_COPPER;
+
+ return AT803X_PAGE_FIBER;
+}
+
static int at803x_enable_rx_delay(struct phy_device *phydev)
{
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
@@ -244,6 +276,7 @@ static int at803x_probe(struct phy_devic
{
struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -251,7 +284,16 @@ static int at803x_probe(struct phy_devic
phydev->priv = priv;
- return 0;
+ /* Some bootloaders leave the fiber page selected.
+ * Switch to the copper page, as otherwise we read
+ * the PHY capabilities from the fiber side.
+ */
+ if ((phydev->phy_id & phydev->drv->phy_id_mask) == (ATH8031_PHY_ID & phydev->drv->phy_id_mask)) {
+ ret = phy_select_page(phydev, AT803X_PAGE_COPPER);
+ ret = phy_restore_page(phydev, AT803X_PAGE_COPPER, ret);
+ }
+
+ return ret;
}
static int at803x_config_init(struct phy_device *phydev)
@@ -466,6 +508,8 @@ static struct phy_driver at803x_driver[]
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
+ .read_page = at803x_read_page,
+ .write_page = at803x_write_page,
/* PHY_GBIT_FEATURES */
.read_status = at803x_read_status,
.aneg_done = at803x_aneg_done,

View File

@ -0,0 +1,41 @@
From 8f7e876273e294b732b42af2e5e6bba91d798954 Mon Sep 17 00:00:00 2001
From: Michael Walle <michael@walle.cc>
Date: Tue, 20 Apr 2021 12:29:29 +0200
Subject: [PATCH] net: phy: at803x: fix probe error if copper page is selected
The commit c329e5afb42f ("net: phy: at803x: select correct page on
config init") selects the copper page during probe. This fails if the
copper page was already selected. In this case, the value of the copper
page (which is 1) is propagated through phy_restore_page() and is
finally returned for at803x_probe(). Fix it, by just using the
at803x_page_write() directly.
Also in case of an error, the regulator is not disabled and leads to a
WARN_ON() when the probe fails. This couldn't happen before, because
at803x_parse_dt() was the last call in at803x_probe(). It is hard to
see, that the parse_dt() actually enables the regulator. Thus move the
regulator_enable() to the probe function and undo it in case of an
error.
Fixes: c329e5afb42f ("net: phy: at803x: select correct page on config init")
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: David Bauer <mail@david-bauer.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/at803x.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -289,8 +289,9 @@ static int at803x_probe(struct phy_devic
* the PHY capabilities from the fiber side.
*/
if ((phydev->phy_id & phydev->drv->phy_id_mask) == (ATH8031_PHY_ID & phydev->drv->phy_id_mask)) {
- ret = phy_select_page(phydev, AT803X_PAGE_COPPER);
- ret = phy_restore_page(phydev, AT803X_PAGE_COPPER, ret);
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+ ret = at803x_write_page(phydev, AT803X_PAGE_COPPER);
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
}
return ret;

View File

@ -1,51 +0,0 @@
From: Roman Yeryomin <roman@advem.lv>
Subject: kernel: add at803x fix for sgmii mode
Some (possibly broken) bootloaders incorreclty initialize at8033
phy. This patch enables sgmii autonegotiation mode.
[john@phrozen.org: felix added this to his upstream queue]
Signed-off-by: Roman Yeryomin <roman@advem.lv>
---
drivers/net/phy/at803x.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -76,6 +76,7 @@
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
+#define AT803X_SGMII_ANEG_EN 0x1000
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
@@ -562,6 +563,27 @@ static int at8031_pll_config(struct phy_
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
+ u32 v;
+
+ if (phydev->drv->phy_id == ATH8031_PHY_ID &&
+ phydev->interface == PHY_INTERFACE_MODE_SGMII)
+ {
+ v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+ /* select SGMII/fiber page */
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
+ v & ~AT803X_BT_BX_REG_SEL);
+ if (ret)
+ return ret;
+ /* enable SGMII autonegotiation */
+ ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
+ if (ret)
+ return ret;
+ /* select copper page */
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
+ v | AT803X_BT_BX_REG_SEL);
+ if (ret)
+ return ret;
+ }
/* The RX and TX delay default is:
* after HW reset: RX delay enabled and TX delay disabled

View File

@ -1,36 +0,0 @@
Add back explicit PHY feature flags for the AR8031 and
AR8033 PHY instead of reading them from the PHY.
The Botloader for Ubiquiti UniFi AC boards (and possibly more)
leave fiber page selected, thus we will end up reading the PHY
capabilities of the SGMII side (which does not offer 10 Mbit/s).
We already have a hack in place, which switches back to the copper
page, however this happens after capabilities are read.
The original conversation about 735-net-phy-at803x-fix-at8033-sgmii-mode
back in 2015 explicitly mention the UniFi AC Lite. The issue however is
not missing autonegotiation on the Fiber side, but the fact the PHY
is never switched to the copper side. So half of this patch is superfluous.
A fix is currently being upstreamed. Once this is mainlined and available to us,
these patches can be dropped:
735-net-phy-at803x-fix-at8033-sgmii-mode.patch
736-net-phy-at803x-add-at8031-features.patch
This was tested on a UniFi AC Lite.
See https://patchwork.kernel.org/project/netdevbpf/list/?series=467341
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -1119,7 +1119,7 @@ static struct phy_driver at803x_driver[]
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
- /* PHY_GBIT_FEATURES */
+ .features = PHY_GBIT_FEATURES,
.read_status = at803x_read_status,
.aneg_done = at803x_aneg_done,
.ack_interrupt = &at803x_ack_interrupt,

View File

@ -1,51 +0,0 @@
From: Roman Yeryomin <roman@advem.lv>
Subject: kernel: add at803x fix for sgmii mode
Some (possibly broken) bootloaders incorreclty initialize at8033
phy. This patch enables sgmii autonegotiation mode.
[john@phrozen.org: felix added this to his upstream queue]
Signed-off-by: Roman Yeryomin <roman@advem.lv>
---
drivers/net/phy/at803x.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -46,6 +46,7 @@
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
+#define AT803X_SGMII_ANEG_EN 0x1000
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
@@ -259,6 +260,27 @@ static int at803x_probe(struct phy_devic
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
+ u32 v;
+
+ if (phydev->drv->phy_id == ATH8031_PHY_ID &&
+ phydev->interface == PHY_INTERFACE_MODE_SGMII)
+ {
+ v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+ /* select SGMII/fiber page */
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
+ v & ~AT803X_BT_BX_REG_SEL);
+ if (ret)
+ return ret;
+ /* enable SGMII autonegotiation */
+ ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
+ if (ret)
+ return ret;
+ /* select copper page */
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
+ v | AT803X_BT_BX_REG_SEL);
+ if (ret)
+ return ret;
+ }
/* The RX and TX delay default is:
* after HW reset: RX delay enabled and TX delay disabled

View File

@ -1,36 +0,0 @@
Add back explicit PHY feature flags for the AR8031 and
AR8033 PHY instead of reading them from the PHY.
The Botloader for Ubiquiti UniFi AC boards (and possibly more)
leave fiber page selected, thus we will end up reading the PHY
capabilities of the SGMII side (which does not offer 10 Mbit/s).
We already have a hack in place, which switches back to the copper
page, however this happens after capabilities are read.
The original conversation about 735-net-phy-at803x-fix-at8033-sgmii-mode
back in 2015 explicitly mention the UniFi AC Lite. The issue however is
not missing autonegotiation on the Fiber side, but the fact the PHY
is never switched to the copper side. So half of this patch is superfluous.
A fix is currently being upstreamed. Once this is mainlined and available to us,
these patches can be dropped:
735-net-phy-at803x-fix-at8033-sgmii-mode.patch
736-net-phy-at803x-add-at8031-features.patch
This was tested on a UniFi AC Lite.
See https://patchwork.kernel.org/project/netdevbpf/list/?series=467341
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -490,7 +490,7 @@ static struct phy_driver at803x_driver[]
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
- /* PHY_GBIT_FEATURES */
+ .features = PHY_GBIT_FEATURES,
.read_status = at803x_read_status,
.aneg_done = at803x_aneg_done,
.ack_interrupt = &at803x_ack_interrupt,

View File

@ -41,7 +41,7 @@ Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
depends on BCM63XX || COMPILE_TEST
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -63,6 +63,8 @@
@@ -62,6 +62,8 @@
#define AT803X_DEBUG_REG_5 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
@ -50,8 +50,8 @@ Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
#define ATH8032_PHY_ID 0x004dd023
@@ -257,6 +259,19 @@ static int at803x_probe(struct phy_devic
return 0;
@@ -299,10 +301,30 @@ static int at803x_probe(struct phy_devic
return ret;
}
+static void at803x_enable_smart_eee(struct phy_device *phydev, int on)
@ -70,9 +70,6 @@ Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
@@ -282,6 +297,13 @@ static int at803x_config_init(struct phy
return ret;
}
+
+#ifdef CONFIG_AT803X_PHY_SMART_EEE

View File

@ -28,10 +28,10 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
+#define AT803X_SMARTEEE_DISABLED_VAL 0x1000
#define AT803X_SGMII_ANEG_EN 0x1000
#define AT803X_DEBUG_ADDR 0x1D
@@ -65,6 +70,9 @@
#define AT803X_DEBUG_DATA 0x1E
@@ -64,6 +69,9 @@
#define AT803X_LPI_EN BIT(8)
@ -41,9 +41,9 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
#define ATH8032_PHY_ID 0x004dd023
@@ -72,12 +80,16 @@
#define AT803X_PHY_ID_MASK 0xffffffef
#define AT8032_PHY_ID_MASK 0xffffffff
@@ -74,12 +82,16 @@
#define AT803X_PAGE_FIBER 0
#define AT803X_PAGE_COPPER 1
+#define AT803X_EEE_FEATURE_DISABLE (1 << 1)
+#define AT803X_VDDIO_1P8V (1 << 2)
@ -58,7 +58,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
};
struct at803x_context {
@@ -141,6 +153,39 @@ static int at803x_disable_tx_delay(struc
@@ -172,6 +184,39 @@ static int at803x_disable_tx_delay(struc
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
}
@ -98,7 +98,7 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
/* save relevant PHY registers to private copy */
static void at803x_context_save(struct phy_device *phydev,
struct at803x_context *context)
@@ -254,6 +299,12 @@ static int at803x_probe(struct phy_devic
@@ -286,6 +331,12 @@ static int at803x_probe(struct phy_devic
if (!priv)
return -ENOMEM;
@ -110,16 +110,16 @@ Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+
phydev->priv = priv;
return 0;
@@ -275,6 +326,7 @@ static void at803x_enable_smart_eee(stru
/* Some bootloaders leave the fiber page selected.
@@ -316,6 +367,7 @@ static void at803x_enable_smart_eee(stru
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
+ struct at803x_priv *priv = phydev->priv;
u32 v;
int ret;
if (phydev->drv->phy_id == ATH8031_PHY_ID &&
@@ -323,6 +375,18 @@ static int at803x_config_init(struct phy
@@ -344,6 +396,18 @@ static int at803x_config_init(struct phy
else
ret = at803x_disable_tx_delay(phydev);

View File

@ -23,7 +23,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
#define AT803X_SFC_ASSERT_CRS BIT(11)
@@ -83,9 +85,18 @@
@@ -82,9 +84,18 @@
#define AT803X_MODE_CFG_MASK 0x0F
#define AT803X_MODE_CFG_SGMII 0x01
@ -42,7 +42,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
#define AT803X_DEBUG_REG_0 0x00
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
@@ -505,10 +516,72 @@ static int at803x_parse_dt(struct phy_de
@@ -532,12 +543,75 @@ static int at803x_parse_dt(struct phy_de
return 0;
}
@ -100,22 +100,25 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
+ .detach = phy_sfp_detach,
+ .module_insert = at803x_sfp_insert,
+};
+
+
static int at803x_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
+ int ret;
int ret;
+
+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
+ ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
+ if (ret < 0)
+ return ret;
+ }
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -709,6 +782,10 @@ static int at803x_read_status(struct phy
return -ENOMEM;
@@ -744,6 +818,10 @@ static int at803x_read_status(struct phy
{
int ss, err, old_link = phydev->link;
@ -126,7 +129,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
@@ -809,6 +886,12 @@ static int at803x_config_aneg(struct phy
@@ -844,6 +922,12 @@ static int at803x_config_aneg(struct phy
{
int ret;
@ -139,7 +142,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
if (ret < 0)
return ret;
@@ -1110,6 +1193,7 @@ static struct phy_driver at803x_driver[]
@@ -1145,6 +1229,7 @@ static struct phy_driver at803x_driver[]
/* Qualcomm Atheros AR8031/AR8033 */
PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
.name = "Qualcomm Atheros AR8031/AR8033",

View File

@ -23,7 +23,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
#define AT803X_SPECIFIC_STATUS 0x11
#define AT803X_SS_SPEED_MASK (3 << 14)
@@ -53,9 +55,18 @@
@@ -52,9 +54,18 @@
#define AT803X_MODE_CFG_MASK 0x0F
#define AT803X_MODE_CFG_SGMII 0x01
@ -42,7 +42,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
#define AT803X_DEBUG_REG_0 0x00
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
@@ -243,10 +254,72 @@ static int at803x_resume(struct phy_devi
@@ -274,12 +285,73 @@ static int at803x_resume(struct phy_devi
return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
}
@ -105,17 +105,18 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
{
struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
+ int ret;
+
int ret;
+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
+ ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
+ if (ret < 0)
+ return ret;
+ }
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -394,6 +467,10 @@ static int at803x_read_status(struct phy
return -ENOMEM;
@@ -415,6 +487,10 @@ static int at803x_read_status(struct phy
{
int ss, err, old_link = phydev->link;
@ -126,7 +127,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
@@ -448,6 +525,19 @@ static int at803x_read_status(struct phy
@@ -469,6 +545,19 @@ static int at803x_read_status(struct phy
return 0;
}
@ -146,7 +147,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
static struct phy_driver at803x_driver[] = {
{
/* ATHEROS 8035 */
@@ -461,6 +551,7 @@ static struct phy_driver at803x_driver[]
@@ -482,6 +571,7 @@ static struct phy_driver at803x_driver[]
.suspend = at803x_suspend,
.resume = at803x_resume,
/* PHY_GBIT_FEATURES */