Skip to content

Commit

Permalink
realtek: Add support for clause45 PHYs
Browse files Browse the repository at this point in the history
This adds support for the MMD access registers the RTL-SoCs use to access clause 45
PHYs via mdio.
This new interface is used to add EEE-support for the RTL8226

Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
  • Loading branch information
Birger Koblitz authored and ynezz committed May 7, 2021
1 parent 515d9c8 commit 4089904
Show file tree
Hide file tree
Showing 6 changed files with 563 additions and 234 deletions.
Expand Up @@ -313,8 +313,29 @@
#define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc)
#define RTL839X_PHYREG_ACCESS_CTRL (0x03DC)
#define RTL839X_PHYREG_CTRL (0x03E0)
#define RTL839X_PHYREG_PORT_CTRL(p) (0x03E4 + ((p >> 5) << 2))
#define RTL839X_PHYREG_PORT_CTRL (0x03E4)
#define RTL839X_PHYREG_DATA_CTRL (0x03F0)
#define RTL839X_PHYREG_MMD_CTRL (0x3F4)

#define RTL930X_SMI_GLB_CTRL (0xCA00)
#define RTL930X_SMI_POLL_CTRL (0xca90)
#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08)
#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C)
#define RTL930X_SMI_PORT0_5_ADDR (0xCB80)
#define RTL930X_SMI_ACCESS_PHY_CTRL_0 (0xCB70)
#define RTL930X_SMI_ACCESS_PHY_CTRL_1 (0xCB74)
#define RTL930X_SMI_ACCESS_PHY_CTRL_2 (0xCB78)
#define RTL930X_SMI_ACCESS_PHY_CTRL_3 (0xCB7C)

#define RTL931X_SMI_GLB_CTRL1 (0x0CBC)
#define RTL931X_SMI_GLB_CTRL0 (0x0CC0)
#define RTL931X_SMI_PORT_POLLING_CTRL (0x0CCC)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_0 (0x0C00)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_1 (0x0C04)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_2 (0x0C08)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_3 (0x0C10)
#define RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL (0x0C14)
#define RTL931X_SMI_INDRT_ACCESS_MMD_CTRL (0xC18)

#define RTL930X_SMI_GLB_CTRL (0xCA00)
#define RTL930X_SMI_POLL_CTRL (0xca90)
Expand Down
73 changes: 73 additions & 0 deletions target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c
Expand Up @@ -513,6 +513,79 @@ int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
return -ETIMEDOUT;
}

/*
* Read an mmd register of a PHY
*/
int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
{
u32 v;

mutex_lock(&smi_lock);

if (rtl838x_smi_wait_op(10000))
goto timeout;

sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);

sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);

v = addr << 16 | reg;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3);

/* mmd-access | read | cmd-start */
v = 1 << 1 | 0 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);

if (rtl838x_smi_wait_op(10000))
goto timeout;

*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;

mutex_unlock(&smi_lock);
return 0;

timeout:
mutex_unlock(&smi_lock);
return -ETIMEDOUT;
}

/*
* Write to an mmd register of a PHY
*/
int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
{
u32 v;

pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
val &= 0xffff;
mutex_lock(&smi_lock);

if (rtl838x_smi_wait_op(10000))
goto timeout;

sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);

sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);

sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3);
sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3);
/* mmd-access | write | cmd-start */
v = 1 << 1 | 1 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);

if (rtl838x_smi_wait_op(10000))
goto timeout;

mutex_unlock(&smi_lock);
return 0;

timeout:
mutex_unlock(&smi_lock);
return -ETIMEDOUT;
}

void rtl8380_get_version(struct rtl838x_switch_priv *priv)
{
u32 rw_save, info_save;
Expand Down
70 changes: 66 additions & 4 deletions target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c
Expand Up @@ -321,6 +321,7 @@ int rtl8390_sds_power(int mac, int val)
return 0;
}


