Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: microchip: add support for side MDIO interface in LAN937x

Implement side MDIO channel support for LAN937x switches, providing an
alternative to SPI for PHY management alongside existing SPI-based
switch configuration. This is needed to reduce SPI load, as SPI can be
relatively expensive for small packets compared to MDIO support.

Also, implemented static mappings for PHY addresses for various LAN937x
models to support different internal PHY configurations. Since the PHY
address mappings are not equal to the port indexes, this patch also
provides PHY address calculation based on hardware strapping
configuration.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241106075942.1636998-6-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Oleksij Rempel and committed by
Jakub Kicinski
f47e6e1e 8bbba416

+223 -16
+7
drivers/net/dsa/microchip/ksz_common.c
··· 411 411 .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, 412 412 .port_setup = lan937x_port_setup, 413 413 .set_ageing_time = lan937x_set_ageing_time, 414 + .mdio_bus_preinit = lan937x_mdio_bus_preinit, 415 + .create_phy_addr_map = lan937x_create_phy_addr_map, 414 416 .r_phy = lan937x_r_phy, 415 417 .w_phy = lan937x_w_phy, 416 418 .r_mib_cnt = ksz9477_r_mib_cnt, ··· 1764 1762 .num_tx_queues = 8, 1765 1763 .num_ipms = 8, 1766 1764 .tc_cbs_supported = true, 1765 + .phy_side_mdio_supported = true, 1767 1766 .ops = &lan937x_dev_ops, 1768 1767 .phylink_mac_ops = &lan937x_phylink_mac_ops, 1769 1768 .mib_names = ksz9477_mib_names, ··· 1793 1790 .num_tx_queues = 8, 1794 1791 .num_ipms = 8, 1795 1792 .tc_cbs_supported = true, 1793 + .phy_side_mdio_supported = true, 1796 1794 .ops = &lan937x_dev_ops, 1797 1795 .phylink_mac_ops = &lan937x_phylink_mac_ops, 1798 1796 .mib_names = ksz9477_mib_names, ··· 1822 1818 .num_tx_queues = 8, 1823 1819 .num_ipms = 8, 1824 1820 .tc_cbs_supported = true, 1821 + .phy_side_mdio_supported = true, 1825 1822 .ops = &lan937x_dev_ops, 1826 1823 .phylink_mac_ops = &lan937x_phylink_mac_ops, 1827 1824 .mib_names = ksz9477_mib_names, ··· 1855 1850 .num_tx_queues = 8, 1856 1851 .num_ipms = 8, 1857 1852 .tc_cbs_supported = true, 1853 + .phy_side_mdio_supported = true, 1858 1854 .ops = &lan937x_dev_ops, 1859 1855 .phylink_mac_ops = &lan937x_phylink_mac_ops, 1860 1856 .mib_names = ksz9477_mib_names, ··· 1888 1882 .num_tx_queues = 8, 1889 1883 .num_ipms = 8, 1890 1884 .tc_cbs_supported = true, 1885 + .phy_side_mdio_supported = true, 1891 1886 .ops = &lan937x_dev_ops, 1892 1887 .phylink_mac_ops = &lan937x_phylink_mac_ops, 1893 1888 .mib_names = ksz9477_mib_names,
+2
drivers/net/dsa/microchip/lan937x.h
··· 13 13 void lan937x_config_cpu_port(struct dsa_switch *ds); 14 14 int lan937x_switch_init(struct ksz_device *dev); 15 15 void lan937x_switch_exit(struct ksz_device *dev); 16 + int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio); 17 + int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio); 16 18 int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); 17 19 int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); 18 20 int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu);
+210 -16
drivers/net/dsa/microchip/lan937x_main.c
··· 18 18 #include "ksz9477.h" 19 19 #include "lan937x.h" 20 20 21 + /* marker for ports without built-in PHY */ 22 + #define LAN937X_NO_PHY U8_MAX 23 + 24 + /* 25 + * lan9370_phy_addr - Mapping of LAN9370 switch ports to PHY addresses. 26 + * 27 + * Each entry corresponds to a specific port on the LAN9370 switch, 28 + * where ports 1-4 are connected to integrated 100BASE-T1 PHYs, and 29 + * Port 5 is connected to an RGMII interface without a PHY. The values 30 + * are based on the documentation (DS00003108E, section 3.3). 31 + */ 32 + static const u8 lan9370_phy_addr[] = { 33 + [0] = 2, /* Port 1, T1 AFE0 */ 34 + [1] = 3, /* Port 2, T1 AFE1 */ 35 + [2] = 5, /* Port 3, T1 AFE3 */ 36 + [3] = 6, /* Port 4, T1 AFE4 */ 37 + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ 38 + }; 39 + 40 + /* 41 + * lan9371_phy_addr - Mapping of LAN9371 switch ports to PHY addresses. 42 + * 43 + * The values are based on the documentation (DS00003109E, section 3.3). 44 + */ 45 + static const u8 lan9371_phy_addr[] = { 46 + [0] = 2, /* Port 1, T1 AFE0 */ 47 + [1] = 3, /* Port 2, T1 AFE1 */ 48 + [2] = 5, /* Port 3, T1 AFE3 */ 49 + [3] = 8, /* Port 4, TX PHY */ 50 + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ 51 + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ 52 + }; 53 + 54 + /* 55 + * lan9372_phy_addr - Mapping of LAN9372 switch ports to PHY addresses. 56 + * 57 + * The values are based on the documentation (DS00003110F, section 3.3). 58 + */ 59 + static const u8 lan9372_phy_addr[] = { 60 + [0] = 2, /* Port 1, T1 AFE0 */ 61 + [1] = 3, /* Port 2, T1 AFE1 */ 62 + [2] = 5, /* Port 3, T1 AFE3 */ 63 + [3] = 8, /* Port 4, TX PHY */ 64 + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ 65 + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ 66 + [6] = 6, /* Port 7, T1 AFE4 */ 67 + [7] = 4, /* Port 8, T1 AFE2 */ 68 + }; 69 + 70 + /* 71 + * lan9373_phy_addr - Mapping of LAN9373 switch ports to PHY addresses. 72 + * 73 + * The values are based on the documentation (DS00003110F, section 3.3). 74 + */ 75 + static const u8 lan9373_phy_addr[] = { 76 + [0] = 2, /* Port 1, T1 AFE0 */ 77 + [1] = 3, /* Port 2, T1 AFE1 */ 78 + [2] = 5, /* Port 3, T1 AFE3 */ 79 + [3] = LAN937X_NO_PHY, /* Port 4, SGMII */ 80 + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ 81 + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ 82 + [6] = 6, /* Port 7, T1 AFE4 */ 83 + [7] = 4, /* Port 8, T1 AFE2 */ 84 + }; 85 + 86 + /* 87 + * lan9374_phy_addr - Mapping of LAN9374 switch ports to PHY addresses. 88 + * 89 + * The values are based on the documentation (DS00003110F, section 3.3). 90 + */ 91 + static const u8 lan9374_phy_addr[] = { 92 + [0] = 2, /* Port 1, T1 AFE0 */ 93 + [1] = 3, /* Port 2, T1 AFE1 */ 94 + [2] = 5, /* Port 3, T1 AFE3 */ 95 + [3] = 7, /* Port 4, T1 AFE5 */ 96 + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ 97 + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ 98 + [6] = 6, /* Port 7, T1 AFE4 */ 99 + [7] = 4, /* Port 8, T1 AFE2 */ 100 + }; 101 + 21 102 static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) 22 103 { 23 104 return regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0); ··· 111 30 bits, set ? bits : 0); 112 31 } 113 32 114 - static int lan937x_enable_spi_indirect_access(struct ksz_device *dev) 33 + /** 34 + * lan937x_create_phy_addr_map - Create port-to-PHY address map for MDIO bus. 35 + * @dev: Pointer to device structure. 36 + * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus. 37 + * 38 + * This function sets up the PHY address mapping for the LAN937x switches, 39 + * which support two access modes for internal PHYs: 40 + * 1. **SPI Access**: A straightforward one-to-one port-to-PHY address 41 + * mapping is applied. 42 + * 2. **MDIO Access**: The PHY address mapping varies based on chip variant 43 + * and strap configuration. An offset is calculated based on strap settings 44 + * to ensure correct PHY addresses are assigned. The offset calculation logic 45 + * is based on Microchip's Article Number 000015828, available at: 46 + * https://microchip.my.site.com/s/article/LAN9374-Virtual-PHY-PHY-Address-Mapping 47 + * 48 + * The function first checks if side MDIO access is disabled, in which case a 49 + * simple direct mapping (port number = PHY address) is applied. If side MDIO 50 + * access is enabled, it reads the strap configuration to determine the correct 51 + * offset for PHY addresses. 52 + * 53 + * The appropriate mapping table is selected based on the chip ID, and the 54 + * `phy_addr_map` is populated with the correct addresses for each port. Any 55 + * port with no PHY is assigned a `LAN937X_NO_PHY` marker. 56 + * 57 + * Return: 0 on success, error code on failure. 58 + */ 59 + int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio) 60 + { 61 + static const u8 *phy_addr_map; 62 + u32 strap_val; 63 + u8 offset = 0; 64 + size_t size; 65 + int ret, i; 66 + 67 + if (!side_mdio) { 68 + /* simple direct mapping */ 69 + for (i = 0; i < dev->info->port_cnt; i++) 70 + dev->phy_addr_map[i] = i; 71 + 72 + return 0; 73 + } 74 + 75 + ret = ksz_read32(dev, REG_SW_CFG_STRAP_VAL, &strap_val); 76 + if (ret < 0) 77 + return ret; 78 + 79 + if (!(strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG)) 80 + offset = 0; 81 + else if (!(strap_val & SW_CASCADE_ID_CFG) && (strap_val & SW_VPHY_ADD_CFG)) 82 + offset = 7; 83 + else if ((strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG)) 84 + offset = 15; 85 + else 86 + offset = 22; 87 + 88 + switch (dev->info->chip_id) { 89 + case LAN9370_CHIP_ID: 90 + phy_addr_map = lan9370_phy_addr; 91 + size = ARRAY_SIZE(lan9370_phy_addr); 92 + break; 93 + case LAN9371_CHIP_ID: 94 + phy_addr_map = lan9371_phy_addr; 95 + size = ARRAY_SIZE(lan9371_phy_addr); 96 + break; 97 + case LAN9372_CHIP_ID: 98 + phy_addr_map = lan9372_phy_addr; 99 + size = ARRAY_SIZE(lan9372_phy_addr); 100 + break; 101 + case LAN9373_CHIP_ID: 102 + phy_addr_map = lan9373_phy_addr; 103 + size = ARRAY_SIZE(lan9373_phy_addr); 104 + break; 105 + case LAN9374_CHIP_ID: 106 + phy_addr_map = lan9374_phy_addr; 107 + size = ARRAY_SIZE(lan9374_phy_addr); 108 + break; 109 + default: 110 + return -EINVAL; 111 + } 112 + 113 + if (size < dev->info->port_cnt) 114 + return -EINVAL; 115 + 116 + for (i = 0; i < dev->info->port_cnt; i++) { 117 + if (phy_addr_map[i] == LAN937X_NO_PHY) 118 + dev->phy_addr_map[i] = phy_addr_map[i]; 119 + else 120 + dev->phy_addr_map[i] = phy_addr_map[i] + offset; 121 + } 122 + 123 + return 0; 124 + } 125 + 126 + /** 127 + * lan937x_mdio_bus_preinit - Pre-initialize MDIO bus for accessing PHYs. 128 + * @dev: Pointer to device structure. 129 + * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus. 130 + * 131 + * This function configures the LAN937x switch for PHY access either through 132 + * SPI or the side MDIO bus, unlocking the necessary registers for each access 133 + * mode. 134 + * 135 + * Operation Modes: 136 + * 1. **SPI Access**: Enables SPI indirect access to address clock domain 137 + * crossing issues when SPI is used for PHY access. 138 + * 2. **MDIO Access**: Grants access to internal PHYs over the side MDIO bus, 139 + * required when using the MDIO bus for PHY management. 140 + * 141 + * Return: 0 on success, error code on failure. 142 + */ 143 + int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio) 115 144 { 116 145 u16 data16; 117 146 int ret; 118 147 119 - /* Enable Phy access through SPI */ 148 + /* Unlock access to the PHYs, needed for SPI and side MDIO access */ 120 149 ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false); 121 150 if (ret < 0) 122 - return ret; 151 + goto print_error; 123 152 124 - ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16); 153 + if (side_mdio) 154 + /* Allow access to internal PHYs over MDIO bus */ 155 + data16 = VPHY_MDIO_INTERNAL_ENABLE; 156 + else 157 + /* Enable SPI indirect access to address clock domain crossing 158 + * issue 159 + */ 160 + data16 = VPHY_SPI_INDIRECT_ENABLE; 161 + 162 + ret = ksz_rmw16(dev, REG_VPHY_SPECIAL_CTRL__2, 163 + VPHY_SPI_INDIRECT_ENABLE | VPHY_MDIO_INTERNAL_ENABLE, 164 + data16); 165 + 166 + print_error: 125 167 if (ret < 0) 126 - return ret; 168 + dev_err(dev->dev, "failed to preinit the MDIO bus\n"); 127 169 128 - /* Allow SPI access */ 129 - data16 |= VPHY_SPI_INDIRECT_ENABLE; 130 - 131 - return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16); 170 + return ret; 132 171 } 133 172 134 173 static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg) ··· 563 362 { 564 363 struct ksz_device *dev = ds->priv; 565 364 int ret; 566 - 567 - /* enable Indirect Access from SPI to the VPHY registers */ 568 - ret = lan937x_enable_spi_indirect_access(dev); 569 - if (ret < 0) { 570 - dev_err(dev->dev, "failed to enable spi indirect access"); 571 - return ret; 572 - } 573 365 574 366 /* The VLAN aware is a global setting. Mixed vlan 575 367 * filterings are not supported.
+4
drivers/net/dsa/microchip/lan937x_reg.h
··· 37 37 #define SW_CLK125_ENB BIT(1) 38 38 #define SW_CLK25_ENB BIT(0) 39 39 40 + #define REG_SW_CFG_STRAP_VAL 0x0200 41 + #define SW_CASCADE_ID_CFG BIT(15) 42 + #define SW_VPHY_ADD_CFG BIT(0) 43 + 40 44 /* 2 - PHY Control */ 41 45 #define REG_SW_CFG_STRAP_OVR 0x0214 42 46 #define SW_VPHY_DISABLE BIT(31)