]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
net: ti: icssg: Add Firmware config and classification APIs.
authorMD Danish Anwar <danishanwar@ti.com>
Thu, 4 Apr 2024 07:08:00 +0000 (12:38 +0530)
committerTom Rini <trini@konsulko.com>
Fri, 12 Apr 2024 19:54:43 +0000 (13:54 -0600)
Add icssg_config.h / .c and icssg_classifier.c files. These are firmware
configuration and classification related files. Add MII helper APIs and
MACROs. These APIs and MACROs will be later used by ICSSG Ethernet driver.
Also introduce icssg_prueth.h which has definition of prueth related
structures.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
Reviewed-by: Ravi Gunasekaran <r-gunasekaran@ti.com>
drivers/net/ti/icss_mii_rt.h [new file with mode: 0644]
drivers/net/ti/icssg_classifier.c [new file with mode: 0644]
drivers/net/ti/icssg_config.c [new file with mode: 0644]
drivers/net/ti/icssg_config.h [new file with mode: 0644]
drivers/net/ti/icssg_prueth.h [new file with mode: 0644]

diff --git a/drivers/net/ti/icss_mii_rt.h b/drivers/net/ti/icss_mii_rt.h
new file mode 100644 (file)
index 0000000..fd95d4d
--- /dev/null
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* PRU-ICSS MII_RT register definitions
+ *
+ * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_PRUSS_MII_RT_H__
+#define __NET_PRUSS_MII_RT_H__
+
+#include <regmap.h>
+
+/* PRUSS_MII_RT Registers */
+#define PRUSS_MII_RT_RXCFG0            0x0
+#define PRUSS_MII_RT_RXCFG1            0x4
+#define PRUSS_MII_RT_TXCFG0            0x10
+#define PRUSS_MII_RT_TXCFG1            0x14
+#define PRUSS_MII_RT_TX_CRC0           0x20
+#define PRUSS_MII_RT_TX_CRC1           0x24
+#define PRUSS_MII_RT_TX_IPG0           0x30
+#define PRUSS_MII_RT_TX_IPG1           0x34
+#define PRUSS_MII_RT_PRS0              0x38
+#define PRUSS_MII_RT_PRS1              0x3c
+#define PRUSS_MII_RT_RX_FRMS0          0x40
+#define PRUSS_MII_RT_RX_FRMS1          0x44
+#define PRUSS_MII_RT_RX_PCNT0          0x48
+#define PRUSS_MII_RT_RX_PCNT1          0x4c
+#define PRUSS_MII_RT_RX_ERR0           0x50
+#define PRUSS_MII_RT_RX_ERR1           0x54
+
+/* PRUSS_MII_RT_RXCFG0/1 bits */
+#define PRUSS_MII_RT_RXCFG_RX_ENABLE           BIT(0)
+#define PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS        BIT(1)
+#define PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE     BIT(2)
+#define PRUSS_MII_RT_RXCFG_RX_MUX_SEL          BIT(3)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EN            BIT(4)
+#define PRUSS_MII_RT_RXCFG_RX_BYTE_SWAP                BIT(5)
+#define PRUSS_MII_RT_RXCFG_RX_AUTO_FWD_PRE     BIT(6)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS  BIT(9)
+
+/* PRUSS_MII_RT_TXCFG0/1 bits */
+#define PRUSS_MII_RT_TXCFG_TX_ENABLE           BIT(0)
+#define PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE    BIT(1)
+#define PRUSS_MII_RT_TXCFG_TX_EN_MODE          BIT(2)
+#define PRUSS_MII_RT_TXCFG_TX_BYTE_SWAP                BIT(3)
+#define PRUSS_MII_RT_TXCFG_TX_MUX_SEL          BIT(8)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_SEQUENCE        BIT(9)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_ESC_ERR BIT(10)
+#define PRUSS_MII_RT_TXCFG_TX_32_MODE_EN       BIT(11)
+#define PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN  BIT(12) /* SR2.0 onwards */
+
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT        16
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_MASK GENMASK(25, 16)
+
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT  28
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK   GENMASK(30, 28)
+
+/* PRUSS_MII_RT_TX_IPG0/1 bits */
+#define PRUSS_MII_RT_TX_IPG_IPG_SHIFT  0
+#define PRUSS_MII_RT_TX_IPG_IPG_MASK   GENMASK(9, 0)
+
+/* PRUSS_MII_RT_PRS0/1 bits */
+#define PRUSS_MII_RT_PRS_COL   BIT(0)
+#define PRUSS_MII_RT_PRS_CRS   BIT(1)
+
+/* PRUSS_MII_RT_RX_FRMS0/1 bits */
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_SHIFT     0
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK      GENMASK(15, 0)
+
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT     16
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK      GENMASK(31, 16)
+
+/* Min/Max in MII_RT_RX_FRMS */
+/* For EMAC and Switch */
+#define PRUSS_MII_RT_RX_FRMS_MAX       (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM   (64)
+
+/* for HSR and PRP */
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_LRE       (PRUSS_MII_RT_RX_FRMS_MAX + \
+                                                ICSS_LRE_TAG_RCT_SIZE)
+/* PRUSS_MII_RT_RX_PCNT0/1 bits */
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_SHIFT    0
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_MASK     GENMASK(3, 0)
+
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_SHIFT    4
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_MASK     GENMASK(7, 4)
+
+/* PRUSS_MII_RT_RX_ERR0/1 bits */
+#define PRUSS_MII_RT_RX_ERR_MIN_PCNT_ERR       BIT(0)
+#define PRUSS_MII_RT_RX_ERR_MAX_PCNT_ERR       BIT(1)
+#define PRUSS_MII_RT_RX_ERR_MIN_FRM_ERR                BIT(2)
+#define PRUSS_MII_RT_RX_ERR_MAX_FRM_ERR                BIT(3)
+
+#define ICSSG_CFG_OFFSET       0
+#define RGMII_CFG_OFFSET       4
+
+/* Constant to choose between MII0 and MII1 */
+#define ICSS_MII0      0
+#define ICSS_MII1      1
+
+/* ICSSG_CFG Register bits */
+#define ICSSG_CFG_SGMII_MODE   BIT(16)
+#define ICSSG_CFG_TX_PRU_EN    BIT(11)
+#define ICSSG_CFG_RX_SFD_TX_SOF_EN     BIT(10)
+#define ICSSG_CFG_RTU_PRU_PSI_SHARE_EN BIT(9)
+#define ICSSG_CFG_IEP1_TX_EN   BIT(8)
+#define ICSSG_CFG_MII1_MODE    GENMASK(6, 5)
+#define ICSSG_CFG_MII1_MODE_SHIFT      5
+#define ICSSG_CFG_MII0_MODE    GENMASK(4, 3)
+#define ICSSG_CFG_MII0_MODE_SHIFT      3
+#define ICSSG_CFG_RX_L2_G_EN   BIT(2)
+#define ICSSG_CFG_TX_L2_EN     BIT(1)
+#define ICSSG_CFG_TX_L1_EN     BIT(0)
+
+enum mii_mode { MII_MODE_MII = 0, MII_MODE_RGMII, MII_MODE_SGMII };
+
+/* RGMII CFG Register bits */
+#define RGMII_CFG_INBAND_EN_MII0       BIT(16)
+#define RGMII_CFG_GIG_EN_MII0  BIT(17)
+#define RGMII_CFG_INBAND_EN_MII1       BIT(20)
+#define RGMII_CFG_GIG_EN_MII1  BIT(21)
+#define RGMII_CFG_FULL_DUPLEX_MII0     BIT(18)
+#define RGMII_CFG_FULL_DUPLEX_MII1     BIT(22)
+#define RGMII_CFG_SPEED_MII0   GENMASK(2, 1)
+#define RGMII_CFG_SPEED_MII1   GENMASK(6, 5)
+#define RGMII_CFG_SPEED_MII0_SHIFT     1
+#define RGMII_CFG_SPEED_MII1_SHIFT     5
+#define RGMII_CFG_FULLDUPLEX_MII0      BIT(3)
+#define RGMII_CFG_FULLDUPLEX_MII1      BIT(7)
+#define RGMII_CFG_FULLDUPLEX_MII0_SHIFT        3
+#define RGMII_CFG_FULLDUPLEX_MII1_SHIFT        7
+#define RGMII_CFG_SPEED_10M    0
+#define RGMII_CFG_SPEED_100M   1
+#define RGMII_CFG_SPEED_1G     2
+
+static inline void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg)
+{
+       u32 val;
+
+       if (mii == ICSS_MII0) {
+               regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, ipg);
+       } else {
+               /* Errata workaround: IEP1 is not read by h/w unless IEP0 is written */
+               regmap_read(mii_rt, PRUSS_MII_RT_TX_IPG0, &val);
+               regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG1, ipg);
+               regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, val);
+       }
+}
+
+static inline void icssg_update_rgmii_cfg(struct regmap *miig_rt, int speed,
+                                         bool full_duplex, int slice, struct prueth_priv *priv)
+{
+       u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0;
+       u32 inband_en_mask, inband_val = 0;
+
+       gig_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 :
+                                       RGMII_CFG_GIG_EN_MII1;
+       if (speed == SPEED_1000)
+               gig_val = gig_en_mask;
+       regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val);
+
+       inband_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_INBAND_EN_MII0 :
+                                       RGMII_CFG_INBAND_EN_MII1;
+       if (speed == SPEED_10 && phy_interface_is_rgmii(priv->phydev))
+               inband_val = inband_en_mask;
+       regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, inband_en_mask, inband_val);
+
+       full_duplex_mask = (slice == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 :
+                                          RGMII_CFG_FULL_DUPLEX_MII1;
+       if (full_duplex)
+               full_duplex_val = full_duplex_mask;
+       regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask,
+                          full_duplex_val);
+}
+
+static inline void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, int phy_if)
+{
+       u32 val, mask, shift;
+
+       mask = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE : ICSSG_CFG_MII1_MODE;
+       shift =  mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE_SHIFT : ICSSG_CFG_MII1_MODE_SHIFT;
+
+       val = MII_MODE_RGMII;
+       if (phy_if == PHY_INTERFACE_MODE_MII)
+               val = MII_MODE_MII;
+
+       val <<= shift;
+       regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, mask, val);
+       regmap_read(miig_rt, ICSSG_CFG_OFFSET, &val);
+}
+
+#endif /* __NET_PRUSS_MII_RT_H__ */
diff --git a/drivers/net/ti/icssg_classifier.c b/drivers/net/ti/icssg_classifier.c
new file mode 100644 (file)
index 0000000..e510a1c
--- /dev/null
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <dm/ofnode.h>
+#include <regmap.h>
+
+#define ICSSG_NUM_CLASSIFIERS  16
+#define ICSSG_NUM_FT1_SLOTS    8
+#define ICSSG_NUM_FT3_SLOTS    16
+
+#define ICSSG_NUM_CLASSIFIERS_IN_USE   1
+
+/* Filter 1 - FT1 */
+#define FT1_NUM_SLOTS  8
+#define FT1_SLOT_SIZE  0x10    /* bytes */
+
+/* offsets from FT1 slot base i.e. slot 1 start */
+#define FT1_DA0                0x0
+#define FT1_DA1                0x4
+#define FT1_DA0_MASK   0x8
+#define FT1_DA1_MASK   0xc
+
+#define FT1_N_REG(slize, n, reg)       (offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg))
+
+#define FT1_LEN_MASK   GENMASK(19, 16)
+#define FT1_LEN_SHIFT  16
+#define FT1_LEN(len)   (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK)
+
+#define FT1_START_MASK GENMASK(14, 0)
+#define FT1_START(start)       ((start) & FT1_START_MASK)
+
+#define FT1_MATCH_SLOT(n)      (GENMASK(23, 16) & (BIT(n) << 16))
+
+enum ft1_cfg_type {
+       FT1_CFG_TYPE_DISABLED = 0,
+       FT1_CFG_TYPE_EQ,
+       FT1_CFG_TYPE_GT,
+       FT1_CFG_TYPE_LT,
+};
+
+#define FT1_CFG_SHIFT(n)       (2 * (n))
+#define FT1_CFG_MASK(n)        (0x3 << FT1_CFG_SHIFT((n)))
+
+/* Filter 3 -  FT3 */
+#define FT3_NUM_SLOTS  16
+#define FT3_SLOT_SIZE  0x20    /* bytes */
+
+/* offsets from FT3 slot n's base */
+#define FT3_START      0
+#define FT3_START_AUTO 0x4
+#define FT3_START_OFFSET       0x8
+#define FT3_JUMP_OFFSET        0xc
+#define FT3_LEN                0x10
+#define FT3_CFG                0x14
+#define FT3_T          0x18
+#define FT3_T_MASK     0x1c
+
+#define FT3_N_REG(slize, n, reg)       \
+       (offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg))
+
+/* offsets from rx_class n's base */
+#define RX_CLASS_AND_EN        0
+#define RX_CLASS_OR_EN 0x4
+
+#define RX_CLASS_NUM_SLOTS     16
+#define RX_CLASS_EN_SIZE       0x8     /* bytes */
+
+#define RX_CLASS_N_REG(slice, n, reg)  \
+       (offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg))
+
+/* RX Class Gates */
+#define RX_CLASS_GATES_SIZE    0x4     /* bytes */
+
+#define RX_CLASS_GATES_N_REG(slice, n) \
+       (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n))
+
+#define RX_CLASS_GATES_ALLOW_MASK      BIT(6)
+#define RX_CLASS_GATES_RAW_MASK                BIT(5)
+#define RX_CLASS_GATES_PHASE_MASK      BIT(4)
+
+/* RX Class traffic data matching bits */
+#define RX_CLASS_FT_UC         BIT(31)
+#define RX_CLASS_FT_MC         BIT(30)
+#define RX_CLASS_FT_BC         BIT(29)
+#define RX_CLASS_FT_FW         BIT(28)
+#define RX_CLASS_FT_RCV                BIT(27)
+#define RX_CLASS_FT_VLAN       BIT(26)
+#define RX_CLASS_FT_DA_P       BIT(25)
+#define RX_CLASS_FT_DA_I       BIT(24)
+#define RX_CLASS_FT_FT1_MATCH_MASK     GENMASK(23, 16)
+#define RX_CLASS_FT_FT1_MATCH_SHIFT    16
+#define RX_CLASS_FT_FT3_MATCH_MASK     GENMASK(15, 0)
+#define RX_CLASS_FT_FT3_MATCH_SHIFT    0
+
+#define RX_CLASS_FT_FT1_MATCH(slot)    \
+       ((BIT(slot) << RX_CLASS_FT_FT1_MATCH_SHIFT) & \
+       RX_CLASS_FT_FT1_MATCH_MASK)
+
+enum rx_class_sel_type {
+       RX_CLASS_SEL_TYPE_OR = 0,
+       RX_CLASS_SEL_TYPE_AND = 1,
+       RX_CLASS_SEL_TYPE_OR_AND_AND = 2,
+       RX_CLASS_SEL_TYPE_OR_OR_AND = 3,
+};
+
+#define FT1_CFG_SHIFT(n)       (2 * (n))
+#define FT1_CFG_MASK(n)                (0x3 << FT1_CFG_SHIFT((n)))
+
+#define RX_CLASS_SEL_SHIFT(n)  (2 * (n))
+#define RX_CLASS_SEL_MASK(n)   (0x3 << RX_CLASS_SEL_SHIFT((n)))
+
+#define ICSSG_CFG_OFFSET       0
+#define MAC_INTERFACE_0                0x18
+#define MAC_INTERFACE_1                0x1c
+
+#define ICSSG_CFG_RX_L2_G_EN   BIT(2)
+
+/* these are register offsets per PRU */
+struct miig_rt_offsets {
+       u32 mac0;
+       u32 mac1;
+       u32 ft1_start_len;
+       u32 ft1_cfg;
+       u32 ft1_slot_base;
+       u32 ft3_slot_base;
+       u32 ft3_p_base;
+       u32 ft_rx_ptr;
+       u32 rx_class_base;
+       u32 rx_class_cfg1;
+       u32 rx_class_cfg2;
+       u32 rx_class_gates_base;
+       u32 rx_green;
+       u32 rx_rate_cfg_base;
+       u32 rx_rate_src_sel0;
+       u32 rx_rate_src_sel1;
+       u32 tx_rate_cfg_base;
+       u32 stat_base;
+       u32 tx_hsr_tag;
+       u32 tx_hsr_seq;
+       u32 tx_vlan_type;
+       u32 tx_vlan_ins;
+};
+
+static struct miig_rt_offsets offs[] = {
+       /* PRU0 */
+       {
+               0x8,
+               0xc,
+               0x80,
+               0x84,
+               0x88,
+               0x108,
+               0x308,
+               0x408,
+               0x40c,
+               0x48c,
+               0x490,
+               0x494,
+               0x4d4,
+               0x4e4,
+               0x504,
+               0x508,
+               0x50c,
+               0x54c,
+               0x63c,
+               0x640,
+               0x644,
+               0x648,
+       },
+       /* PRU1 */
+       {
+               0x10,
+               0x14,
+               0x64c,
+               0x650,
+               0x654,
+               0x6d4,
+               0x8d4,
+               0x9d4,
+               0x9d8,
+               0xa58,
+               0xa5c,
+               0xa60,
+               0xaa0,
+               0xab0,
+               0xad0,
+               0xad4,
+               0xad8,
+               0xb18,
+               0xc08,
+               0xc0c,
+               0xc10,
+               0xc14,
+       },
+};
+
+static inline u32 addr_to_da0(const u8 *addr)
+{
+       return (u32)(addr[0] | addr[1] << 8 |
+               addr[2] << 16 | addr[3] << 24);
+};
+
+static inline u32 addr_to_da1(const u8 *addr)
+{
+       return (u32)(addr[4] | addr[5] << 8);
+};
+
+static void rx_class_ft1_set_start_len(struct regmap *miig_rt, int slice,
+                                      u16 start, u8 len)
+{
+       u32 offset, val;
+
+       offset = offs[slice].ft1_start_len;
+       val = FT1_LEN(len) | FT1_START(start);
+       regmap_write(miig_rt, offset, val);
+}
+
+static void rx_class_ft1_set_da(struct regmap *miig_rt, int slice,
+                               int n, const u8 *addr)
+{
+       u32 offset;
+
+       offset = FT1_N_REG(slice, n, FT1_DA0);
+       regmap_write(miig_rt, offset, addr_to_da0(addr));
+       offset = FT1_N_REG(slice, n, FT1_DA1);
+       regmap_write(miig_rt, offset, addr_to_da1(addr));
+}
+
+static void rx_class_ft1_set_da_mask(struct regmap *miig_rt, int slice,
+                                    int n, const u8 *addr)
+{
+       u32 offset;
+
+       offset = FT1_N_REG(slice, n, FT1_DA0_MASK);
+       regmap_write(miig_rt, offset, addr_to_da0(addr));
+       offset = FT1_N_REG(slice, n, FT1_DA1_MASK);
+       regmap_write(miig_rt, offset, addr_to_da1(addr));
+}
+
+static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n,
+                                     enum ft1_cfg_type type)
+{
+       u32 offset;
+
+       offset = offs[slice].ft1_cfg;
+       regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n),
+                          type << FT1_CFG_SHIFT(n));
+}
+
+static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n,
+                                 enum rx_class_sel_type type)
+{
+       u32 offset;
+
+       offset = offs[slice].rx_class_cfg1;
+       regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n),
+                          type << RX_CLASS_SEL_SHIFT(n));
+}
+
+static void rx_class_set_and(struct regmap *miig_rt, int slice, int n,
+                            u32 data)
+{
+       u32 offset;
+
+       offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN);
+       regmap_write(miig_rt, offset, data);
+}
+
+static void rx_class_set_or(struct regmap *miig_rt, int slice, int n,
+                           u32 data)
+{
+       u32 offset;
+
+       offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN);
+       regmap_write(miig_rt, offset, data);
+}
+
+void icssg_class_set_host_mac_addr(struct regmap *miig_rt, u8 *mac)
+{
+       regmap_write(miig_rt, MAC_INTERFACE_0, addr_to_da0(mac));
+       regmap_write(miig_rt, MAC_INTERFACE_1, addr_to_da1(mac));
+}
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac)
+{
+       regmap_write(miig_rt, offs[slice].mac0, addr_to_da0(mac));
+       regmap_write(miig_rt, offs[slice].mac1, addr_to_da1(mac));
+}
+
+void icssg_class_disable_n(struct regmap *miig_rt, int slice, int n)
+{
+       u32 data, offset;
+
+       /* AND_EN = 0 */
+       rx_class_set_and(miig_rt, slice, n, 0);
+       /* OR_EN = 0 */
+       rx_class_set_or(miig_rt, slice, n, 0);
+
+       /* set CFG1 to OR */
+       rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR);
+
+       /* configure gate */
+       offset = RX_CLASS_GATES_N_REG(slice, n);
+       regmap_read(miig_rt, offset, &data);
+       /* clear class_raw so we go through filters */
+       data &= ~RX_CLASS_GATES_RAW_MASK;
+       /* set allow and phase mask */
+       data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK;
+       regmap_write(miig_rt, offset, data);
+}
+
+/* disable all RX traffic */
+void icssg_class_disable(struct regmap *miig_rt, int slice)
+{
+       int n;
+
+       /* Enable RX_L2_G */
+       regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN,
+                          ICSSG_CFG_RX_L2_G_EN);
+
+       for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++)
+               icssg_class_disable_n(miig_rt, slice, n);
+
+       /* FT1 Disabled */
+       for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) {
+               u8 addr[] = { 0, 0, 0, 0, 0, 0, };
+
+               rx_class_ft1_cfg_set_type(miig_rt, slice, n,
+                                         FT1_CFG_TYPE_DISABLED);
+               rx_class_ft1_set_da(miig_rt, slice, n, addr);
+               rx_class_ft1_set_da_mask(miig_rt, slice, n, addr);
+       }
+
+       /* clear CFG2 */
+       regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti)
+{
+       u32 data;
+
+       /* defaults */
+       icssg_class_disable(miig_rt, slice);
+
+       /* Setup Classifier */
+       /* match on Broadcast or MAC_PRU address */
+       data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P;
+
+       /* multicast? */
+       if (allmulti)
+               data |= RX_CLASS_FT_MC;
+
+       rx_class_set_or(miig_rt, slice, 0, data);
+
+       /* set CFG1 for OR_OR_AND for classifier */
+       rx_class_sel_set_type(miig_rt, slice, 0,
+                             RX_CLASS_SEL_TYPE_OR_OR_AND);
+
+       /* clear CFG2 */
+       regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+/* required for SR2 for SAV check */
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr)
+{
+       u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, };
+
+       rx_class_ft1_set_start_len(miig_rt, slice, 6, 6);
+       rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr);
+       rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr);
+       rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ);
+}
diff --git a/drivers/net/ti/icssg_config.c b/drivers/net/ti/icssg_config.c
new file mode 100644 (file)
index 0000000..7cf3f73
--- /dev/null
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <phy.h>
+#include "icssg_prueth.h"
+#include "icssg_switch_map.h"
+#include "icss_mii_rt.h"
+#include <dm/device_compat.h>
+
+/* TX IPG Values to be set for 100M and 1G link speeds.  These values are
+ * in ocp_clk cycles. So need change if ocp_clk is changed for a specific
+ * h/w design.
+ */
+
+/* SR2.0 IPG is in rgmii_clk (125MHz) clock cycles + 1 */
+#define MII_RT_TX_IPG_100M      0x17
+#define MII_RT_TX_IPG_1G        0xb
+
+#define        ICSSG_QUEUES_MAX                64
+#define        ICSSG_QUEUE_OFFSET              0xd00
+#define        ICSSG_QUEUE_PEEK_OFFSET         0xe00
+#define        ICSSG_QUEUE_CNT_OFFSET          0xe40
+#define        ICSSG_QUEUE_RESET_OFFSET        0xf40
+
+#define        ICSSG_NUM_TX_QUEUES     8
+
+#define        RECYCLE_Q_SLICE0        16
+#define        RECYCLE_Q_SLICE1        17
+
+#define        ICSSG_NUM_OTHER_QUEUES  5       /* port, host and special queues */
+
+#define        PORT_HI_Q_SLICE0        32
+#define        PORT_LO_Q_SLICE0        33
+#define        HOST_HI_Q_SLICE0        34
+#define        HOST_LO_Q_SLICE0        35
+#define        HOST_SPL_Q_SLICE0       40      /* Special Queue */
+
+#define        PORT_HI_Q_SLICE1        36
+#define        PORT_LO_Q_SLICE1        37
+#define        HOST_HI_Q_SLICE1        38
+#define        HOST_LO_Q_SLICE1        39
+#define        HOST_SPL_Q_SLICE1       41      /* Special Queue */
+
+#define MII_RXCFG_DEFAULT      (PRUSS_MII_RT_RXCFG_RX_ENABLE | \
+                                PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
+                                PRUSS_MII_RT_RXCFG_RX_L2_EN | \
+                                PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
+
+#define MII_TXCFG_DEFAULT      (PRUSS_MII_RT_TXCFG_TX_ENABLE | \
+                                PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
+                                PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
+                                PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
+
+#define ICSSG_CFG_DEFAULT      (ICSSG_CFG_TX_L1_EN | \
+                                ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
+                                ICSSG_CFG_TX_PRU_EN | /* SR2.0 only */ \
+                                ICSSG_CFG_SGMII_MODE)
+
+#define FDB_GEN_CFG1           0x60
+#define SMEM_VLAN_OFFSET       8
+#define SMEM_VLAN_OFFSET_MASK  GENMASK(25, 8)
+
+#define FDB_GEN_CFG2           0x64
+#define FDB_VLAN_EN            BIT(6)
+#define FDB_HOST_EN            BIT(2)
+#define FDB_PRU1_EN            BIT(1)
+#define FDB_PRU0_EN            BIT(0)
+#define FDB_EN_ALL             (FDB_PRU0_EN | FDB_PRU1_EN | \
+                                FDB_HOST_EN | FDB_VLAN_EN)
+
+struct map {
+       int queue;
+       u32 pd_addr_start;
+       u32 flags;
+       bool special;
+};
+
+struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
+       {
+               { PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
+               { PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
+               { HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
+               { HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
+               { HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
+       },
+       {
+               { PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
+               { PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
+               { HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
+               { HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
+               { HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
+       },
+};
+
+static void icssg_config_mii_init(struct prueth_priv *priv, int slice)
+{
+       struct prueth *prueth = priv->prueth;
+       struct regmap *mii_rt = prueth->mii_rt;
+       u32 txcfg_reg, pcnt_reg;
+       u32 txcfg;
+
+       txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+                                      PRUSS_MII_RT_TXCFG1;
+       pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+                                      PRUSS_MII_RT_RX_PCNT1;
+
+       txcfg = MII_TXCFG_DEFAULT;
+
+       if (prueth->phy_interface == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
+               txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+       else if (prueth->phy_interface != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
+               txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
+       regmap_write(mii_rt, txcfg_reg, txcfg);
+       regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
+static void icssg_miig_queues_init(struct prueth_priv *priv, int slice)
+{
+       struct prueth *prueth = priv->prueth;
+       void __iomem *smem = (void __iomem *)prueth->shram.pa;
+       struct regmap *miig_rt = prueth->miig_rt;
+       int queue = 0, i, j;
+       u8 pd[ICSSG_SPECIAL_PD_SIZE];
+       u32 *pdword;
+
+       /* reset hwqueues */
+       if (slice)
+               queue = ICSSG_NUM_TX_QUEUES;
+
+       for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
+               regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+               queue++;
+       }
+
+       queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
+       regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+
+       for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
+               regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET,
+                            hwq_map[slice][i].queue);
+       }
+
+       /* initialize packet descriptors in SMEM */
+       /* push pakcet descriptors to hwqueues */
+
+       pdword = (u32 *)pd;
+       for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
+               struct map *mp;
+               int pd_size, num_pds;
+               u32 pdaddr;
+
+               mp = &hwq_map[slice][j];
+               if (mp->special) {
+                       pd_size = ICSSG_SPECIAL_PD_SIZE;
+                       num_pds = ICSSG_NUM_SPECIAL_PDS;
+               } else  {
+                       pd_size = ICSSG_NORMAL_PD_SIZE;
+                       num_pds = ICSSG_NUM_NORMAL_PDS;
+               }
+
+               for (i = 0; i < num_pds; i++) {
+                       memset(pd, 0, pd_size);
+
+                       pdword[0] &= cpu_to_le32(ICSSG_FLAG_MASK);
+                       pdword[0] |= cpu_to_le32(mp->flags);
+                       pdaddr = mp->pd_addr_start + i * pd_size;
+
+                       memcpy_toio(smem + pdaddr, pd, pd_size);
+                       queue = mp->queue;
+                       regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
+                                    pdaddr);
+               }
+       }
+}
+
+void icssg_config_ipg(struct prueth_priv *priv, int speed, int mii)
+{
+       struct prueth *prueth = priv->prueth;
+
+       switch (speed) {
+       case SPEED_1000:
+               icssg_mii_update_ipg(prueth->mii_rt, mii, MII_RT_TX_IPG_1G);
+               break;
+       case SPEED_100:
+               icssg_mii_update_ipg(prueth->mii_rt, mii, MII_RT_TX_IPG_100M);
+               break;
+       default:
+               /* Other links speeds not supported */
+               pr_err("Unsupported link speed\n");
+               return;
+       }
+}
+
+static void emac_r30_cmd_init(struct prueth_priv *priv)
+{
+       struct prueth *prueth = priv->prueth;
+       struct icssg_r30_cmd *p;
+       int i;
+
+       p = (struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+       for (i = 0; i < 4; i++)
+               writel(EMAC_NONE, &p->cmd[i]);
+}
+
+static int emac_r30_is_done(struct prueth_priv *priv)
+{
+       struct prueth *prueth = priv->prueth;
+       const struct icssg_r30_cmd *p;
+       int i;
+       u32 cmd;
+
+       p = (const struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+       for (i = 0; i < 4; i++) {
+               cmd = readl(&p->cmd[i]);
+               if (cmd != EMAC_NONE)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int prueth_emac_buffer_setup(struct prueth_priv *priv)
+{
+       struct prueth *prueth = priv->prueth;
+       struct icssg_buffer_pool_cfg *bpool_cfg;
+       struct icssg_rxq_ctx *rxq_ctx;
+       int slice = priv->port_id;
+       u32 addr;
+       int i;
+
+       /* Layout to have 64KB aligned buffer pool
+        * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
+        */
+
+       addr = lower_32_bits(prueth->sram_pa);
+       if (slice)
+               addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+
+       if (addr % SZ_64K) {
+               dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
+               return -EINVAL;
+       }
+
+       bpool_cfg = (struct icssg_buffer_pool_cfg *)(prueth->dram[priv->port_id].pa + BUFFER_POOL_0_ADDR_OFFSET);
+       /* workaround for f/w bug. bpool 0 needs to be initilalized */
+       bpool_cfg[0].addr = cpu_to_le32(addr);
+       bpool_cfg[0].len = 0;
+
+       for (i = PRUETH_EMAC_BUF_POOL_START;
+            i < (PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS);
+            i++) {
+               bpool_cfg[i].addr = cpu_to_le32(addr);
+               bpool_cfg[i].len = cpu_to_le32(PRUETH_EMAC_BUF_POOL_SIZE);
+               addr += PRUETH_EMAC_BUF_POOL_SIZE;
+       }
+
+       if (!slice)
+               addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+       else
+               addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2;
+
+       rxq_ctx = (struct icssg_rxq_ctx *)(prueth->dram[priv->port_id].pa + HOST_RX_Q_PRE_CONTEXT_OFFSET);
+
+       for (i = 0; i < 3; i++)
+               rxq_ctx->start[i] = cpu_to_le32(addr);
+
+       addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+       rxq_ctx->end = cpu_to_le32(addr);
+
+       /* Express RX buffer queue */
+       rxq_ctx = (struct icssg_rxq_ctx *)(prueth->dram[priv->port_id].pa + HOST_RX_Q_EXP_CONTEXT_OFFSET);
+       for (i = 0; i < 3; i++)
+               rxq_ctx->start[i] = cpu_to_le32(addr);
+
+       addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+       rxq_ctx->end = cpu_to_le32(addr);
+
+       return 0;
+}
+
+static void icssg_init_emac_mode(struct prueth *prueth)
+{
+       u8 mac[6] = { 0 };
+
+       regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK, 0);
+       regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0);
+       /* Clear host MAC address */
+       icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
+}
+
+int icssg_config(struct prueth_priv *priv)
+{
+       struct prueth *prueth = priv->prueth;
+       void *config = (void *)(prueth->dram[priv->port_id].pa + ICSSG_CONFIG_OFFSET);
+       u8 *cfg_byte_ptr = config;
+       struct icssg_flow_cfg *flow_cfg;
+       u32 mask;
+       int ret;
+
+       int slice = priv->port_id;
+
+       icssg_init_emac_mode(prueth);
+
+       memset_io(config, 0, TAS_GATE_MASK_LIST0);
+       icssg_miig_queues_init(priv, slice);
+
+       prueth->speed = SPEED_1000;
+       prueth->duplex = DUPLEX_FULL;
+       if (!phy_interface_is_rgmii(priv->phydev)) {
+               prueth->speed = SPEED_100;
+               prueth->duplex = DUPLEX_FULL;
+       }
+
+       regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
+                          ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
+       icssg_miig_set_interface_mode(prueth->miig_rt, ICSS_MII0, prueth->phy_interface);
+       icssg_miig_set_interface_mode(prueth->miig_rt, ICSS_MII1, prueth->phy_interface);
+       icssg_config_mii_init(priv, slice);
+
+       icssg_config_ipg(priv, SPEED_1000, slice);
+       icssg_update_rgmii_cfg(prueth->miig_rt, SPEED_1000, true, slice, priv);
+
+       /* set GPI mode */
+       pruss_cfg_gpimode(prueth->pruss, slice, PRUSS_GPI_MODE_MII);
+
+       /* enable XFR shift for PRU and RTU */
+       mask = PRUSS_SPP_XFER_SHIFT_EN | PRUSS_SPP_RTU_XFR_SHIFT_EN;
+       pruss_cfg_update(prueth->pruss, PRUSS_CFG_SPP, mask, mask);
+
+       flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+       flow_cfg->rx_base_flow = prueth->dma_rx.id;
+       flow_cfg->mgm_base_flow = 0;
+       *(cfg_byte_ptr + SPL_PKT_DEFAULT_PRIORITY) = 0;
+       *(cfg_byte_ptr + QUEUE_NUM_UNTAGGED) = 0x0;
+
+       ret = prueth_emac_buffer_setup(priv);
+
+       if (ret)
+               return ret;
+
+       emac_r30_cmd_init(priv);
+       return 0;
+}
+
+/* commands to program ICSSG R30 registers */
+static struct icssg_r30_cmd emac_r32_bitmask[] = {
+       {{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}},      /* EMAC_PORT_DISABLE */
+       {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}},      /* EMAC_PORT_BLOCK */
+       {{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}},      /* EMAC_PORT_FORWARD */
+       {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}},      /* EMAC_PORT_FORWARD_WO_LEARNING */
+       {{0xffff0001, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},       /* ACCEPT ALL */
+       {{0xfffe0002, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},       /* ACCEPT TAGGED */
+       {{0xfffc0000, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},       /* ACCEPT UNTAGGED and PRIO */
+       {{EMAC_NONE,  0xffff0020, EMAC_NONE, EMAC_NONE}},       /* TAS Trigger List change */
+       {{EMAC_NONE,  0xdfff1000, EMAC_NONE, EMAC_NONE}},       /* TAS set state ENABLE*/
+       {{EMAC_NONE,  0xefff2000, EMAC_NONE, EMAC_NONE}},       /* TAS set state RESET*/
+       {{EMAC_NONE,  0xcfff0000, EMAC_NONE, EMAC_NONE}},       /* TAS set state DISABLE*/
+       {{EMAC_NONE,  EMAC_NONE,  0xffff0400, EMAC_NONE}},      /* UC flooding ENABLE*/
+       {{EMAC_NONE,  EMAC_NONE,  0xfbff0000, EMAC_NONE}},      /* UC flooding DISABLE*/
+       {{EMAC_NONE,  EMAC_NONE,  0xffff0800, EMAC_NONE}},      /* MC flooding ENABLE*/
+       {{EMAC_NONE,  EMAC_NONE,  0xf7ff0000, EMAC_NONE}},      /* MC flooding DISABLE*/
+       {{EMAC_NONE,  0xffff4000, EMAC_NONE, EMAC_NONE}},       /* Preemption on Tx ENABLE*/
+       {{EMAC_NONE,  0xbfff0000, EMAC_NONE, EMAC_NONE}}        /* Preemption on Tx DISABLE*/
+};
+
+int emac_set_port_state(struct prueth_priv *priv,
+                       enum icssg_port_state_cmd cmd)
+{
+       struct prueth *prueth = priv->prueth;
+       struct icssg_r30_cmd *p;
+       int ret = -ETIMEDOUT;
+       int timeout = 10;
+       int i;
+
+       p = (struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+       if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
+               dev_err(prueth->dev, "invalid port command\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 4; i++)
+               writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
+
+       /* wait for done */
+       while (timeout) {
+               if (emac_r30_is_done(priv)) {
+                       ret = 0;
+                       break;
+               }
+
+               udelay(2000);
+               timeout--;
+       }
+
+       if (ret == -ETIMEDOUT)
+               dev_err(prueth->dev, "timeout waiting for command done\n");
+
+       return ret;
+}
diff --git a/drivers/net/ti/icssg_config.h b/drivers/net/ti/icssg_config.h
new file mode 100644 (file)
index 0000000..e2859c7
--- /dev/null
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_CONFIG_H
+#define __NET_TI_ICSSG_CONFIG_H
+
+struct icssg_buffer_pool_cfg {
+       __le32  addr;
+       __le32  len;
+} __packed;
+
+struct icssg_flow_cfg {
+       __le16 rx_base_flow;
+       __le16 mgm_base_flow;
+} __packed;
+
+/* Config area lies in shared RAM */
+#define ICSSG_CONFIG_OFFSET_SLICE0   0
+#define ICSSG_CONFIG_OFFSET_SLICE1   0x8000
+
+/* pstate speed/duplex command to set speed and duplex settings
+ * in firmware.
+ * Command format : 0x8102ssPN. ss - sequence number: currently not
+ * used by driver, P - port number: For switch, N - Speed/Duplex state
+ * - Possible values of N:
+ * 0x0 - 10Mbps/Half duplex ;
+ * 0x8 - 10Mbps/Full duplex ;
+ * 0x2 - 100Mbps/Half duplex;
+ * 0xa - 100Mbps/Full duplex;
+ * 0xc - 1Gbps/Full duplex;
+ * NOTE: The above are same as bits [3..1](slice 0) or bits [8..6](slice 1) of
+ * RGMII CFG register. So suggested to read the register to populate the command
+ * bits.
+ */
+#define ICSSG_PSTATE_SPEED_DUPLEX_CMD  0x81020000
+#define ICSSG_PSTATE_FULL_DUPLEX       BIT(3)
+#define ICSSG_PSTATE_SPEED_100         BIT(1)
+#define ICSSG_PSTATE_SPEED_1000                BIT(2)
+
+/* Flow IDs used in config structure to firmware. Should match with
+ * flow_id in struct dma for rx channels.
+ */
+#define ICSSG_RX_CHAN_FLOW_ID          0 /* flow id for host port */
+#define ICSSG_RX_MGM_CHAN_FLOW_ID      1 /* flow id for command response */
+
+/* Used to notify the FW of the current link speed */
+#define PORT_LINK_SPEED_OFFSET                    0x00A8
+
+#define FW_LINK_SPEED_1G                           (0x00)
+#define FW_LINK_SPEED_100M                         (0x01)
+#define FW_LINK_SPEED_10M                          (0x02)
+#define FW_LINK_SPEED_HD                           (0x80)
+
+#define PRUETH_PKT_TYPE_CMD    0x10
+#define PRUETH_NAV_PS_DATA_SIZE        16      /* Protocol specific data size */
+#define PRUETH_NAV_SW_DATA_SIZE        16      /* SW related data size */
+#define PRUETH_MAX_RX_FLOWS    1       /* excluding default flow */
+#define PRUETH_RX_FLOW_DATA    0       /* FIXME: f/w bug to change to highest priority flow */
+
+#define PRUETH_EMAC_BUF_POOL_SIZE      SZ_8K
+#define PRUETH_EMAC_POOLS_PER_SLICE    24
+#define PRUETH_EMAC_BUF_POOL_START     8
+#define PRUETH_NUM_BUF_POOLS   8
+#define PRUETH_EMAC_RX_CTX_BUF_SIZE    SZ_16K  /* per slice */
+#define MSMC_RAM_SIZE  (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
+                             PRUETH_EMAC_RX_CTX_BUF_SIZE))
+
+struct icssg_rxq_ctx {
+       __le32 start[3];
+       __le32 end;
+} __packed;
+
+/* Load time Fiwmware Configuration */
+
+#define ICSSG_FW_MGMT_CMD_HEADER       0x81
+#define ICSSG_FW_MGMT_FDB_CMD_TYPE     0x03
+#define ICSSG_FW_MGMT_CMD_TYPE         0x04
+#define ICSSG_FW_MGMT_PKT              0x80000000
+
+struct icssg_r30_cmd {
+       u32 cmd[4];
+} __packed;
+
+enum icssg_port_state_cmd {
+       ICSSG_EMAC_PORT_DISABLE = 0,
+       ICSSG_EMAC_PORT_BLOCK,
+       ICSSG_EMAC_PORT_FORWARD,
+       ICSSG_EMAC_PORT_FORWARD_WO_LEARNING,
+       ICSSG_EMAC_PORT_ACCEPT_ALL,
+       ICSSG_EMAC_PORT_ACCEPT_TAGGED,
+       ICSSG_EMAC_PORT_ACCEPT_UNTAGGED_N_PRIO,
+       ICSSG_EMAC_PORT_TAS_TRIGGER,
+       ICSSG_EMAC_PORT_TAS_ENABLE,
+       ICSSG_EMAC_PORT_TAS_RESET,
+       ICSSG_EMAC_PORT_TAS_DISABLE,
+       ICSSG_EMAC_PORT_UC_FLOODING_ENABLE,
+       ICSSG_EMAC_PORT_UC_FLOODING_DISABLE,
+       ICSSG_EMAC_PORT_MC_FLOODING_ENABLE,
+       ICSSG_EMAC_PORT_MC_FLOODING_DISABLE,
+       ICSSG_EMAC_PORT_PREMPT_TX_ENABLE,
+       ICSSG_EMAC_PORT_PREMPT_TX_DISABLE,
+       ICSSG_EMAC_PORT_MAX_COMMANDS
+};
+
+#define EMAC_NONE           0xffff0000
+#define EMAC_PRU0_P_DI      0xffff0004
+#define EMAC_PRU1_P_DI      0xffff0040
+#define EMAC_TX_P_DI        0xffff0100
+
+#define EMAC_PRU0_P_EN      0xfffb0000
+#define EMAC_PRU1_P_EN      0xffbf0000
+#define EMAC_TX_P_EN        0xfeff0000
+
+#define EMAC_P_BLOCK        0xffff0040
+#define EMAC_TX_P_BLOCK     0xffff0200
+#define EMAC_P_UNBLOCK      0xffbf0000
+#define EMAC_TX_P_UNBLOCK   0xfdff0000
+#define EMAC_LEAN_EN        0xfff70000
+#define EMAC_LEAN_DI        0xffff0008
+
+#define EMAC_ACCEPT_ALL     0xffff0001
+#define EMAC_ACCEPT_TAG     0xfffe0002
+#define EMAC_ACCEPT_PRIOR   0xfffc0000
+
+/* Config area lies in DRAM */
+#define ICSSG_CONFIG_OFFSET                    0x0
+
+#define ICSSG_NUM_NORMAL_PDS   64
+#define ICSSG_NUM_SPECIAL_PDS  16
+
+#define ICSSG_NORMAL_PD_SIZE   8
+#define ICSSG_SPECIAL_PD_SIZE  20
+
+#define ICSSG_FLAG_MASK                0xff00ffff
+
+struct icssg_setclock_desc {
+       u8 request;
+       u8 restore;
+       u8 acknowledgment;
+       u8 cmp_status;
+       u32 margin;
+       u32 cyclecounter0_set;
+       u32 cyclecounter1_set;
+       u32 iepcount_set;
+       u32 rsvd1;
+       u32 rsvd2;
+       u32 CMP0_current;
+       u32 iepcount_current;
+       u32 difference;
+       u32 cyclecounter0_new;
+       u32 cyclecounter1_new;
+       u32 CMP0_new;
+} __packed;
+
+#define ICSSG_CMD_POP_SLICE0   56
+#define ICSSG_CMD_POP_SLICE1   60
+
+#define ICSSG_CMD_PUSH_SLICE0  57
+#define ICSSG_CMD_PUSH_SLICE1  61
+
+#define ICSSG_RSP_POP_SLICE0   58
+#define ICSSG_RSP_POP_SLICE1   62
+
+#define ICSSG_RSP_PUSH_SLICE0  56
+#define ICSSG_RSP_PUSH_SLICE1  60
+
+#define ICSSG_TS_POP_SLICE0    59
+#define ICSSG_TS_POP_SLICE1    63
+
+#define ICSSG_TS_PUSH_SLICE0   40
+#define ICSSG_TS_PUSH_SLICE1   41
+
+#endif /* __NET_TI_ICSSG_CONFIG_H */
diff --git a/drivers/net/ti/icssg_prueth.h b/drivers/net/ti/icssg_prueth.h
new file mode 100644 (file)
index 0000000..3313773
--- /dev/null
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_PRUETH_H
+#define __NET_TI_ICSSG_PRUETH_H
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm/lists.h>
+#include <dm/ofnode.h>
+#include <dm/device.h>
+#include <dma-uclass.h>
+#include <regmap.h>
+#include <linux/sizes.h>
+#include <linux/pruss_driver.h>
+#include "icssg_config.h"
+#include "icssg_switch_map.h"
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac);
+void icssg_class_set_host_mac_addr(struct regmap *miig_rt, u8 *mac);
+void icssg_class_disable(struct regmap *miig_rt, int slice);
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti);
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr);
+
+enum prueth_mac {
+       PRUETH_MAC0 = 0,
+       PRUETH_MAC1,
+       PRUETH_NUM_MACS,
+};
+
+enum prueth_port {
+       PRUETH_PORT_HOST = 0,   /* host side port */
+       PRUETH_PORT_MII0,       /* physical port MII 0 */
+       PRUETH_PORT_MII1,       /* physical port MII 1 */
+};
+
+struct prueth {
+       struct udevice          *dev;
+       struct udevice          *pruss;
+       struct regmap           *miig_rt;
+       struct regmap           *mii_rt;
+       fdt_addr_t              mdio_base;
+       struct pruss_mem_region shram;
+       struct pruss_mem_region dram[PRUETH_NUM_MACS];
+       phys_addr_t             tmaddr;
+       struct mii_dev          *bus;
+       u32                     sram_pa;
+       ofnode                  eth_node[PRUETH_NUM_MACS];
+       u32                     mdio_freq;
+       int                     phy_interface;
+       struct                  clk mdiofck;
+       struct dma              dma_tx;
+       struct dma              dma_rx;
+       struct dma              dma_rx_mgm;
+       u32                     rx_next;
+       u32                     rx_pend;
+       int                     slice;
+       bool                    mdio_manual_mode;
+       int                     speed;
+       int                     duplex;
+};
+
+struct prueth_priv {
+       struct udevice          *dev;
+       struct prueth           *prueth;
+       u32                     port_id;
+       struct phy_device       *phydev;
+       bool                    has_phy;
+       ofnode                  phy_node;
+       u32                     phy_addr;
+       int                     phy_interface;
+};
+
+/* config helpers */
+void icssg_config_ipg(struct prueth_priv *priv, int speed, int mii);
+int icssg_config(struct prueth_priv *priv);
+int emac_set_port_state(struct prueth_priv *priv, enum icssg_port_state_cmd cmd);
+
+#endif /* __NET_TI_ICSSG_PRUETH_H */