diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 911aace422848..c79a5128235f9 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -26,11 +26,6 @@ #include "ksz8795_reg.h" #include "ksz8.h" -static bool ksz_is_ksz88x3(struct ksz_device *dev) -{ - return dev->chip_id == 0x8830; -} - static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); @@ -1116,7 +1111,6 @@ void ksz8_port_mirror_del(struct ksz_device *dev, int port, static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port) { struct ksz_port *p = &dev->ports[port]; - u8 data8; if (!p->interface && dev->compat_interface) { dev_warn(dev->dev, @@ -1125,40 +1119,6 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port) port); p->interface = dev->compat_interface; } - - /* Configure MII interface for proper network communication. */ - ksz_read8(dev, REG_PORT_5_CTRL_6, &data8); - data8 &= ~PORT_INTERFACE_TYPE; - data8 &= ~PORT_GMII_1GPS_MODE; - switch (p->interface) { - case PHY_INTERFACE_MODE_MII: - p->phydev.speed = SPEED_100; - break; - case PHY_INTERFACE_MODE_RMII: - data8 |= PORT_INTERFACE_RMII; - p->phydev.speed = SPEED_100; - break; - case PHY_INTERFACE_MODE_GMII: - data8 |= PORT_GMII_1GPS_MODE; - data8 |= PORT_INTERFACE_GMII; - p->phydev.speed = SPEED_1000; - break; - default: - data8 &= ~PORT_RGMII_ID_IN_ENABLE; - data8 &= ~PORT_RGMII_ID_OUT_ENABLE; - if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || - p->interface == PHY_INTERFACE_MODE_RGMII_RXID) - data8 |= PORT_RGMII_ID_IN_ENABLE; - if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || - p->interface == PHY_INTERFACE_MODE_RGMII_TXID) - data8 |= PORT_RGMII_ID_OUT_ENABLE; - data8 |= PORT_GMII_1GPS_MODE; - data8 |= PORT_INTERFACE_RGMII; - p->phydev.speed = SPEED_1000; - break; - } - ksz_write8(dev, REG_PORT_5_CTRL_6, data8); - p->phydev.duplex = 1; } void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port) diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index a848eb4c54cb5..77487d6118242 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -170,15 +170,7 @@ #define REG_PORT_5_CTRL_6 0x56 #define PORT_MII_INTERNAL_CLOCK BIT(7) -#define PORT_GMII_1GPS_MODE BIT(6) -#define PORT_RGMII_ID_IN_ENABLE BIT(4) -#define PORT_RGMII_ID_OUT_ENABLE BIT(3) #define PORT_GMII_MAC_MODE BIT(2) -#define PORT_INTERFACE_TYPE 0x3 -#define PORT_INTERFACE_MII 0 -#define PORT_INTERFACE_RMII 1 -#define PORT_INTERFACE_GMII 2 -#define PORT_INTERFACE_RGMII 3 #define REG_PORT_1_CTRL_7 0x17 #define REG_PORT_2_CTRL_7 0x27 diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 6453642fa14cc..4b14d80d27ede 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -19,11 +19,6 @@ #include "ksz_common.h" #include "ksz9477.h" -/* Used with variable features to indicate capabilities. */ -#define GBIT_SUPPORT BIT(0) -#define NEW_XMII BIT(1) -#define IS_9893 BIT(2) - static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); @@ -866,142 +861,18 @@ void ksz9477_port_mirror_del(struct ksz_device *dev, int port, PORT_MIRROR_SNIFFER, false); } -static bool ksz9477_get_gbit(struct ksz_device *dev, u8 data) -{ - bool gbit; - - if (dev->features & NEW_XMII) - gbit = !(data & PORT_MII_NOT_1GBIT); - else - gbit = !!(data & PORT_MII_1000MBIT_S1); - return gbit; -} - -static void ksz9477_set_gbit(struct ksz_device *dev, bool gbit, u8 *data) -{ - if (dev->features & NEW_XMII) { - if (gbit) - *data &= ~PORT_MII_NOT_1GBIT; - else - *data |= PORT_MII_NOT_1GBIT; - } else { - if (gbit) - *data |= PORT_MII_1000MBIT_S1; - else - *data &= ~PORT_MII_1000MBIT_S1; - } -} - -static int ksz9477_get_xmii(struct ksz_device *dev, u8 data) -{ - int mode; - - if (dev->features & NEW_XMII) { - switch (data & PORT_MII_SEL_M) { - case PORT_MII_SEL: - mode = 0; - break; - case PORT_RMII_SEL: - mode = 1; - break; - case PORT_GMII_SEL: - mode = 2; - break; - default: - mode = 3; - } - } else { - switch (data & PORT_MII_SEL_M) { - case PORT_MII_SEL_S1: - mode = 0; - break; - case PORT_RMII_SEL_S1: - mode = 1; - break; - case PORT_GMII_SEL_S1: - mode = 2; - break; - default: - mode = 3; - } - } - return mode; -} - -static void ksz9477_set_xmii(struct ksz_device *dev, int mode, u8 *data) -{ - u8 xmii; - - if (dev->features & NEW_XMII) { - switch (mode) { - case 0: - xmii = PORT_MII_SEL; - break; - case 1: - xmii = PORT_RMII_SEL; - break; - case 2: - xmii = PORT_GMII_SEL; - break; - default: - xmii = PORT_RGMII_SEL; - break; - } - } else { - switch (mode) { - case 0: - xmii = PORT_MII_SEL_S1; - break; - case 1: - xmii = PORT_RMII_SEL_S1; - break; - case 2: - xmii = PORT_GMII_SEL_S1; - break; - default: - xmii = PORT_RGMII_SEL_S1; - break; - } - } - *data &= ~PORT_MII_SEL_M; - *data |= xmii; -} - static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) { phy_interface_t interface; bool gbit; - int mode; - u8 data8; if (port < dev->phy_port_cnt) return PHY_INTERFACE_MODE_NA; - ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); - gbit = ksz9477_get_gbit(dev, data8); - mode = ksz9477_get_xmii(dev, data8); - switch (mode) { - case 2: - interface = PHY_INTERFACE_MODE_GMII; - if (gbit) - break; - fallthrough; - case 0: - interface = PHY_INTERFACE_MODE_MII; - break; - case 1: - interface = PHY_INTERFACE_MODE_RMII; - break; - default: - interface = PHY_INTERFACE_MODE_RGMII; - if (data8 & PORT_RGMII_ID_EG_ENABLE) - interface = PHY_INTERFACE_MODE_RGMII_TXID; - if (data8 & PORT_RGMII_ID_IG_ENABLE) { - interface = PHY_INTERFACE_MODE_RGMII_RXID; - if (data8 & PORT_RGMII_ID_EG_ENABLE) - interface = PHY_INTERFACE_MODE_RGMII_ID; - } - break; - } + + gbit = ksz_get_gbit(dev, port); + + interface = ksz_get_xmii(dev, port, gbit); + return interface; } @@ -1073,10 +944,9 @@ void ksz9477_get_caps(struct ksz_device *dev, int port, void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) { - struct ksz_port *p = &dev->ports[port]; struct dsa_switch *ds = dev->ds; - u8 data8, member; u16 data16; + u8 member; /* enable tag tail for host port */ if (cpu_port) @@ -1116,44 +986,6 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, true); - - /* configure MAC to 1G & RGMII mode */ - ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); - switch (p->interface) { - case PHY_INTERFACE_MODE_MII: - ksz9477_set_xmii(dev, 0, &data8); - ksz9477_set_gbit(dev, false, &data8); - p->phydev.speed = SPEED_100; - break; - case PHY_INTERFACE_MODE_RMII: - ksz9477_set_xmii(dev, 1, &data8); - ksz9477_set_gbit(dev, false, &data8); - p->phydev.speed = SPEED_100; - break; - case PHY_INTERFACE_MODE_GMII: - ksz9477_set_xmii(dev, 2, &data8); - ksz9477_set_gbit(dev, true, &data8); - p->phydev.speed = SPEED_1000; - break; - default: - ksz9477_set_xmii(dev, 3, &data8); - ksz9477_set_gbit(dev, true, &data8); - data8 &= ~PORT_RGMII_ID_IG_ENABLE; - data8 &= ~PORT_RGMII_ID_EG_ENABLE; - if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || - p->interface == PHY_INTERFACE_MODE_RGMII_RXID) - data8 |= PORT_RGMII_ID_IG_ENABLE; - if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || - p->interface == PHY_INTERFACE_MODE_RGMII_TXID) - data8 |= PORT_RGMII_ID_EG_ENABLE; - /* On KSZ9893, disable RGMII in-band status support */ - if (dev->features & IS_9893) - data8 &= ~PORT_MII_MAC_MODE; - p->phydev.speed = SPEED_1000; - break; - } - ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); - p->phydev.duplex = 1; } if (cpu_port) @@ -1341,9 +1173,6 @@ int ksz9477_switch_init(struct ksz_device *dev) dev->features &= ~GBIT_SUPPORT; dev->phy_port_cnt = 2; } else { - /* Chip uses new XMII register definitions. */ - dev->features |= NEW_XMII; - /* Chip does not support gigabit. */ if (!(data8 & SW_GIGABIT_ABLE)) dev->features &= ~GBIT_SUPPORT; diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h b/drivers/net/dsa/microchip/ksz9477_reg.h index d0cce4ca3cf9c..ddf99d1e4bbd3 100644 --- a/drivers/net/dsa/microchip/ksz9477_reg.h +++ b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -1175,35 +1175,11 @@ #define PORT_LINK_STATUS_FAIL BIT(0) /* 3 - xMII */ -#define REG_PORT_XMII_CTRL_0 0x0300 - #define PORT_SGMII_SEL BIT(7) -#define PORT_MII_FULL_DUPLEX BIT(6) -#define PORT_MII_100MBIT BIT(4) #define PORT_GRXC_ENABLE BIT(0) -#define REG_PORT_XMII_CTRL_1 0x0301 - #define PORT_RMII_CLK_SEL BIT(7) -/* S1 */ -#define PORT_MII_1000MBIT_S1 BIT(6) -/* S2 */ -#define PORT_MII_NOT_1GBIT BIT(6) #define PORT_MII_SEL_EDGE BIT(5) -#define PORT_RGMII_ID_IG_ENABLE BIT(4) -#define PORT_RGMII_ID_EG_ENABLE BIT(3) -#define PORT_MII_MAC_MODE BIT(2) -#define PORT_MII_SEL_M 0x3 -/* S1 */ -#define PORT_MII_SEL_S1 0x0 -#define PORT_RMII_SEL_S1 0x1 -#define PORT_GMII_SEL_S1 0x2 -#define PORT_RGMII_SEL_S1 0x3 -/* S2 */ -#define PORT_RGMII_SEL 0x0 -#define PORT_RMII_SEL 0x1 -#define PORT_GMII_SEL 0x2 -#define PORT_MII_SEL 0x3 /* 4 - MAC */ #define REG_PORT_MAC_CTRL_0 0x0400 diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index fd12a68c1dcd0..ed7d137cba994 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -222,8 +222,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = { .mirror_add = ksz9477_port_mirror_add, .mirror_del = ksz9477_port_mirror_del, .get_caps = lan937x_phylink_get_caps, - .phylink_mac_config = lan937x_phylink_mac_config, - .phylink_mac_link_up = lan937x_phylink_mac_link_up, + .setup_rgmii_delay = lan937x_setup_rgmii_delay, .fdb_dump = ksz9477_fdb_dump, .fdb_add = ksz9477_fdb_add, .fdb_del = ksz9477_fdb_del, @@ -257,6 +256,8 @@ static const u16 ksz8795_regs[] = { [S_START_CTRL] = 0x01, [S_BROADCAST_CTRL] = 0x06, [S_MULTICAST_CTRL] = 0x04, + [P_XMII_CTRL_0] = 0x06, + [P_XMII_CTRL_1] = 0x56, }; static const u32 ksz8795_masks[] = { @@ -279,6 +280,24 @@ static const u32 ksz8795_masks[] = { [DYNAMIC_MAC_TABLE_FID] = GENMASK(26, 20), [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(26, 24), [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(28, 27), + [P_MII_TX_FLOW_CTRL] = BIT(5), + [P_MII_RX_FLOW_CTRL] = BIT(5), +}; + +static const u8 ksz8795_xmii_ctrl0[] = { + [P_MII_100MBIT] = 0, + [P_MII_10MBIT] = 1, + [P_MII_FULL_DUPLEX] = 0, + [P_MII_HALF_DUPLEX] = 1, +}; + +static const u8 ksz8795_xmii_ctrl1[] = { + [P_RGMII_SEL] = 3, + [P_GMII_SEL] = 2, + [P_RMII_SEL] = 1, + [P_MII_SEL] = 0, + [P_GMII_1GBIT] = 1, + [P_GMII_NOT_1GBIT] = 0, }; static const u8 ksz8795_shifts[] = { @@ -351,20 +370,42 @@ static const u16 ksz9477_regs[] = { [S_START_CTRL] = 0x0300, [S_BROADCAST_CTRL] = 0x0332, [S_MULTICAST_CTRL] = 0x0331, + [P_XMII_CTRL_0] = 0x0300, + [P_XMII_CTRL_1] = 0x0301, }; static const u32 ksz9477_masks[] = { [ALU_STAT_WRITE] = 0, [ALU_STAT_READ] = 1, + [P_MII_TX_FLOW_CTRL] = BIT(5), + [P_MII_RX_FLOW_CTRL] = BIT(3), }; static const u8 ksz9477_shifts[] = { [ALU_STAT_INDEX] = 16, }; +static const u8 ksz9477_xmii_ctrl0[] = { + [P_MII_100MBIT] = 1, + [P_MII_10MBIT] = 0, + [P_MII_FULL_DUPLEX] = 1, + [P_MII_HALF_DUPLEX] = 0, +}; + +static const u8 ksz9477_xmii_ctrl1[] = { + [P_RGMII_SEL] = 0, + [P_RMII_SEL] = 1, + [P_GMII_SEL] = 2, + [P_MII_SEL] = 3, + [P_GMII_1GBIT] = 0, + [P_GMII_NOT_1GBIT] = 1, +}; + static const u32 lan937x_masks[] = { [ALU_STAT_WRITE] = 1, [ALU_STAT_READ] = 2, + [P_MII_TX_FLOW_CTRL] = BIT(5), + [P_MII_RX_FLOW_CTRL] = BIT(3), }; static const u8 lan937x_shifts[] = { @@ -388,6 +429,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz8795_regs, .masks = ksz8795_masks, .shifts = ksz8795_shifts, + .xmii_ctrl0 = ksz8795_xmii_ctrl0, + .xmii_ctrl1 = ksz8795_xmii_ctrl1, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -424,6 +467,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz8795_regs, .masks = ksz8795_masks, .shifts = ksz8795_shifts, + .xmii_ctrl0 = ksz8795_xmii_ctrl0, + .xmii_ctrl1 = ksz8795_xmii_ctrl1, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -446,6 +491,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz8795_regs, .masks = ksz8795_masks, .shifts = ksz8795_shifts, + .xmii_ctrl0 = ksz8795_xmii_ctrl0, + .xmii_ctrl1 = ksz8795_xmii_ctrl1, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -488,6 +535,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = ksz9477_masks, .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, false, true, false}, .supports_rmii = {false, false, false, false, @@ -514,6 +563,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = ksz9477_masks, .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, @@ -539,6 +590,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = ksz9477_masks, .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ .supports_mii = {false, false, true}, .supports_rmii = {false, false, true}, .supports_rgmii = {false, false, true}, @@ -561,6 +614,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = ksz9477_masks, .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, @@ -586,6 +641,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = lan937x_masks, .shifts = lan937x_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, true}, .supports_rmii = {false, false, false, false, true}, .supports_rgmii = {false, false, false, false, true}, @@ -607,6 +664,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = lan937x_masks, .shifts = lan937x_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, true, true}, .supports_rmii = {false, false, false, false, true, true}, .supports_rgmii = {false, false, false, false, true, true}, @@ -628,6 +687,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = lan937x_masks, .shifts = lan937x_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -653,6 +714,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = lan937x_masks, .shifts = lan937x_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -678,6 +741,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .regs = ksz9477_regs, .masks = lan937x_masks, .shifts = lan937x_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, .supports_mii = {false, false, false, false, true, true, false, false}, .supports_rmii = {false, false, false, false, @@ -1343,14 +1408,205 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) return dev->dev_ops->max_mtu(dev, port); } +static void ksz_set_xmii(struct ksz_device *dev, int port, + phy_interface_t interface) +{ + const u8 *bitval = dev->info->xmii_ctrl1; + struct ksz_port *p = &dev->ports[port]; + const u16 *regs = dev->info->regs; + u8 data8; + + ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); + + data8 &= ~(P_MII_SEL_M | P_RGMII_ID_IG_ENABLE | + P_RGMII_ID_EG_ENABLE); + + switch (interface) { + case PHY_INTERFACE_MODE_MII: + data8 |= bitval[P_MII_SEL]; + break; + case PHY_INTERFACE_MODE_RMII: + data8 |= bitval[P_RMII_SEL]; + break; + case PHY_INTERFACE_MODE_GMII: + data8 |= bitval[P_GMII_SEL]; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + data8 |= bitval[P_RGMII_SEL]; + /* On KSZ9893, disable RGMII in-band status support */ + if (dev->features & IS_9893) + data8 &= ~P_MII_MAC_MODE; + break; + default: + dev_err(dev->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(interface), port); + return; + } + + if (p->rgmii_tx_val) + data8 |= P_RGMII_ID_EG_ENABLE; + + if (p->rgmii_rx_val) + data8 |= P_RGMII_ID_IG_ENABLE; + + /* Write the updated value */ + ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8); +} + +phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit) +{ + const u8 *bitval = dev->info->xmii_ctrl1; + const u16 *regs = dev->info->regs; + phy_interface_t interface; + u8 data8; + u8 val; + + ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); + + val = FIELD_GET(P_MII_SEL_M, data8); + + if (val == bitval[P_MII_SEL]) { + if (gbit) + interface = PHY_INTERFACE_MODE_GMII; + else + interface = PHY_INTERFACE_MODE_MII; + } else if (val == bitval[P_RMII_SEL]) { + interface = PHY_INTERFACE_MODE_RGMII; + } else { + interface = PHY_INTERFACE_MODE_RGMII; + if (data8 & P_RGMII_ID_EG_ENABLE) + interface = PHY_INTERFACE_MODE_RGMII_TXID; + if (data8 & P_RGMII_ID_IG_ENABLE) { + interface = PHY_INTERFACE_MODE_RGMII_RXID; + if (data8 & P_RGMII_ID_EG_ENABLE) + interface = PHY_INTERFACE_MODE_RGMII_ID; + } + } + + return interface; +} + static void ksz_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { struct ksz_device *dev = ds->priv; + if (ksz_is_ksz88x3(dev)) + return; + + /* Internal PHYs */ + if (dev->info->internal_phy[port]) + return; + + if (phylink_autoneg_inband(mode)) { + dev_err(dev->dev, "In-band AN not supported!\n"); + return; + } + + ksz_set_xmii(dev, port, state->interface); + if (dev->dev_ops->phylink_mac_config) dev->dev_ops->phylink_mac_config(dev, port, mode, state); + + if (dev->dev_ops->setup_rgmii_delay) + dev->dev_ops->setup_rgmii_delay(dev, port); +} + +bool ksz_get_gbit(struct ksz_device *dev, int port) +{ + const u8 *bitval = dev->info->xmii_ctrl1; + const u16 *regs = dev->info->regs; + bool gbit = false; + u8 data8; + bool val; + + ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); + + val = FIELD_GET(P_GMII_1GBIT_M, data8); + + if (val == bitval[P_GMII_1GBIT]) + gbit = true; + + return gbit; +} + +static void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit) +{ + const u8 *bitval = dev->info->xmii_ctrl1; + const u16 *regs = dev->info->regs; + u8 data8; + + ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); + + data8 &= ~P_GMII_1GBIT_M; + + if (gbit) + data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_1GBIT]); + else + data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_NOT_1GBIT]); + + /* Write the updated value */ + ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8); +} + +static void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed) +{ + const u8 *bitval = dev->info->xmii_ctrl0; + const u16 *regs = dev->info->regs; + u8 data8; + + ksz_pread8(dev, port, regs[P_XMII_CTRL_0], &data8); + + data8 &= ~P_MII_100MBIT_M; + + if (speed == SPEED_100) + data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_100MBIT]); + else + data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_10MBIT]); + + /* Write the updated value */ + ksz_pwrite8(dev, port, regs[P_XMII_CTRL_0], data8); +} + +static void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed) +{ + if (speed == SPEED_1000) + ksz_set_gbit(dev, port, true); + else + ksz_set_gbit(dev, port, false); + + if (speed == SPEED_100 || speed == SPEED_10) + ksz_set_100_10mbit(dev, port, speed); +} + +static void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex, + bool tx_pause, bool rx_pause) +{ + const u8 *bitval = dev->info->xmii_ctrl0; + const u32 *masks = dev->info->masks; + const u16 *regs = dev->info->regs; + u8 mask; + u8 val; + + mask = P_MII_DUPLEX_M | masks[P_MII_TX_FLOW_CTRL] | + masks[P_MII_RX_FLOW_CTRL]; + + if (duplex == DUPLEX_FULL) + val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_FULL_DUPLEX]); + else + val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_HALF_DUPLEX]); + + if (tx_pause) + val |= masks[P_MII_TX_FLOW_CTRL]; + + if (rx_pause) + val |= masks[P_MII_RX_FLOW_CTRL]; + + ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val); } static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, @@ -1360,6 +1616,19 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, int duplex, bool tx_pause, bool rx_pause) { struct ksz_device *dev = ds->priv; + struct ksz_port *p; + + p = &dev->ports[port]; + + /* Internal PHYs */ + if (dev->info->internal_phy[port]) + return; + + p->phydev.speed = speed; + + ksz_port_set_xmii_speed(dev, port, speed); + + ksz_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause); if (dev->dev_ops->phylink_mac_link_up) dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface, @@ -1494,6 +1763,43 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) } EXPORT_SYMBOL(ksz_switch_alloc); +static void ksz_parse_rgmii_delay(struct ksz_device *dev, int port_num, + struct device_node *port_dn) +{ + phy_interface_t phy_mode = dev->ports[port_num].interface; + int rx_delay = -1, tx_delay = -1; + + if (!phy_interface_mode_is_rgmii(phy_mode)) + return; + + of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay); + of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay); + + if (rx_delay == -1 && tx_delay == -1) { + dev_warn(dev->dev, + "Port %d interpreting RGMII delay settings based on \"phy-mode\" property, " + "please update device tree to specify \"rx-internal-delay-ps\" and " + "\"tx-internal-delay-ps\"", + port_num); + + if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || + phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + rx_delay = 2000; + + if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || + phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + tx_delay = 2000; + } + + if (rx_delay < 0) + rx_delay = 0; + if (tx_delay < 0) + tx_delay = 0; + + dev->ports[port_num].rgmii_rx_val = rx_delay; + dev->ports[port_num].rgmii_tx_val = tx_delay; +} + int ksz_switch_register(struct ksz_device *dev) { const struct ksz_chip_data *info; @@ -1591,6 +1897,8 @@ int ksz_switch_register(struct ksz_device *dev) } of_get_phy_mode(port, &dev->ports[port_num].interface); + + ksz_parse_rgmii_delay(dev, port_num, port); } of_node_put(ports); } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index d5dddb7ec045d..764ada3a0f42a 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -51,6 +51,8 @@ struct ksz_chip_data { const u16 *regs; const u32 *masks; const u8 *shifts; + const u8 *xmii_ctrl0; + const u8 *xmii_ctrl1; int stp_ctrl_reg; int broadcast_ctrl_reg; int multicast_ctrl_reg; @@ -77,6 +79,8 @@ struct ksz_port { struct ksz_port_mib mib; phy_interface_t interface; u16 max_frame; + u32 rgmii_tx_val; + u32 rgmii_rx_val; }; struct ksz_device { @@ -169,6 +173,8 @@ enum ksz_regs { S_START_CTRL, S_BROADCAST_CTRL, S_MULTICAST_CTRL, + P_XMII_CTRL_0, + P_XMII_CTRL_1, }; enum ksz_masks { @@ -193,6 +199,8 @@ enum ksz_masks { DYNAMIC_MAC_TABLE_TIMESTAMP, ALU_STAT_WRITE, ALU_STAT_READ, + P_MII_TX_FLOW_CTRL, + P_MII_RX_FLOW_CTRL, }; enum ksz_shifts { @@ -208,6 +216,22 @@ enum ksz_shifts { ALU_STAT_INDEX, }; +enum ksz_xmii_ctrl0 { + P_MII_100MBIT, + P_MII_10MBIT, + P_MII_FULL_DUPLEX, + P_MII_HALF_DUPLEX, +}; + +enum ksz_xmii_ctrl1 { + P_RGMII_SEL, + P_RMII_SEL, + P_GMII_SEL, + P_MII_SEL, + P_GMII_1GBIT, + P_GMII_NOT_1GBIT, +}; + struct alu_struct { /* entry 1 */ u8 is_static:1; @@ -279,6 +303,7 @@ struct ksz_dev_ops { phy_interface_t interface, struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause); + void (*setup_rgmii_delay)(struct ksz_device *dev, int port); void (*config_cpu_port)(struct dsa_switch *ds); int (*enable_stp_addr)(struct ksz_device *dev); int (*reset)(struct ksz_device *dev); @@ -293,6 +318,8 @@ void ksz_switch_remove(struct ksz_device *dev); void ksz_init_mib_timer(struct ksz_device *dev); void ksz_r_mib_stats64(struct ksz_device *dev, int port); void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); +bool ksz_get_gbit(struct ksz_device *dev, int port); +phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit); extern const struct ksz_chip_data ksz_switch_chips[]; /* Common register access functions */ @@ -399,6 +426,14 @@ static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); } +static inline void ksz_prmw8(struct ksz_device *dev, int port, int offset, + u8 mask, u8 val) +{ + regmap_update_bits(dev->regmap[0], + dev->dev_ops->get_port_addr(port, offset), + mask, val); +} + static inline void ksz_regmap_lock(void *__mtx) { struct mutex *mtx = __mtx; @@ -411,6 +446,11 @@ static inline void ksz_regmap_unlock(void *__mtx) mutex_unlock(mtx); } +static inline bool ksz_is_ksz88x3(struct ksz_device *dev) +{ + return dev->chip_id == KSZ8830_CHIP_ID; +} + static inline int is_lan937x(struct ksz_device *dev) { return dev->chip_id == LAN9370_CHIP_ID || @@ -456,6 +496,20 @@ static inline int is_lan937x(struct ksz_device *dev) #define SW_START 0x01 +/* Used with variable features to indicate capabilities. */ +#define GBIT_SUPPORT BIT(0) +#define IS_9893 BIT(2) + +/* xMII configuration */ +#define P_MII_DUPLEX_M BIT(6) +#define P_MII_100MBIT_M BIT(4) + +#define P_GMII_1GBIT_M BIT(6) +#define P_RGMII_ID_IG_ENABLE BIT(4) +#define P_RGMII_ID_EG_ENABLE BIT(3) +#define P_MII_MAC_MODE BIT(2) +#define P_MII_SEL_M 0x3 + /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h index 72ba9cb2fbc66..4e0b1dccec270 100644 --- a/drivers/net/dsa/microchip/lan937x.h +++ b/drivers/net/dsa/microchip/lan937x.h @@ -17,11 +17,5 @@ void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu); void lan937x_phylink_get_caps(struct ksz_device *dev, int port, struct phylink_config *config); -void lan937x_phylink_mac_link_up(struct ksz_device *dev, int port, - unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, - int duplex, bool tx_pause, bool rx_pause); -void lan937x_phylink_mac_config(struct ksz_device *dev, int port, - unsigned int mode, - const struct phylink_link_state *state); +void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port); #endif diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index c29d175ca6f72..daedd2bf20c1b 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -234,6 +234,8 @@ int lan937x_reset_switch(struct ksz_device *dev) void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) { + const u32 *masks = dev->info->masks; + const u16 *regs = dev->info->regs; struct dsa_switch *ds = dev->ds; u8 member; @@ -254,8 +256,9 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); if (!dev->info->internal_phy[port]) - lan937x_port_cfg(dev, port, REG_PORT_XMII_CTRL_0, - PORT_MII_TX_FLOW_CTRL | PORT_MII_RX_FLOW_CTRL, + lan937x_port_cfg(dev, port, regs[P_XMII_CTRL_0], + masks[P_MII_TX_FLOW_CTRL] | + masks[P_MII_RX_FLOW_CTRL], true); if (cpu_port) @@ -312,75 +315,43 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu) return 0; } -static void lan937x_config_gbit(struct ksz_device *dev, bool gbit, u8 *data) +static void lan937x_set_tune_adj(struct ksz_device *dev, int port, + u16 reg, u8 val) { - if (gbit) - *data &= ~PORT_MII_NOT_1GBIT; - else - *data |= PORT_MII_NOT_1GBIT; -} + u16 data16; -static void lan937x_mac_config(struct ksz_device *dev, int port, - phy_interface_t interface) -{ - u8 data8; - - ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); - - /* clear MII selection & set it based on interface later */ - data8 &= ~PORT_MII_SEL_M; - - /* configure MAC based on interface */ - switch (interface) { - case PHY_INTERFACE_MODE_MII: - lan937x_config_gbit(dev, false, &data8); - data8 |= PORT_MII_SEL; - break; - case PHY_INTERFACE_MODE_RMII: - lan937x_config_gbit(dev, false, &data8); - data8 |= PORT_RMII_SEL; - break; - default: - dev_err(dev->dev, "Unsupported interface '%s' for port %d\n", - phy_modes(interface), port); - return; - } + ksz_pread16(dev, port, reg, &data16); - /* Write the updated value */ - ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); + /* Update tune Adjust */ + data16 |= FIELD_PREP(PORT_TUNE_ADJ, val); + ksz_pwrite16(dev, port, reg, data16); + + /* write DLL reset to take effect */ + data16 |= PORT_DLL_RESET; + ksz_pwrite16(dev, port, reg, data16); } -static void lan937x_config_interface(struct ksz_device *dev, int port, - int speed, int duplex, - bool tx_pause, bool rx_pause) +static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port) { - u8 xmii_ctrl0, xmii_ctrl1; - - ksz_pread8(dev, port, REG_PORT_XMII_CTRL_0, &xmii_ctrl0); - ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &xmii_ctrl1); - - xmii_ctrl0 &= ~(PORT_MII_100MBIT | PORT_MII_FULL_DUPLEX | - PORT_MII_TX_FLOW_CTRL | PORT_MII_RX_FLOW_CTRL); - - if (speed == SPEED_1000) - lan937x_config_gbit(dev, true, &xmii_ctrl1); - else - lan937x_config_gbit(dev, false, &xmii_ctrl1); + u8 val; - if (speed == SPEED_100) - xmii_ctrl0 |= PORT_MII_100MBIT; + /* Apply different codes based on the ports as per characterization + * results + */ + val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS : + RGMII_2_TX_DELAY_2NS; - if (duplex) - xmii_ctrl0 |= PORT_MII_FULL_DUPLEX; + lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val); +} - if (tx_pause) - xmii_ctrl0 |= PORT_MII_TX_FLOW_CTRL; +static void lan937x_set_rgmii_rx_delay(struct ksz_device *dev, int port) +{ + u8 val; - if (rx_pause) - xmii_ctrl0 |= PORT_MII_RX_FLOW_CTRL; + val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS : + RGMII_2_RX_DELAY_2NS; - ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_0, xmii_ctrl0); - ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, xmii_ctrl1); + lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_4, val); } void lan937x_phylink_get_caps(struct ksz_device *dev, int port, @@ -395,33 +366,21 @@ void lan937x_phylink_get_caps(struct ksz_device *dev, int port, } } -void lan937x_phylink_mac_link_up(struct ksz_device *dev, int port, - unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, - int duplex, bool tx_pause, bool rx_pause) +void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port) { - /* Internal PHYs */ - if (dev->info->internal_phy[port]) - return; + struct ksz_port *p = &dev->ports[port]; - lan937x_config_interface(dev, port, speed, duplex, - tx_pause, rx_pause); -} - -void lan937x_phylink_mac_config(struct ksz_device *dev, int port, - unsigned int mode, - const struct phylink_link_state *state) -{ - /* Internal PHYs */ - if (dev->info->internal_phy[port]) - return; - - if (phylink_autoneg_inband(mode)) { - dev_err(dev->dev, "In-band AN not supported!\n"); - return; + if (p->rgmii_tx_val) { + lan937x_set_rgmii_tx_delay(dev, port); + dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n", + port); } - lan937x_mac_config(dev, port, state->interface); + if (p->rgmii_rx_val) { + lan937x_set_rgmii_rx_delay(dev, port); + dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n", + port); + } } int lan937x_setup(struct dsa_switch *ds) diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h index c187d0a3e7fa0..ba4adaddb3ecc 100644 --- a/drivers/net/dsa/microchip/lan937x_reg.h +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -131,24 +131,16 @@ #define REG_PORT_T1_PHY_CTRL_BASE 0x0100 /* 3 - xMII */ -#define REG_PORT_XMII_CTRL_0 0x0300 #define PORT_SGMII_SEL BIT(7) -#define PORT_MII_FULL_DUPLEX BIT(6) -#define PORT_MII_TX_FLOW_CTRL BIT(5) -#define PORT_MII_100MBIT BIT(4) -#define PORT_MII_RX_FLOW_CTRL BIT(3) #define PORT_GRXC_ENABLE BIT(0) -#define REG_PORT_XMII_CTRL_1 0x0301 -#define PORT_MII_NOT_1GBIT BIT(6) #define PORT_MII_SEL_EDGE BIT(5) -#define PORT_RGMII_ID_IG_ENABLE BIT(4) -#define PORT_RGMII_ID_EG_ENABLE BIT(3) -#define PORT_MII_MAC_MODE BIT(2) -#define PORT_MII_SEL_M 0x3 -#define PORT_RGMII_SEL 0x0 -#define PORT_RMII_SEL 0x1 -#define PORT_MII_SEL 0x2 + +#define REG_PORT_XMII_CTRL_4 0x0304 +#define REG_PORT_XMII_CTRL_5 0x0306 + +#define PORT_DLL_RESET BIT(15) +#define PORT_TUNE_ADJ GENMASK(13, 7) /* 4 - MAC */ #define REG_PORT_MAC_CTRL_0 0x0400 @@ -175,6 +167,18 @@ #define P_PRIO_CTRL REG_PORT_MRI_PRIO_CTRL +/* The port number as per the datasheet */ +#define RGMII_2_PORT_NUM 5 +#define RGMII_1_PORT_NUM 6 + +#define LAN937X_RGMII_2_PORT (RGMII_2_PORT_NUM - 1) +#define LAN937X_RGMII_1_PORT (RGMII_1_PORT_NUM - 1) + +#define RGMII_1_TX_DELAY_2NS 2 +#define RGMII_2_TX_DELAY_2NS 0 +#define RGMII_1_RX_DELAY_2NS 0x1B +#define RGMII_2_RX_DELAY_2NS 0x14 + #define LAN937X_TAG_LEN 2 #endif