/* Lane a Tx Reset Control Register */
#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
-#define LNaTRSTCTL_HLT_REQ BIT(27)
-#define LNaTRSTCTL_RST_DONE BIT(30)
#define LNaTRSTCTL_RST_REQ BIT(31)
+#define LNaTRSTCTL_RST_DONE BIT(30)
+#define LNaTRSTCTL_HLT_REQ BIT(27)
+#define LNaTRSTCTL_STP_REQ BIT(26)
+#define LNaTRSTCTL_DIS BIT(24)
/* Lane a Tx General Control Register */
#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
/* Lane a Rx Reset Control Register */
#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
-#define LNaRRSTCTL_HLT_REQ BIT(27)
-#define LNaRRSTCTL_RST_DONE BIT(30)
#define LNaRRSTCTL_RST_REQ BIT(31)
+#define LNaRRSTCTL_RST_DONE BIT(30)
+#define LNaRRSTCTL_HLT_REQ BIT(27)
+#define LNaRRSTCTL_STP_REQ BIT(26)
+#define LNaRRSTCTL_DIS BIT(24)
#define LNaRRSTCTL_CDR_LOCK BIT(12)
/* Lane a Rx General Control Register */
#define LYNX_28G_LANE_RESET_SLEEP_US 100
#define LYNX_28G_LANE_RESET_TIMEOUT_US 1000000
+#define LYNX_28G_LANE_STOP_SLEEP_US 100
+#define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000
+
enum lynx_28g_eq_type {
EQ_TYPE_NO_EQ = 0,
EQ_TYPE_2TAP = 1,
!(rrstctl & LNaRRSTCTL_HLT_REQ);
}
+static bool lynx_28g_lane_stop_done(struct lynx_28g_lane *lane)
+{
+ u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ u32 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+
+ return !(trstctl & LNaTRSTCTL_STP_REQ) &&
+ !(rrstctl & LNaRRSTCTL_STP_REQ);
+}
+
static bool lynx_28g_lane_reset_done(struct lynx_28g_lane *lane)
{
u32 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
(rrstctl & LNaRRSTCTL_RST_DONE);
}
-static int lynx_28g_power_off(struct phy *phy)
+/* Halting puts the lane in a mode in which it can be reconfigured */
+static int lynx_28g_lane_halt(struct phy *phy)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
bool done;
int err;
- if (!lane->powered_up)
- return 0;
-
/* Issue a halt request */
lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
LNaTRSTCTL_HLT_REQ);
'A' + lane->id, ERR_PTR(err));
}
- lane->powered_up = false;
-
- return 0;
+ return err;
}
-static int lynx_28g_power_on(struct phy *phy)
+static int lynx_28g_lane_reset(struct phy *phy)
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
bool done;
int err;
- if (lane->powered_up)
- return 0;
-
/* Issue a reset request on the lane */
lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
LNaTRSTCTL_RST_REQ);
'A' + lane->id, ERR_PTR(err));
}
+ return err;
+}
+
+static int lynx_28g_power_off(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ bool done;
+ int err;
+
+ if (!lane->powered_up)
+ return 0;
+
+ /* Issue a stop request */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_STP_REQ,
+ LNaTRSTCTL_STP_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_STP_REQ,
+ LNaRRSTCTL_STP_REQ);
+
+ /* Wait until the stop process is complete */
+ err = read_poll_timeout(lynx_28g_lane_stop_done, done, done,
+ LYNX_28G_LANE_STOP_SLEEP_US,
+ LYNX_28G_LANE_STOP_TIMEOUT_US,
+ false, lane);
+ if (err) {
+ dev_err(&phy->dev, "Lane %c stop failed: %pe\n",
+ 'A' + lane->id, ERR_PTR(err));
+ }
+
+ /* Power down the RX and TX portions of the lane */
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_DIS,
+ LNaRRSTCTL_DIS);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_DIS,
+ LNaTRSTCTL_DIS);
+
+ lane->powered_up = false;
+
+ return 0;
+}
+
+static int lynx_28g_power_on(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ int err;
+
+ if (lane->powered_up)
+ return 0;
+
+ /* Power up the RX and TX portions of the lane */
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, 0, LNaRRSTCTL_DIS);
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, 0, LNaTRSTCTL_DIS);
+
+ err = lynx_28g_lane_reset(phy);
+ if (err)
+ return err;
+
lane->powered_up = true;
return 0;
/* If the lane is powered up, put the lane into the halt state while
* the reconfiguration is being done.
*/
- if (powered_up)
- lynx_28g_power_off(phy);
+ if (powered_up) {
+ err = lynx_28g_lane_halt(phy);
+ if (err)
+ goto out;
+ }
err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
if (err)
out:
if (powered_up)
- lynx_28g_power_on(phy);
+ lynx_28g_lane_reset(phy);
return err;
}