On Wed, Feb 17, 2021 at 02:21:39PM +0800, DENG Qingfang wrote:
> Support Realtek RTL8366S/SR switch
> 
> Signed-off-by: DENG Qingfang <dqf...@gmail.com>
> ---
>  drivers/net/dsa/Kconfig            |    1 +
>  drivers/net/dsa/Makefile           |    2 +-
>  drivers/net/dsa/realtek-smi-core.c |    3 +-
>  drivers/net/dsa/realtek-smi-core.h |    1 +
>  drivers/net/dsa/rtl8366s.c         | 1165 ++++++++++++++++++++++++++++
>  5 files changed, 1169 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/net/dsa/rtl8366s.c
> 
> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
> index 3af373e90806..52f1df6ef53a 100644
> --- a/drivers/net/dsa/Kconfig
> +++ b/drivers/net/dsa/Kconfig
> @@ -75,6 +75,7 @@ config NET_DSA_REALTEK_SMI
>       tristate "Realtek SMI Ethernet switch family support"
>       depends on NET_DSA
>       select NET_DSA_TAG_RTL4_A
> +     select NET_DSA_TAG_RTL8366S
>       select FIXED_PHY
>       select IRQ_DOMAIN
>       select REALTEK_PHY
> diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
> index f3598c040994..8c51c25d8378 100644
> --- a/drivers/net/dsa/Makefile
> +++ b/drivers/net/dsa/Makefile
> @@ -10,7 +10,7 @@ obj-$(CONFIG_NET_DSA_MT7530)        += mt7530.o
>  obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
>  obj-$(CONFIG_NET_DSA_QCA8K)  += qca8k.o
>  obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
> -realtek-smi-objs             := realtek-smi-core.o rtl8366.o rtl8366rb.o
> +realtek-smi-objs             := realtek-smi-core.o rtl8366.o rtl8366rb.o 
> rtl8366s.o
>  obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
>  obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
>  obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
> diff --git a/drivers/net/dsa/realtek-smi-core.c 
> b/drivers/net/dsa/realtek-smi-core.c
> index 8e49d4f85d48..e0ced416c362 100644
> --- a/drivers/net/dsa/realtek-smi-core.c
> +++ b/drivers/net/dsa/realtek-smi-core.c
> @@ -480,9 +480,8 @@ static const struct of_device_id realtek_smi_of_match[] = 
> {
>               .data = &rtl8366rb_variant,
>       },
>       {
> -             /* FIXME: add support for RTL8366S and more */
>               .compatible = "realtek,rtl8366s",
> -             .data = NULL,
> +             .data = &rtl8366s_variant,
>       },
>       { /* sentinel */ },
>  };
> diff --git a/drivers/net/dsa/realtek-smi-core.h 
> b/drivers/net/dsa/realtek-smi-core.h
> index fcf465f7f922..a5d45b6f6de3 100644
> --- a/drivers/net/dsa/realtek-smi-core.h
> +++ b/drivers/net/dsa/realtek-smi-core.h
> @@ -143,5 +143,6 @@ int rtl8366_get_sset_count(struct dsa_switch *ds, int 
> port, int sset);
>  void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t 
> *data);
>  
>  extern const struct realtek_smi_variant rtl8366rb_variant;
> +extern const struct realtek_smi_variant rtl8366s_variant;
>  
>  #endif /*  _REALTEK_SMI_H */
> diff --git a/drivers/net/dsa/rtl8366s.c b/drivers/net/dsa/rtl8366s.c
> new file mode 100644
> index 000000000000..718e492f8bbd
> --- /dev/null
> +++ b/drivers/net/dsa/rtl8366s.c
> @@ -0,0 +1,1165 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Realtek SMI subdriver for the Realtek RTL8366S ethernet switch
> + *
> + * Copyright (C) 2021 DENG, Qingfang <dqf...@gmail.com>
> + * Copyright (C) 2009-2010 Gabor Juhos <juh...@openwrt.org>
> + * Copyright (C) 2010 Antti Seppälä <a.sepp...@gmail.com>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/etherdevice.h>
> +#include <linux/if_bridge.h>
> +#include <linux/regmap.h>
> +
> +#include "realtek-smi-core.h"
> +
> +#define RTL8366S_PHY_NO_MAX  4
> +#define RTL8366S_PHY_PAGE_MAX        7
> +#define RTL8366S_PHY_ADDR_MAX        31
> +
> +/* Switch Global Configuration register */
> +#define RTL8366S_SGCR                                0x0000
> +#define RTL8366S_SGCR_EN_BC_STORM_CTRL               BIT(0)
> +#define RTL8366S_SGCR_MAX_LENGTH(_x)         (_x << 4)
> +#define RTL8366S_SGCR_MAX_LENGTH_MASK                
> RTL8366S_SGCR_MAX_LENGTH(0x3)
> +#define RTL8366S_SGCR_MAX_LENGTH_1522                
> RTL8366S_SGCR_MAX_LENGTH(0x0)
> +#define RTL8366S_SGCR_MAX_LENGTH_1536                
> RTL8366S_SGCR_MAX_LENGTH(0x1)
> +#define RTL8366S_SGCR_MAX_LENGTH_1552                
> RTL8366S_SGCR_MAX_LENGTH(0x2)
> +#define RTL8366S_SGCR_MAX_LENGTH_16000               
> RTL8366S_SGCR_MAX_LENGTH(0x3)
> +#define RTL8366S_SGCR_EN_VLAN                        BIT(13)
> +
> +/* Port Enable Control register */
> +#define RTL8366S_PECR                                0x0001
> +
> +/* Switch Security Control registers */
> +#define RTL8366S_SSCR0                               0x0002
> +#define RTL8366S_SSCR1                               0x0003
> +#define RTL8366S_SSCR2                               0x0004
> +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA               BIT(0)
> +
> +/* Port Mode Control registers */
> +#define RTL8366S_PMC0                                0x0005
> +#define RTL8366S_PMC0_SPI                    BIT(0)
> +#define RTL8366S_PMC0_EN_AUTOLOAD            BIT(1)
> +#define RTL8366S_PMC0_PROBE                  BIT(2)
> +#define RTL8366S_PMC0_DIS_BISR                       BIT(3)
> +#define RTL8366S_PMC0_ADCTEST                        BIT(4)
> +#define RTL8366S_PMC0_SRAM_DIAG                      BIT(5)
> +#define RTL8366S_PMC0_EN_SCAN                        BIT(6)
> +#define RTL8366S_PMC0_P4_IOMODE_MASK         GENMASK(9, 7)
> +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_GMAC  \
> +     FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 0)
> +#define RTL8366S_PMC0_P4_IOMODE_GMAC_TO_RGMII        \
> +     FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 1)
> +#define RTL8366S_PMC0_P4_IOMODE_PHY_TO_RGMII \
> +     FIELD_PREP(RTL8366S_PMC0_P4_IOMODE_MASK, 2)
> +#define RTL8366S_PMC0_P5_IOMODE_MASK         GENMASK(12, 10)
> +#define RTL8366S_PMC0_SDSMODE_MASK           GENMASK(15, 13)
> +#define RTL8366S_PMC1                                0x0006
> +
> +/* Port Mirror Control Register */
> +#define RTL8366S_PMCR                                0x0007
> +#define RTL8366S_PMCR_SOURCE_MASK            GENMASK(3, 0)
> +#define RTL8366S_PMCR_MINITOR_MASK           GENMASK(7, 4)
> +#define RTL8366S_PMCR_MIRROR_RX                      BIT(8)
> +#define RTL8366S_PMCR_MIRROR_TX                      BIT(9)
> +#define RTL8366S_PMCR_MIRROR_SPC             BIT(10)
> +#define RTL8366S_PMCR_MIRROR_ISO             BIT(11)
> +
> +/* Keep format on egress */
> +#define RTL8366S_EGRESS_KEEP_FORMAT_REG              0x0008
> +#define RTL8366S_EGRESS_KEEP_FORMAT_MASK     GENMASK(15, 8)
> +#define RTL8366S_EGRESS_KEEP_FORMAT_ALL      \
> +     FIELD_PREP(RTL8366S_EGRESS_KEEP_FORMAT_MASK, RTL8366S_PORT_ALL)
> +
> +/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */
> +#define RTL8366S_GREEN_ETHERNET_CTRL_REG     0x000a
> +#define RTL8366S_GREEN_ETHERNET_CTRL_MASK    0x0018
> +#define RTL8366S_GREEN_ETHERNET_TX           BIT(3)
> +#define RTL8366S_GREEN_ETHERNET_RX           BIT(4)
> +
> +/* bits 0..7 = port 0, bits 8..15 = port 1 */
> +#define RTL8366S_PAACR0                      0x0011
> +/* bits 0..7 = port 2, bits 8..15 = port 3 */
> +#define RTL8366S_PAACR1                      0x0012
> +/* bits 0..7 = port 4, bits 8..15 = port 5 */
> +#define RTL8366S_PAACR2                      0x0013
> +#define RTL8366S_PAACR_SPEED_10M     0
> +#define RTL8366S_PAACR_SPEED_100M    1
> +#define RTL8366S_PAACR_SPEED_1000M   2
> +#define RTL8366S_PAACR_FULL_DUPLEX   BIT(2)
> +#define RTL8366S_PAACR_LINK_UP               BIT(4)
> +#define RTL8366S_PAACR_TX_PAUSE              BIT(5)
> +#define RTL8366S_PAACR_RX_PAUSE              BIT(6)
> +#define RTL8366S_PAACR_AN            BIT(7)
> +
> +#define RTL8366S_PAACR_CPU_PORT      (RTL8366S_PAACR_SPEED_1000M | \
> +                              RTL8366S_PAACR_FULL_DUPLEX | \
> +                              RTL8366S_PAACR_LINK_UP | \
> +                              RTL8366S_PAACR_TX_PAUSE | \
> +                              RTL8366S_PAACR_RX_PAUSE)
> +
> +/* Spanning Tree Protocol register */
> +#define RTL8366S_STP_BASE                    0x003a
> +#define RTL8366S_STP_REG(_p) \
> +             (RTL8366S_STP_BASE + (_p))
> +#define RTL8366S_STP_MASK                    GENMASK(1, 0)
> +
> +enum RTL8366S_STP_STATE
> +{
> +     RTL8366S_STP_DISABLED = 0,
> +     RTL8366S_STP_BLOCKING,
> +     RTL8366S_STP_LEARNING,
> +     RTL8366S_STP_FORWARDING,
> +};
> +
> +#define RTL8366S_CPU_CTRL_REG                        0x004f
> +#define RTL8366S_CPU_DROP_UNKNOWN_DA         BIT(14)
> +#define RTL8366S_CPU_NO_TAG                  BIT(15)
> +
> +#define RTL8366S_PORT_VLAN_CTRL_BASE         0x0058
> +#define RTL8366S_PORT_VLAN_CTRL_REG(_p)  \
> +             (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4)
> +#define RTL8366S_PORT_VLAN_CTRL_MASK         0xf
> +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p)    (4 * ((_p) % 4))
> +
> +#define RTL8366S_PORT_LINK_STATUS_BASE               0x0060
> +#define RTL8366S_PORT_STATUS_SPEED_MASK              0x0003
> +#define RTL8366S_PORT_STATUS_DUPLEX_MASK     0x0004
> +#define RTL8366S_PORT_STATUS_LINK_MASK               0x0010
> +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK    0x0020
> +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK    0x0040
> +#define RTL8366S_PORT_STATUS_AN_MASK         0x0080
> +
> +#define RTL8366S_RESET_CTRL_REG                      0x0100
> +#define RTL8366S_CHIP_CTRL_RESET_HW          BIT(0)
> +#define RTL8366S_CHIP_CTRL_RESET_SW          BIT(1)
> +
> +#define RTL8366S_CHIP_VERSION_CTRL_REG               0x0104
> +#define RTL8366S_CHIP_VERSION_MASK           0xf
> +#define RTL8366S_CHIP_ID_REG                 0x0105
> +#define RTL8366S_CHIP_ID_8366                        0x8366
> +
> +/* VLAN 4K access registers */
> +#define RTL8366S_VLAN_TB_CTRL_REG            0x010f
> +
> +#define RTL8366S_TABLE_ACCESS_CTRL_REG               0x0180
> +#define RTL8366S_TABLE_VLAN_READ_CTRL                0x0E01
> +#define RTL8366S_TABLE_VLAN_WRITE_CTRL               0x0F01
> +
> +#define RTL8366S_VLAN_TABLE_READ_BASE                0x018B
> +#define RTL8366S_VLAN_TABLE_WRITE_BASE               0x0185
> +
> +/* VLAN filtering registers */
> +#define RTL8366S_VLAN_TAGINGRESS_REG         0x0378
> +#define RTL8366S_VLAN_MEMBERINGRESS_REG              0x0379
> +
> +/* Link aggregation registers */
> +#define RTL8366S_LAGCR                               0x0380
> +#define RTL8366S_LAGCR_MODE_DUMP             BIT(0)
> +#define RTL8366S_LAGCR_HASHSEL_MASK          GENMASK(2, 1)
> +#define RTL8366S_LAGCR_HASHSEL_DA_SA \
> +     FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 0)
> +#define RTL8366S_LAGCR_HASHSEL_DA    \
> +     FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 1)
> +#define RTL8366S_LAGCR_HASHSEL_SA    \
> +     FIELD_PREP(RTL8366S_LAGCR_HASHSEL_MASK, 2)
> +#define RTL8366S_LAGCR_PORTMAP_MASK          GENMASK(8, 3)
> +
> +#define RTL8366S_LAG_MAPPING_BASE            0x0381
> +#define RTL8366S_LAG_MAPPING_BIT             3
> +#define RTL8366S_LAG_MAPPING_MASK            GENMASK(2, 0)
> +
> +#define RTL8366S_LAG_FC_CTRL_REG             0x0383
> +#define RTL8366S_LAG_FC_MASK                 GENMASK(5, 0)
> +
> +#define RTL8366S_LAG_QEMPTY_REG                      0x0384
> +#define RTL8366S_LAG_QEMPTY_MASK             GENMASK(5, 0)
> +
> +/* RMA register address */
> +#define RTL8366S_RMA_CONTROL_REG             0x0391
> +#define RTL8366S_RMA_IGMP                    BIT(10)
> +#define RTL8366S_RMA_MLD                     BIT(11)
> +#define RTL8366S_RMA_USER_DEFINED_BASE               0x0392
> +
> +/* LED control registers */
> +#define RTL8366S_LED_BLINKRATE_REG           0x0420
> +#define RTL8366S_LED_BLINKRATE_BIT           0
> +#define RTL8366S_LED_BLINKRATE_MASK          0x0007
> +
> +#define RTL8366S_LED_CTRL_REG                        0x0421
> +#define RTL8366S_LED_0_1_CTRL_REG            0x0422
> +#define RTL8366S_LED_2_3_CTRL_REG            0x0423
> +
> +#define RTL8366S_MIB_COUNT                   33
> +#define RTL8366S_GLOBAL_MIB_COUNT            1
> +#define RTL8366S_MIB_COUNTER_PORT_OFFSET     0x0040
> +#define RTL8366S_MIB_COUNTER_BASE            0x1000
> +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2    0x0008
> +#define RTL8366S_MIB_COUNTER_BASE2           0x1180
> +#define RTL8366S_MIB_CTRL_REG                        0x11F0
> +#define RTL8366S_MIB_CTRL_USER_MASK          0x01FF
> +#define RTL8366S_MIB_CTRL_BUSY_MASK          0x0001
> +#define RTL8366S_MIB_CTRL_RESET_MASK         0x0002
> +
> +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK  0x0004
> +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT     0x0003
> +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK    0x01FC
> +
> +
> +#define RTL8366S_VLAN_MC_BASE(_x)            (0x0016 + (_x) * 2)
> +
> +#define RTL8366S_MAC_FORCE_CTRL0_REG         0x0F04
> +#define RTL8366S_MAC_FORCE_CTRL1_REG         0x0F05
> +
> +/* PHY registers control */
> +#define RTL8366S_PHY_ACCESS_CTRL_REG         0x8028
> +#define RTL8366S_PHY_ACCESS_DATA_REG         0x8029
> +
> +#define RTL8366S_PHY_CTRL_READ                       1
> +#define RTL8366S_PHY_CTRL_WRITE                      0
> +
> +#define RTL8366S_PORT_NUM_CPU                5
> +#define RTL8366S_NUM_PORTS           6
> +#define RTL8366S_NUM_VLANS           16
> +#define RTL8366S_NUM_LEDGROUPS               4
> +#define RTL8366S_NUM_VIDS            4096
> +#define RTL8366S_PRIORITYMAX         7
> +#define RTL8366S_FIDMAX                      7
> +
> +
> +#define RTL8366S_PORT_1                      BIT(0) /* In userspace port 0 */
> +#define RTL8366S_PORT_2                      BIT(1) /* In userspace port 1 */
> +#define RTL8366S_PORT_3                      BIT(2) /* In userspace port 2 */
> +#define RTL8366S_PORT_4                      BIT(3) /* In userspace port 3 */
> +#define RTL8366S_PORT_5                      BIT(4) /* In userspace port 4 */
> +#define RTL8366S_PORT_CPU            BIT(5) /* CPU port */
> +
> +#define RTL8366S_PORT_ALL            (RTL8366S_PORT_1 |      \
> +                                      RTL8366S_PORT_2 |      \
> +                                      RTL8366S_PORT_3 |      \
> +                                      RTL8366S_PORT_4 |      \
> +                                      RTL8366S_PORT_5 |      \
> +                                      RTL8366S_PORT_CPU)
> +
> +#define RTL8366S_PORT_ALL_BUT_CPU    (RTL8366S_PORT_1 |      \
> +                                      RTL8366S_PORT_2 |      \
> +                                      RTL8366S_PORT_3 |      \
> +                                      RTL8366S_PORT_4 |      \
> +                                      RTL8366S_PORT_5)
> +
> +#define RTL8366S_PORT_ALL_EXTERNAL   RTL8366S_PORT_ALL_BUT_CPU
> +
> +#define RTL8366S_PORT_ALL_INTERNAL   RTL8366S_PORT_CPU
> +
> +#define RTL8366S_VLAN_VID_MASK               0xfff
> +#define RTL8366S_VLAN_PRIORITY_SHIFT 12
> +#define RTL8366S_VLAN_PRIORITY_MASK  0x7
> +#define RTL8366S_VLAN_MEMBER_MASK    0x3f
> +#define RTL8366S_VLAN_UNTAG_SHIFT    6
> +#define RTL8366S_VLAN_UNTAG_MASK     0x3f
> +#define RTL8366S_VLAN_FID_SHIFT              12
> +#define RTL8366S_VLAN_FID_MASK               0x7
> +
> +/* Green Ethernet Feature for PHY ports */
> +#define RTL8366S_PHY_POWER_SAVING_CTRL_REG   0x000c
> +#define RTL8366S_PHY_POWER_SAVING_MASK               0x1000
> +
> +#define RTL8366S_PHY_REG_MASK                        0x001f
> +#define RTL8366S_PHY_PAGE_OFFSET             5
> +#define RTL8366S_PHY_PAGE_MASK                       GENMASK(7, 5)
> +#define RTL8366S_PHY_NO_OFFSET                       9
> +#define RTL8366S_PHY_NO_MASK                 GENMASK(13, 9)
> +
> +#define RTL8366S_MIB_RXB_ID          0       /* IfInOctets */
> +#define RTL8366S_MIB_TXB_ID          20      /* IfOutOctets */

