mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 23:42:43 +00:00
realtek: Add support for clause45 PHYs
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>
This commit is contained in:
parent
515d9c85f2
commit
408990464c
@ -313,8 +313,29 @@
|
|||||||
#define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc)
|
#define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc)
|
||||||
#define RTL839X_PHYREG_ACCESS_CTRL (0x03DC)
|
#define RTL839X_PHYREG_ACCESS_CTRL (0x03DC)
|
||||||
#define RTL839X_PHYREG_CTRL (0x03E0)
|
#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_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_GLB_CTRL (0xCA00)
|
||||||
#define RTL930X_SMI_POLL_CTRL (0xca90)
|
#define RTL930X_SMI_POLL_CTRL (0xca90)
|
||||||
|
@ -513,6 +513,79 @@ timeout:
|
|||||||
return -ETIMEDOUT;
|
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)
|
void rtl8380_get_version(struct rtl838x_switch_priv *priv)
|
||||||
{
|
{
|
||||||
u32 rw_save, info_save;
|
u32 rw_save, info_save;
|
||||||
|
@ -321,6 +321,7 @@ int rtl8390_sds_power(int mac, int val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
@ -358,10 +359,9 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
|||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
||||||
mutex_lock(&smi_lock);
|
mutex_lock(&smi_lock);
|
||||||
/* Clear both port registers */
|
|
||||||
sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0));
|
// Set PHY to access
|
||||||
sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0) + 4);
|
rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL);
|
||||||
sw_w32_mask(0, BIT(port), RTL839X_PHYREG_PORT_CTRL(port));
|
|
||||||
|
|
||||||
sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL);
|
sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL);
|
||||||
|
|
||||||
@ -383,6 +383,68 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
|||||||
return err;
|
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)
|
void rtl8390_get_version(struct rtl838x_switch_priv *priv)
|
||||||
{
|
{
|
||||||
u32 info;
|
u32 info;
|
||||||
|
@ -382,7 +382,6 @@ int rtl9300_sds_power(int mac, int val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
@ -445,7 +444,6 @@ int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write to an mmd register of the PHY
|
* Write to an mmd register of the PHY
|
||||||
*/
|
*/
|
||||||
|
@ -175,6 +175,7 @@ static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e)
|
|||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
|
irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct dsa_switch *ds = dev_id;
|
struct dsa_switch *ds = dev_id;
|
||||||
@ -199,7 +200,6 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
@ -264,6 +264,73 @@ int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
|||||||
return 0;
|
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)
|
void rtl931x_print_matrix(void)
|
||||||
{
|
{
|
||||||
volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0);
|
volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0);
|
||||||
|
@ -18,12 +18,26 @@
|
|||||||
extern struct rtl83xx_soc_info soc_info;
|
extern struct rtl83xx_soc_info soc_info;
|
||||||
extern struct mutex smi_lock;
|
extern struct mutex smi_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This lock protects the state of the SoC automatically polling the PHYs over the SMI
|
||||||
|
* bus to detect e.g. link and media changes. For operations on the PHYs such as
|
||||||
|
* patching or other configuration changes such as EEE, polling needs to be disabled
|
||||||
|
* since otherwise these operations may fails or lead to unpredictable results.
|
||||||
|
*/
|
||||||
|
DEFINE_MUTEX(poll_lock);
|
||||||
|
|
||||||
static const struct firmware rtl838x_8380_fw;
|
static const struct firmware rtl838x_8380_fw;
|
||||||
static const struct firmware rtl838x_8214fc_fw;
|
static const struct firmware rtl838x_8214fc_fw;
|
||||||
static const struct firmware rtl838x_8218b_fw;
|
static const struct firmware rtl838x_8218b_fw;
|
||||||
|
|
||||||
|
int rtl838x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||||
|
int rtl838x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
|
||||||
|
int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||||
|
int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
|
||||||
int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||||
int rtl930x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
|
int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
|
||||||
|
int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||||
|
int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
|
||||||
|
|
||||||
static int read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
static int read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
||||||
{ switch (soc_info.family) {
|
{ switch (soc_info.family) {
|
||||||
@ -54,6 +68,93 @@ static int write_phy(u32 port, u32 page, u32 reg, u32 val)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
|
||||||
|
{
|
||||||
|
switch (soc_info.family) {
|
||||||
|
case RTL8380_FAMILY_ID:
|
||||||
|
return rtl838x_read_mmd_phy(port, devnum, regnum, val);
|
||||||
|
case RTL8390_FAMILY_ID:
|
||||||
|
return rtl839x_read_mmd_phy(port, devnum, regnum, val);
|
||||||
|
case RTL9300_FAMILY_ID:
|
||||||
|
return rtl930x_read_mmd_phy(port, devnum, regnum, val);
|
||||||
|
case RTL9310_FAMILY_ID:
|
||||||
|
return rtl931x_read_mmd_phy(port, devnum, regnum, val);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val)
|
||||||
|
{
|
||||||
|
switch (soc_info.family) {
|
||||||
|
case RTL8380_FAMILY_ID:
|
||||||
|
return rtl838x_write_mmd_phy(port, devnum, reg, val);
|
||||||
|
case RTL8390_FAMILY_ID:
|
||||||
|
return rtl839x_write_mmd_phy(port, devnum, reg, val);
|
||||||
|
case RTL9300_FAMILY_ID:
|
||||||
|
return rtl930x_write_mmd_phy(port, devnum, reg, val);
|
||||||
|
case RTL9310_FAMILY_ID:
|
||||||
|
return rtl931x_write_mmd_phy(port, devnum, reg, val);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 disable_polling(int port)
|
||||||
|
{
|
||||||
|
u64 saved_state;
|
||||||
|
|
||||||
|
mutex_lock(&poll_lock);
|
||||||
|
|
||||||
|
switch (soc_info.family) {
|
||||||
|
case RTL8380_FAMILY_ID:
|
||||||
|
saved_state = sw_r32(RTL838X_SMI_POLL_CTRL);
|
||||||
|
sw_w32_mask(BIT(port), 0, RTL838X_SMI_POLL_CTRL);
|
||||||
|
break;
|
||||||
|
case RTL8390_FAMILY_ID:
|
||||||
|
saved_state = sw_r32(RTL839X_SMI_PORT_POLLING_CTRL + 4);
|
||||||
|
saved_state <<= 32;
|
||||||
|
saved_state |= sw_r32(RTL839X_SMI_PORT_POLLING_CTRL);
|
||||||
|
sw_w32_mask(BIT(port % 32), 0,
|
||||||
|
RTL839X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2));
|
||||||
|
break;
|
||||||
|
case RTL9300_FAMILY_ID:
|
||||||
|
saved_state = sw_r32(RTL930X_SMI_POLL_CTRL);
|
||||||
|
sw_w32_mask(BIT(port), 0, RTL930X_SMI_POLL_CTRL);
|
||||||
|
break;
|
||||||
|
case RTL9310_FAMILY_ID:
|
||||||
|
pr_warn("%s not implemented for RTL931X\n", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&poll_lock);
|
||||||
|
|
||||||
|
return saved_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resume_polling(u64 saved_state)
|
||||||
|
{
|
||||||
|
mutex_lock(&poll_lock);
|
||||||
|
|
||||||
|
switch (soc_info.family) {
|
||||||
|
case RTL8380_FAMILY_ID:
|
||||||
|
sw_w32(saved_state, RTL838X_SMI_POLL_CTRL);
|
||||||
|
break;
|
||||||
|
case RTL8390_FAMILY_ID:
|
||||||
|
sw_w32(saved_state >> 32, RTL839X_SMI_PORT_POLLING_CTRL + 4);
|
||||||
|
sw_w32(saved_state, RTL839X_SMI_PORT_POLLING_CTRL);
|
||||||
|
break;
|
||||||
|
case RTL9300_FAMILY_ID:
|
||||||
|
sw_w32(saved_state, RTL930X_SMI_POLL_CTRL);
|
||||||
|
break;
|
||||||
|
case RTL9310_FAMILY_ID:
|
||||||
|
pr_warn("%s not implemented for RTL931X\n", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&poll_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void rtl8380_int_phy_on_off(int mac, bool on)
|
static void rtl8380_int_phy_on_off(int mac, bool on)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
@ -94,18 +195,6 @@ static void rtl8380_phy_reset(int mac)
|
|||||||
write_phy(mac, 0, 0, val | BIT(15));
|
write_phy(mac, 0, 0, val | BIT(15));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8380_sds_rst(int mac)
|
|
||||||
{
|
|
||||||
u32 offset = (mac == 24) ? 0 : 0x100;
|
|
||||||
|
|
||||||
sw_w32_mask(1 << 11, 0, RTL8380_SDS4_FIB_REG0 + offset);
|
|
||||||
sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset);
|
|
||||||
sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset);
|
|
||||||
sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset);
|
|
||||||
sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset);
|
|
||||||
pr_info("SERDES reset: %d\n", mac);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the SerDes by powering it off and set a new operations mode
|
* Reset the SerDes by powering it off and set a new operations mode
|
||||||
* of the SerDes. 0x1f is off. Other modes are
|
* of the SerDes. 0x1f is off. Other modes are
|
||||||
@ -307,6 +396,7 @@ static int rtl8393_read_status(struct phy_device *phydev)
|
|||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, 0x1f);
|
||||||
@ -331,20 +421,20 @@ static int rtl8226_read_status(struct phy_device *phydev)
|
|||||||
|
|
||||||
// Link status must be read twice
|
// Link status must be read twice
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA402, &val);
|
read_mmd_phy(port, MMD_VEND2, 0xA402, &val);
|
||||||
}
|
}
|
||||||
phydev->link = val & BIT(2) ? 1 : 0;
|
phydev->link = val & BIT(2) ? 1 : 0;
|
||||||
if (!phydev->link)
|
if (!phydev->link)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Read duplex status
|
// Read duplex status
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
phydev->duplex = !!(val & BIT(3));
|
phydev->duplex = !!(val & BIT(3));
|
||||||
|
|
||||||
// Read speed
|
// Read speed
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
||||||
switch (val & 0x0630) {
|
switch (val & 0x0630) {
|
||||||
case 0x0000:
|
case 0x0000:
|
||||||
phydev->speed = SPEED_10;
|
phydev->speed = SPEED_10;
|
||||||
@ -371,7 +461,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8266_advertise_aneg(struct phy_device *phydev)
|
static int rtl8226_advertise_aneg(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 v;
|
u32 v;
|
||||||
@ -379,7 +469,7 @@ static int rtl8266_advertise_aneg(struct phy_device *phydev)
|
|||||||
|
|
||||||
pr_info("In %s\n", __func__);
|
pr_info("In %s\n", __func__);
|
||||||
|
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_AN, 16, &v);
|
ret = read_mmd_phy(port, MMD_AN, 16, &v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -388,31 +478,30 @@ static int rtl8266_advertise_aneg(struct phy_device *phydev)
|
|||||||
v |= BIT(7); // HD 100M
|
v |= BIT(7); // HD 100M
|
||||||
v |= BIT(8); // FD 100M
|
v |= BIT(8); // FD 100M
|
||||||
|
|
||||||
ret = rtl930x_write_mmd_phy(port, MMD_AN, 16, v);
|
ret = write_mmd_phy(port, MMD_AN, 16, v);
|
||||||
|
|
||||||
// Allow 1GBit
|
// Allow 1GBit
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA412, &v);
|
ret = read_mmd_phy(port, MMD_VEND2, 0xA412, &v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
v |= BIT(9); // FD 1000M
|
v |= BIT(9); // FD 1000M
|
||||||
|
|
||||||
ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA412, v);
|
ret = write_mmd_phy(port, MMD_VEND2, 0xA412, v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Allow 2.5G
|
// Allow 2.5G
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_AN, 32, &v);
|
ret = read_mmd_phy(port, MMD_AN, 32, &v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
v |= BIT(7);
|
v |= BIT(7);
|
||||||
ret = rtl930x_write_mmd_phy(port, MMD_AN, 32, v);
|
ret = write_mmd_phy(port, MMD_AN, 32, v);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int rtl8226_config_aneg(struct phy_device *phydev)
|
static int rtl8226_config_aneg(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -421,26 +510,26 @@ static int rtl8226_config_aneg(struct phy_device *phydev)
|
|||||||
|
|
||||||
pr_info("In %s\n", __func__);
|
pr_info("In %s\n", __func__);
|
||||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||||
ret = rtl8266_advertise_aneg(phydev);
|
ret = rtl8226_advertise_aneg(phydev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
// AutoNegotiationEnable
|
// AutoNegotiationEnable
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_AN, 0, &v);
|
ret = read_mmd_phy(port, MMD_AN, 0, &v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
v |= BIT(12); // Enable AN
|
v |= BIT(12); // Enable AN
|
||||||
ret = rtl930x_write_mmd_phy(port, MMD_AN, 0, v);
|
ret = write_mmd_phy(port, MMD_AN, 0, v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// RestartAutoNegotiation
|
// RestartAutoNegotiation
|
||||||
ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA400, &v);
|
ret = read_mmd_phy(port, MMD_VEND2, 0xA400, &v);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
v |= BIT(9);
|
v |= BIT(9);
|
||||||
|
|
||||||
ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA400, v);
|
ret = write_mmd_phy(port, MMD_VEND2, 0xA400, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("%s: Ret is already: %d\n", __func__, ret);
|
pr_info("%s: Ret is already: %d\n", __func__, ret);
|
||||||
@ -451,6 +540,68 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtl8226_get_eee(struct phy_device *phydev,
|
||||||
|
struct ethtool_eee *e)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
int addr = phydev->mdio.addr;
|
||||||
|
|
||||||
|
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
|
||||||
|
|
||||||
|
read_mmd_phy(addr, MMD_AN, 60, &val);
|
||||||
|
if (e->eee_enabled) {
|
||||||
|
e->eee_enabled = !!(val & BIT(1));
|
||||||
|
if (!e->eee_enabled) {
|
||||||
|
read_mmd_phy(addr, MMD_AN, 62, &val);
|
||||||
|
e->eee_enabled = !!(val & BIT(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtl8226_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
|
||||||
|
{
|
||||||
|
int port = phydev->mdio.addr;
|
||||||
|
u64 poll_state;
|
||||||
|
bool an_enabled;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled);
|
||||||
|
|
||||||
|
poll_state = disable_polling(port);
|
||||||
|
|
||||||
|
// Remember aneg state
|
||||||
|
read_mmd_phy(port, MMD_AN, 0, &val);
|
||||||
|
an_enabled = !!(val & BIT(12));
|
||||||
|
|
||||||
|
// Setup 100/1000MBit
|
||||||
|
read_mmd_phy(port, MMD_AN, 60, &val);
|
||||||
|
if (e->eee_enabled)
|
||||||
|
val |= 0x6;
|
||||||
|
else
|
||||||
|
val &= 0x6;
|
||||||
|
write_mmd_phy(port, MMD_AN, 60, val);
|
||||||
|
|
||||||
|
// Setup 2.5GBit
|
||||||
|
read_mmd_phy(port, MMD_AN, 62, &val);
|
||||||
|
if (e->eee_enabled)
|
||||||
|
val |= 0x1;
|
||||||
|
else
|
||||||
|
val &= 0x1;
|
||||||
|
write_mmd_phy(port, MMD_AN, 62, val);
|
||||||
|
|
||||||
|
// RestartAutoNegotiation
|
||||||
|
read_mmd_phy(port, MMD_VEND2, 0xA400, &val);
|
||||||
|
val |= BIT(9);
|
||||||
|
write_mmd_phy(port, MMD_VEND2, 0xA400, val);
|
||||||
|
|
||||||
|
resume_polling(poll_state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct fw_header *rtl838x_request_fw(struct phy_device *phydev,
|
static struct fw_header *rtl838x_request_fw(struct phy_device *phydev,
|
||||||
const struct firmware *fw,
|
const struct firmware *fw,
|
||||||
const char *name)
|
const char *name)
|
||||||
@ -750,79 +901,6 @@ static int rtl8218b_ext_match_phy_device(struct phy_device *phydev)
|
|||||||
return phydev->phy_id == PHY_ID_RTL8218B_E;
|
return phydev->phy_id == PHY_ID_RTL8218B_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read an mmd register of the PHY
|
|
||||||
*/
|
|
||||||
static int rtl83xx_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 the PHY
|
|
||||||
*/
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rtl8218b_read_mmd(struct phy_device *phydev,
|
static int rtl8218b_read_mmd(struct phy_device *phydev,
|
||||||
int devnum, u16 regnum)
|
int devnum, u16 regnum)
|
||||||
{
|
{
|
||||||
@ -830,7 +908,7 @@ static int rtl8218b_read_mmd(struct phy_device *phydev,
|
|||||||
u32 val;
|
u32 val;
|
||||||
int addr = phydev->mdio.addr;
|
int addr = phydev->mdio.addr;
|
||||||
|
|
||||||
ret = rtl83xx_read_mmd_phy(addr, devnum, regnum, &val);
|
ret = read_mmd_phy(addr, devnum, regnum, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
return val;
|
return val;
|
||||||
@ -850,8 +928,7 @@ static int rtl8226_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|||||||
int err;
|
int err;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
err = rtl930x_read_mmd_phy(port, devnum, regnum, &val);
|
err = read_mmd_phy(port, devnum, regnum, &val);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
return val;
|
return val;
|
||||||
@ -861,7 +938,7 @@ static int rtl8226_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
|
|||||||
{
|
{
|
||||||
int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr
|
int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr
|
||||||
|
|
||||||
return rtl930x_write_mmd_phy(port, devnum, regnum, val);
|
return write_mmd_phy(port, devnum, regnum, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre)
|
static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre)
|
||||||
@ -957,90 +1034,46 @@ static int rtl8214fc_get_port(struct phy_device *phydev)
|
|||||||
return PORT_MII;
|
return PORT_MII;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8218b_eee_set_u_boot(int port, bool enable)
|
/*
|
||||||
{
|
* Enable EEE on the RTL8218B PHYs
|
||||||
u32 val;
|
* The method used is not the preferred way (which would be based on the MAC-EEE state,
|
||||||
bool an_enabled;
|
* but the only way that works since the kernel first enables EEE in the MAC
|
||||||
|
* and then sets up the PHY. The MAC-based approach would require the oppsite.
|
||||||
/* Set GPHY page to copper */
|
*/
|
||||||
write_phy(port, 0, 30, 0x0001);
|
void rtl8218d_eee_set(int port, bool enable)
|
||||||
read_phy(port, 0, 0, &val);
|
|
||||||
an_enabled = val & (1 << 12);
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
/* 100/1000M EEE Capability */
|
|
||||||
write_phy(port, 0, 13, 0x0007);
|
|
||||||
write_phy(port, 0, 14, 0x003C);
|
|
||||||
write_phy(port, 0, 13, 0x4007);
|
|
||||||
write_phy(port, 0, 14, 0x0006);
|
|
||||||
|
|
||||||
read_phy(port, 0x0A43, 25, &val);
|
|
||||||
val |= 1 << 4;
|
|
||||||
write_phy(port, 0x0A43, 25, val);
|
|
||||||
} else {
|
|
||||||
/* 100/1000M EEE Capability */
|
|
||||||
write_phy(port, 0, 13, 0x0007);
|
|
||||||
write_phy(port, 0, 14, 0x003C);
|
|
||||||
write_phy(port, 0, 13, 0x0007);
|
|
||||||
write_phy(port, 0, 14, 0x0000);
|
|
||||||
|
|
||||||
read_phy(port, 0x0A43, 25, &val);
|
|
||||||
val &= ~(1 << 4);
|
|
||||||
write_phy(port, 0x0A43, 25, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restart AN if enabled */
|
|
||||||
if (an_enabled) {
|
|
||||||
read_phy(port, 0, 0, &val);
|
|
||||||
val |= (1 << 12) | (1 << 9);
|
|
||||||
write_phy(port, 0, 0, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPHY page back to auto*/
|
|
||||||
write_phy(port, 0xa42, 29, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: unused
|
|
||||||
void rtl8380_rtl8218b_eee_set(int port, bool enable)
|
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
bool an_enabled;
|
bool an_enabled;
|
||||||
|
|
||||||
pr_debug("In %s %d, enable %d\n", __func__, port, enable);
|
pr_debug("In %s %d, enable %d\n", __func__, port, enable);
|
||||||
/* Set GPHY page to copper */
|
/* Set GPHY page to copper */
|
||||||
write_phy(port, 0xa42, 29, 0x0001);
|
write_phy(port, 0xa42, 30, 0x0001);
|
||||||
|
|
||||||
read_phy(port, 0, 0, &val);
|
read_phy(port, 0, 0, &val);
|
||||||
an_enabled = val & (1 << 12);
|
an_enabled = val & BIT(12);
|
||||||
|
|
||||||
/* MAC based EEE */
|
/* Enable 100M (bit 1) / 1000M (bit 2) EEE */
|
||||||
read_phy(port, 0xa43, 25, &val);
|
read_mmd_phy(port, 7, 60, &val);
|
||||||
val &= ~(1 << 5);
|
val |= BIT(2) | BIT(1);
|
||||||
write_phy(port, 0xa43, 25, val);
|
write_mmd_phy(port, 7, 60, enable ? 0x6 : 0);
|
||||||
|
|
||||||
/* 100M / 1000M EEE */
|
|
||||||
if (enable)
|
|
||||||
rtl838x_write_mmd_phy(port, 7, 60, 0x6);
|
|
||||||
else
|
|
||||||
rtl838x_write_mmd_phy(port, 7, 60, 0);
|
|
||||||
|
|
||||||
/* 500M EEE ability */
|
/* 500M EEE ability */
|
||||||
read_phy(port, 0xa42, 20, &val);
|
read_phy(port, 0xa42, 20, &val);
|
||||||
if (enable)
|
if (enable)
|
||||||
val |= 1 << 7;
|
val |= BIT(7);
|
||||||
else
|
else
|
||||||
val &= ~(1 << 7);
|
val &= ~BIT(7);
|
||||||
write_phy(port, 0xa42, 20, val);
|
write_phy(port, 0xa42, 20, val);
|
||||||
|
|
||||||
/* Restart AN if enabled */
|
/* Restart AN if enabled */
|
||||||
if (an_enabled) {
|
if (an_enabled) {
|
||||||
read_phy(port, 0, 0, &val);
|
read_phy(port, 0, 0, &val);
|
||||||
val |= (1 << 12) | (1 << 9);
|
val |= BIT(9);
|
||||||
write_phy(port, 0, 0, val);
|
write_phy(port, 0, 0, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GPHY page back to auto*/
|
/* GPHY page back to auto*/
|
||||||
write_phy(port, 0xa42, 29, 0);
|
write_phy(port, 0xa42, 30, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8218b_get_eee(struct phy_device *phydev,
|
static int rtl8218b_get_eee(struct phy_device *phydev,
|
||||||
@ -1049,16 +1082,21 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
|
|||||||
u32 val;
|
u32 val;
|
||||||
int addr = phydev->mdio.addr;
|
int addr = phydev->mdio.addr;
|
||||||
|
|
||||||
pr_debug("In %s, port %d\n", __func__, addr);
|
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 */
|
||||||
write_phy(addr, 0xa42, 29, 0x0001);
|
write_phy(addr, 0xa42, 29, 0x0001);
|
||||||
|
|
||||||
rtl83xx_read_mmd_phy(addr, 7, 60, &val);
|
read_phy(addr, 7, 60, &val);
|
||||||
if (e->eee_enabled && (!!(val & (1 << 7))))
|
if (e->eee_enabled) {
|
||||||
e->eee_enabled = !!(val & (1 << 7));
|
// Verify vs MAC-based EEE
|
||||||
else
|
e->eee_enabled = !!(val & BIT(7));
|
||||||
e->eee_enabled = 0;
|
if (!e->eee_enabled) {
|
||||||
|
read_phy(addr, 0x0A43, 25, &val);
|
||||||
|
e->eee_enabled = !!(val & BIT(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
|
||||||
|
|
||||||
/* GPHY page to auto */
|
/* GPHY page to auto */
|
||||||
write_phy(addr, 0xa42, 29, 0x0000);
|
write_phy(addr, 0xa42, 29, 0x0000);
|
||||||
@ -1066,49 +1104,24 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: unused
|
static int rtl8218d_get_eee(struct phy_device *phydev,
|
||||||
void rtl8380_rtl8218b_green_set(int mac, bool enable)
|
struct ethtool_eee *e)
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
/* Set GPHY page to copper */
|
|
||||||
write_phy(mac, 0xa42, 29, 0x0001);
|
|
||||||
|
|
||||||
write_phy(mac, 0, 27, 0x8011);
|
|
||||||
read_phy(mac, 0, 28, &val);
|
|
||||||
if (enable) {
|
|
||||||
val |= 1 << 9;
|
|
||||||
write_phy(mac, 0, 27, 0x8011);
|
|
||||||
write_phy(mac, 0, 28, val);
|
|
||||||
} else {
|
|
||||||
val &= ~(1 << 9);
|
|
||||||
write_phy(mac, 0, 27, 0x8011);
|
|
||||||
write_phy(mac, 0, 28, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPHY page to auto */
|
|
||||||
write_phy(mac, 0xa42, 29, 0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: unused
|
|
||||||
int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e)
|
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
int addr = phydev->mdio.addr;
|
int addr = phydev->mdio.addr;
|
||||||
|
|
||||||
pr_debug("In %s %d\n", __func__, addr);
|
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
|
||||||
/* Set GPHY page to copper */
|
|
||||||
write_phy(addr, 0xa42, 29, 0x0001);
|
|
||||||
|
|
||||||
write_phy(addr, 0, 27, 0x8011);
|
/* Set GPHY page to copper */
|
||||||
read_phy(addr, 0, 28, &val);
|
write_phy(addr, 0xa42, 30, 0x0001);
|
||||||
if (e->eee_enabled && (!!(val & (1 << 9))))
|
|
||||||
e->eee_enabled = !!(val & (1 << 9));
|
read_phy(addr, 7, 60, &val);
|
||||||
else
|
if (e->eee_enabled)
|
||||||
e->eee_enabled = 0;
|
e->eee_enabled = !!(val & BIT(7));
|
||||||
|
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
|
||||||
|
|
||||||
/* GPHY page to auto */
|
/* GPHY page to auto */
|
||||||
write_phy(addr, 0xa42, 29, 0x0000);
|
write_phy(addr, 0xa42, 30, 0x0000);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1116,20 +1129,56 @@ int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e
|
|||||||
static int rtl8214fc_set_eee(struct phy_device *phydev,
|
static int rtl8214fc_set_eee(struct phy_device *phydev,
|
||||||
struct ethtool_eee *e)
|
struct ethtool_eee *e)
|
||||||
{
|
{
|
||||||
u32 pollMask;
|
u32 poll_state;
|
||||||
int addr = phydev->mdio.addr;
|
int port = phydev->mdio.addr;
|
||||||
|
bool an_enabled;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
pr_debug("In %s port %d, enabled %d\n", __func__, addr, e->eee_enabled);
|
pr_debug("In %s port %d, enabled %d\n", __func__, port, e->eee_enabled);
|
||||||
|
|
||||||
if (rtl8380_rtl8214fc_media_is_fibre(addr)) {
|
if (rtl8380_rtl8214fc_media_is_fibre(port)) {
|
||||||
netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", addr);
|
netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", port);
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
pollMask = sw_r32(RTL838X_SMI_POLL_CTRL);
|
poll_state = disable_polling(port);
|
||||||
sw_w32(0, RTL838X_SMI_POLL_CTRL);
|
|
||||||
rtl8218b_eee_set_u_boot(addr, (bool) e->eee_enabled);
|
/* Set GPHY page to copper */
|
||||||
sw_w32(pollMask, RTL838X_SMI_POLL_CTRL);
|
write_phy(port, 0xa42, 29, 0x0001);
|
||||||
|
|
||||||
|
// Get auto-negotiation status
|
||||||
|
read_phy(port, 0, 0, &val);
|
||||||
|
an_enabled = val & BIT(12);
|
||||||
|
|
||||||
|
pr_info("%s: aneg: %d\n", __func__, an_enabled);
|
||||||
|
read_phy(port, 0x0A43, 25, &val);
|
||||||
|
val &= ~BIT(5); // Use MAC-based EEE
|
||||||
|
write_phy(port, 0x0A43, 25, val);
|
||||||
|
|
||||||
|
/* Enable 100M (bit 1) / 1000M (bit 2) EEE */
|
||||||
|
write_phy(port, 7, 60, e->eee_enabled ? 0x6 : 0);
|
||||||
|
|
||||||
|
/* 500M EEE ability */
|
||||||
|
read_phy(port, 0xa42, 20, &val);
|
||||||
|
if (e->eee_enabled)
|
||||||
|
val |= BIT(7);
|
||||||
|
else
|
||||||
|
val &= ~BIT(7);
|
||||||
|
write_phy(port, 0xa42, 20, val);
|
||||||
|
|
||||||
|
/* Restart AN if enabled */
|
||||||
|
if (an_enabled) {
|
||||||
|
pr_info("%s: doing aneg\n", __func__);
|
||||||
|
read_phy(port, 0, 0, &val);
|
||||||
|
val |= BIT(9);
|
||||||
|
write_phy(port, 0, 0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GPHY page back to auto*/
|
||||||
|
write_phy(port, 0xa42, 29, 0);
|
||||||
|
|
||||||
|
resume_polling(poll_state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1147,18 +1196,72 @@ static int rtl8214fc_get_eee(struct phy_device *phydev,
|
|||||||
return rtl8218b_get_eee(phydev, e);
|
return rtl8218b_get_eee(phydev, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8218b_set_eee(struct phy_device *phydev,
|
static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
|
||||||
struct ethtool_eee *e)
|
{
|
||||||
|
int port = phydev->mdio.addr;
|
||||||
|
u64 poll_state;
|
||||||
|
u32 val;
|
||||||
|
bool an_enabled;
|
||||||
|
|
||||||
|
pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled);
|
||||||
|
|
||||||
|
poll_state = disable_polling(port);
|
||||||
|
|
||||||
|
/* Set GPHY page to copper */
|
||||||
|
write_phy(port, 0, 30, 0x0001);
|
||||||
|
read_phy(port, 0, 0, &val);
|
||||||
|
an_enabled = val & BIT(12);
|
||||||
|
|
||||||
|
if (e->eee_enabled) {
|
||||||
|
/* 100/1000M EEE Capability */
|
||||||
|
write_phy(port, 0, 13, 0x0007);
|
||||||
|
write_phy(port, 0, 14, 0x003C);
|
||||||
|
write_phy(port, 0, 13, 0x4007);
|
||||||
|
write_phy(port, 0, 14, 0x0006);
|
||||||
|
|
||||||
|
read_phy(port, 0x0A43, 25, &val);
|
||||||
|
val |= BIT(4);
|
||||||
|
write_phy(port, 0x0A43, 25, val);
|
||||||
|
} else {
|
||||||
|
/* 100/1000M EEE Capability */
|
||||||
|
write_phy(port, 0, 13, 0x0007);
|
||||||
|
write_phy(port, 0, 14, 0x003C);
|
||||||
|
write_phy(port, 0, 13, 0x0007);
|
||||||
|
write_phy(port, 0, 14, 0x0000);
|
||||||
|
|
||||||
|
read_phy(port, 0x0A43, 25, &val);
|
||||||
|
val &= ~BIT(4);
|
||||||
|
write_phy(port, 0x0A43, 25, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart AN if enabled */
|
||||||
|
if (an_enabled) {
|
||||||
|
read_phy(port, 0, 0, &val);
|
||||||
|
val |= BIT(9);
|
||||||
|
write_phy(port, 0, 0, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GPHY page back to auto*/
|
||||||
|
write_phy(port, 0xa42, 30, 0);
|
||||||
|
|
||||||
|
pr_info("%s done\n", __func__);
|
||||||
|
resume_polling(poll_state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtl8218d_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
|
||||||
{
|
{
|
||||||
u32 pollMask;
|
|
||||||
int addr = phydev->mdio.addr;
|
int addr = phydev->mdio.addr;
|
||||||
|
u64 poll_state;
|
||||||
|
|
||||||
pr_debug("In %s, port %d, enabled %d\n", __func__, addr, e->eee_enabled);
|
pr_info("In %s, port %d, enabled %d\n", __func__, addr, e->eee_enabled);
|
||||||
|
|
||||||
pollMask = sw_r32(RTL838X_SMI_POLL_CTRL);
|
poll_state = disable_polling(addr);
|
||||||
sw_w32(0, RTL838X_SMI_POLL_CTRL);
|
|
||||||
rtl8218b_eee_set_u_boot(addr, (bool) e->eee_enabled);
|
rtl8218d_eee_set(addr, (bool) e->eee_enabled);
|
||||||
sw_w32(pollMask, RTL838X_SMI_POLL_CTRL);
|
|
||||||
|
resume_polling(poll_state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1791,7 +1894,10 @@ static struct phy_driver rtl83xx_phy_driver[] = {
|
|||||||
.suspend = genphy_suspend,
|
.suspend = genphy_suspend,
|
||||||
.resume = genphy_resume,
|
.resume = genphy_resume,
|
||||||
.set_loopback = genphy_loopback,
|
.set_loopback = genphy_loopback,
|
||||||
}, {
|
.set_eee = rtl8218d_set_eee,
|
||||||
|
.get_eee = rtl8218d_get_eee,
|
||||||
|
},
|
||||||
|
{
|
||||||
PHY_ID_MATCH_MODEL(PHY_ID_RTL8226),
|
PHY_ID_MATCH_MODEL(PHY_ID_RTL8226),
|
||||||
.name = "REALTEK RTL8226",
|
.name = "REALTEK RTL8226",
|
||||||
.features = PHY_GBIT_FEATURES,
|
.features = PHY_GBIT_FEATURES,
|
||||||
@ -1805,6 +1911,8 @@ static struct phy_driver rtl83xx_phy_driver[] = {
|
|||||||
.write_page = rtl8226_write_page,
|
.write_page = rtl8226_write_page,
|
||||||
.read_status = rtl8226_read_status,
|
.read_status = rtl8226_read_status,
|
||||||
.config_aneg = rtl8226_config_aneg,
|
.config_aneg = rtl8226_config_aneg,
|
||||||
|
.set_eee = rtl8226_set_eee,
|
||||||
|
.get_eee = rtl8226_get_eee,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
|
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
|
||||||
|
Loading…
Reference in New Issue
Block a user