int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
{
u32 v;
Expand Down Expand Up @@ -358,10 +359,9 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
return -ENOTSUPP;

mutex_lock(&smi_lock);
/* Clear both port registers */
sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0));
sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0) + 4);
sw_w32_mask(0, BIT(port), RTL839X_PHYREG_PORT_CTRL(port));

// Set PHY to access
rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);

sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL);

Expand All @@ -383,6 +383,68 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
return err;
}

/*
* Read an mmd register of the PHY
*/
int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{
int err = 0;
u32 v;

mutex_lock(&smi_lock);

// Set PHY to access
sw_w32_mask(0xffff << 16, port << 16, RTL839X_PHYREG_DATA_CTRL);

// Set MMD device number and register to write to
sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);

v = BIT(2) | BIT(0); // MMD-access | EXEC
sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);

do {
v = sw_r32(RTL839X_PHYREG_ACCESS_CTRL);
} while (v & BIT(0));
// There is no error-checking via BIT 1 of v, as it does not seem to be set correctly
*val = (sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff);
pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);

mutex_unlock(&smi_lock);

return err;
}

/*
* Write to an mmd register of the PHY
*/
int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{
int err = 0;
u32 v;

mutex_lock(&smi_lock);

// Set PHY to access
rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);

// Set data to write
sw_w32_mask(0xffff << 16, val << 16, RTL839X_PHYREG_DATA_CTRL);

// Set MMD device number and register to write to
sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL);

v = BIT(3) | BIT(2) | BIT(0); // WRITE | MMD-access | EXEC
sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL);

do {
v = sw_r32(RTL839X_PHYREG_ACCESS_CTRL);
} while (v & BIT(0));

pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
mutex_unlock(&smi_lock);
return err;
}

void rtl8390_get_version(struct rtl838x_switch_priv *priv)
{
u32 info;
Expand Down
Expand Up @@ -382,7 +382,6 @@ int rtl9300_sds_power(int mac, int val)
return 0;
}


int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val)
{
u32 v;
Expand Down Expand Up @@ -445,7 +444,6 @@ int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
return err;
}


/*
* Write to an mmd register of the PHY
*/
Expand Down
69 changes: 68 additions & 1 deletion target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c
Expand Up @@ -175,6 +175,7 @@ static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e)
// TODO: Implement
return entry;
}

irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
{
struct dsa_switch *ds = dev_id;
Expand All @@ -199,7 +200,6 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}


int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
{
u32 v;
Expand Down Expand Up @@ -264,6 +264,73 @@ int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
return 0;
}

/*
* Read an mmd register of the PHY
*/
int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{
int err = 0;
u32 v;
int type = 1; // TODO: For C45 PHYs need to set to 2

mutex_lock(&smi_lock);

// Set PHY to access via port-number
sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL);

// Set MMD device number and register to write to
sw_w32(devnum << 16 | (regnum & 0xffff), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);

v = type << 2 | BIT(0); // MMD-access-type | EXEC
sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);

do {
v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
} while (v & BIT(0));

// There is no error-checking via BIT 1 of v, as it does not seem to be set correctly

*val = (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_3) & 0xffff);

pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);

mutex_unlock(&smi_lock);

return err;
}

/*
* Write to an mmd register of the PHY
*/
int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{
int err = 0;
u32 v;
int type = 1; // TODO: For C45 PHYs need to set to 2

mutex_lock(&smi_lock);

// Set PHY to access via port-number
sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL);

// Set data to write
sw_w32_mask(0xffff << 16, val << 16, RTL931X_SMI_INDRT_ACCESS_CTRL_3);

// Set MMD device number and register to write to
sw_w32(devnum << 16 | (regnum & 0xffff), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);

v = BIT(4) | type << 2 | BIT(0); // WRITE | MMD-access-type | EXEC
sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);

do {
v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
} while (v & BIT(0));

pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
mutex_unlock(&smi_lock);
return err;
}

void rtl931x_print_matrix(void)
{
volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0);
Expand Down

0 comments on commit 4089904

Please sign in to comment.