realtek: rtl83xx-phy: abstract and document PHY features

Replace magic values with more self-descriptive code now that I start
to understand more about the design of the PHY (and MDIO controller).

Remove one line before reading RTL8214FC internal PHY id which turned
out to be a no-op and can hence safely be removed (confirmed by
INAGAKI Hiroshi[1])

[1]: df8e6be59a (r66890713)

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2022-02-10 20:17:58 +00:00
parent 68c66b0fa3
commit eef7f17652

View file

@ -22,7 +22,34 @@ extern struct mutex smi_lock;
#define PHY_PAGE_2 2 #define PHY_PAGE_2 2
#define PHY_PAGE_4 4 #define PHY_PAGE_4 4
#define PARK_PAGE 0x1f
/* all Clause-22 RealTek MDIO PHYs use register 0x1f for page select */
#define RTL8XXX_PAGE_SELECT 0x1f
#define RTL8XXX_PAGE_MAIN 0x0000
#define RTL821X_PAGE_PORT 0x0266
#define RTL821X_PAGE_POWER 0x0a40
#define RTL821X_PAGE_GPHY 0x0a42
#define RTL821X_PAGE_MAC 0x0a43
#define RTL821X_PAGE_STATE 0x0b80
#define RTL821X_PAGE_PATCH 0x0b82
/*
* Using the special page 0xfff with the MDIO controller found in
* RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing
* the cache and paging engine of the MDIO controller.
*/
#define RTL83XX_PAGE_RAW 0x0fff
/* internal RTL821X PHY uses register 0x1d to select media page */
#define RTL821XINT_MEDIA_PAGE_SELECT 0x1d
/* external RTL821X PHY uses register 0x1e to select media page */
#define RTL821XEXT_MEDIA_PAGE_SELECT 0x1e
#define RTL821X_MEDIA_PAGE_AUTO 0
#define RTL821X_MEDIA_PAGE_COPPER 1
#define RTL821X_MEDIA_PAGE_FIBRE 3
#define RTL821X_MEDIA_PAGE_INTERNAL 8
#define RTL9300_PHY_ID_MASK 0xf0ffffff #define RTL9300_PHY_ID_MASK 0xf0ffffff
@ -103,12 +130,12 @@ static void rtl8380_int_phy_on_off(struct phy_device *phydev, bool on)
static void rtl8380_rtl8214fc_on_off(struct phy_device *phydev, bool on) static void rtl8380_rtl8214fc_on_off(struct phy_device *phydev, bool on)
{ {
/* fiber ports */ /* fiber ports */
phy_write_paged(phydev, 4095, 30, 3); phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE);
phy_modify(phydev, 16, BIT(11), on?0:BIT(11)); phy_modify(phydev, 0x10, BIT(11), on?0:BIT(11));
/* copper ports */ /* copper ports */
phy_write_paged(phydev, 4095, 30, 1); phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
phy_modify_paged(phydev, 0xa40, 16, BIT(11), on?0:BIT(11)); phy_modify_paged(phydev, RTL821X_PAGE_POWER, 0x10, BIT(11), on?0:BIT(11));
} }
static void rtl8380_phy_reset(struct phy_device *phydev) static void rtl8380_phy_reset(struct phy_device *phydev)
@ -400,12 +427,12 @@ static int rtl8393_read_status(struct phy_device *phydev)
static int rtl8226_read_page(struct phy_device *phydev) static int rtl8226_read_page(struct phy_device *phydev)
{ {
return __phy_read(phydev, 0x1f); return __phy_read(phydev, RTL8XXX_PAGE_SELECT);
} }
static int rtl8226_write_page(struct phy_device *phydev, int page) static int rtl8226_write_page(struct phy_device *phydev, int page)
{ {
return __phy_write(phydev, 0x1f, page); return __phy_write(phydev, RTL8XXX_PAGE_SELECT, page);
} }
static int rtl8226_read_status(struct phy_device *phydev) static int rtl8226_read_status(struct phy_device *phydev)
@ -641,6 +668,25 @@ out:
return NULL; return NULL;
} }
static void rtl821x_phy_setup_package_broadcast(struct phy_device *phydev, bool enable)
{
int mac = phydev->mdio.addr;
/* select main page 0 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
/* write to 0x8 to register 0x1d on main page 0 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
/* select page 0x266 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL821X_PAGE_PORT);
/* set phy id and target broadcast bitmap in register 0x16 on page 0x266 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, 0x16, (enable?0xff00:0x00) | mac);
/* return to main page 0 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
/* write to 0x0 to register 0x1d on main page 0 */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
mdelay(1);
}
static int rtl8390_configure_generic(struct phy_device *phydev) static int rtl8390_configure_generic(struct phy_device *phydev)
{ {
int mac = phydev->mdio.addr; int mac = phydev->mdio.addr;
@ -714,13 +760,13 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
/* Ready PHY for patch */ /* Ready PHY for patch */
for (p = 0; p < 8; p++) { for (p = 0; p < 8; p++) {
phy_package_port_write_paged(phydev, p, 0xfff, 0x1f, 0x0b82); phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL821X_PAGE_PATCH);
phy_package_port_write_paged(phydev, p, 0xfff, 0x10, 0x0010); phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW, 0x10, 0x0010);
} }
msleep(500); msleep(500);
for (p = 0; p < 8; p++) { for (p = 0; p < 8; p++) {
for (i = 0; i < 100 ; i++) { for (i = 0; i < 100 ; i++) {
val = phy_package_port_read_paged(phydev, p, 0x0b80, 0x10); val = phy_package_port_read_paged(phydev, p, RTL821X_PAGE_STATE, 0x10);
if (val & 0x40) if (val & 0x40)
break; break;
} }
@ -734,14 +780,14 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
for (p = 0; p < 8; p++) { for (p = 0; p < 8; p++) {
i = 0; i = 0;
while (rtl838x_6275B_intPhy_perport[i * 2]) { while (rtl838x_6275B_intPhy_perport[i * 2]) {
phy_package_port_write_paged(phydev, p, 0xfff, phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW,
rtl838x_6275B_intPhy_perport[i * 2], rtl838x_6275B_intPhy_perport[i * 2],
rtl838x_6275B_intPhy_perport[i * 2 + 1]); rtl838x_6275B_intPhy_perport[i * 2 + 1]);
i++; i++;
} }
i = 0; i = 0;
while (rtl8218b_6276B_hwEsd_perport[i * 2]) { while (rtl8218b_6276B_hwEsd_perport[i * 2]) {
phy_package_port_write_paged(phydev, p, 0xfff, phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW,
rtl8218b_6276B_hwEsd_perport[i * 2], rtl8218b_6276B_hwEsd_perport[i * 2],
rtl8218b_6276B_hwEsd_perport[i * 2 + 1]); rtl8218b_6276B_hwEsd_perport[i * 2 + 1]);
i++; i++;
@ -806,9 +852,9 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
msleep(100); msleep(100);
/* Get Chip revision */ /* Get Chip revision */
phy_write_paged(phydev, 0xfff, 0x1f, 0x0); phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
phy_write_paged(phydev, 0xfff, 0x1b, 0x4); phy_write_paged(phydev, RTL83XX_PAGE_RAW, 0x1b, 0x4);
val = phy_read_paged(phydev, 0xfff, 0x1c); val = phy_read_paged(phydev, RTL83XX_PAGE_RAW, 0x1c);
phydev_info(phydev, "Detected chip revision %04x\n", val); phydev_info(phydev, "Detected chip revision %04x\n", val);
@ -816,22 +862,22 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
while (rtl8380_rtl8218b_perchip[i * 3] while (rtl8380_rtl8218b_perchip[i * 3]
&& rtl8380_rtl8218b_perchip[i * 3 + 1]) { && rtl8380_rtl8218b_perchip[i * 3 + 1]) {
phy_package_port_write_paged(phydev, rtl8380_rtl8218b_perchip[i * 3], phy_package_port_write_paged(phydev, rtl8380_rtl8218b_perchip[i * 3],
0xfff, rtl8380_rtl8218b_perchip[i * 3 + 1], RTL83XX_PAGE_RAW, rtl8380_rtl8218b_perchip[i * 3 + 1],
rtl8380_rtl8218b_perchip[i * 3 + 2]); rtl8380_rtl8218b_perchip[i * 3 + 2]);
i++; i++;
} }
/* Enable PHY */ /* Enable PHY */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
phy_package_port_write_paged(phydev, i, 0xfff, 0x00, 0x1140); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, 0x00, 0x1140);
} }
mdelay(100); mdelay(100);
/* Request patch */ /* Request patch */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0b82); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL821X_PAGE_PATCH);
phy_package_port_write_paged(phydev, i, 0xfff, 0x10, 0x0010); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, 0x10, 0x0010);
} }
mdelay(300); mdelay(300);
@ -839,7 +885,7 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
/* Verify patch readiness */ /* Verify patch readiness */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
for (l = 0; l < 100; l++) { for (l = 0; l < 100; l++) {
val = phy_package_port_read_paged(phydev, i, 0xb80, 0x10); val = phy_package_port_read_paged(phydev, i, RTL821X_PAGE_STATE, 0x10);
if (val & 0x40) if (val & 0x40)
break; break;
} }
@ -850,15 +896,9 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
} }
/* Use Broadcast ID method for patching */ /* Use Broadcast ID method for patching */
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000); rtl821x_phy_setup_package_broadcast(phydev, true);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
phy_write_paged(phydev, 0xfff, 0x16, 0xff00 + mac);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
mdelay(1);
phy_write_paged(phydev, 0xfff, 30, 8); phy_write_paged(phydev, RTL83XX_PAGE_RAW, 30, 8);
phy_write_paged(phydev, 0x26e, 17, 0xb); phy_write_paged(phydev, 0x26e, 17, 0xb);
phy_write_paged(phydev, 0x26e, 16, 0x2); phy_write_paged(phydev, 0x26e, 16, 0x2);
mdelay(1); mdelay(1);
@ -868,19 +908,13 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
i = 0; i = 0;
while (rtl8218B_6276B_rtl8380_perport[i * 2]) { while (rtl8218B_6276B_rtl8380_perport[i * 2]) {
phy_write_paged(phydev, 0xfff, rtl8218B_6276B_rtl8380_perport[i * 2], phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8218B_6276B_rtl8380_perport[i * 2],
rtl8218B_6276B_rtl8380_perport[i * 2 + 1]); rtl8218B_6276B_rtl8380_perport[i * 2 + 1]);
i++; i++;
} }
/*Disable broadcast ID*/ /*Disable broadcast ID*/
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000); rtl821x_phy_setup_package_broadcast(phydev, false);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
phy_write_paged(phydev, 0xfff, 0x16, 0x00 + mac);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
mdelay(1);
return 0; return 0;
} }
@ -908,25 +942,25 @@ static void rtl8380_rtl8214fc_media_set(struct phy_device *phydev, bool set_fibr
int val, media, power; int val, media, power;
pr_info("%s: port %d, set_fibre: %d\n", __func__, mac, set_fibre); pr_info("%s: port %d, set_fibre: %d\n", __func__, mac, set_fibre);
phy_package_write_paged(phydev, 0xfff, 29, 8); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
val = phy_package_read_paged(phydev, 0x266, reg[mac % 4]); val = phy_package_read_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4]);
media = (val >> 10) & 0x3; media = (val >> 10) & 0x3;
pr_info("Current media %x\n", media); pr_info("Current media %x\n", media);
if (media & 0x2) { if (media & 0x2) {
pr_info("Powering off COPPER\n"); pr_info("Powering off COPPER\n");
phy_package_write_paged(phydev, 0xfff, 29, 1); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
/* Ensure power is off */ /* Ensure power is off */
power = phy_package_read_paged(phydev, 0xa40, 16); power = phy_package_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
if (!(power & (1 << 11))) if (!(power & (1 << 11)))
phy_package_write_paged(phydev, 0xa40, 16, power | (1 << 11)); phy_package_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power | (1 << 11));
} else { } else {
pr_info("Powering off FIBRE"); pr_info("Powering off FIBRE");
phy_package_write_paged(phydev, 0xfff, 29, 3); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE);
/* Ensure power is off */ /* Ensure power is off */
power = phy_package_read_paged(phydev, 0xa40, 16); power = phy_package_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
if (!(power & (1 << 11))) if (!(power & (1 << 11)))
phy_package_write_paged(phydev, 0xa40, 16, power | (1 << 11)); phy_package_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power | (1 << 11));
} }
if (set_fibre) { if (set_fibre) {
@ -936,27 +970,27 @@ static void rtl8380_rtl8214fc_media_set(struct phy_device *phydev, bool set_fibr
val |= 1 << 10; val |= 1 << 10;
val |= 1 << 11; val |= 1 << 11;
} }
phy_package_write_paged(phydev, 0xfff, 29, 8); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
phy_package_write_paged(phydev, 0x266, reg[mac % 4], val); phy_package_write_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4], val);
phy_package_write_paged(phydev, 0xfff, 29, 0); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
if (set_fibre) { if (set_fibre) {
pr_info("Powering on FIBRE"); pr_info("Powering on FIBRE");
phy_package_write_paged(phydev, 0xfff, 29, 3); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_FIBRE);
/* Ensure power is off */ /* Ensure power is off */
power = phy_package_read_paged(phydev, 0xa40, 16); power = phy_package_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
if (power & (1 << 11)) if (power & (1 << 11))
phy_package_write_paged(phydev, 0xa40, 16, power & ~(1 << 11)); phy_package_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power & ~(1 << 11));
} else { } else {
pr_info("Powering on COPPER\n"); pr_info("Powering on COPPER\n");
phy_package_write_paged(phydev, 0xfff, 29, 1); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
/* Ensure power is off */ /* Ensure power is off */
power = phy_package_read_paged(phydev, 0xa40, 16); power = phy_package_read_paged(phydev, RTL821X_PAGE_POWER, 0x10);
if (power & (1 << 11)) if (power & (1 << 11))
phy_package_write_paged(phydev, 0xa40, 16, power & ~(1 << 11)); phy_package_write_paged(phydev, RTL821X_PAGE_POWER, 0x10, power & ~(1 << 11));
} }
phy_package_write_paged(phydev, 0xfff, 29, 0); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
} }
static bool rtl8380_rtl8214fc_media_is_fibre(struct phy_device *phydev) static bool rtl8380_rtl8214fc_media_is_fibre(struct phy_device *phydev)
@ -966,9 +1000,9 @@ static bool rtl8380_rtl8214fc_media_is_fibre(struct phy_device *phydev)
static int reg[] = {16, 19, 20, 21}; static int reg[] = {16, 19, 20, 21};
u32 val; u32 val;
phy_package_write_paged(phydev, 0xfff, 29, 8); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_INTERNAL);
val = phy_package_read_paged(phydev, 0x266, reg[mac % 4]); val = phy_package_read_paged(phydev, RTL821X_PAGE_PORT, reg[mac % 4]);
phy_package_write_paged(phydev, 0xfff, 29, 0); phy_package_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
if (val & (1 << 11)) if (val & (1 << 11))
return false; return false;
return true; return true;
@ -1008,7 +1042,7 @@ void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
pr_debug("In %s %d, enable %d\n", __func__, phydev->mdio.addr, enable); pr_debug("In %s %d, enable %d\n", __func__, phydev->mdio.addr, enable);
/* Set GPHY page to copper */ /* Set GPHY page to copper */
phy_write_paged(phydev, 0xa42, 30, 0x0001); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
val = phy_read(phydev, 0); val = phy_read(phydev, 0);
an_enabled = val & BIT(12); an_enabled = val & BIT(12);
@ -1019,12 +1053,12 @@ void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
phy_write_mmd(phydev, 7, 60, enable ? 0x6 : 0); phy_write_mmd(phydev, 7, 60, enable ? 0x6 : 0);
/* 500M EEE ability */ /* 500M EEE ability */
val = phy_read_paged(phydev, 0xa42, 20); val = phy_read_paged(phydev, RTL821X_PAGE_GPHY, 20);
if (enable) if (enable)
val |= BIT(7); val |= BIT(7);
else else
val &= ~BIT(7); val &= ~BIT(7);
phy_write_paged(phydev, 0xa42, 20, val); phy_write_paged(phydev, RTL821X_PAGE_GPHY, 20, val);
/* Restart AN if enabled */ /* Restart AN if enabled */
if (an_enabled) { if (an_enabled) {
@ -1034,7 +1068,7 @@ void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
} }
/* GPHY page back to auto*/ /* GPHY page back to auto*/
phy_write_paged(phydev, 0xa42, 30, 0); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
} }
static int rtl8218b_get_eee(struct phy_device *phydev, static int rtl8218b_get_eee(struct phy_device *phydev,
@ -1046,21 +1080,21 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled); pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
/* Set GPHY page to copper */ /* Set GPHY page to copper */
phy_write_paged(phydev, 0xa42, 29, 0x0001); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
val = phy_read_paged(phydev, 7, 60); val = phy_read_paged(phydev, 7, 60);
if (e->eee_enabled) { if (e->eee_enabled) {
// Verify vs MAC-based EEE // Verify vs MAC-based EEE
e->eee_enabled = !!(val & BIT(7)); e->eee_enabled = !!(val & BIT(7));
if (!e->eee_enabled) { if (!e->eee_enabled) {
val = phy_read_paged(phydev, 0x0A43, 25); val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
e->eee_enabled = !!(val & BIT(4)); e->eee_enabled = !!(val & BIT(4));
} }
} }
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled); pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
/* GPHY page to auto */ /* GPHY page to auto */
phy_write_paged(phydev, 0xa42, 29, 0x0000); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
return 0; return 0;
} }
@ -1074,7 +1108,7 @@ static int rtl8218d_get_eee(struct phy_device *phydev,
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled); pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
/* Set GPHY page to copper */ /* Set GPHY page to copper */
phy_write_paged(phydev, 0xa42, 30, 0x0001); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
val = phy_read_paged(phydev, 7, 60); val = phy_read_paged(phydev, 7, 60);
if (e->eee_enabled) if (e->eee_enabled)
@ -1082,7 +1116,7 @@ static int rtl8218d_get_eee(struct phy_device *phydev,
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled); pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
/* GPHY page to auto */ /* GPHY page to auto */
phy_write_paged(phydev, 0xa42, 30, 0x0000); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
return 0; return 0;
} }
@ -1105,28 +1139,28 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
poll_state = disable_polling(port); poll_state = disable_polling(port);
/* Set GPHY page to copper */ /* Set GPHY page to copper */
phy_write_paged(phydev, 0xa42, 29, 0x0001); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
// Get auto-negotiation status // Get auto-negotiation status
val = phy_read(phydev, 0); val = phy_read(phydev, 0);
an_enabled = val & BIT(12); an_enabled = val & BIT(12);
pr_info("%s: aneg: %d\n", __func__, an_enabled); pr_info("%s: aneg: %d\n", __func__, an_enabled);
val = phy_read_paged(phydev, 0x0A43, 25); val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
val &= ~BIT(5); // Use MAC-based EEE val &= ~BIT(5); // Use MAC-based EEE
phy_write_paged(phydev, 0x0A43, 25, val); phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
/* Enable 100M (bit 1) / 1000M (bit 2) EEE */ /* Enable 100M (bit 1) / 1000M (bit 2) EEE */
phy_write_paged(phydev, 7, 60, e->eee_enabled ? 0x6 : 0); phy_write_paged(phydev, 7, 60, e->eee_enabled ? 0x6 : 0);
/* 500M EEE ability */ /* 500M EEE ability */
val = phy_read_paged(phydev, 0xa42, 20); val = phy_read_paged(phydev, RTL821X_PAGE_GPHY, 20);
if (e->eee_enabled) if (e->eee_enabled)
val |= BIT(7); val |= BIT(7);
else else
val &= ~BIT(7); val &= ~BIT(7);
phy_write_paged(phydev, 0xa42, 20, val); phy_write_paged(phydev, RTL821X_PAGE_GPHY, 20, val);
/* Restart AN if enabled */ /* Restart AN if enabled */
if (an_enabled) { if (an_enabled) {
@ -1137,7 +1171,7 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
} }
/* GPHY page back to auto*/ /* GPHY page back to auto*/
phy_write_paged(phydev, 0xa42, 29, 0); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
resume_polling(poll_state); resume_polling(poll_state);
@ -1170,7 +1204,7 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
poll_state = disable_polling(port); poll_state = disable_polling(port);
/* Set GPHY page to copper */ /* Set GPHY page to copper */
phy_write(phydev, 30, 0x0001); phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
val = phy_read(phydev, 0); val = phy_read(phydev, 0);
an_enabled = val & BIT(12); an_enabled = val & BIT(12);
@ -1181,9 +1215,9 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
phy_write(phydev, 13, 0x4007); phy_write(phydev, 13, 0x4007);
phy_write(phydev, 14, 0x0006); phy_write(phydev, 14, 0x0006);
val = phy_read_paged(phydev, 0x0A43, 25); val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
val |= BIT(4); val |= BIT(4);
phy_write_paged(phydev, 0x0A43, 25, val); phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
} else { } else {
/* 100/1000M EEE Capability */ /* 100/1000M EEE Capability */
phy_write(phydev, 13, 0x0007); phy_write(phydev, 13, 0x0007);
@ -1191,9 +1225,9 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
phy_write(phydev, 13, 0x0007); phy_write(phydev, 13, 0x0007);
phy_write(phydev, 14, 0x0000); phy_write(phydev, 14, 0x0000);
val = phy_read_paged(phydev, 0x0A43, 25); val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
val &= ~BIT(4); val &= ~BIT(4);
phy_write_paged(phydev, 0x0A43, 25, val); phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
} }
/* Restart AN if enabled */ /* Restart AN if enabled */
@ -1204,7 +1238,7 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
} }
/* GPHY page back to auto*/ /* GPHY page back to auto*/
phy_write_paged(phydev, 0xa42, 30, 0); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
pr_info("%s done\n", __func__); pr_info("%s done\n", __func__);
resume_polling(poll_state); resume_polling(poll_state);
@ -1247,7 +1281,7 @@ static int rtl8380_configure_rtl8214c(struct phy_device *phydev)
phydev_info(phydev, "Detected external RTL8214C\n"); phydev_info(phydev, "Detected external RTL8214C\n");
/* GPHY auto conf */ /* GPHY auto conf */
phy_write_paged(phydev, 0xa42, 29, 0); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
return 0; return 0;
} }
@ -1267,10 +1301,9 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
pr_debug("Phy on MAC %d: %x\n", mac, phy_id); pr_debug("Phy on MAC %d: %x\n", mac, phy_id);
/* Read internal PHY id */ /* Read internal PHY id */
phy_write_paged(phydev, 0, 30, 0x0001); phy_write_paged(phydev, 0, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
phy_write_paged(phydev, 0, 31, 0x0a42); phy_write_paged(phydev, 0x1f, 0x1b, 0x0002);
phy_write_paged(phydev, 31, 27, 0x0002); val = phy_read_paged(phydev, 0x1f, 0x1c);
val = phy_read_paged(phydev, 31, 28);
if (val != 0x6276) { if (val != 0x6276) {
phydev_err(phydev, "Expected external RTL8214FC, found PHY-ID %x\n", val); phydev_err(phydev, "Expected external RTL8214FC, found PHY-ID %x\n", val);
return -1; return -1;
@ -1293,8 +1326,8 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
+ h->parts[1].start; + h->parts[1].start;
/* detect phy version */ /* detect phy version */
phy_write_paged(phydev, 0xfff, 27, 0x0004); phy_write_paged(phydev, RTL83XX_PAGE_RAW, 27, 0x0004);
val = phy_read_paged(phydev, 0xfff, 28); val = phy_read_paged(phydev, RTL83XX_PAGE_RAW, 28);
val = phy_read(phydev, 16); val = phy_read(phydev, 16);
if (val & (1 << 11)) if (val & (1 << 11))
@ -1303,7 +1336,7 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
rtl8380_phy_reset(phydev); rtl8380_phy_reset(phydev);
msleep(100); msleep(100);
phy_write_paged(phydev, 0, 30, 0x0001); phy_write_paged(phydev, 0, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
i = 0; i = 0;
while (rtl8380_rtl8214fc_perchip[i * 3] while (rtl8380_rtl8214fc_perchip[i * 3]
@ -1314,10 +1347,10 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
val = phy_read_paged(phydev, 0x260, 13); val = phy_read_paged(phydev, 0x260, 13);
val = (val & 0x1f00) | (rtl8380_rtl8214fc_perchip[i * 3 + 2] val = (val & 0x1f00) | (rtl8380_rtl8214fc_perchip[i * 3 + 2]
& 0xe0ff); & 0xe0ff);
phy_write_paged(phydev, 0xfff, phy_write_paged(phydev, RTL83XX_PAGE_RAW,
rtl8380_rtl8214fc_perchip[i * 3 + 1], val); rtl8380_rtl8214fc_perchip[i * 3 + 1], val);
} else { } else {
phy_write_paged(phydev, 0xfff, phy_write_paged(phydev, RTL83XX_PAGE_RAW,
rtl8380_rtl8214fc_perchip[i * 3 + 1], rtl8380_rtl8214fc_perchip[i * 3 + 1],
rtl8380_rtl8214fc_perchip[i * 3 + 2]); rtl8380_rtl8214fc_perchip[i * 3 + 2]);
} }
@ -1326,21 +1359,21 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
/* Force copper medium */ /* Force copper medium */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
phy_package_port_write_paged(phydev, i, 0xfff, 0x1e, 0x0001); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
} }
/* Enable PHY */ /* Enable PHY */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
phy_package_port_write_paged(phydev, i, 0xfff, 0x00, 0x1140); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, 0x00, 0x1140);
} }
mdelay(100); mdelay(100);
/* Disable Autosensing */ /* Disable Autosensing */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
for (l = 0; l < 100; l++) { for (l = 0; l < 100; l++) {
val = phy_package_port_read_paged(phydev, i, 0x0a42, 0x10); val = phy_package_port_read_paged(phydev, i, RTL821X_PAGE_GPHY, 0x10);
if ((val & 0x7) >= 3) if ((val & 0x7) >= 3)
break; break;
} }
@ -1352,15 +1385,15 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
/* Request patch */ /* Request patch */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0b82); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL821X_PAGE_PATCH);
phy_package_port_write_paged(phydev, i, 0xfff, 0x10, 0x0010); phy_package_port_write_paged(phydev, i, RTL83XX_PAGE_RAW, 0x10, 0x0010);
} }
mdelay(300); mdelay(300);
/* Verify patch readiness */ /* Verify patch readiness */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
for (l = 0; l < 100; l++) { for (l = 0; l < 100; l++) {
val = phy_package_port_read_paged(phydev, i, 0xb80, 0x10); val = phy_package_port_read_paged(phydev, i, RTL821X_PAGE_STATE, 0x10);
if (val & 0x40) if (val & 0x40)
break; break;
} }
@ -1370,34 +1403,22 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
} }
} }
/* Use Broadcast ID method for patching */ /* Use Broadcast ID method for patching */
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000); rtl821x_phy_setup_package_broadcast(phydev, true);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
phy_write_paged(phydev, 0xfff, 0x16, 0xff00 + mac);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
mdelay(1);
i = 0; i = 0;
while (rtl8380_rtl8214fc_perport[i * 2]) { while (rtl8380_rtl8214fc_perport[i * 2]) {
phy_write_paged(phydev, 0xfff, rtl8380_rtl8214fc_perport[i * 2], phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8380_rtl8214fc_perport[i * 2],
rtl8380_rtl8214fc_perport[i * 2 + 1]); rtl8380_rtl8214fc_perport[i * 2 + 1]);
i++; i++;
} }
/*Disable broadcast ID*/ /*Disable broadcast ID*/
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000); rtl821x_phy_setup_package_broadcast(phydev, false);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
phy_write_paged(phydev, 0xfff, 0x16, 0x00 + mac);
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
mdelay(1);
/* Auto medium selection */ /* Auto medium selection */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
phy_write_paged(phydev, 0xfff, 0x1f, 0x0000); phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL8XXX_PAGE_SELECT, RTL8XXX_PAGE_MAIN);
phy_write_paged(phydev, 0xfff, 0x1e, 0x0000); phy_write_paged(phydev, RTL83XX_PAGE_RAW, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
} }
return 0; return 0;