net: dsa: microchip: Add KSZ8895/KSZ8864 switch support
authorTristram Ha <tristram.ha@microchip.com>
Mon, 26 Aug 2024 21:43:08 +0000 (21:43 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 27 Aug 2024 23:14:18 +0000 (16:14 -0700)
KSZ8895/KSZ8864 is a switch family between KSZ8863/73 and KSZ8795, so it
shares some registers and functions in those switches already
implemented in the KSZ DSA driver.

Signed-off-by: Tristram Ha <tristram.ha@microchip.com>
Tested-by: Pieter Van Trappen <pieter.van.trappen@cern.ch>
Reviewed-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/microchip/ksz_dcb.c
drivers/net/dsa/microchip/ksz_spi.c
include/linux/platform_data/microchip-ksz.h

index a01079297a8cd323e0a3f1ccfca71a6213e21759..aa09d89debf02598474808af24c578c54692b45c 100644 (file)
@@ -188,6 +188,8 @@ int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
        case KSZ8765_CHIP_ID:
                return ksz8795_change_mtu(dev, frame_size);
        case KSZ8830_CHIP_ID:
+       case KSZ8864_CHIP_ID:
+       case KSZ8895_CHIP_ID:
                return ksz8863_change_mtu(dev, frame_size);
        }
 
