#define RX_EN_93XX 0x10
#define TX_DO 0x2
#define WRAP 0x2
+#define MAX_PORTS 57
+#define MAX_SMI_BUSSES 4
#define RING_BUFFER 1600
u32 lastEvent;
u16 rxrings;
u16 rxringlen;
+ u8 smi_bus[MAX_PORTS];
+ u8 smi_addr[MAX_PORTS];
+ bool smi_bus_isc45[MAX_SMI_BUSSES];
+ bool phy_is_internal[MAX_PORTS];
};
extern int rtl838x_phy_init(struct rtl838x_eth_priv *priv);
{
int i;
int pos;
+ struct rtl838x_eth_priv *priv = bus->priv;
+ u32 c45_mask = 0;
+ u32 poll_sel[2];
+ u32 poll_ctrl = 0;
- pr_info("RTL930X_SMI_PORT0_15_POLLING_SEL %08x 16-27: %08x\n",
- sw_r32(RTL930X_SMI_PORT0_15_POLLING_SEL),
- sw_r32(RTL930X_SMI_PORT16_27_POLLING_SEL));
+ // Mapping of port to phy-addresses on an SMI bus
+ poll_sel[0] = poll_sel[1] = 0;
+ for (i = 0; i < 28; i++) {
+ pos = (i % 6) * 5;
+ sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos,
+ RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4);
- pr_info("%s: Enable SMI polling on SMI bus 0, SMI1, SMI2, disable on SMI3\n", __func__);
- sw_w32_mask(BIT(20) | BIT(21) | BIT(22), BIT(23), RTL930X_SMI_GLB_CTRL);
+ pos = (i * 2) % 32;
+ poll_sel[i / 16] |= priv->smi_bus[i] << pos;
+ poll_ctrl |= BIT(20 + priv->smi_bus[i]);
+ }
- pr_info("RTL9300 Powering on SerDes ports\n");
- rtl9300_sds_power(24, 1);
- rtl9300_sds_power(25, 1);
- rtl9300_sds_power(26, 1);
- rtl9300_sds_power(27, 1);
- mdelay(200);
+ // Configure which SMI bus is behind which port number
+ sw_w32(poll_sel[0], RTL930X_SMI_PORT0_15_POLLING_SEL);
+ sw_w32(poll_sel[1], RTL930X_SMI_PORT16_27_POLLING_SEL);
- // RTL930X_SMI_PORT0_15_POLLING_SEL 55550000 16-27: 00f9aaaa
- // i.e SMI=0 for all ports
- for (i = 0; i < 5; i++)
- pr_info("port phy: %08x\n", sw_r32(RTL930X_SMI_PORT0_5_ADDR + i *4));
+ // Enable polling on the respective SMI busses
+ sw_w32_mask(0, poll_ctrl, RTL930X_SMI_GLB_CTRL);
- // 1-to-1 mapping of port to phy-address
- for (i = 0; i < 24; i++) {
- pos = (i % 6) * 5;
- sw_w32_mask(0x1f << pos, i << pos, RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4);
- }
+ // Configure which SMI busses are polled in c45 based on a c45 PHY being on that bus
+ for (i = 0; i < 4; i++)
+ if (priv->smi_bus_isc45[i])
+ c45_mask |= BIT(i + 16);
- // ports 24 and 25 have PHY addresses 8 and 9, ports 26/27 PHY 26/27
- sw_w32(8 | 9 << 5 | 26 << 10 | 27 << 15, RTL930X_SMI_PORT0_5_ADDR + 4 * 4);
+ pr_info("c45_mask: %08x\n", c45_mask);
+ sw_w32_mask(0, c45_mask, RTL930X_SMI_GLB_CTRL);
- // Ports 24 and 25 live on SMI bus 1 and 2
- sw_w32_mask(0x3 << 16, 0x1 << 16, RTL930X_SMI_PORT16_27_POLLING_SEL);
- sw_w32_mask(0x3 << 18, 0x2 << 18, RTL930X_SMI_PORT16_27_POLLING_SEL);
-
- // SMI bus 1 and 2 speak Clause 45 TODO: Configure from .dts
- sw_w32_mask(0, BIT(17) | BIT(18), RTL930X_SMI_GLB_CTRL);
+ // Ports 24 to 27 are 2.5 or 10Gig, set this type (1) or (0) for internal SerDes
+ for (i = 24; i < 28; i++) {
+ pos = (i - 24) * 3 + 12;
+ if (priv->phy_is_internal[i])
+ sw_w32_mask(0x7 << pos, 0 << pos, RTL930X_SMI_MAC_TYPE_CTRL);
+ else
+ sw_w32_mask(0x7 << pos, 1 << pos, RTL930X_SMI_MAC_TYPE_CTRL);
+ }
- // Ports 24 and 25 are 2.5 Gig, set this type (1)
- sw_w32_mask(0x7 << 12, 1 << 12, RTL930X_SMI_MAC_TYPE_CTRL);
- sw_w32_mask(0x7 << 15, 1 << 15, RTL930X_SMI_MAC_TYPE_CTRL);
+ // TODO: Set up RTL9300_SMI_10GPHY_POLLING_SEL_0 for Aquantia PHYs on e.g. XGS 1250
return 0;
}
static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
{
- struct device_node *mii_np;
+ struct device_node *mii_np, *dn;
+ u32 pn;
int ret;
pr_debug("%s called\n", __func__);
priv->mii_bus->priv = priv;
priv->mii_bus->parent = &priv->pdev->dev;
+ for_each_node_by_name(dn, "ethernet-phy") {
+ u32 smi_addr[2];
+
+ if (of_property_read_u32(dn, "reg", &pn))
+ continue;
+
+ if (of_property_read_u32_array(dn, "rtl9300,smi-address", &smi_addr[0], 2)) {
+ smi_addr[0] = 0;
+ smi_addr[1] = pn;
+ }
+
+ if (pn < MAX_PORTS) {
+ priv->smi_bus[pn] = smi_addr[0];
+ priv->smi_addr[pn] = smi_addr[1];
+ } else {
+ pr_err("%s: illegal port number %d\n", __func__, pn);
+ }
+
+ if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45"))
+ priv->smi_bus_isc45[smi_addr[0]] = true;
+
+ if (of_property_read_bool(dn, "phy-is-integrated")) {
+ priv->phy_is_internal[pn] = true;
+ }
+
+ }
+
snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
ret = of_mdiobus_register(priv->mii_bus, mii_np);