80
80
#define MVEBU_COMPHY_TX_SLEW_RATE (n ) (0x974 + (n) * 0x1000)
81
81
#define MVEBU_COMPHY_TX_SLEW_RATE_EMPH (n ) ((n) << 5)
82
82
#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)
83
85
#define MVEBU_COMPHY_DTL_CTRL (n ) (0x984 + (n) * 0x1000)
84
86
#define MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN BIT(2)
85
87
#define MVEBU_COMPHY_FRAME_DETECT0 (n ) (0xa14 + (n) * 0x1000)
@@ -258,6 +260,7 @@ struct mvebu_comphy_priv {
258
260
struct clk * mg_core_clk ;
259
261
struct clk * axi_clk ;
260
262
unsigned long cp_phys ;
263
+ bool enable_emp_workaround ;
261
264
};
262
265
263
266
struct mvebu_comphy_lane {
@@ -714,6 +717,22 @@ static int mvebu_comphy_set_mode_10gbaser(struct phy *phy)
714
717
return mvebu_comphy_init_plls (lane );
715
718
}
716
719
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
+
717
736
static int mvebu_comphy_power_on_legacy (struct phy * phy )
718
737
{
719
738
struct mvebu_comphy_lane * lane = phy_get_drvdata (phy );
@@ -825,7 +844,7 @@ static int mvebu_comphy_power_on(struct phy *phy)
825
844
ret = mvebu_comphy_smc (COMPHY_SIP_POWER_ON , priv -> cp_phys , lane -> id ,
826
845
fw_param );
827
846
if (!ret )
828
- return ret ;
847
+ goto out ;
829
848
830
849
if (ret == - EOPNOTSUPP )
831
850
dev_err (priv -> dev ,
@@ -837,7 +856,18 @@ static int mvebu_comphy_power_on(struct phy *phy)
837
856
838
857
try_legacy :
839
858
/* 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 ;
841
871
}
842
872
843
873
static int mvebu_comphy_set_mode (struct phy * phy ,
@@ -1028,6 +1058,12 @@ static int mvebu_comphy_probe(struct platform_device *pdev)
1028
1058
struct mvebu_comphy_lane * lane ;
1029
1059
struct phy * phy ;
1030
1060
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
+ }
1031
1067
1032
1068
ret = of_property_read_u32 (child , "reg" , & val );
1033
1069
if (ret < 0 ) {
@@ -1060,6 +1096,7 @@ static int mvebu_comphy_probe(struct platform_device *pdev)
1060
1096
lane -> submode = PHY_INTERFACE_MODE_NA ;
1061
1097
lane -> id = val ;
1062
1098
lane -> port = -1 ;
1099
+ lane -> enable_emp_quirk = enable_emp_quirk ;
1063
1100
phy_set_drvdata (phy , lane );
1064
1101
1065
1102
/*
0 commit comments