Skip to content

Commit c329e5a

Browse files
blocktrrondavem330
authored andcommitted
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>
1 parent bd363f5 commit c329e5a

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

drivers/net/phy/at803x.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@
144144
#define ATH8035_PHY_ID 0x004dd072
145145
#define AT8030_PHY_ID_MASK 0xffffffef
146146

147+
#define AT803X_PAGE_FIBER 0
148+
#define AT803X_PAGE_COPPER 1
149+
147150
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
148151
MODULE_AUTHOR("Matus Ujhelyi");
149152
MODULE_LICENSE("GPL");
@@ -198,6 +201,35 @@ static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
198201
return phy_write(phydev, AT803X_DEBUG_DATA, val);
199202
}
200203

204+
static int at803x_write_page(struct phy_device *phydev, int page)
205+
{
206+
int mask;
207+
int set;
208+
209+
if (page == AT803X_PAGE_COPPER) {
210+
set = AT803X_BT_BX_REG_SEL;
211+
mask = 0;
212+
} else {
213+
set = 0;
214+
mask = AT803X_BT_BX_REG_SEL;
215+
}
216+
217+
return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
218+
}
219+
220+
static int at803x_read_page(struct phy_device *phydev)
221+
{
222+
int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
223+
224+
if (ccr < 0)
225+
return ccr;
226+
227+
if (ccr & AT803X_BT_BX_REG_SEL)
228+
return AT803X_PAGE_COPPER;
229+
230+
return AT803X_PAGE_FIBER;
231+
}
232+
201233
static int at803x_enable_rx_delay(struct phy_device *phydev)
202234
{
203235
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
@@ -535,14 +567,28 @@ static int at803x_probe(struct phy_device *phydev)
535567
{
536568
struct device *dev = &phydev->mdio.dev;
537569
struct at803x_priv *priv;
570+
int ret;
538571

539572
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
540573
if (!priv)
541574
return -ENOMEM;
542575

543576
phydev->priv = priv;
544577

545-
return at803x_parse_dt(phydev);
578+
ret = at803x_parse_dt(phydev);
579+
if (ret)
580+
return ret;
581+
582+
/* Some bootloaders leave the fiber page selected.
583+
* Switch to the copper page, as otherwise we read
584+
* the PHY capabilities from the fiber side.
585+
*/
586+
if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) {
587+
ret = phy_select_page(phydev, AT803X_PAGE_COPPER);
588+
ret = phy_restore_page(phydev, AT803X_PAGE_COPPER, ret);
589+
}
590+
591+
return ret;
546592
}
547593

548594
static void at803x_remove(struct phy_device *phydev)
@@ -1166,6 +1212,8 @@ static struct phy_driver at803x_driver[] = {
11661212
.get_wol = at803x_get_wol,
11671213
.suspend = at803x_suspend,
11681214
.resume = at803x_resume,
1215+
.read_page = at803x_read_page,
1216+
.write_page = at803x_write_page,
11691217
/* PHY_GBIT_FEATURES */
11701218
.read_status = at803x_read_status,
11711219
.config_intr = &at803x_config_intr,

0 commit comments

Comments
 (0)