|
|
@@ -22,35 +22,50 @@ static const struct firmware rtl838x_8380_fw;
|
|
|
static const struct firmware rtl838x_8214fc_fw;
|
|
|
static const struct firmware rtl838x_8218b_fw;
|
|
|
|
|
|
+int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
|
|
+int rtl930x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
|
|
|
|
|
|
static int read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
|
|
-{
|
|
|
- if (soc_info.family == RTL8390_FAMILY_ID)
|
|
|
- return rtl839x_read_phy(port, page, reg, val);
|
|
|
- else
|
|
|
+{ switch (soc_info.family) {
|
|
|
+ case RTL8380_FAMILY_ID:
|
|
|
return rtl838x_read_phy(port, page, reg, val);
|
|
|
+ case RTL8390_FAMILY_ID:
|
|
|
+ return rtl839x_read_phy(port, page, reg, val);
|
|
|
+ case RTL9300_FAMILY_ID:
|
|
|
+ return rtl930x_read_phy(port, page, reg, val);
|
|
|
+ case RTL9310_FAMILY_ID:
|
|
|
+ return rtl931x_read_phy(port, page, reg, val);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
static int write_phy(u32 port, u32 page, u32 reg, u32 val)
|
|
|
{
|
|
|
- if (soc_info.family == RTL8390_FAMILY_ID)
|
|
|
- return rtl839x_write_phy(port, page, reg, val);
|
|
|
- else
|
|
|
+ switch (soc_info.family) {
|
|
|
+ case RTL8380_FAMILY_ID:
|
|
|
return rtl838x_write_phy(port, page, reg, val);
|
|
|
+ case RTL8390_FAMILY_ID:
|
|
|
+ return rtl839x_write_phy(port, page, reg, val);
|
|
|
+ case RTL9300_FAMILY_ID:
|
|
|
+ return rtl930x_write_phy(port, page, reg, val);
|
|
|
+ case RTL9310_FAMILY_ID:
|
|
|
+ return rtl931x_write_phy(port, page, reg, val);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static void int_phy_on_off(int mac, bool on)
|
|
|
+static void rtl8380_int_phy_on_off(int mac, bool on)
|
|
|
{
|
|
|
u32 val;
|
|
|
|
|
|
read_phy(mac, 0, 0, &val);
|
|
|
if (on)
|
|
|
- write_phy(mac, 0, 0, val & ~(1 << 11));
|
|
|
+ write_phy(mac, 0, 0, val & ~BIT(11));
|
|
|
else
|
|
|
- write_phy(mac, 0, 0, val | (1 << 11));
|
|
|
+ write_phy(mac, 0, 0, val | BIT(11));
|
|
|
}
|
|
|
|
|
|
-static void rtl8214fc_on_off(int mac, bool on)
|
|
|
+static void rtl8380_rtl8214fc_on_off(int mac, bool on)
|
|
|
{
|
|
|
u32 val;
|
|
|
|
|
|
@@ -58,25 +73,194 @@ static void rtl8214fc_on_off(int mac, bool on)
|
|
|
write_phy(mac, 4095, 30, 3);
|
|
|
read_phy(mac, 0, 16, &val);
|
|
|
if (on)
|
|
|
- write_phy(mac, 0, 16, val & ~(1 << 11));
|
|
|
+ write_phy(mac, 0, 16, val & ~BIT(11));
|
|
|
else
|
|
|
- write_phy(mac, 0, 16, val | (1 << 11));
|
|
|
+ write_phy(mac, 0, 16, val | BIT(11));
|
|
|
|
|
|
/* copper ports */
|
|
|
write_phy(mac, 4095, 30, 1);
|
|
|
read_phy(mac, 0, 16, &val);
|
|
|
if (on)
|
|
|
- write_phy(mac, 0xa40, 16, val & ~(1 << 11));
|
|
|
+ write_phy(mac, 0xa40, 16, val & ~BIT(11));
|
|
|
else
|
|
|
- write_phy(mac, 0xa40, 16, val | (1 << 11));
|
|
|
+ write_phy(mac, 0xa40, 16, val | BIT(11));
|
|
|
}
|
|
|
|
|
|
-static void phy_reset(int mac)
|
|
|
+static void rtl8380_phy_reset(int mac)
|
|
|
{
|
|
|
u32 val;
|
|
|
|
|
|
read_phy(mac, 0, 0, &val);
|
|
|
- write_phy(mac, 0, 0, val | (0x1 << 15));
|
|
|
+ write_phy(mac, 0, 0, val | BIT(15));
|
|
|
+}
|
|
|
+
|
|
|
+static void rtl8380_sds_rst(int mac)
|
|
|
+{
|
|
|
+ u32 offset = (mac == 24) ? 0 : 0x100;
|
|
|
+
|
|
|
+ sw_w32_mask(1 << 11, 0, RTL8380_SDS4_FIB_REG0 + offset);
|
|
|
+ sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset);
|
|
|
+ sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset);
|
|
|
+ sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset);
|
|
|
+ sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset);
|
|
|
+ pr_info("SERDES reset: %d\n", mac);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Reset the SerDes by powering it off and set a new operations mode
|
|
|
+ * of the SerDes. 0x1f is off. Other modes are
|
|
|
+ * 0x01: QSGMII 0x04: 1000BX_FIBER 0x05: FIBER100
|
|
|
+ * 0x06: QSGMII 0x09: RSGMII 0x0d: USXGMII
|
|
|
+ * 0x10: XSGMII 0x12: HISGMII 0x16: 2500Base_X
|
|
|
+ * 0x17: RXAUI_LITE 0x19: RXAUI_PLUS 0x1a: 10G Base-R
|
|
|
+ * 0x1b: 10GR1000BX_AUTO 0x1f: OFF
|
|
|
+ */
|
|
|
+void rtl9300_sds_rst(int sds_num, u32 mode)
|
|
|
+{
|
|
|
+ // The access registers for SDS_MODE_SEL and the LSB for each SDS within
|
|
|
+ u16 regs[] = { 0x0194, 0x0194, 0x0194, 0x0194, 0x02a0, 0x02a0, 0x02a0, 0x02a0,
|
|
|
+ 0x02A4, 0x02A4, 0x0198, 0x0198 };
|
|
|
+ u8 lsb[] = { 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 0, 6};
|
|
|
+
|
|
|
+ pr_info("SerDes: %s %d\n", __func__, mode);
|
|
|
+ if (sds_num < 0 || sds_num > 11) {
|
|
|
+ pr_err("Wrong SerDes number: %d\n", sds_num);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sw_w32_mask(0x1f << lsb[sds_num], 0x1f << lsb[sds_num], regs[sds_num]);
|
|
|
+ mdelay(10);
|
|
|
+
|
|
|
+ sw_w32_mask(0x1f << lsb[sds_num], mode << lsb[sds_num], regs[sds_num]);
|
|
|
+ mdelay(10);
|
|
|
+
|
|
|
+ pr_info("SDS: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n",
|
|
|
+ sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * On the RTL839x family of SoCs with inbuilt SerDes, these SerDes are accessed through
|
|
|
+ * a 2048 bit register that holds the contents of the PHY being simulated by the SoC.
|
|
|
+ */
|
|
|
+int rtl839x_read_sds_phy(int phy_addr, int phy_reg)
|
|
|
+{
|
|
|
+ int offset = 0;
|
|
|
+ int reg;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ if (phy_addr == 49)
|
|
|
+ offset = 0x100;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For the RTL8393 internal SerDes, we simulate a PHY ID in registers 2/3
|
|
|
+ * which would otherwise read as 0.
|
|
|
+ */
|
|
|
+ if (soc_info.id == 0x8393) {
|
|
|
+ if (phy_reg == 2)
|
|
|
+ return 0x1c;
|
|
|
+ if (phy_reg == 3)
|
|
|
+ return 0x8393;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Register RTL839X_SDS12_13_XSG0 is 2048 bit broad, the MSB (bit 15) of the
|
|
|
+ * 0th PHY register is bit 1023 (in byte 0x80). Because PHY-registers are 16
|
|
|
+ * bit broad, we offset by reg << 1. In the SoC 2 registers are stored in
|
|
|
+ * one 32 bit register.
|
|
|
+ */
|
|
|
+ reg = (phy_reg << 1) & 0xfc;
|
|
|
+ val = sw_r32(RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg);
|
|
|
+
|
|
|
+ if (phy_reg & 1)
|
|
|
+ val = (val >> 16) & 0xffff;
|
|
|
+ else
|
|
|
+ val &= 0xffff;
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * On the RTL930x family of SoCs, the internal SerDes are accessed through an IO
|
|
|
+ * register which simulates commands to an internal MDIO bus.
|
|
|
+ */
|
|
|
+int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u32 cmd = phy_addr << 2 | page << 7 | phy_reg << 13 | 1;
|
|
|
+
|
|
|
+ pr_info("%s: phy_addr %d, phy_reg: %d\n", __func__, phy_addr, phy_reg);
|
|
|
+ sw_w32(cmd, RTL930X_SDS_INDACS_CMD);
|
|
|
+
|
|
|
+ for (i = 0; i < 100; i++) {
|
|
|
+ if (!(sw_r32(RTL930X_SDS_INDACS_CMD) & 0x1))
|
|
|
+ break;
|
|
|
+ mdelay(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i >= 100)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ pr_info("%s: returning %04x\n", __func__, sw_r32(RTL930X_SDS_INDACS_DATA) & 0xffff);
|
|
|
+ return sw_r32(RTL930X_SDS_INDACS_DATA) & 0xffff;
|
|
|
+}
|
|
|
+
|
|
|
+int rtl930x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u32 cmd;
|
|
|
+
|
|
|
+ sw_w32(v, RTL930X_SDS_INDACS_DATA);
|
|
|
+ cmd = phy_addr << 2 | page << 7 | phy_reg << 13 | 0x3;
|
|
|
+
|
|
|
+ for (i = 0; i < 100; i++) {
|
|
|
+ if (!(sw_r32(RTL930X_SDS_INDACS_CMD) & 0x1))
|
|
|
+ break;
|
|
|
+ mdelay(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i >= 100)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * On the RTL838x SoCs, the internal SerDes is accessed through direct access to
|
|
|
+ * standard PHY registers, where a 32 bit register holds a 16 bit word as found
|
|
|
+ * in a standard page 0 of a PHY
|
|
|
+ */
|
|
|
+int rtl838x_read_sds_phy(int phy_addr, int phy_reg)
|
|
|
+{
|
|
|
+ int offset = 0;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ if (phy_addr == 26)
|
|
|
+ offset = 0x100;
|
|
|
+ val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff;
|
|
|
+
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v)
|
|
|
+{
|
|
|
+ int offset = 0;
|
|
|
+ int reg;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ if (phy_addr == 49)
|
|
|
+ offset = 0x100;
|
|
|
+
|
|
|
+ reg = (phy_reg << 1) & 0xfc;
|
|
|
+ val = v;
|
|
|
+ if (phy_reg & 1) {
|
|
|
+ val = val << 16;
|
|
|
+ sw_w32_mask(0xffff0000, val,
|
|
|
+ RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg);
|
|
|
+ } else {
|
|
|
+ sw_w32_mask(0xffff, val,
|
|
|
+ RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* Read the link and speed status of the 2 internal SGMII/1000Base-X
|
|
|
@@ -123,6 +307,149 @@ static int rtl8393_read_status(struct phy_device *phydev)
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
+static int rtl8226_read_page(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ return __phy_read(phydev, 0x1f);
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl8226_write_page(struct phy_device *phydev, int page)
|
|
|
+{
|
|
|
+ return __phy_write(phydev, 0x1f, page);
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl8226_read_status(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ int ret = 0, i;
|
|
|
+ u32 val;
|
|
|
+ int port = phydev->mdio.addr;
|
|
|
+
|
|
|
+// TODO: ret = genphy_read_status(phydev);
|
|
|
+// if (ret < 0) {
|
|
|
+// pr_info("%s: genphy_read_status failed\n", __func__);
|
|
|
+// return ret;
|
|
|
+// }
|
|
|
+
|
|
|
+ // Link status must be read twice
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
+ rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA402, &val);
|
|
|
+ }
|
|
|
+ phydev->link = val & BIT(2) ? 1 : 0;
|
|
|
+ if (!phydev->link)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ // Read duplex status
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ phydev->duplex = !!(val & BIT(3));
|
|
|
+
|
|
|
+ // Read speed
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
|
|
|
+ switch (val & 0x0630) {
|
|
|
+ case 0x0000:
|
|
|
+ phydev->speed = SPEED_10;
|
|
|
+ break;
|
|
|
+ case 0x0010:
|
|
|
+ phydev->speed = SPEED_100;
|
|
|
+ break;
|
|
|
+ case 0x0020:
|
|
|
+ phydev->speed = SPEED_1000;
|
|
|
+ break;
|
|
|
+ case 0x0200:
|
|
|
+ phydev->speed = SPEED_10000;
|
|
|
+ break;
|
|
|
+ case 0x0210:
|
|
|
+ phydev->speed = SPEED_2500;
|
|
|
+ break;
|
|
|
+ case 0x0220:
|
|
|
+ phydev->speed = SPEED_5000;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl8266_advertise_aneg(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ u32 v;
|
|
|
+ int port = phydev->mdio.addr;
|
|
|
+
|
|
|
+ pr_info("In %s\n", __func__);
|
|
|
+
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_AN, 16, &v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ v |= BIT(5); // HD 10M
|
|
|
+ v |= BIT(6); // FD 10M
|
|
|
+ v |= BIT(7); // HD 100M
|
|
|
+ v |= BIT(8); // FD 100M
|
|
|
+
|
|
|
+ ret = rtl930x_write_mmd_phy(port, MMD_AN, 16, v);
|
|
|
+
|
|
|
+ // Allow 1GBit
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA412, &v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ v |= BIT(9); // FD 1000M
|
|
|
+
|
|
|
+ ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA412, v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ // Allow 2.5G
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_AN, 32, &v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ v |= BIT(7);
|
|
|
+ ret = rtl930x_write_mmd_phy(port, MMD_AN, 32, v);
|
|
|
+
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int rtl8226_config_aneg(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ u32 v;
|
|
|
+ int port = phydev->mdio.addr;
|
|
|
+
|
|
|
+ pr_info("In %s\n", __func__);
|
|
|
+ if (phydev->autoneg == AUTONEG_ENABLE) {
|
|
|
+ ret = rtl8266_advertise_aneg(phydev);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ // AutoNegotiationEnable
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_AN, 0, &v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ v |= BIT(12); // Enable AN
|
|
|
+ ret = rtl930x_write_mmd_phy(port, MMD_AN, 0, v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ // RestartAutoNegotiation
|
|
|
+ ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA400, &v);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ v |= BIT(9);
|
|
|
+
|
|
|
+ ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA400, v);
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_info("%s: Ret is already: %d\n", __func__, ret);
|
|
|
+// TODO: ret = __genphy_config_aneg(phydev, ret);
|
|
|
+
|
|
|
+out:
|
|
|
+ pr_info("%s: And ret is now: %d\n", __func__, ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
static struct fw_header *rtl838x_request_fw(struct phy_device *phydev,
|
|
|
const struct firmware *fw,
|
|
|
@@ -234,9 +561,9 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
|
|
|
|
|
|
read_phy(mac, 0, 0, &val);
|
|
|
if (val & (1 << 11))
|
|
|
- int_phy_on_off(mac, true);
|
|
|
+ rtl8380_int_phy_on_off(mac, true);
|
|
|
else
|
|
|
- phy_reset(mac);
|
|
|
+ rtl8380_phy_reset(mac);
|
|
|
msleep(100);
|
|
|
|
|
|
/* Ready PHY for patch */
|
|
|
@@ -326,9 +653,9 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
|
|
|
|
|
|
read_phy(mac, 0, 0, &val);
|
|
|
if (val & (1 << 11))
|
|
|
- int_phy_on_off(mac, true);
|
|
|
+ rtl8380_int_phy_on_off(mac, true);
|
|
|
else
|
|
|
- phy_reset(mac);
|
|
|
+ rtl8380_phy_reset(mac);
|
|
|
msleep(100);
|
|
|
|
|
|
/* Get Chip revision */
|
|
|
@@ -517,6 +844,26 @@ static int rtl8218b_write_mmd(struct phy_device *phydev,
|
|
|
return rtl838x_write_mmd_phy(addr, devnum, regnum, val);
|
|
|
}
|
|
|
|
|
|
+static int rtl8226_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
|
|
+{
|
|
|
+ int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr
|
|
|
+ int err;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ err = rtl930x_read_mmd_phy(port, devnum, regnum, &val);
|
|
|
+
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl8226_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val)
|
|
|
+{
|
|
|
+ int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr
|
|
|
+
|
|
|
+ return rtl930x_write_mmd_phy(port, devnum, regnum, val);
|
|
|
+}
|
|
|
+
|
|
|
static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre)
|
|
|
{
|
|
|
int base = mac - (mac % 4);
|
|
|
@@ -654,7 +1001,7 @@ static void rtl8218b_eee_set_u_boot(int port, bool enable)
|
|
|
}
|
|
|
|
|
|
// TODO: unused
|
|
|
-static void rtl8380_rtl8218b_eee_set(int port, bool enable)
|
|
|
+void rtl8380_rtl8218b_eee_set(int port, bool enable)
|
|
|
{
|
|
|
u32 val;
|
|
|
bool an_enabled;
|
|
|
@@ -720,7 +1067,7 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
|
|
|
}
|
|
|
|
|
|
// TODO: unused
|
|
|
-static void rtl8380_rtl8218b_green_set(int mac, bool enable)
|
|
|
+void rtl8380_rtl8218b_green_set(int mac, bool enable)
|
|
|
{
|
|
|
u32 val;
|
|
|
|
|
|
@@ -744,7 +1091,7 @@ static void rtl8380_rtl8218b_green_set(int mac, bool enable)
|
|
|
}
|
|
|
|
|
|
// TODO: unused
|
|
|
-static int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e)
|
|
|
+int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e)
|
|
|
{
|
|
|
u32 val;
|
|
|
int addr = phydev->mdio.addr;
|
|
|
@@ -886,9 +1233,9 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
|
|
|
|
|
|
read_phy(mac, 0, 16, &val);
|
|
|
if (val & (1 << 11))
|
|
|
- rtl8214fc_on_off(mac, true);
|
|
|
+ rtl8380_rtl8214fc_on_off(mac, true);
|
|
|
else
|
|
|
- phy_reset(mac);
|
|
|
+ rtl8380_phy_reset(mac);
|
|
|
|
|
|
msleep(100);
|
|
|
write_phy(mac, 0, 30, 0x0001);
|
|
|
@@ -1143,6 +1490,45 @@ static int rtl8390_configure_serdes(struct phy_device *phydev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int rtl9300_configure_serdes(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
|
+ int phy_addr = phydev->mdio.addr;
|
|
|
+ int sds_num = 0;
|
|
|
+ int v;
|
|
|
+
|
|
|
+ phydev_info(phydev, "Configuring internal RTL9300 SERDES\n");
|
|
|
+
|
|
|
+ switch (phy_addr) {
|
|
|
+ case 26:
|
|
|
+ sds_num = 8;
|
|
|
+ break;
|
|
|
+ case 27:
|
|
|
+ sds_num = 9;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ dev_err(dev, "Not a SerDes PHY\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Set default Medium to fibre */
|
|
|
+ v = rtl930x_read_sds_phy(sds_num, 0x1f, 11);
|
|
|
+ if (v < 0) {
|
|
|
+ dev_err(dev, "Cannot access SerDes PHY %d\n", phy_addr);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ v |= BIT(2);
|
|
|
+ rtl930x_write_sds_phy(sds_num, 0x1f, 11, v);
|
|
|
+
|
|
|
+ // TODO: this needs to be configurable via ethtool/.dts
|
|
|
+ pr_info("Setting 10G/1000BX auto fibre medium\n");
|
|
|
+ rtl9300_sds_rst(sds_num, 0x1b);
|
|
|
+
|
|
|
+ // TODO: Apply patch set for fibre type
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int rtl8214fc_phy_probe(struct phy_device *phydev)
|
|
|
{
|
|
|
struct device *dev = &phydev->mdio.dev;
|
|
|
@@ -1232,6 +1618,43 @@ static int rtl8218b_int_phy_probe(struct phy_device *phydev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int rtl8218d_phy_probe(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
|
+ struct rtl838x_phy_priv *priv;
|
|
|
+ int addr = phydev->mdio.addr;
|
|
|
+
|
|
|
+ pr_info("%s: id: %d\n", __func__, addr);
|
|
|
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
|
+ if (!priv)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ priv->name = "RTL8218D";
|
|
|
+
|
|
|
+ /* All base addresses of the PHYs start at multiples of 8 */
|
|
|
+ if (!(addr % 8)) {
|
|
|
+ /* Configuration must be done while patching still possible */
|
|
|
+// TODO: return configure_rtl8218d(phydev);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int rtl8226_phy_probe(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
|
+ struct rtl838x_phy_priv *priv;
|
|
|
+ int addr = phydev->mdio.addr;
|
|
|
+
|
|
|
+ pr_info("%s: id: %d\n", __func__, addr);
|
|
|
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
|
+ if (!priv)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ priv->name = "RTL8226";
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int rtl838x_serdes_probe(struct phy_device *phydev)
|
|
|
{
|
|
|
struct device *dev = &phydev->mdio.dev;
|
|
|
@@ -1299,6 +1722,26 @@ static int rtl8390_serdes_probe(struct phy_device *phydev)
|
|
|
return rtl8390_configure_generic(phydev);
|
|
|
}
|
|
|
|
|
|
+static int rtl9300_serdes_probe(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ struct device *dev = &phydev->mdio.dev;
|
|
|
+ struct rtl838x_phy_priv *priv;
|
|
|
+ int addr = phydev->mdio.addr;
|
|
|
+
|
|
|
+ if (soc_info.family != RTL9300_FAMILY_ID)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ if (addr < 24)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
|
+ if (!priv)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ priv->name = "RTL9300 Serdes";
|
|
|
+ return rtl9300_configure_serdes(phydev);
|
|
|
+}
|
|
|
+
|
|
|
static struct phy_driver rtl83xx_phy_driver[] = {
|
|
|
{
|
|
|
PHY_ID_MATCH_MODEL(PHY_ID_RTL8214C),
|
|
|
@@ -1340,6 +1783,29 @@ static struct phy_driver rtl83xx_phy_driver[] = {
|
|
|
.set_eee = rtl8218b_set_eee,
|
|
|
.get_eee = rtl8218b_get_eee,
|
|
|
},
|
|
|
+ {
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_RTL8218D),
|
|
|
+ .name = "REALTEK RTL8218D",
|
|
|
+ .features = PHY_GBIT_FEATURES,
|
|
|
+ .probe = rtl8218d_phy_probe,
|
|
|
+ .suspend = genphy_suspend,
|
|
|
+ .resume = genphy_resume,
|
|
|
+ .set_loopback = genphy_loopback,
|
|
|
+ }, {
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_RTL8226),
|
|
|
+ .name = "REALTEK RTL8226",
|
|
|
+ .features = PHY_GBIT_FEATURES,
|
|
|
+ .probe = rtl8226_phy_probe,
|
|
|
+ .suspend = genphy_suspend,
|
|
|
+ .resume = genphy_resume,
|
|
|
+ .set_loopback = genphy_loopback,
|
|
|
+ .read_mmd = rtl8226_read_mmd,
|
|
|
+ .write_mmd = rtl8226_write_mmd,
|
|
|
+ .read_page = rtl8226_read_page,
|
|
|
+ .write_page = rtl8226_write_page,
|
|
|
+ .read_status = rtl8226_read_status,
|
|
|
+ .config_aneg = rtl8226_config_aneg,
|
|
|
+ },
|
|
|
{
|
|
|
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
|
|
|
.name = "Realtek RTL8218B (internal)",
|
|
|
@@ -1383,7 +1849,16 @@ static struct phy_driver rtl83xx_phy_driver[] = {
|
|
|
.suspend = genphy_suspend,
|
|
|
.resume = genphy_resume,
|
|
|
.set_loopback = genphy_loopback,
|
|
|
- }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ PHY_ID_MATCH_MODEL(PHY_ID_RTL9300_I),
|
|
|
+ .name = "REALTEK RTL9300 SERDES",
|
|
|
+ .features = PHY_GBIT_FIBRE_FEATURES,
|
|
|
+ .probe = rtl9300_serdes_probe,
|
|
|
+ .suspend = genphy_suspend,
|
|
|
+ .resume = genphy_resume,
|
|
|
+ .set_loopback = genphy_loopback,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
module_phy_driver(rtl83xx_phy_driver);
|