net: dsa: microchip: add common duplex and flow control function
authorArun Ramadoss <arun.ramadoss@microchip.com>
Sun, 24 Jul 2022 09:28:17 +0000 (14:58 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 27 Jul 2022 08:39:17 +0000 (09:39 +0100)
This patch add common function for configuring the Full/Half duplex and
transmit/receive flow control. KSZ8795 uses the Global control register
4 for configuring the duplex and flow control, whereas all other KSZ9477
based switch uses the xMII Control 0 register.

Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/microchip/ksz9477_reg.h
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/microchip/lan937x_main.c
drivers/net/dsa/microchip/lan937x_reg.h

index 2649fdf..6ca8593 100644 (file)
 #define REG_PORT_XMII_CTRL_0           0x0300
 
 #define PORT_SGMII_SEL                 BIT(7)
-#define PORT_MII_FULL_DUPLEX           BIT(6)
 #define PORT_GRXC_ENABLE               BIT(0)
 
 #define REG_PORT_XMII_CTRL_1           0x0301
index 85392d3..28c21f5 100644 (file)
@@ -281,11 +281,15 @@ 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[] = {
@@ -370,6 +374,8 @@ static const u16 ksz9477_regs[] = {
 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[] = {
@@ -379,6 +385,8 @@ static const u8 ksz9477_shifts[] = {
 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[] = {
@@ -389,6 +397,8 @@ static const u8 ksz9477_xmii_ctrl1[] = {
 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[] = {
@@ -1468,6 +1478,32 @@ void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed)
                ksz_set_100_10mbit(dev, port, speed);
 }
 
+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,
                                    unsigned int mode,
                                    phy_interface_t interface,
index d87dc88..3577fa2 100644 (file)
@@ -197,6 +197,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 {
@@ -215,6 +217,8 @@ enum ksz_shifts {
 enum ksz_xmii_ctrl0 {
        P_MII_100MBIT,
        P_MII_10MBIT,
+       P_MII_FULL_DUPLEX,
+       P_MII_HALF_DUPLEX,
 };
 
 enum ksz_xmii_ctrl1 {
@@ -310,6 +314,8 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
 bool ksz_get_gbit(struct ksz_device *dev, int port);
 void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit);
 void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed);
+void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex,
+                        bool tx_pause, bool rx_pause);
 extern const struct ksz_chip_data ksz_switch_chips[];
 
 /* Common register access functions */
@@ -416,6 +422,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;
@@ -474,6 +488,7 @@ static inline int is_lan937x(struct ksz_device *dev)
 #define SW_START                       0x01
 
 /* xMII configuration */
+#define P_MII_DUPLEX_M                 BIT(6)
 #define P_MII_100MBIT_M                        BIT(4)
 
 #define P_GMII_1GBIT_M                 BIT(6)
index c48bae2..450ad05 100644 (file)
@@ -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)
@@ -346,25 +349,9 @@ static void lan937x_config_interface(struct ksz_device *dev, int port,
                                     int speed, int duplex,
                                     bool tx_pause, bool rx_pause)
 {
-       u8 xmii_ctrl0;
-
        ksz_port_set_xmii_speed(dev, port, speed);
 
-       ksz_pread8(dev, port, REG_PORT_XMII_CTRL_0, &xmii_ctrl0);
-
-       xmii_ctrl0 &= ~(PORT_MII_FULL_DUPLEX | PORT_MII_TX_FLOW_CTRL |
-                       PORT_MII_RX_FLOW_CTRL);
-
-       if (duplex)
-               xmii_ctrl0 |= PORT_MII_FULL_DUPLEX;
-
-       if (tx_pause)
-               xmii_ctrl0 |= PORT_MII_TX_FLOW_CTRL;
-
-       if (rx_pause)
-               xmii_ctrl0 |= PORT_MII_RX_FLOW_CTRL;
-
-       ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_0, xmii_ctrl0);
+       ksz_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause);
 }
 
 void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
index b9364f6..d5eb6dc 100644 (file)
 /* 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_RX_FLOW_CTRL          BIT(3)
 #define PORT_GRXC_ENABLE               BIT(0)
 
 #define REG_PORT_XMII_CTRL_1           0x0301