Commit d7445d1f authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Add support for a KR redriver

This patch provides support for the presence of a KR redriver chip in
between the device PCS and an external PHY.  When a redriver chip is
present the device must perform clause 73 auto-negotiation in order to
set the redriver chip for the downstream connection.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 732f2ab7
...@@ -1062,6 +1062,16 @@ ...@@ -1062,6 +1062,16 @@
#define XP_PROP_4_MUX_ADDR_LO_WIDTH 3 #define XP_PROP_4_MUX_ADDR_LO_WIDTH 3
#define XP_PROP_4_MUX_CHAN_INDEX 4 #define XP_PROP_4_MUX_CHAN_INDEX 4
#define XP_PROP_4_MUX_CHAN_WIDTH 3 #define XP_PROP_4_MUX_CHAN_WIDTH 3
#define XP_PROP_4_REDRV_ADDR_INDEX 16
#define XP_PROP_4_REDRV_ADDR_WIDTH 7
#define XP_PROP_4_REDRV_IF_INDEX 23
#define XP_PROP_4_REDRV_IF_WIDTH 1
#define XP_PROP_4_REDRV_LANE_INDEX 24
#define XP_PROP_4_REDRV_LANE_WIDTH 3
#define XP_PROP_4_REDRV_MODEL_INDEX 28
#define XP_PROP_4_REDRV_MODEL_WIDTH 3
#define XP_PROP_4_REDRV_PRESENT_INDEX 31
#define XP_PROP_4_REDRV_PRESENT_WIDTH 1
/* I2C Control register offsets */ /* I2C Control register offsets */
#define IC_CON 0x0000 #define IC_CON 0x0000
......
...@@ -179,6 +179,7 @@ static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata) ...@@ -179,6 +179,7 @@ static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
{ {
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_enable_interrupts(pdata); xgbe_an73_enable_interrupts(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -254,6 +255,10 @@ static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) ...@@ -254,6 +255,10 @@ static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
static void xgbe_sfi_mode(struct xgbe_prv_data *pdata) static void xgbe_sfi_mode(struct xgbe_prv_data *pdata)
{ {
/* If a KR re-driver is present, change to KR mode instead */
if (pdata->kr_redrv)
return xgbe_kr_mode(pdata);
/* Disable KR training */ /* Disable KR training */
xgbe_an73_disable_kr_training(pdata); xgbe_an73_disable_kr_training(pdata);
...@@ -433,6 +438,7 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata) ...@@ -433,6 +438,7 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata)
{ {
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_restart(pdata); xgbe_an73_restart(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -448,6 +454,7 @@ static void xgbe_an_disable(struct xgbe_prv_data *pdata) ...@@ -448,6 +454,7 @@ static void xgbe_an_disable(struct xgbe_prv_data *pdata)
{ {
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_disable(pdata); xgbe_an73_disable(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -687,6 +694,7 @@ static irqreturn_t xgbe_an_isr(int irq, void *data) ...@@ -687,6 +694,7 @@ static irqreturn_t xgbe_an_isr(int irq, void *data)
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_isr(pdata); xgbe_an73_isr(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -895,6 +903,7 @@ static void xgbe_an_state_machine(struct work_struct *work) ...@@ -895,6 +903,7 @@ static void xgbe_an_state_machine(struct work_struct *work)
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_state_machine(pdata); xgbe_an73_state_machine(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -910,16 +919,18 @@ static void xgbe_an_state_machine(struct work_struct *work) ...@@ -910,16 +919,18 @@ static void xgbe_an_state_machine(struct work_struct *work)
static void xgbe_an37_init(struct xgbe_prv_data *pdata) static void xgbe_an37_init(struct xgbe_prv_data *pdata)
{ {
unsigned int reg; unsigned int advertising, reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata);
/* Set up Advertisement register */ /* Set up Advertisement register */
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
if (pdata->phy.advertising & ADVERTISED_Pause) if (advertising & ADVERTISED_Pause)
reg |= 0x100; reg |= 0x100;
else else
reg &= ~0x100; reg &= ~0x100;
if (pdata->phy.advertising & ADVERTISED_Asym_Pause) if (advertising & ADVERTISED_Asym_Pause)
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
...@@ -954,11 +965,13 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata) ...@@ -954,11 +965,13 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata)
static void xgbe_an73_init(struct xgbe_prv_data *pdata) static void xgbe_an73_init(struct xgbe_prv_data *pdata)
{ {
unsigned int reg; unsigned int advertising, reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata);
/* Set up Advertisement register 3 first */ /* Set up Advertisement register 3 first */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
if (pdata->phy.advertising & ADVERTISED_10000baseR_FEC) if (advertising & ADVERTISED_10000baseR_FEC)
reg |= 0xc000; reg |= 0xc000;
else else
reg &= ~0xc000; reg &= ~0xc000;
...@@ -967,13 +980,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -967,13 +980,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 2 next */ /* Set up Advertisement register 2 next */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) if (advertising & ADVERTISED_10000baseKR_Full)
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) || if ((advertising & ADVERTISED_1000baseKX_Full) ||
(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) (advertising & ADVERTISED_2500baseX_Full))
reg |= 0x20; reg |= 0x20;
else else
reg &= ~0x20; reg &= ~0x20;
...@@ -982,12 +995,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -982,12 +995,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 1 last */ /* Set up Advertisement register 1 last */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
if (pdata->phy.advertising & ADVERTISED_Pause) if (advertising & ADVERTISED_Pause)
reg |= 0x400; reg |= 0x400;
else else
reg &= ~0x400; reg &= ~0x400;
if (pdata->phy.advertising & ADVERTISED_Asym_Pause) if (advertising & ADVERTISED_Asym_Pause)
reg |= 0x800; reg |= 0x800;
else else
reg &= ~0x800; reg &= ~0x800;
...@@ -1006,6 +1019,7 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata) ...@@ -1006,6 +1019,7 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
switch (pdata->an_mode) { switch (pdata->an_mode) {
case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73:
case XGBE_AN_MODE_CL73_REDRV:
xgbe_an73_init(pdata); xgbe_an73_init(pdata);
break; break;
case XGBE_AN_MODE_CL37: case XGBE_AN_MODE_CL37:
...@@ -1149,10 +1163,15 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) ...@@ -1149,10 +1163,15 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
if (ret) if (ret)
return ret; return ret;
if (pdata->phy.autoneg != AUTONEG_ENABLE) if (pdata->phy.autoneg != AUTONEG_ENABLE) {
return xgbe_phy_config_fixed(pdata); ret = xgbe_phy_config_fixed(pdata);
if (ret || !pdata->kr_redrv)
return ret;
netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
} else {
netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
}
/* Disable auto-negotiation interrupt */ /* Disable auto-negotiation interrupt */
disable_irq(pdata->an_irq); disable_irq(pdata->an_irq);
......
...@@ -295,6 +295,11 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -295,6 +295,11 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
return mode; return mode;
} }
static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata)
{
return pdata->phy.advertising;
}
static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
{ {
/* Nothing uniquely required for an configuration */ /* Nothing uniquely required for an configuration */
...@@ -831,6 +836,8 @@ void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if) ...@@ -831,6 +836,8 @@ void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if)
phy_impl->an_config = xgbe_phy_an_config; phy_impl->an_config = xgbe_phy_an_config;
phy_impl->an_advertising = xgbe_phy_an_advertising;
phy_impl->an_outcome = xgbe_phy_an_outcome; phy_impl->an_outcome = xgbe_phy_an_outcome;
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
......
This diff is collapsed.
...@@ -508,6 +508,7 @@ enum xgbe_xpcs_access { ...@@ -508,6 +508,7 @@ enum xgbe_xpcs_access {
enum xgbe_an_mode { enum xgbe_an_mode {
XGBE_AN_MODE_CL73 = 0, XGBE_AN_MODE_CL73 = 0,
XGBE_AN_MODE_CL73_REDRV,
XGBE_AN_MODE_CL37, XGBE_AN_MODE_CL37,
XGBE_AN_MODE_CL37_SGMII, XGBE_AN_MODE_CL37_SGMII,
XGBE_AN_MODE_NONE, XGBE_AN_MODE_NONE,
...@@ -807,6 +808,9 @@ struct xgbe_phy_impl_if { ...@@ -807,6 +808,9 @@ struct xgbe_phy_impl_if {
/* Configure auto-negotiation settings */ /* Configure auto-negotiation settings */
int (*an_config)(struct xgbe_prv_data *); int (*an_config)(struct xgbe_prv_data *);
/* Set/override auto-negotiation advertisement settings */
unsigned int (*an_advertising)(struct xgbe_prv_data *);
/* Process results of auto-negotiation */ /* Process results of auto-negotiation */
enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
...@@ -1124,6 +1128,8 @@ struct xgbe_prv_data { ...@@ -1124,6 +1128,8 @@ struct xgbe_prv_data {
unsigned long link_check; unsigned long link_check;
struct completion mdio_complete; struct completion mdio_complete;
unsigned int kr_redrv;
char an_name[IFNAMSIZ + 32]; char an_name[IFNAMSIZ + 32];
struct workqueue_struct *an_workqueue; struct workqueue_struct *an_workqueue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment