]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: dsa: microchip: add DSA support for microchip LAN937x
authorArun Ramadoss <arun.ramadoss@microchip.com>
Fri, 1 Jul 2022 15:01:46 +0000 (20:31 +0530)
committerDavid S. Miller <davem@davemloft.net>
Sat, 2 Jul 2022 15:34:05 +0000 (16:34 +0100)
Basic DSA driver support for lan937x and the device will be
configured through SPI interface.
It adds the lan937x_dev_ops in ksz_common.c file and tries to reuse the
functionality of ksz9477 series switch.

drivers/net/dsa/microchip/ path is already part of MAINTAINERS &
the new files come under this path. Hence no update needed to the
MAINTAINERS

Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/microchip/Kconfig
drivers/net/dsa/microchip/Makefile
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/lan937x.h [new file with mode: 0644]
drivers/net/dsa/microchip/lan937x_main.c [new file with mode: 0644]
drivers/net/dsa/microchip/lan937x_reg.h [new file with mode: 0644]

index 2edb880807907d0581e02ad722ff3921683240cb..06b1efdb5e7d67b1077bd576c50e45f60567d605 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig NET_DSA_MICROCHIP_KSZ_COMMON
-       tristate "Microchip KSZ8795/KSZ9477 series switch support"
+       tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support"
        depends on NET_DSA
        select NET_DSA_TAG_KSZ
        help
index b2ba7c1bcb939b3ca0c9e76f42f70487ce4e11a7..28873559efc2b84bc446dd0d35f755f65fd0c02a 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)      += ksz_switch.o
 ksz_switch-objs := ksz_common.o
 ksz_switch-objs += ksz9477.o
 ksz_switch-objs += ksz8795.o
+ksz_switch-objs += lan937x_main.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)    += ksz9477_i2c.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI)                += ksz_spi.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)    += ksz8863_smi.o
index d631a4bf35ed6bed91aec75612f336fa4d017072..83e44598d00c43e3b9506ef9ae9a8500bcccb4bd 100644 (file)
@@ -23,6 +23,7 @@
 #include "ksz_common.h"
 #include "ksz8.h"
 #include "ksz9477.h"
+#include "lan937x.h"
 
 #define MIB_COUNTER_NUM 0x20
 
@@ -201,6 +202,34 @@ static const struct ksz_dev_ops ksz9477_dev_ops = {
        .exit = ksz9477_switch_exit,
 };
 
+static const struct ksz_dev_ops lan937x_dev_ops = {
+       .setup = lan937x_setup,
+       .get_port_addr = ksz9477_get_port_addr,
+       .cfg_port_member = ksz9477_cfg_port_member,
+       .port_setup = lan937x_port_setup,
+       .r_mib_cnt = ksz9477_r_mib_cnt,
+       .r_mib_pkt = ksz9477_r_mib_pkt,
+       .r_mib_stat64 = ksz_r_mib_stats64,
+       .freeze_mib = ksz9477_freeze_mib,
+       .port_init_cnt = ksz9477_port_init_cnt,
+       .vlan_filtering = ksz9477_port_vlan_filtering,
+       .vlan_add = ksz9477_port_vlan_add,
+       .vlan_del = ksz9477_port_vlan_del,
+       .mirror_add = ksz9477_port_mirror_add,
+       .mirror_del = ksz9477_port_mirror_del,
+       .fdb_dump = ksz9477_fdb_dump,
+       .fdb_add = ksz9477_fdb_add,
+       .fdb_del = ksz9477_fdb_del,
+       .mdb_add = ksz9477_mdb_add,
+       .mdb_del = ksz9477_mdb_del,
+       .max_mtu = ksz9477_max_mtu,
+       .config_cpu_port = lan937x_config_cpu_port,
+       .enable_stp_addr = ksz9477_enable_stp_addr,
+       .reset = lan937x_reset_switch,
+       .init = lan937x_switch_init,
+       .exit = lan937x_switch_exit,
+};
+
 static const u16 ksz8795_regs[] = {
        [REG_IND_CTRL_0]                = 0x6E,
        [REG_IND_DATA_8]                = 0x70,
@@ -542,6 +571,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
@@ -562,6 +592,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 6,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
@@ -582,6 +613,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 8,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
@@ -606,6 +638,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x38,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
@@ -630,6 +663,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 8,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h
new file mode 100644 (file)
index 0000000..534f5a7
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip lan937x dev ops headers
+ * Copyright (C) 2019-2022 Microchip Technology Inc.
+ */
+
+#ifndef __LAN937X_CFG_H
+#define __LAN937X_CFG_H
+
+int lan937x_reset_switch(struct ksz_device *dev);
+int lan937x_setup(struct dsa_switch *ds);
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port);
+void lan937x_config_cpu_port(struct dsa_switch *ds);
+int lan937x_switch_init(struct ksz_device *dev);
+void lan937x_switch_exit(struct ksz_device *dev);
+#endif
diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
new file mode 100644 (file)
index 0000000..e167a0c
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip LAN937X switch driver main logic
+ * Copyright (C) 2019-2022 Microchip Technology Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/if_bridge.h>
+#include <linux/math.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "lan937x_reg.h"
+#include "ksz_common.h"
+#include "lan937x.h"
+
+static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+       return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
+}
+
+static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset,
+                           u8 bits, bool set)
+{
+       return regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
+                                 bits, set ? bits : 0);
+}
+
+int lan937x_reset_switch(struct ksz_device *dev)
+{
+       u32 data32;
+       int ret;
+
+       /* reset switch */
+       ret = lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
+       if (ret < 0)
+               return ret;
+
+       /* Enable Auto Aging */
+       ret = lan937x_cfg(dev, REG_SW_LUE_CTRL_1, SW_LINK_AUTO_AGING, true);
+       if (ret < 0)
+               return ret;
+
+       /* disable interrupts */
+       ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
+       if (ret < 0)
+               return ret;
+
+       ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF);
+       if (ret < 0)
+               return ret;
+
+       return ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
+}
+
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+       struct dsa_switch *ds = dev->ds;
+       u8 member;
+
+       /* enable tag tail for host port */
+       if (cpu_port)
+               lan937x_port_cfg(dev, port, REG_PORT_CTRL_0,
+                                PORT_TAIL_TAG_ENABLE, true);
+
+       /* disable frame check length field */
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_CHECK_LENGTH,
+                        false);
+
+       /* set back pressure for half duplex */
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE,
+                        true);
+
+       /* enable 802.1p priority */
+       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,
+                                true);
+
+       if (cpu_port)
+               member = dsa_user_ports(ds);
+       else
+               member = BIT(dsa_upstream_port(ds, port));
+
+       dev->dev_ops->cfg_port_member(dev, port, member);
+}
+
+void lan937x_config_cpu_port(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       struct dsa_port *dp;
+
+       dsa_switch_for_each_cpu_port(dp, ds) {
+               if (dev->info->cpu_ports & (1 << dp->index)) {
+                       dev->cpu_port = dp->index;
+
+                       /* enable cpu port */
+                       lan937x_port_setup(dev, dp->index, true);
+               }
+       }
+
+       dsa_switch_for_each_user_port(dp, ds) {
+               ksz_port_stp_state_set(ds, dp->index, BR_STATE_DISABLED);
+       }
+}
+
+int lan937x_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+
+       /* The VLAN aware is a global setting. Mixed vlan
+        * filterings are not supported.
+        */
+       ds->vlan_filtering_is_global = true;
+
+       /* Enable aggressive back off for half duplex & UNH mode */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_0,
+                   (SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF | SW_AGGR_BACKOFF),
+                   true);
+
+       /* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop
+        * packets when 16 or more collisions occur
+        */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, true);
+
+       /* enable global MIB counter freeze function */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
+
+       /* disable CLK125 & CLK25, 1: disable, 0: enable */
+       lan937x_cfg(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1,
+                   (SW_CLK125_ENB | SW_CLK25_ENB), true);
+
+       return 0;
+}
+
+int lan937x_switch_init(struct ksz_device *dev)
+{
+       dev->port_mask = (1 << dev->info->port_cnt) - 1;
+
+       return 0;
+}
+
+void lan937x_switch_exit(struct ksz_device *dev)
+{
+       lan937x_reset_switch(dev);
+}
+
+MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>");
+MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h
new file mode 100644 (file)
index 0000000..5e27b2b
--- /dev/null
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip LAN937X switch register definitions
+ * Copyright (C) 2019-2021 Microchip Technology Inc.
+ */
+#ifndef __LAN937X_REG_H
+#define __LAN937X_REG_H
+
+#define PORT_CTRL_ADDR(port, addr)     ((addr) | (((port) + 1)  << 12))
+
+/* 0 - Operation */
+#define REG_SW_INT_STATUS__4           0x0010
+#define REG_SW_INT_MASK__4             0x0014
+
+#define LUE_INT                                BIT(31)
+#define TRIG_TS_INT                    BIT(30)
+#define APB_TIMEOUT_INT                        BIT(29)
+#define OVER_TEMP_INT                  BIT(28)
+#define HSR_INT                                BIT(27)
+#define PIO_INT                                BIT(26)
+#define POR_READY_INT                  BIT(25)
+
+#define SWITCH_INT_MASK                        \
+       (LUE_INT | TRIG_TS_INT | APB_TIMEOUT_INT | OVER_TEMP_INT | HSR_INT | \
+        PIO_INT | POR_READY_INT)
+
+#define REG_SW_PORT_INT_STATUS__4      0x0018
+#define REG_SW_PORT_INT_MASK__4                0x001C
+
+/* 1 - Global */
+#define REG_SW_GLOBAL_OUTPUT_CTRL__1   0x0103
+#define SW_CLK125_ENB                  BIT(1)
+#define SW_CLK25_ENB                   BIT(0)
+
+/* 3 - Operation Control */
+#define REG_SW_OPERATION               0x0300
+
+#define SW_DOUBLE_TAG                  BIT(7)
+#define SW_OVER_TEMP_ENABLE            BIT(2)
+#define SW_RESET                       BIT(1)
+
+#define REG_SW_LUE_CTRL_0              0x0310
+
+#define SW_VLAN_ENABLE                 BIT(7)
+#define SW_DROP_INVALID_VID            BIT(6)
+#define SW_AGE_CNT_M                   0x7
+#define SW_AGE_CNT_S                   3
+#define SW_RESV_MCAST_ENABLE           BIT(2)
+
+#define REG_SW_LUE_CTRL_1              0x0311
+
+#define UNICAST_LEARN_DISABLE          BIT(7)
+#define SW_FLUSH_STP_TABLE             BIT(5)
+#define SW_FLUSH_MSTP_TABLE            BIT(4)
+#define SW_SRC_ADDR_FILTER             BIT(3)
+#define SW_AGING_ENABLE                        BIT(2)
+#define SW_FAST_AGING                  BIT(1)
+#define SW_LINK_AUTO_AGING             BIT(0)
+
+#define REG_SW_MAC_CTRL_0              0x0330
+#define SW_NEW_BACKOFF                 BIT(7)
+#define SW_PAUSE_UNH_MODE              BIT(1)
+#define SW_AGGR_BACKOFF                        BIT(0)
+
+#define REG_SW_MAC_CTRL_1              0x0331
+#define SW_SHORT_IFG                   BIT(7)
+#define MULTICAST_STORM_DISABLE                BIT(6)
+#define SW_BACK_PRESSURE               BIT(5)
+#define FAIR_FLOW_CTRL                 BIT(4)
+#define NO_EXC_COLLISION_DROP          BIT(3)
+#define SW_LEGAL_PACKET_DISABLE                BIT(1)
+#define SW_PASS_SHORT_FRAME            BIT(0)
+
+#define REG_SW_MAC_CTRL_6              0x0336
+#define SW_MIB_COUNTER_FLUSH           BIT(7)
+#define SW_MIB_COUNTER_FREEZE          BIT(6)
+
+/* 4 - LUE */
+#define REG_SW_ALU_STAT_CTRL__4                0x041C
+
+#define REG_SW_ALU_VAL_B               0x0424
+#define ALU_V_OVERRIDE                 BIT(31)
+#define ALU_V_USE_FID                  BIT(30)
+#define ALU_V_PORT_MAP                 0xFF
+
+/* Port Registers */
+
+/* 0 - Operation */
+#define REG_PORT_CTRL_0                        0x0020
+
+#define PORT_MAC_LOOPBACK              BIT(7)
+#define PORT_MAC_REMOTE_LOOPBACK       BIT(6)
+#define PORT_K2L_INSERT_ENABLE         BIT(5)
+#define PORT_K2L_DEBUG_ENABLE          BIT(4)
+#define PORT_TAIL_TAG_ENABLE           BIT(2)
+#define PORT_QUEUE_SPLIT_ENABLE                0x3
+
+/* 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)
+
+/* 4 - MAC */
+#define REG_PORT_MAC_CTRL_0            0x0400
+#define PORT_CHECK_LENGTH              BIT(2)
+#define PORT_BROADCAST_STORM           BIT(1)
+#define PORT_JUMBO_PACKET              BIT(0)
+
+#define REG_PORT_MAC_CTRL_1            0x0401
+#define PORT_BACK_PRESSURE             BIT(3)
+#define PORT_PASS_ALL                  BIT(0)
+
+/* 8 - Classification and Policing */
+#define REG_PORT_MRI_PRIO_CTRL         0x0801
+#define PORT_HIGHEST_PRIO              BIT(7)
+#define PORT_OR_PRIO                   BIT(6)
+#define PORT_MAC_PRIO_ENABLE           BIT(4)
+#define PORT_VLAN_PRIO_ENABLE          BIT(3)
+#define PORT_802_1P_PRIO_ENABLE                BIT(2)
+#define PORT_DIFFSERV_PRIO_ENABLE      BIT(1)
+#define PORT_ACL_PRIO_ENABLE           BIT(0)
+
+#define P_PRIO_CTRL                    REG_PORT_MRI_PRIO_CTRL
+
+#endif