Skip to content

Commit

Permalink
realtek: phy: proper RTL8218B, RTL8214FC, RTL8214FB detection
Browse files Browse the repository at this point in the history
Three PHYs share the same identifier. Until now we simply assume
the type depending of the bus address it is attached to. Make it
better and check the chip mode register instead.

The kernel will either detect by id/mask or by match_phy_device().
Remove the unneeded settings.

Signed-off-by: Markus Stockhausen <[email protected]>
  • Loading branch information
plappermaul committed Sep 22, 2024
1 parent a30a9e4 commit ccb0dbd
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 43 deletions.
108 changes: 79 additions & 29 deletions target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,80 @@ static int resume_polling(u64 saved_state)
return 0;
}

int rtph_821x_match_phy_device(struct phy_device *phydev)
{
u64 poll_state;
int rawpage, port = phydev->mdio.addr & ~3;
int oldpage, chip_mode, chip_cfg_mode;

if (soc_info.family != RTL8380_FAMILY_ID && soc_info.family != RTL8390_FAMILY_ID)
return 0;

if (phydev->phy_id == PHY_ID_RTL8218B_E)
return PHY_IS_RTL8218B_E;

if (phydev->phy_id != PHY_ID_RTL8214_OR_8218)
return 0;

if (soc_info.family == RTL8380_FAMILY_ID)
rawpage = RTL838X_PAGE_RAW;
else
rawpage = RTL839X_PAGE_RAW;

poll_state = disable_polling(port);
/*
* At this stage the write_page()/read_page() PHY functions are not yet
* registered and normal paged access is not possible. The following
* detection routine works because our MDIO bus has all the Realtek
* PHY page handling (register 31) integrated into the port functions.
*/
oldpage = phy_port_read_paged(phydev, port, rawpage, 31);
phy_port_write_paged(phydev, port, rawpage, 31, 0xa42);
phy_port_write_paged(phydev, port, rawpage, 29, 0x008);
phy_port_write_paged(phydev, port, rawpage, 31, 0x278);
phy_port_write_paged(phydev, port, rawpage, 18, 0x455);
phy_port_write_paged(phydev, port, rawpage, 31, 0x260);
chip_mode = phy_port_read_paged(phydev, port, rawpage, 18);
phy_port_write_paged(phydev, port, rawpage, 31, 0xa42);
phy_port_write_paged(phydev, port, rawpage, 29, 0x000);
phy_port_write_paged(phydev, port, rawpage, 31, oldpage);

resume_polling(poll_state);

pr_debug("%s(%d): got chip mode %x\n", __func__, phydev->mdio.addr, chip_mode);

/* we checked the 4th port of a RTL8218B and got no config values */
if (!chip_mode)
return PHY_IS_RTL8218B_E;

chip_cfg_mode = (chip_mode >> 4) & 0xf;
chip_mode &= 0xf;

if (chip_mode == 0xd || chip_mode == 0xf)
return PHY_IS_RTL8218B_E;

if (chip_mode == 0x4 || chip_mode == 0x6)
return PHY_IS_RTL8214FC;

if (chip_mode != 0xc && chip_mode != 0xe)
return 0;

if (chip_cfg_mode == 0x4 || chip_cfg_mode == 0x6)
return PHY_IS_RTL8214FC;

return PHY_IS_RTL8214FB;
}

static int rtph_8218b_ext_match_phy_device(struct phy_device *phydev)
{
return rtph_821x_match_phy_device(phydev) == PHY_IS_RTL8218B_E;
}

static int rtph_8214fc_match_phy_device(struct phy_device *phydev)
{
return rtph_821x_match_phy_device(phydev) == PHY_IS_RTL8214FC;
}

static void rtl8380_int_phy_on_off(struct phy_device *phydev, bool on)
{
phy_modify(phydev, 0, BMCR_PDOWN, on ? 0 : BMCR_PDOWN);
Expand Down Expand Up @@ -936,21 +1010,6 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
return 0;
}

static int rtl8218b_ext_match_phy_device(struct phy_device *phydev)
{
int addr = phydev->mdio.addr;

/* Both the RTL8214FC and the external RTL8218B have the same
* PHY ID. On the RTL838x, the RTL8218B can only be attached_dev
* at PHY IDs 0-7, while the RTL8214FC must be attached via
* the pair of SGMII/1000Base-X with higher PHY-IDs
*/
if (soc_info.family == RTL8380_FAMILY_ID)
return phydev->phy_id == PHY_ID_RTL8218B_E && addr < 8;
else
return phydev->phy_id == PHY_ID_RTL8218B_E;
}