@@ -384,7 +386,7 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
 void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
                    u64 *dropped, u64 *cnt)
 {
-       if (ksz_is_ksz88x3(dev))
+       if (is_ksz88xx(dev))
                ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
        else
                ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
@@ -392,7 +394,7 @@ void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
 
 void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
 {
-       if (ksz_is_ksz88x3(dev))
+       if (is_ksz88xx(dev))
                return;
 
        /* enable the port for flush/freeze function */
@@ -410,7 +412,8 @@ void ksz8_port_init_cnt(struct ksz_device *dev, int port)
        struct ksz_port_mib *mib = &dev->ports[port].mib;
        u64 *dropped;
 
-       if (!ksz_is_ksz88x3(dev)) {
+       /* For KSZ8795 family. */
+       if (ksz_is_ksz87xx(dev)) {
                /* flush all enabled port MIB counters */
                ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
                ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
@@ -609,11 +612,11 @@ static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
                        shifts[STATIC_MAC_FWD_PORTS];
        alu->is_override = (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0;
 
-       /* KSZ8795 family switches have STATIC_MAC_TABLE_USE_FID and
+       /* KSZ8795/KSZ8895 family switches have STATIC_MAC_TABLE_USE_FID and
         * STATIC_MAC_TABLE_FID definitions off by 1 when doing read on the
         * static MAC table compared to doing write.
         */
-       if (ksz_is_ksz87xx(dev))
+       if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
                data_hi >>= 1;
        alu->is_static = true;
        alu->is_use_fid = (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0;
@@ -1692,7 +1695,8 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
        for (i = 0; i < dev->phy_port_cnt; i++) {
                p = &dev->ports[i];
 
-               if (!ksz_is_ksz88x3(dev)) {
+               /* For KSZ8795 family. */
+               if (ksz_is_ksz87xx(dev)) {
                        ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
                        if (remote & KSZ8_PORT_FIBER_MODE)
                                p->fiber = 1;
index cd3991792b69f7d6b958b27c9fda523e142c8fe6..6609bf271ad002fd92ed688507f001987b3fdbc1 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Microchip switch driver main logic
  *
- * Copyright (C) 2017-2019 Microchip Technology Inc.
+ * Copyright (C) 2017-2024 Microchip Technology Inc.
  */
 
 #include <linux/delay.h>
@@ -277,7 +277,7 @@ static const struct phylink_mac_ops ksz8_phylink_mac_ops = {
        .mac_link_up    = ksz8_phylink_mac_link_up,
 };
 
-static const struct ksz_dev_ops ksz88x3_dev_ops = {
+static const struct ksz_dev_ops ksz88xx_dev_ops = {
        .setup = ksz8_setup,
        .get_port_addr = ksz8_get_port_addr,
        .cfg_port_member = ksz8_cfg_port_member,
@@ -572,6 +572,61 @@ static u8 ksz8863_shifts[] = {
        [DYNAMIC_MAC_SRC_PORT]          = 20,
 };
 
+static const u16 ksz8895_regs[] = {
+       [REG_SW_MAC_ADDR]               = 0x68,
+       [REG_IND_CTRL_0]                = 0x6E,
+       [REG_IND_DATA_8]                = 0x70,
+       [REG_IND_DATA_CHECK]            = 0x72,
+       [REG_IND_DATA_HI]               = 0x71,
+       [REG_IND_DATA_LO]               = 0x75,
+       [REG_IND_MIB_CHECK]             = 0x75,
+       [P_FORCE_CTRL]                  = 0x0C,
+       [P_LINK_STATUS]                 = 0x0E,
+       [P_LOCAL_CTRL]                  = 0x0C,
+       [P_NEG_RESTART_CTRL]            = 0x0D,
+       [P_REMOTE_STATUS]               = 0x0E,
+       [P_SPEED_STATUS]                = 0x09,
+       [S_TAIL_TAG_CTRL]               = 0x0C,
+       [P_STP_CTRL]                    = 0x02,
+       [S_START_CTRL]                  = 0x01,
+       [S_BROADCAST_CTRL]              = 0x06,
+       [S_MULTICAST_CTRL]              = 0x04,
+};
+
+static const u32 ksz8895_masks[] = {
+       [PORT_802_1P_REMAPPING]         = BIT(7),
+       [SW_TAIL_TAG_ENABLE]            = BIT(1),
+       [MIB_COUNTER_OVERFLOW]          = BIT(7),
+       [MIB_COUNTER_VALID]             = BIT(6),
+       [VLAN_TABLE_FID]                = GENMASK(6, 0),
+       [VLAN_TABLE_MEMBERSHIP]         = GENMASK(11, 7),
+       [VLAN_TABLE_VALID]              = BIT(12),
+       [STATIC_MAC_TABLE_VALID]        = BIT(21),
+       [STATIC_MAC_TABLE_USE_FID]      = BIT(23),
+       [STATIC_MAC_TABLE_FID]          = GENMASK(30, 24),
+       [STATIC_MAC_TABLE_OVERRIDE]     = BIT(22),
+       [STATIC_MAC_TABLE_FWD_PORTS]    = GENMASK(20, 16),
+       [DYNAMIC_MAC_TABLE_ENTRIES_H]   = GENMASK(6, 0),
+       [DYNAMIC_MAC_TABLE_MAC_EMPTY]   = BIT(7),
+       [DYNAMIC_MAC_TABLE_NOT_READY]   = BIT(7),
+       [DYNAMIC_MAC_TABLE_ENTRIES]     = GENMASK(31, 29),
+       [DYNAMIC_MAC_TABLE_FID]         = GENMASK(22, 16),
+       [DYNAMIC_MAC_TABLE_SRC_PORT]    = GENMASK(26, 24),
+       [DYNAMIC_MAC_TABLE_TIMESTAMP]   = GENMASK(28, 27),
+};
+
+static const u8 ksz8895_shifts[] = {
+       [VLAN_TABLE_MEMBERSHIP_S]       = 7,
+       [VLAN_TABLE]                    = 13,
+       [STATIC_MAC_FWD_PORTS]          = 16,
+       [STATIC_MAC_FID]                = 24,
+       [DYNAMIC_MAC_ENTRIES_H]         = 3,
+       [DYNAMIC_MAC_ENTRIES]           = 29,
+       [DYNAMIC_MAC_FID]               = 16,
+       [DYNAMIC_MAC_TIMESTAMP]         = 27,
+       [DYNAMIC_MAC_SRC_PORT]          = 24,
+};
+
 static const u16 ksz9477_regs[] = {
        [REG_SW_MAC_ADDR]               = 0x0302,
        [P_STP_CTRL]                    = 0x0B04,
@@ -1397,7 +1452,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .port_cnt = 3,
                .num_tx_queues = 4,
                .num_ipms = 4,
-               .ops = &ksz88x3_dev_ops,
+               .ops = &ksz88xx_dev_ops,
                .phylink_mac_ops = &ksz8830_phylink_mac_ops,
                .mib_names = ksz88xx_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
@@ -1412,6 +1467,61 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .rd_table = &ksz8873_register_set,
        },
 
+       [KSZ8864] = {
+               /* WARNING
+                * =======
+                * KSZ8864 is similar to KSZ8895, except the first port
+                * does not exist.
+                *           external  cpu
+                * KSZ8864   1,2,3      4
+                * KSZ8895   0,1,2,3    4
+                * port_cnt is configured as 5, even though it is 4
+                */
+               .chip_id = KSZ8864_CHIP_ID,
+               .dev_name = "KSZ8864",
+               .num_vlans = 4096,
+               .num_alus = 0,
+               .num_statics = 32,
+               .cpu_ports = 0x10,      /* can be configured as cpu port */
+               .port_cnt = 5,          /* total cpu and user ports */
+               .num_tx_queues = 4,
+               .num_ipms = 4,
+               .ops = &ksz88xx_dev_ops,
+               .phylink_mac_ops = &ksz8830_phylink_mac_ops,
+               .mib_names = ksz88xx_mib_names,
+               .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
+               .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8895_regs,
+               .masks = ksz8895_masks,
+               .shifts = ksz8895_shifts,
+               .supports_mii = {false, false, false, false, true},
+               .supports_rmii = {false, false, false, false, true},
+               .internal_phy = {false, true, true, true, false},
+       },
+
+       [KSZ8895] = {
+               .chip_id = KSZ8895_CHIP_ID,
+               .dev_name = "KSZ8895",
+               .num_vlans = 4096,
+               .num_alus = 0,
+               .num_statics = 32,
+               .cpu_ports = 0x10,      /* can be configured as cpu port */
+               .port_cnt = 5,          /* total cpu and user ports */
+               .num_tx_queues = 4,
+               .num_ipms = 4,
+               .ops = &ksz88xx_dev_ops,
+               .phylink_mac_ops = &ksz8830_phylink_mac_ops,
+               .mib_names = ksz88xx_mib_names,
+               .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
+               .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8895_regs,
+               .masks = ksz8895_masks,
+               .shifts = ksz8895_shifts,
+               .supports_mii = {false, false, false, false, true},
+               .supports_rmii = {false, false, false, false, true},
+               .internal_phy = {true, true, true, true, false},
+       },
+
        [KSZ9477] = {
                .chip_id = KSZ9477_CHIP_ID,
                .dev_name = "KSZ9477",
@@ -2937,9 +3047,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
        struct ksz_device *dev = ds->priv;
        enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE;
 
-       if (dev->chip_id == KSZ8795_CHIP_ID ||
-           dev->chip_id == KSZ8794_CHIP_ID ||
-           dev->chip_id == KSZ8765_CHIP_ID)
+       if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev))
                proto = DSA_TAG_PROTO_KSZ8795;
 
        if (dev->chip_id == KSZ8830_CHIP_ID ||
@@ -3055,6 +3163,8 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port)
        case KSZ8765_CHIP_ID:
                return KSZ8795_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
        case KSZ8830_CHIP_ID:
+       case KSZ8864_CHIP_ID:
+       case KSZ8895_CHIP_ID:
                return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
        case KSZ8563_CHIP_ID:
        case KSZ8567_CHIP_ID:
@@ -3412,6 +3522,18 @@ static int ksz_switch_detect(struct ksz_device *dev)
                else
                        return -ENODEV;
                break;
+       case KSZ8895_FAMILY_ID:
+               if (id2 == KSZ8895_CHIP_ID_95 ||
+                   id2 == KSZ8895_CHIP_ID_95R)
+                       dev->chip_id = KSZ8895_CHIP_ID;
+               else
+                       return -ENODEV;
+               ret = ksz_read8(dev, REG_KSZ8864_CHIP_ID, &id4);
+               if (ret)
+                       return ret;
+               if (id4 & SW_KSZ8864)
+                       dev->chip_id = KSZ8864_CHIP_ID;
+               break;
        default:
                ret = ksz_read32(dev, REG_CHIP_ID0, &id32);
                if (ret)
index 8094d90d6ca46ffee737df4635c04e4bea670a6f..e08d5a1339f41b936150cc2cd2725c03a221a472 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* Microchip switch driver common header
  *
- * Copyright (C) 2017-2019 Microchip Technology Inc.
+ * Copyright (C) 2017-2024 Microchip Technology Inc.
  */
 
 #ifndef __KSZ_COMMON_H
@@ -201,6 +201,8 @@ enum ksz_model {
        KSZ8794,
        KSZ8765,
        KSZ8830,
+       KSZ8864,
+       KSZ8895,
        KSZ9477,
        KSZ9896,
        KSZ9897,
@@ -629,9 +631,21 @@ static inline bool ksz_is_ksz88x3(struct ksz_device *dev)
        return dev->chip_id == KSZ8830_CHIP_ID;
 }
 
+static inline bool ksz_is_8895_family(struct ksz_device *dev)
+{
+       return dev->chip_id == KSZ8895_CHIP_ID ||
+              dev->chip_id == KSZ8864_CHIP_ID;
+}
+
 static inline bool is_ksz8(struct ksz_device *dev)
 {
-       return ksz_is_ksz87xx(dev) || ksz_is_ksz88x3(dev);
+       return ksz_is_ksz87xx(dev) || ksz_is_ksz88x3(dev) ||
+              ksz_is_8895_family(dev);
+}
+
+static inline bool is_ksz88xx(struct ksz_device *dev)
+{
+       return ksz_is_ksz88x3(dev) || ksz_is_8895_family(dev);
 }
 
 static inline bool is_ksz9477(struct ksz_device *dev)
@@ -665,6 +679,7 @@ static inline bool is_lan937x_tx_phy(struct ksz_device *dev, int port)
 #define SW_FAMILY_ID_M                 GENMASK(15, 8)
 #define KSZ87_FAMILY_ID                        0x87
 #define KSZ88_FAMILY_ID                        0x88
+#define KSZ8895_FAMILY_ID              0x95
 
 #define KSZ8_PORT_STATUS_0             0x08
 #define KSZ8_PORT_FIBER_MODE           BIT(7)
@@ -673,6 +688,12 @@ static inline bool is_lan937x_tx_phy(struct ksz_device *dev, int port)
 #define KSZ87_CHIP_ID_94               0x6
 #define KSZ87_CHIP_ID_95               0x9
 #define KSZ88_CHIP_ID_63               0x3
+#define KSZ8895_CHIP_ID_95             0x4
+#define KSZ8895_CHIP_ID_95R            0x6
+
+/* KSZ8895 specific register */
+#define REG_KSZ8864_CHIP_ID            0xFE
+#define SW_KSZ8864                     BIT(7)
 
 #define SW_REV_ID_M                    GENMASK(7, 4)
 
index 086bc9b3cf5362196be609f052bb3c4fc848ae61..30b4a6186e38f43099c7ff503cf9a53bcc1b4909 100644 (file)
@@ -113,7 +113,7 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,
 static void ksz_get_dscp_prio_reg(struct ksz_device *dev, int *reg,
                                  int *per_reg, u8 *mask)
 {
-       if (ksz_is_ksz87xx(dev)) {
+       if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev)) {
                *reg = KSZ8765_REG_TOS_DSCP_CTRL;
                *per_reg = 4;
                *mask = GENMASK(1, 0);
index 8e8d83213b04ce1b6875d84328ea35607b5b078a..f4287310e89fbc548efa082793f07dba5511ea02 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Microchip ksz series register access through SPI
  *
- * Copyright (C) 2017 Microchip Technology Inc.
+ * Copyright (C) 2017-2024 Microchip Technology Inc.
  *     Tristram Ha <Tristram.Ha@microchip.com>
  */
 
@@ -60,6 +60,9 @@ static int ksz_spi_probe(struct spi_device *spi)
                 chip->chip_id == KSZ8794_CHIP_ID ||
                 chip->chip_id == KSZ8765_CHIP_ID)
                regmap_config = ksz8795_regmap_config;
+       else if (chip->chip_id == KSZ8895_CHIP_ID ||
+                chip->chip_id == KSZ8864_CHIP_ID)
+               regmap_config = ksz8863_regmap_config;
        else
                regmap_config = ksz9477_regmap_config;
 
@@ -136,10 +139,18 @@ static const struct of_device_id ksz_dt_ids[] = {
                .compatible = "microchip,ksz8863",
                .data = &ksz_switch_chips[KSZ8830]
        },
+       {
+               .compatible = "microchip,ksz8864",
+               .data = &ksz_switch_chips[KSZ8864]
+       },
        {
                .compatible = "microchip,ksz8873",
                .data = &ksz_switch_chips[KSZ8830]
        },
+       {
+               .compatible = "microchip,ksz8895",
+               .data = &ksz_switch_chips[KSZ8895]
+       },
        {
                .compatible = "microchip,ksz9477",
                .data = &ksz_switch_chips[KSZ9477]
@@ -201,7 +212,9 @@ static const struct spi_device_id ksz_spi_ids[] = {
        { "ksz8794" },
        { "ksz8795" },
        { "ksz8863" },
+       { "ksz8864" },
        { "ksz8873" },
+       { "ksz8895" },
        { "ksz9477" },
        { "ksz9896" },
        { "ksz9897" },
index 8c659db4da6b337e99e6388f38209c9d23f7a2c6..d074019474f533227114f6ab9e30cbf4ef59f1ea 100644 (file)
@@ -28,6 +28,8 @@ enum ksz_chip_id {
        KSZ8794_CHIP_ID = 0x8794,
        KSZ8765_CHIP_ID = 0x8765,
        KSZ8830_CHIP_ID = 0x8830,
+       KSZ8864_CHIP_ID = 0x8864,
+       KSZ8895_CHIP_ID = 0x8895,
        KSZ9477_CHIP_ID = 0x00947700,
        KSZ9896_CHIP_ID = 0x00989600,
        KSZ9897_CHIP_ID = 0x00989700,