#define RTPCS_93XX_SDS_MODE_QSGMII 0x06
#define RTPCS_93XX_SDS_MODE_USXGMII 0x0d
#define RTPCS_93XX_SDS_MODE_XSGMII 0x10
+#define RTPCS_93XX_SDS_MODE_HISGMII 0x12
#define RTPCS_93XX_SDS_MODE_2500BASEX 0x16
#define RTPCS_93XX_SDS_MODE_10GBASER 0x1a
#define RTPCS_93XX_SDS_MODE_OFF 0x1f
[RTPCS_SDS_MODE_2500BASEX] = RTPCS_93XX_SDS_MODE_2500BASEX,
[RTPCS_SDS_MODE_10GBASER] = RTPCS_93XX_SDS_MODE_10GBASER,
[RTPCS_SDS_MODE_QSGMII] = RTPCS_93XX_SDS_MODE_QSGMII,
+ [RTPCS_SDS_MODE_HISGMII] = RTPCS_93XX_SDS_MODE_HISGMII,
[RTPCS_SDS_MODE_XSGMII] = RTPCS_93XX_SDS_MODE_XSGMII,
[RTPCS_SDS_MODE_USXGMII_10GSXGMII] = RTPCS_93XX_SDS_MODE_USXGMII,
[RTPCS_SDS_MODE_USXGMII_10GDXGMII] = RTPCS_93XX_SDS_MODE_USXGMII,
return 0;
}
+/*
+ * Read/write the SerDes IP mode register: page 0x1f reg 0x09, bits 11:7
+ * hold the 5-bit mode value, bit 6 is the "force mode" enable. The same
+ * physical field is used on RTL930x and RTL931x.
+ */
+static int rtpcs_93xx_sds_get_ip_mode(struct rtpcs_serdes *sds)
+{
+ const s16 *vals = sds->ctrl->cfg->sds_hw_mode_vals;
+ int raw;
+
+ raw = rtpcs_sds_read_bits(sds, 0x1f, 0x09, 11, 7);
+ if (raw < 0)
+ return raw;
+
+ for (int i = 0; i < RTPCS_SDS_MODE_MAX; i++)
+ if (vals[i] == raw)
+ return i;
+
+ return -ENOENT;
+}
+
+static int rtpcs_93xx_sds_set_ip_mode(struct rtpcs_serdes *sds, enum rtpcs_sds_mode hw_mode)
+{
+ int raw;
+
+ if (hw_mode >= RTPCS_SDS_MODE_MAX)
+ return -EINVAL;
+
+ raw = sds->ctrl->cfg->sds_hw_mode_vals[hw_mode];
+ if (raw < 0)
+ return -EOPNOTSUPP;
+
+ /* BIT(0) is force mode enable bit */
+ return rtpcs_sds_write_bits(sds, 0x1f, 0x09, 11, 6, raw << 1 | BIT(0));
+}
+
/* RTL930X */
/* This mapping is not coherent so it cannot be expressed arithmetically */
return -EBUSY;
}
-static int __rtpcs_930x_sds_get_ip_mode(struct rtpcs_serdes *sds)
-{
- return rtpcs_sds_read_bits(sds, 0x1f, 0x09, 11, 7);
-}
-
-static int __rtpcs_930x_sds_set_ip_mode(struct rtpcs_serdes *sds, u32 mode)
-{
- /* BIT(0) is force mode enable bit */
- return rtpcs_sds_write_bits(sds, 0x1f, 0x09, 11, 6, (mode & 0x1f) << 1 | BIT(0));
-}
-
static void rtpcs_930x_sds_set_power(struct rtpcs_serdes *sds, bool on)
{
int power_down = on ? 0x0 : 0x3;
{
enum rtpcs_sds_pll_speed speed;
enum rtpcs_sds_pll_type old_pll;
- int mode, ret;
+ int hw_mode, ret;
- mode = __rtpcs_930x_sds_get_ip_mode(sds);
+ hw_mode = rtpcs_93xx_sds_get_ip_mode(sds);
+ if (hw_mode < 0)
+ return hw_mode;
ret = rtpcs_930x_sds_get_pll_select(sds, &old_pll);
if (ret < 0)
return ret;
rtpcs_930x_sds_set_power(sds, false);
- __rtpcs_930x_sds_set_ip_mode(sds, RTPCS_93XX_SDS_MODE_OFF);
+ rtpcs_93xx_sds_set_ip_mode(sds, RTPCS_SDS_MODE_OFF);
ret = rtpcs_93xx_sds_set_pll_config(sds, pll, speed);
if (ret < 0)
if (ret < 0)
return ret;
- __rtpcs_930x_sds_set_ip_mode(sds, mode);
+ rtpcs_93xx_sds_set_ip_mode(sds, hw_mode);
if (rtpcs_930x_sds_wait_clock_ready(sds))
pr_err("%s: SDS %d could not sync clock\n", __func__, sds->id);
return ret;
}
-static int rtpcs_930x_sds_set_ip_mode(struct rtpcs_serdes *sds,
- enum rtpcs_sds_mode hw_mode)
+static int rtpcs_930x_sds_apply_ip_mode(struct rtpcs_serdes *sds,
+ enum rtpcs_sds_mode hw_mode)
{
- int mode_val, ret;
+ int ret;
/*
* TODO: Usually one would expect that it is enough to modify the SDS_MODE_SEL_*
* if this sequence should quit early in case of errors.
*/
- if (hw_mode >= RTPCS_SDS_MODE_MAX)
- return -EINVAL;
-
- mode_val = sds->ctrl->cfg->sds_hw_mode_vals[hw_mode];
- if (mode_val < 0) {
- pr_err("%s: SDS %d does not support mode %d\n", __func__,
- sds->id, hw_mode);
- return mode_val;
- }
-
rtpcs_930x_sds_set_power(sds, false);
- ret = __rtpcs_930x_sds_set_ip_mode(sds, RTPCS_93XX_SDS_MODE_OFF);
+ ret = rtpcs_93xx_sds_set_ip_mode(sds, RTPCS_SDS_MODE_OFF);
if (ret < 0)
return ret;
pr_err("%s: SDS %d could not configure PLL for mode %d: %d\n", __func__,
sds->id, hw_mode, ret);
- ret = __rtpcs_930x_sds_set_ip_mode(sds, mode_val);
+ ret = rtpcs_93xx_sds_set_ip_mode(sds, hw_mode);
if (ret < 0)
return ret;
case RTPCS_SDS_MODE_1000BASEX:
case RTPCS_SDS_MODE_2500BASEX:
case RTPCS_SDS_MODE_10GBASER:
- return rtpcs_930x_sds_set_ip_mode(sds, hw_mode);
+ return rtpcs_930x_sds_apply_ip_mode(sds, hw_mode);
default:
break;
}
/*
- * rtpcs_931x_sds_set_ip_mode
- *
- * Set the SerDes mode in the SerDes IP block's registers.
+ * Set the SerDes mode in the SerDes IP block's registers, after clearing
+ * the symbol error counter and forcing the MAC mode off.
*/
-static int rtpcs_931x_sds_set_ip_mode(struct rtpcs_serdes *sds,
- enum rtpcs_sds_mode hw_mode)
+static int rtpcs_931x_sds_apply_ip_mode(struct rtpcs_serdes *sds,
+ enum rtpcs_sds_mode hw_mode)
{
- u32 mode_val;
int ret;
/* clear symbol error count before changing mode */
if (ret)
return ret;
- switch (hw_mode) {
- case RTPCS_SDS_MODE_OFF:
- mode_val = 0x3f;
- break;
-
- case RTPCS_SDS_MODE_SGMII:
- mode_val = 0x5;
- break;
-
- case RTPCS_SDS_MODE_1000BASEX:
- /* serdes mode FIBER1G */
- mode_val = 0x9;
- break;
-
- case RTPCS_SDS_MODE_2500BASEX:
- /* available SDK code doesn't have this value. based on brute-forcing
- * the SerDes mode register field until the link is working
- */
- mode_val = 0x2d;
- break;
-
- case RTPCS_SDS_MODE_10GBASER:
- mode_val = 0x35;
- break;
-/* case MII_10GR1000BX_AUTO:
- mode_val = 0x39;
- break; */
-
- case RTPCS_SDS_MODE_USXGMII_10GSXGMII:
- case RTPCS_SDS_MODE_USXGMII_10GDXGMII:
- case RTPCS_SDS_MODE_USXGMII_10GQXGMII:
- case RTPCS_SDS_MODE_USXGMII_5GSXGMII:
- case RTPCS_SDS_MODE_USXGMII_5GDXGMII:
- case RTPCS_SDS_MODE_USXGMII_2_5GSXGMII:
- mode_val = 0x1b;
- break;
- case RTPCS_SDS_MODE_HISGMII:
- mode_val = 0x25;
- break;
- default:
- return -ENOTSUPP;
- }
-
- pr_info("%s writing analog SerDes Mode value %02x\n", __func__, mode_val);
- return rtpcs_sds_write_bits(sds, 0x1f, 0x9, 11, 6, mode_val);
+ return rtpcs_93xx_sds_set_ip_mode(sds, hw_mode);
}
static int rtpcs_931x_sds_set_mode(struct rtpcs_serdes *sds,
if (hw_mode == RTPCS_SDS_MODE_XSGMII)
return rtpcs_93xx_sds_set_mac_mode(sds, hw_mode);
- ret = rtpcs_931x_sds_set_ip_mode(sds, hw_mode);
+ ret = rtpcs_931x_sds_apply_ip_mode(sds, hw_mode);
if (ret)
return ret;