static bool rtl8214fc_media_is_fibre(struct phy_device *phydev)
{
int mac = phydev->mdio.addr;
Expand Down Expand Up @@ -1459,13 +1518,6 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
return 0;
}

static int rtl8214fc_match_phy_device(struct phy_device *phydev)
{
int addr = phydev->mdio.addr;

return phydev->phy_id == PHY_ID_RTL8214FC && addr >= 24;
}

static int rtl8380_configure_serdes(struct phy_device *phydev)
{
u32 v;
Expand Down Expand Up @@ -3856,10 +3908,9 @@ static struct phy_driver rtl83xx_phy_driver[] = {
.set_loopback = genphy_loopback,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_RTL8214FC),
.match_phy_device = rtph_8214fc_match_phy_device,
.name = "Realtek RTL8214FC",
.features = PHY_GBIT_FIBRE_FEATURES,
.match_phy_device = rtl8214fc_match_phy_device,
.probe = rtl8214fc_phy_probe,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
Expand All @@ -3872,10 +3923,9 @@ static struct phy_driver rtl83xx_phy_driver[] = {
.get_eee = rtl8214fc_get_eee,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_E),
.match_phy_device = rtph_8218b_ext_match_phy_device,
.name = "Realtek RTL8218B (external)",
.features = PHY_GBIT_FEATURES,
.match_phy_device = rtl8218b_ext_match_phy_device,
.probe = rtl8218b_ext_phy_probe,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
Expand Down Expand Up @@ -3990,12 +4040,12 @@ static struct phy_driver rtl83xx_phy_driver[] = {

module_phy_driver(rtl83xx_phy_driver);

static struct mdio_device_id __maybe_unused rtl83xx_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_RTL8214FC) },
static struct mdio_device_id __maybe_unused rtph_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_RTL8214_OR_8218) },
{ }
};

MODULE_DEVICE_TABLE(mdio, rtl83xx_tbl);
MODULE_DEVICE_TABLE(mdio, rtph_tbl);

MODULE_AUTHOR("B. Koblitz");
MODULE_DESCRIPTION("RTL83xx PHY driver");
Expand Down
32 changes: 18 additions & 14 deletions target/linux/realtek/files-6.6/drivers/net/phy/rtl83xx-phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,25 @@ struct __attribute__ ((__packed__)) fw_header {
};

/* TODO: fixed path? */
#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw"
#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw"
#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw"
#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw"
#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw"
#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw"

/* External RTL8218B and RTL8214FC IDs are identical */
#define PHY_ID_RTL8214C 0x001cc942
#define PHY_ID_RTL8214FC 0x001cc981
#define PHY_ID_RTL8218B_E 0x001cc981
#define PHY_ID_RTL8218D 0x001cc983
#define PHY_ID_RTL8218B_I 0x001cca40
#define PHY_ID_RTL8221B 0x001cc849
#define PHY_ID_RTL8226 0x001cc838
#define PHY_ID_RTL8390_GENERIC 0x001ccab0
#define PHY_ID_RTL8393_I 0x001c8393
#define PHY_ID_RTL9300_I 0x70d03106
#define PHY_ID_RTL8214C 0x001cc942
#define PHY_ID_RTL8218B_E 0x001cc980
#define PHY_ID_RTL8214_OR_8218 0x001cc981
#define PHY_ID_RTL8218D 0x001cc983
#define PHY_ID_RTL8218B_I 0x001cca40
#define PHY_ID_RTL8221B 0x001cc849
#define PHY_ID_RTL8226 0x001cc838
#define PHY_ID_RTL8390_GENERIC 0x001ccab0
#define PHY_ID_RTL8393_I 0x001c8393
#define PHY_ID_RTL9300_I 0x70d03106

/* These PHYs share the same id (0x001cc981) */
#define PHY_IS_RTL8214FC 1
#define PHY_IS_RTL8214FB 2
#define PHY_IS_RTL8218B_E 3

/* Registers of the internal Serdes of the 8380 */
#define RTL838X_SDS_MODE_SEL (0x0028)
Expand Down

0 comments on commit ccb0dbd

Please sign in to comment.