I'm not going to do a detailed review on a driver that is a 90% copy of
rtl8366rb. You should probably spend some time to avoid duplicating
what is common.

> +
> +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = {
> +     { 0,  0, 4, "IfInOctets"                                },
> +     { 0,  4, 4, "EtherStatsOctets"                          },
> +     { 0,  8, 2, "EtherStatsUnderSizePkts"                   },
> +     { 0, 10, 2, "EtherFragments"                            },
> +     { 0, 12, 2, "EtherStatsPkts64Octets"                    },
> +     { 0, 14, 2, "EtherStatsPkts65to127Octets"               },
> +     { 0, 16, 2, "EtherStatsPkts128to255Octets"              },
> +     { 0, 18, 2, "EtherStatsPkts256to511Octets"              },
> +     { 0, 20, 2, "EtherStatsPkts512to1023Octets"             },
> +     { 0, 22, 2, "EtherStatsPkts1024to1518Octets"            },
> +     { 0, 24, 2, "EtherOversizeStats"                        },
> +     { 0, 26, 2, "EtherStatsJabbers"                         },
> +     { 0, 28, 2, "IfInUcastPkts"                             },
> +     { 0, 30, 2, "EtherStatsMulticastPkts"                   },
> +     { 0, 32, 2, "EtherStatsBroadcastPkts"                   },
> +     { 0, 34, 2, "EtherStatsDropEvents"                      },
> +     { 0, 36, 2, "Dot3StatsFCSErrors"                        },
> +     { 0, 38, 2, "Dot3StatsSymbolErrors"                     },
> +     { 0, 40, 2, "Dot3InPauseFrames"                         },
> +     { 0, 42, 2, "Dot3ControlInUnknownOpcodes"               },
> +     { 0, 44, 4, "IfOutOctets"                               },
> +     { 0, 48, 2, "Dot3StatsSingleCollisionFrames"            },
> +     { 0, 50, 2, "Dot3StatMultipleCollisionFrames"           },
> +     { 0, 52, 2, "Dot3sDeferredTransmissions"                },
> +     { 0, 54, 2, "Dot3StatsLateCollisions"                   },
> +     { 0, 56, 2, "EtherStatsCollisions"                      },
> +     { 0, 58, 2, "Dot3StatsExcessiveCollisions"              },
> +     { 0, 60, 2, "Dot3OutPauseFrames"                        },
> +     { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"        },
> +
> +     /*
> +      * The following counters are accessible at a different
> +      * base address.
> +      */
> +     { 1,  0, 2, "Dot1dTpPortInDiscards"                     },
> +     { 1,  2, 2, "IfOutUcastPkts"                            },
> +     { 1,  4, 2, "IfOutMulticastPkts"                        },
> +     { 1,  6, 2, "IfOutBroadcastPkts"                        },
> +};
> +
> +static int rtl8366s_get_mib_counter(struct realtek_smi *smi,
> +                                 int port,
> +                                 struct rtl8366_mib_counter *mib,
> +                                 u64 *mibvalue)
> +{
> +     u32 addr, val;
> +     int ret;
> +     int i;
> +
> +     switch (mib->base) {
> +     case 0:
> +             addr = RTL8366S_MIB_COUNTER_BASE +
> +                    RTL8366S_MIB_COUNTER_PORT_OFFSET * port;
> +             break;
> +     case 1:
> +             addr = RTL8366S_MIB_COUNTER_BASE2 +
> +                    RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port;
> +             break;
> +     default:
> +             return -EINVAL;
> +     }
> +
> +     addr += mib->offset;
> +
> +     /*
> +      * Writing access counter address first
> +      * then ASIC will prepare 64bits counter wait for being retrived
> +      */
> +     ret = regmap_write(smi->map, addr, 0);
> +     if (ret)
> +             return ret;
> +
> +     /* read MIB control register */
> +     ret =  regmap_read(smi->map, RTL8366S_MIB_CTRL_REG, &val);
> +     if (ret)
> +             return -EIO;
> +
> +     if (val & RTL8366S_MIB_CTRL_BUSY_MASK)
> +             return -EBUSY;
> +
> +     if (val & RTL8366S_MIB_CTRL_RESET_MASK)
> +             return -EIO;
> +
> +     /* Read each individual MIB 16 bits at the time */
> +     *mibvalue = 0;
> +     for (i = mib->length; i > 0; i--) {
> +             ret = regmap_read(smi->map, addr + (i - 1), &val);
> +             if (ret)
> +                     return ret;
> +             *mibvalue = (*mibvalue << 16) | (val & 0xFFFF);
> +     }
> +     return 0;
> +}
> +
> +static int rtl8366s_phy_read(struct realtek_smi *smi, int phy, int regnum)
> +{
> +     u32 val;
> +     u32 reg;
> +     int ret;
> +
> +     if (phy > RTL8366S_PHY_NO_MAX)
> +             return -EINVAL;
> +
> +     ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG,
> +                        RTL8366S_PHY_CTRL_READ);
> +     if (ret)
> +             return ret;
> +
> +     reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum;
> +
> +     ret = regmap_write(smi->map, reg, 0);
> +     if (ret)
> +             return ret;
> +
> +     ret = regmap_read(smi->map, RTL8366S_PHY_ACCESS_DATA_REG, &val);
> +     if (ret)
> +             return ret;
> +
> +     return val;
> +}
> +
> +static int rtl8366s_phy_write(struct realtek_smi *smi, int phy, int regnum,
> +                            u16 val)
> +{
> +     u32 reg;
> +     int ret;
> +
> +     if (phy > RTL8366S_PHY_NO_MAX)
> +             return -EINVAL;
> +
> +     ret = regmap_write(smi->map, RTL8366S_PHY_ACCESS_CTRL_REG,
> +                        RTL8366S_PHY_CTRL_WRITE);
> +     if (ret)
> +             return ret;
> +
> +     reg = 0x8000 | (1 << (phy + RTL8366S_PHY_NO_OFFSET)) | regnum;
> +
> +     ret = regmap_write(smi->map, reg, val);
> +     if (ret)
> +             return ret;
> +
> +     return 0;
> +}
> +
> +static int rtl8366s_reset_chip(struct realtek_smi *smi)
> +{
> +     int timeout = 10;
> +     u32 val;
> +     int ret;
> +
> +     realtek_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG,
> +                                 RTL8366S_CHIP_CTRL_RESET_HW);
> +     do {
> +             usleep_range(20000, 25000);
> +             ret = regmap_read(smi->map, RTL8366S_RESET_CTRL_REG, &val);
> +             if (ret)
> +                     return ret;
> +
> +             if (!(val & RTL8366S_CHIP_CTRL_RESET_HW))
> +                     break;
> +     } while (--timeout);
> +
> +     if (!timeout) {
> +             dev_err(smi->dev, "timeout waiting for the switch to reset\n");
> +             return -EIO;
> +     }
> +
> +     return 0;
> +}
> +
> +static enum dsa_tag_protocol rtl8366s_get_tag_protocol(struct dsa_switch *ds,
> +                                                    int port,
> +                                                    enum dsa_tag_protocol mp)
> +{
> +     return DSA_TAG_PROTO_RTL8366S;
> +}
> +
> +static void
> +rtl8366s_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode,
> +                  phy_interface_t interface, struct phy_device *phydev,
> +                  int speed, int duplex, bool tx_pause, bool rx_pause)
> +{
> +     struct realtek_smi *smi = ds->priv;
> +     int ret;
> +
> +     if (port != RTL8366S_PORT_NUM_CPU)
> +             return;
> +
> +     /* Force the fixed CPU port into 1Gbit mode, no autonegotiation */
> +     ret = regmap_update_bits(smi->map, RTL8366S_MAC_FORCE_CTRL1_REG,
> +                              BIT(port), BIT(port));
> +     if (ret) {
> +             dev_err(smi->dev, "failed to force 1Gbit on CPU port\n");
> +             return;
> +     }
> +
> +     ret = regmap_update_bits(smi->map, RTL8366S_PAACR2,
> +                              0xFF00U,
> +                              RTL8366S_PAACR_CPU_PORT << 8);
> +     if (ret) {
> +             dev_err(smi->dev, "failed to set PAACR on CPU port\n");
> +             return;
> +     }
> +
> +     /* Enable the CPU port */
> +     ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port),
> +                              0);
> +     if (ret) {
> +             dev_err(smi->dev, "failed to enable the CPU port\n");
> +             return;
> +     }
> +}
> +
> +static void
> +rtl8366s_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
> +                    phy_interface_t interface)
> +{
> +     struct realtek_smi *smi = ds->priv;
> +     int ret;
> +
> +     if (port != RTL8366S_PORT_NUM_CPU)
> +             return;
> +
> +     /* Disable the CPU port */
> +     ret = regmap_update_bits(smi->map, RTL8366S_PECR, BIT(port),
> +                              BIT(port));
> +     if (ret) {
> +             dev_err(smi->dev, "failed to disable the CPU port\n");
> +             return;
> +     }
> +}
> +
> +static int rtl8366s_setup(struct dsa_switch *ds)
> +{
> +     struct realtek_smi *smi = ds->priv;
> +     int ret;
> +
> +     /* Reset chip */
> +     ret = rtl8366s_reset_chip(smi);
> +     if (ret)
> +             return ret;
> +
> +     /* Set up the "green ethernet" feature */
> +     ret = regmap_update_bits(smi->map, RTL8366S_GREEN_ETHERNET_CTRL_REG,
> +                              RTL8366S_GREEN_ETHERNET_CTRL_MASK,
> +                              RTL8366S_GREEN_ETHERNET_TX |
> +                              RTL8366S_GREEN_ETHERNET_RX);
> +     if (ret)
> +             return ret;
> +
> +     /* Enable CPU port with custom tag 8899 */
> +     ret = regmap_write(smi->map, RTL8366S_CPU_CTRL_REG,
> +                        RTL8366S_PORT_CPU);
> +     if (ret)
> +             return ret;
> +
> +     /* Make sure we default-enable the fixed CPU port */
> +     ret = regmap_update_bits(smi->map, RTL8366S_PECR,
> +                              RTL8366S_PORT_CPU, 0);
> +     if (ret)
> +             return ret;
> +
> +     /* Enable learning for all ports */
> +     ret = regmap_write(smi->map, RTL8366S_SSCR0, 0);
> +     if (ret)
> +             return ret;

DSA has a new way of dealing with address learning.
For the user ports, .port_pre_bridge_flags and .port_bridge_flags get
called now. You should start with address learning disabled and implement
those operations.
For the CPU port, DSA does not manage address learning (yet). So if you
support it there, you need to enable it manually.

Reply via email to