Skip to content

Commit c160f3f

Browse files
committed
phy: marvell: phy-mvebu-cp110-comphy: add emphasis workaround
This commit enables the TX_EMPH_AMP_FORCE bit as a workaround for an issue that causes an endless up/down link loop in case of a specific SFP+ 10G transceiver connected to two Armada 8040 boards.
1 parent c34cf18 commit c160f3f

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

drivers/phy/marvell/phy-mvebu-cp110-comphy.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
#define MVEBU_COMPHY_TX_SLEW_RATE(n) (0x974 + (n) * 0x1000)
8181
#define MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n) ((n) << 5)
8282
#define MVEBU_COMPHY_TX_SLEW_RATE_SLC(n) ((n) << 10)
83+
#define MVEBU_COMPHY_TX_AMP_EMP(n) (0x978 + (n) * 0x1000)
84+
#define MVEBU_COMPHY_TX_EMPH_AMP_FORCE BIT(8)
8385
#define MVEBU_COMPHY_DTL_CTRL(n) (0x984 + (n) * 0x1000)
8486
#define MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN BIT(2)
8587
#define MVEBU_COMPHY_FRAME_DETECT0(n) (0xa14 + (n) * 0x1000)
@@ -258,6 +260,7 @@ struct mvebu_comphy_priv {
258260
struct clk *mg_core_clk;
259261
struct clk *axi_clk;
260262
unsigned long cp_phys;
263+
bool enable_emp_workaround;
261264
};
262265

263266
struct mvebu_comphy_lane {
@@ -714,6 +717,22 @@ static int mvebu_comphy_set_mode_10gbaser(struct phy *phy)
714717
return mvebu_comphy_init_plls(lane);
715718
}
716719

720+
/**
721+
* Workaround for an HW eratta on the 260C BB. In some cases,
722+
* some SFP+ transivers that are connected to another 260C won't
723+
* be able to raise a link and get into an endless up/down loop.
724+
* Writing this magic values works around this issue somehow.
725+
*/
726+
static int mvebu_comphy_power_on_emp_workaround(struct phy *phy) {
727+
struct mvebu_comphy_priv *priv = lane->priv;
728+
struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
729+
u32 val;
730+
val = readl(priv->base + MVEBU_COMPHY_TX_AMP_EMP(lane->id));
731+
val |= MVEBU_COMPHY_TX_EMPH_AMP_FORCE;
732+
writel(val, priv->base + MVEBU_COMPHY_TX_AMP_EMP(lane->id));
733+
return 0;
734+
}
735+
717736
static int mvebu_comphy_power_on_legacy(struct phy *phy)
718737
{
719738
struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);
@@ -825,7 +844,7 @@ static int mvebu_comphy_power_on(struct phy *phy)
825844
ret = mvebu_comphy_smc(COMPHY_SIP_POWER_ON, priv->cp_phys, lane->id,
826845
fw_param);
827846
if (!ret)
828-
return ret;
847+
goto out;
829848

830849
if (ret == -EOPNOTSUPP)
831850
dev_err(priv->dev,
@@ -837,7 +856,18 @@ static int mvebu_comphy_power_on(struct phy *phy)
837856

838857
try_legacy:
839858
/* Fallback to Linux's implementation */
840-
return mvebu_comphy_power_on_legacy(phy);
859+
ret = mvebu_comphy_power_on_legacy(phy);
860+
861+
out:
862+
if (!ret
863+
&& lane->mode == PHY_MODE_ETHERNET
864+
&& lane->submode == PHY_INTERFACE_MODE_10GBASER
865+
&& priv->enable_emp_workaround) {
866+
dev_warn(priv->dev, "Performing emphesis workaround on PHY %d", lane->id);
867+
ret = mvebu_comphy_power_on_emp_workaround(phy);
868+
}
869+
870+
return ret;
841871
}
842872

843873
static int mvebu_comphy_set_mode(struct phy *phy,
@@ -1028,6 +1058,12 @@ static int mvebu_comphy_probe(struct platform_device *pdev)
10281058
struct mvebu_comphy_lane *lane;
10291059
struct phy *phy;
10301060
u32 val;
1061+
bool enable_emp_quirk = false;
1062+
1063+
ret = of_property_read_u32(child, "enable-emp-quirk", &val);
1064+
if (ret >= 0 && val) {
1065+
enable_emp_quirk = true;
1066+
}
10311067

10321068
ret = of_property_read_u32(child, "reg", &val);
10331069
if (ret < 0) {
@@ -1060,6 +1096,7 @@ static int mvebu_comphy_probe(struct platform_device *pdev)
10601096
lane->submode = PHY_INTERFACE_MODE_NA;
10611097
lane->id = val;
10621098
lane->port = -1;
1099+
lane->enable_emp_quirk = enable_emp_quirk;
10631100
phy_set_drvdata(phy, lane);
10641101

10651102
/*

0 commit comments

Comments
 (0)