summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2021-06-23 20:40:52 +0530
committerPraneeth Bajjuri <praneeth@ti.com>2021-06-24 01:16:26 -0500
commite9e64fac4f1207cc8e981b3dc831ee8fb1f456a9 (patch)
tree6287ff83c65640ad76bf480e20aebcff1ba31353 /drivers
parent92b4f8cb4a42265df2269a3797de40c772fa25e6 (diff)
net: ti: icssg-prueth: Add ICSSG ethernet driver
This is the PURSS Ethernet driver for TI AM654 Sr2.0 and laterSoCs with the ICSSG PRU Sub-system running EMAC firmware. This driver caters to either of the slices(pru/rtu pair) of the icssg subsystem. One and exactly one of the slices is supported as the u-boot ethernet supports probing one interface at a time. Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Keerthy <j-keerthy@ti.com> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ti/Kconfig8
-rw-r--r--drivers/net/ti/Makefile1
-rw-r--r--drivers/net/ti/icss_mii_rt.h167
-rw-r--r--drivers/net/ti/icssg_classifier.c367
-rw-r--r--drivers/net/ti/icssg_config.c356
-rw-r--r--drivers/net/ti/icssg_config.h173
-rw-r--r--drivers/net/ti/icssg_prueth.c534
-rw-r--r--drivers/net/ti/icssg_prueth.h70
-rw-r--r--drivers/net/ti/icssg_switch_map.h163
9 files changed, 1839 insertions, 0 deletions
diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig
index f2dbbd0128..305b244cb9 100644
--- a/drivers/net/ti/Kconfig
+++ b/drivers/net/ti/Kconfig
@@ -32,3 +32,11 @@ config TI_AM65_CPSW_NUSS
help
This driver supports TI K3 MCU CPSW Nuss Ethernet controller
in Texas Instruments K3 AM65x SoCs.
+
+config TI_AM64_ICSSG_PRUETH
+ bool "TI Gigabit PRU Ethernet driver"
+ depends on ARCH_K3
+ select PHYLIB
+ help
+ Support Gigabit Ethernet ports over the ICSSG PRU Subsystem
+ This subsystem is available starting with the AM65 platform.
diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile
index 8d3808bb4b..161e00711b 100644
--- a/drivers/net/ti/Makefile
+++ b/drivers/net/ti/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o
obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o
+obj-$(CONFIG_TI_AM64_ICSSG_PRUETH) += icssg_prueth.o cpsw_mdio.o icssg_classifier.o icssg_config.o
diff --git a/drivers/net/ti/icss_mii_rt.h b/drivers/net/ti/icss_mii_rt.h
new file mode 100644
index 0000000000..bb5f2e8492
--- /dev/null
+++ b/drivers/net/ti/icss_mii_rt.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* PRU-ICSS MII_RT register definitions
+ *
+ * Copyright (C) 2015-2020 Texas Instruments Incorporated - http://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_GIG_EN_MII0 BIT(17)
+#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, bool gig_en,
+ bool full_duplex, int mii)
+{
+ u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0;
+
+ gig_en_mask = (mii == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 :
+ RGMII_CFG_GIG_EN_MII1;
+ if (gig_en)
+ gig_val = gig_en_mask;
+ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val);
+
+ full_duplex_mask = (mii == 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);
+}
+
+#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
index 0000000000..413bcb4936
--- /dev/null
+++ b/drivers/net/ti/icssg_classifier.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ */
+
+#include <common.h>
+#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 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_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;
+ int n;
+
+ /* defaults */
+ icssg_class_disable(miig_rt, slice);
+
+ /* Setup Classifier */
+ for (n = 0; n < ICSSG_NUM_CLASSIFIERS_IN_USE; n++) {
+ /* 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, n, data);
+
+ /* set CFG1 for OR_OR_AND for classifier */
+ rx_class_sel_set_type(miig_rt, slice, n,
+ 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, 0, 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
index 0000000000..07c05b3795
--- /dev/null
+++ b/drivers/net/ti/icssg_config.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Ethernet driver
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://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)
+
+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 *prueth, int mii)
+{
+ struct regmap *mii_rt = prueth->mii_rt;
+ u32 rxcfg_reg, txcfg_reg, pcnt_reg;
+ u32 rxcfg, txcfg;
+
+ rxcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
+ PRUSS_MII_RT_RXCFG1;
+ txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+ PRUSS_MII_RT_TXCFG1;
+ pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+ PRUSS_MII_RT_RX_PCNT1;
+
+ icssg_config_ipg(prueth, SPEED_1000, mii);
+
+ rxcfg = MII_RXCFG_DEFAULT;
+ txcfg = MII_TXCFG_DEFAULT;
+
+ if (mii == ICSS_MII1) {
+ rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
+ txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+ }
+
+ regmap_write(mii_rt, rxcfg_reg, rxcfg);
+ regmap_write(mii_rt, txcfg_reg, txcfg);
+ regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
+static void icssg_config_rgmii_init(struct prueth *prueth, int slice)
+{
+ 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;
+ u32 mii_mode;
+
+ mii_mode = MII_MODE_RGMII << ICSSG_CFG_MII0_MODE_SHIFT;
+ mii_mode |= MII_MODE_RGMII << ICSSG_CFG_MII1_MODE_SHIFT;
+ regmap_write(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_DEFAULT | mii_mode);
+
+ icssg_update_rgmii_cfg(miig_rt, true, true, slice);
+ /* 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 *prueth, int speed, int mii)
+{
+ 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 *prueth)
+{
+ int i;
+ struct icssg_r30_cmd *p;
+
+ p = (struct icssg_r30_cmd *)(prueth->dram.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 *prueth)
+{
+ const struct icssg_r30_cmd *p;
+ int i;
+ u32 cmd;
+
+ p = (const struct icssg_r30_cmd *)(prueth->dram.pa + MGR_R30_CMD_OFFSET);
+
+ for (i = 0; i < 4; i++) {
+ cmd = readl(&p->cmd[i]);
+ if (cmd != EMAC_NONE)
+ return 0;
+ }
+
+ return 1;
+}
+
+int icssg_config(struct prueth *prueth)
+{
+ void *config = (void *)(prueth->dram.pa + ICSSG_CONFIG_OFFSET);
+ u8 *cfg_byte_ptr = config;
+ struct icssg_flow_cfg *flow_cfg;
+ struct icssg_buffer_pool_cfg *bpool_cfg;
+ struct icssg_rxq_ctx *rxq_ctx;
+ int i;
+ u32 addr, mask;
+ int slice = prueth->slice;
+
+ rxq_ctx = (struct icssg_rxq_ctx *)(prueth->dram.pa + HOST_RX_Q_PRE_CONTEXT_OFFSET);
+ memset_io(config, 0, TAS_GATE_MASK_LIST0);
+ icssg_config_rgmii_init(prueth, slice);
+ icssg_config_mii_init(prueth, slice);
+
+ /* set GPMUX to MII mode */
+ pruss_cfg_set_gpmux(prueth->pruss, slice, 2);
+
+ /* 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);
+
+ /* set C28 to 0x100 */
+/* This is currently hacked into pru_rproc.c
+ * pru_rproc_set_ctable(prueth->pru[slice], PRU_C28, 0x100 << 8);
+ * pru_rproc_set_ctable(prueth->rtu[slice], PRU_C28, 0x100 << 8);
+ * pru_rproc_set_ctable(prueth->txpru[slice], PRU_C28, 0x100 << 8);
+ */
+
+ bpool_cfg = (struct icssg_buffer_pool_cfg *)(prueth->dram.pa + BUFFER_POOL_0_ADDR_OFFSET);
+
+ flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+ flow_cfg->rx_base_flow = cpu_to_le32(ICSSG_RX_CHAN_FLOW_ID);
+ flow_cfg->mgm_base_flow = 0;
+ *(cfg_byte_ptr + SPL_PKT_DEFAULT_PRIORITY) = 0;
+ *(cfg_byte_ptr + QUEUE_NUM_UNTAGGED) = 0x0;
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+ if (slice)
+ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+
+ 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);
+
+ emac_r30_cmd_init(prueth);
+ return 0;
+}
+
+/* commands to program ICSSG R30 registers */
+static struct icssg_r30_cmd emac_r32_bitmask[] = {
+ {{0xffff0004, 0xffff0100, 0xffff0100, EMAC_NONE}}, /* EMAC_PORT_DISABLE */
+ {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}}, /* EMAC_PORT_BLOCK */
+ {{0xffbb0000, 0xfcff0000, 0xdcff0000, 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 *prueth,
+ enum icssg_port_state_cmd cmd)
+{
+ struct icssg_r30_cmd *p;
+ int ret = -ETIMEDOUT;
+ int timeout = 10;
+ int i;
+
+ p = (struct icssg_r30_cmd *)(prueth->dram.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(prueth)) {
+ 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
index 0000000000..bdf3a12f56
--- /dev/null
+++ b/drivers/net/ti/icssg_config.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://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;
+
+/* Shutdown command to stop processing at firmware.
+ * Command format : 0x8101ss00. ss - sequence number. Currently not used
+ * by driver.
+ */
+#define ICSSG_SHUTDOWN_CMD 0x81010000
+
+/* 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 */
+
+/*------------------------ SR2.0 related --------------------------*/
+
+#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.c b/drivers/net/ti/icssg_prueth.c
new file mode 100644
index 0000000000..1d14f00312
--- /dev/null
+++ b/drivers/net/ti/icssg_prueth.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments K3 AM65 PRU Ethernet Driver
+ *
+ * Copyright (C) 2019-2021, Texas Instruments, Incorporated
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <clk.h>
+#include <dm/lists.h>
+#include <dm/device.h>
+#include <dma-uclass.h>
+#include <dm/of_access.h>
+#include <fs_loader.h>
+#include <miiphy.h>
+#include <misc.h>
+#include <net.h>
+#include <phy.h>
+#include <power-domain.h>
+#include <linux/soc/ti/ti-udma.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+#include <linux/pruss_driver.h>
+#include <dm/device_compat.h>
+
+#include "cpsw_mdio.h"
+#include "icssg_prueth.h"
+#include "icss_mii_rt.h"
+
+#define ICSS_SLICE0 0
+#define ICSS_SLICE1 1
+
+#ifdef PKTSIZE_ALIGN
+#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
+#else
+#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN)
+#endif
+
+#ifdef PKTBUFSRX
+#define UDMA_RX_DESC_NUM PKTBUFSRX
+#else
+#define UDMA_RX_DESC_NUM 4
+#endif
+
+/* Config region lies in shared RAM */
+#define ICSS_CONFIG_OFFSET_SLICE0 0
+#define ICSS_CONFIG_OFFSET_SLICE1 0x8000
+
+/* Firmware flags */
+#define ICSS_SET_RUN_FLAG_VLAN_ENABLE BIT(0) /* switch only */
+#define ICSS_SET_RUN_FLAG_FLOOD_UNICAST BIT(1) /* switch only */
+#define ICSS_SET_RUN_FLAG_PROMISC BIT(2) /* MAC only */
+#define ICSS_SET_RUN_FLAG_MULTICAST_PROMISC BIT(3) /* MAC only */
+
+/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
+#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
+
+static int icssg_phy_init(struct udevice *dev)
+{
+ struct prueth *priv = dev_get_priv(dev);
+ struct phy_device *phydev;
+ u32 supported = PHY_GBIT_FEATURES;
+ int ret;
+
+ phydev = phy_connect(priv->bus,
+ priv->phy_addr,
+ priv->dev,
+ priv->phy_interface);
+
+ if (!phydev) {
+ dev_err(dev, "phy_connect() failed\n");
+ return -ENODEV;
+ }
+
+ /* disable unsupported features */
+ supported &= ~(PHY_10BT_FEATURES |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+
+ phydev->supported &= supported;
+ phydev->advertising = phydev->supported;
+
+#ifdef CONFIG_DM_ETH
+ if (ofnode_valid(priv->phy_node))
+ phydev->node = priv->phy_node;
+#endif
+
+ priv->phydev = phydev;
+ ret = phy_config(phydev);
+ if (ret < 0)
+ pr_err("phy_config() failed: %d", ret);
+
+ return ret;
+}
+
+static int icssg_mdio_init(struct udevice *dev)
+{
+ struct prueth *prueth = dev_get_priv(dev);
+
+ prueth->bus = cpsw_mdio_init(dev->name, prueth->mdio_base,
+ prueth->mdio_freq,
+ clk_get_rate(&prueth->mdiofck));
+ if (!prueth->bus)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int icssg_update_link(struct prueth *priv)
+{
+ struct phy_device *phy = priv->phydev;
+ bool gig_en = false, full_duplex = false;
+
+ if (phy->link) { /* link up */
+ if (phy->speed == SPEED_1000)
+ gig_en = true;
+ if (phy->duplex == DUPLEX_FULL)
+ full_duplex = true;
+ /* Set the RGMII cfg for gig en and full duplex */
+ icssg_update_rgmii_cfg(priv->miig_rt, gig_en, full_duplex,
+ priv->slice);
+ /* update the Tx IPG based on 100M/1G speed */
+ icssg_config_ipg(priv, phy->speed, priv->slice);
+
+ printf("link up on port %d, speed %d, %s duplex\n",
+ priv->port_id, phy->speed,
+ (phy->duplex == DUPLEX_FULL) ? "full" : "half");
+ } else {
+ printf("link down on port %d\n", priv->port_id);
+ }
+
+ return phy->link;
+}
+
+static int prueth_start(struct udevice *dev)
+{
+ struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
+ struct prueth *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev->platdata;
+ int ret, i;
+ char chn_name[16];
+
+ icssg_class_set_mac_addr(priv->miig_rt, priv->slice,
+ (u8 *)pdata->enetaddr);
+
+ icssg_class_default(priv->miig_rt, priv->slice, 1);
+
+ /* To differentiate channels for SLICE0 vs SLICE1 */
+ snprintf(chn_name, sizeof(chn_name), "tx%d-0", priv->slice);
+
+ ret = dma_get_by_name(dev, chn_name, &priv->dma_tx);
+ if (ret)
+ dev_err(dev, "TX dma get failed %d\n", ret);
+
+ snprintf(chn_name, sizeof(chn_name), "rx%d", priv->slice);
+ ret = dma_get_by_name(dev, chn_name, &priv->dma_rx);
+ if (ret)
+ dev_err(dev, "RX dma get failed %d\n", ret);
+
+ /* check if the rx_flow_id of dma_rx is as expected since
+ * driver hardcode that value in config struct to firmware
+ * in probe. Just add this sanity check to catch any change
+ * to rx channel assignment in the future.
+ */
+ dma_get_cfg(&priv->dma_rx, 0, (void **)&dma_rx_cfg_data);
+ if (dma_rx_cfg_data->flow_id_base != ICSSG_RX_CHAN_FLOW_ID)
+ dev_err(dev,
+ "RX dma flow id bad, expected %d, actual %ld\n",
+ ICSSG_RX_CHAN_FLOW_ID, priv->dma_rx.id);
+
+ for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
+ ret = dma_prepare_rcv_buf(&priv->dma_rx,
+ net_rx_packets[i],
+ UDMA_RX_BUF_SIZE);
+ if (ret)
+ dev_err(dev, "RX dma add buf failed %d\n", ret);
+ }
+
+ ret = dma_enable(&priv->dma_tx);
+ if (ret) {
+ dev_err(dev, "TX dma_enable failed %d\n", ret);
+ goto tx_fail;
+ }
+
+ ret = dma_enable(&priv->dma_rx);
+ if (ret) {
+ dev_err(dev, "RX dma_enable failed %d\n", ret);
+ goto rx_fail;
+ }
+
+ ret = phy_startup(priv->phydev);
+ if (ret) {
+ dev_err(dev, "phy_startup failed\n");
+ goto phy_fail;
+ }
+
+ ret = icssg_update_link(priv);
+ if (!ret) {
+ ret = -ENODEV;
+ goto phy_shut;
+ }
+
+ return 0;
+
+phy_shut:
+ phy_shutdown(priv->phydev);
+phy_fail:
+ dma_disable(&priv->dma_rx);
+ dma_free(&priv->dma_rx);
+rx_fail:
+ dma_disable(&priv->dma_tx);
+ dma_free(&priv->dma_tx);
+
+tx_fail:
+ icssg_class_disable(priv->miig_rt, priv->slice);
+
+ return ret;
+}
+
+void prueth_print_buf(ulong addr, const void *data, uint width,
+ uint count, uint linelen)
+{
+ print_buffer(addr, data, width, count, linelen);
+}
+
+static int prueth_send(struct udevice *dev, void *packet, int length)
+{
+ struct prueth *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dma_send(&priv->dma_tx, packet, length, NULL);
+
+ return ret;
+}
+
+static int prueth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct prueth *priv = dev_get_priv(dev);
+ int ret;
+
+ /* try to receive a new packet */
+ ret = dma_receive(&priv->dma_rx, (void **)packetp, NULL);
+
+ return ret;
+}
+
+static int prueth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct prueth *priv = dev_get_priv(dev);
+ int ret = 0;
+
+ if (length > 0) {
+ u32 pkt = priv->rx_next % UDMA_RX_DESC_NUM;
+
+ dev_dbg(dev, "%s length:%d pkt:%u\n", __func__, length, pkt);
+
+ ret = dma_prepare_rcv_buf(&priv->dma_rx,
+ net_rx_packets[pkt],
+ UDMA_RX_BUF_SIZE);
+ priv->rx_next++;
+ }
+
+ return ret;
+}
+
+static void prueth_stop(struct udevice *dev)
+{
+ struct prueth *priv = dev_get_priv(dev);
+
+ icssg_class_disable(priv->miig_rt, priv->slice);
+
+ phy_shutdown(priv->phydev);
+
+ dma_disable(&priv->dma_tx);
+ dma_free(&priv->dma_tx);
+
+ dma_disable(&priv->dma_rx);
+ dma_free(&priv->dma_rx);
+
+ /* Workaround for shutdown command */
+ writel(0x0, priv->tmaddr + priv->slice * 0x200);
+}
+
+static const struct eth_ops prueth_ops = {
+ .start = prueth_start,
+ .send = prueth_send,
+ .recv = prueth_recv,
+ .free_pkt = prueth_free_pkt,
+ .stop = prueth_stop,
+};
+
+static int icssg_ofdata_parse_phy(struct udevice *dev, ofnode port_np)
+{
+ struct prueth *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args out_args;
+ const char *phy_mode;
+ int ret = 0;
+
+ phy_mode = ofnode_read_string(port_np, "phy-mode");
+ if (phy_mode) {
+ priv->phy_interface =
+ phy_get_interface_by_name(phy_mode);
+ if (priv->phy_interface == -1) {
+ dev_err(dev, "Invalid PHY mode '%s'\n",
+ phy_mode);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ ret = ofnode_parse_phandle_with_args(port_np, "phy-handle",
+ NULL, 0, 0, &out_args);
+ if (ret) {
+ dev_err(dev, "can't parse phy-handle port (%d)\n", ret);
+ ret = 0;
+ }
+
+ priv->phy_node = out_args.node;
+ ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr);
+ if (ret)
+ dev_err(dev, "failed to get phy_addr port (%d)\n", ret);
+
+out:
+ return ret;
+}
+
+static int prueth_config_rgmiidelay(struct prueth *prueth,
+ ofnode eth_np)
+{
+ struct udevice *dev = prueth->dev;
+ struct regmap *ctrl_mmr;
+ int ret = 0;
+ ofnode node;
+ u32 tmp[2];
+
+ ret = ofnode_read_u32_array(eth_np, "syscon-rgmii-delay", tmp, 2);
+ if (ret) {
+ dev_err(dev, "no syscon-rgmii-delay\n");
+ return ret;
+ }
+
+ node = ofnode_get_by_phandle(tmp[0]);
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "can't get syscon-rgmii-delay node\n");
+ return -EINVAL;
+ }
+
+ ctrl_mmr = syscon_node_to_regmap(node);
+ if (!ctrl_mmr) {
+ dev_err(dev, "can't get ctrl_mmr regmap\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(ctrl_mmr, tmp[1], ICSSG_CTRL_RGMII_ID_MODE, 0);
+
+ return 0;
+}
+
+static int prueth_probe(struct udevice *dev)
+{
+ struct prueth *prueth;
+ int ret = 0;
+ ofnode eth0_node, eth1_node, node, pruss_node, mdio_node, sram_node;
+ u32 phandle, err, sp;
+ struct udevice **prussdev = NULL;
+
+ prueth = dev_get_priv(dev);
+ prueth->dev = dev;
+ err = ofnode_read_u32(dev_ofnode(dev), "ti,prus", &phandle);
+ if (err)
+ return err;
+
+ node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
+ pruss_node = ofnode_get_parent(node);
+ err = misc_init_by_ofnode(pruss_node);
+ if (err)
+ return err;
+
+ ret = device_find_global_by_ofnode(pruss_node, prussdev);
+ if (ret)
+ dev_err(dev, "error getting the pruss dev\n");
+ prueth->pruss = *prussdev;
+
+ ret = pruss_request_mem_region(*prussdev, PRUSS_MEM_SHRD_RAM2,
+ &prueth->shram);
+ if (ret)
+ return ret;
+
+ ret = pruss_request_tm_region(*prussdev, &prueth->tmaddr);
+ if (ret)
+ return ret;
+
+ node = dev_ofnode(dev);
+ eth0_node = ofnode_find_subnode(node, "ethernet-mii0");
+ eth1_node = ofnode_find_subnode(node, "ethernet-mii1");
+ /* one node must be present and available else we fail */
+ if (!ofnode_valid(eth0_node) && !ofnode_valid(eth1_node)) {
+ dev_err(dev, "neither ethernet-mii0 nor ethernet-mii1 node available\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Exactly one node must be present as uboot ethernet framework does
+ * not support two interfaces in a single probe. So Device Tree should
+ * have exactly one of mii0 or mii1 interface.
+ */
+ if (ofnode_valid(eth0_node) && ofnode_valid(eth1_node)) {
+ dev_err(dev, "Both slices cannot be supported\n");
+ return -EINVAL;
+ }
+
+ if (ofnode_valid(eth0_node)) {
+ prueth->slice = 0;
+ icssg_ofdata_parse_phy(dev, eth0_node);
+ prueth->eth_node[PRUETH_MAC0] = eth0_node;
+ }
+
+ if (ofnode_valid(eth1_node)) {
+ prueth->slice = 1;
+ icssg_ofdata_parse_phy(dev, eth1_node);
+ prueth->eth_node[PRUETH_MAC0] = eth1_node;
+ }
+
+ ret = pruss_request_mem_region(*prussdev,
+ prueth->slice ? PRUSS_MEM_DRAM1 : PRUSS_MEM_DRAM0,
+ &prueth->dram);
+ if (ret) {
+ dev_err(dev, "could not request DRAM%d region\n", prueth->slice);
+ return ret;
+ }
+
+ prueth->miig_rt = syscon_regmap_lookup_by_phandle(dev, "mii-g-rt");
+ if (!prueth->miig_rt) {
+ dev_err(dev, "couldn't get mii-g-rt syscon regmap\n");
+ return -ENODEV;
+ }
+
+ prueth->mii_rt = syscon_regmap_lookup_by_phandle(dev, "mii-rt");
+ if (!prueth->mii_rt) {
+ dev_err(dev, "couldn't get mii-rt syscon regmap\n");
+ return -ENODEV;
+ }
+
+ ret = ofnode_read_u32(dev_ofnode(dev), "sram", &sp);
+ if (ret) {
+ dev_err(dev, "sram node fetch failed %d\n", ret);
+ return ret;
+ }
+
+ sram_node = ofnode_get_by_phandle(sp);
+ if (!ofnode_valid(sram_node))
+ return -EINVAL;
+
+ prueth->sram_pa = ofnode_get_addr(sram_node);
+ if (prueth->sram_pa % SZ_64K != 0) {
+ /* This is constraint for SR2.0 firmware */
+ dev_err(dev, "sram address needs to be 64KB aligned\n");
+ return -EINVAL;
+ }
+
+ if (!prueth->slice) {
+ ret = prueth_config_rgmiidelay(prueth, eth0_node);
+ if (ret) {
+ dev_err(dev, "prueth_config_rgmiidelay failed\n");
+ return ret;
+ }
+ } else {
+ ret = prueth_config_rgmiidelay(prueth, eth1_node);
+ if (ret) {
+ dev_err(dev, "prueth_config_rgmiidelay failed\n");
+ return ret;
+ }
+ }
+
+ mdio_node = ofnode_find_subnode(pruss_node, "mdio");
+ prueth->mdio_base = ofnode_get_addr(mdio_node);
+ ofnode_read_u32(mdio_node, "bus_freq", &prueth->mdio_freq);
+
+ ret = clk_get_by_name_nodev(mdio_node, "fck", &prueth->mdiofck);
+ if (ret) {
+ dev_err(dev, "failed to get clock %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&prueth->mdiofck);
+ if (ret) {
+ dev_err(dev, "clk_enable failed %d\n", ret);
+ return ret;
+ }
+
+ ret = icssg_mdio_init(dev);
+ if (ret)
+ return ret;
+
+ ret = icssg_phy_init(dev);
+ if (ret) {
+ dev_err(dev, "phy_init failed\n");
+ goto out;
+ }
+
+ /* Set Load time configuration */
+ icssg_config(prueth);
+
+ return 0;
+out:
+ cpsw_mdio_free(prueth->bus);
+ clk_disable(&prueth->mdiofck);
+
+ return ret;
+}
+
+static const struct udevice_id prueth_ids[] = {
+ { .compatible = "ti,am654-icssg-prueth" },
+ { }
+};
+
+U_BOOT_DRIVER(prueth) = {
+ .name = "prueth",
+ .id = UCLASS_ETH,
+ .of_match = prueth_ids,
+ .probe = prueth_probe,
+ .ops = &prueth_ops,
+ .priv_auto_alloc_size = sizeof(struct prueth),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/net/ti/icssg_prueth.h b/drivers/net/ti/icssg_prueth.h
new file mode 100644
index 0000000000..97df3ab2ab
--- /dev/null
+++ b/drivers/net/ti/icssg_prueth.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
+ *
+ * Copyright (C) 2019, Texas Instruments, Incorporated
+ *
+ */
+
+#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/pruss_driver.h>
+#include "icssg_config.h"
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, 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;
+ phys_addr_t tmaddr;
+ struct mii_dev *bus;
+ u32 port_id;
+ u32 sram_pa;
+ struct phy_device *phydev;
+ bool has_phy;
+ ofnode phy_node;
+ u32 phy_addr;
+ ofnode eth_node[PRUETH_NUM_MACS];
+ u32 mdio_freq;
+ int phy_interface;
+ struct clk mdiofck;
+ struct dma dma_tx;
+ struct dma dma_rx;
+ u32 rx_next;
+ u32 rx_pend;
+ int slice;
+};
+
+/* config helpers */
+void icssg_config_ipg(struct prueth *prueth, int speed, int mii);
+int icssg_config(struct prueth *prueth);
+
+#endif /* __NET_TI_ICSSG_PRUETH_H */
diff --git a/drivers/net/ti/icssg_switch_map.h b/drivers/net/ti/icssg_switch_map.h
new file mode 100644
index 0000000000..4343601ca3
--- /dev/null
+++ b/drivers/net/ti/icssg_switch_map.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_SWITCH_MAP_H
+#define __NET_TI_ICSSG_SWITCH_MAP_H
+
+/* Memory Usage of : SHARED_MEMORY
+ *
+ */
+
+/*Time after which FDB entries are checked for aged out values. Value in nanoseconds*/
+#define FDB_AGEING_TIMEOUT_OFFSET 0x0014
+/*default VLAN tag for Host Port*/
+#define HOST_PORT_DF_VLAN_OFFSET 0x001C
+/*Same as HOST_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET HOST_PORT_DF_VLAN_OFFSET
+/*default VLAN tag for P1 Port*/
+#define P1_PORT_DF_VLAN_OFFSET 0x0020
+/*Same as P1_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET P1_PORT_DF_VLAN_OFFSET
+/*default VLAN tag for P2 Port*/
+#define P2_PORT_DF_VLAN_OFFSET 0x0024
+/*Same as P2_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET P2_PORT_DF_VLAN_OFFSET
+/*VLAN-FID Table offset. 4096 VIDs. 2B per VID = 8KB = 0x2000*/
+#define VLAN_STATIC_REG_TABLE_OFFSET 0x0100
+/*VLAN-FID Table offset for EMAC*/
+#define EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET VLAN_STATIC_REG_TABLE_OFFSET
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC0_HI 0x2104
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC0_LO 0x2F6C
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC1_HI 0x3DD4
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC1_LO 0x4C3C
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC0_HI 0x5AA4
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC0_LO 0x5F0C
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC1_HI 0x6374
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC1_LO 0x67DC
+/*special packet descriptor Q reserved memory*/
+#define HOST_SPPD0 0x7AAC
+/*special packet descriptor Q reserved memory*/
+#define HOST_SPPD1 0x7EAC
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_CYCLECOUNT_OFFSET 0x83EC
+/*IEP count hi roll over count*/
+#define TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET 0x83F4
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET 0x83F8
+/*Set clock descriptor*/
+#define TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET 0x83FC
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET 0x843C
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_COUNT_OFFSET 0x8440
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET 0x8444
+/*Control variable to generate SYNC1*/
+#define TIMESYNC_FW_WC_ISOM_PIN_SIGNAL_EN_OFFSET 0x844C
+/*SystemTime Sync0 periodicity*/
+#define TIMESYNC_FW_ST_SYNCOUT_PERIOD_OFFSET 0x8450
+/*pktTxDelay for P1 = link speed dependent p1 mac delay + p1 phy delay*/
+#define TIMESYNC_FW_WC_PKTTXDELAY_P1_OFFSET 0x8454
+/*pktTxDelay for P2 = link speed dependent p2 mac delay + p2 phy delay*/
+#define TIMESYNC_FW_WC_PKTTXDELAY_P2_OFFSET 0x8458
+/*Set clock operation done signal for next task*/
+#define TIMESYNC_FW_SIG_PNFW_OFFSET 0x845C
+/*Set clock operation done signal for next task*/
+#define TIMESYNC_FW_SIG_TIMESYNCFW_OFFSET 0x8460
+
+/* Memory Usage of : MSMC
+ *
+ */
+
+/* Memory Usage of : DMEM0
+ *
+ */
+
+/*New list is copied at this time*/
+#define TAS_CONFIG_CHANGE_TIME 0x000C
+/*config change error counter*/
+#define TAS_CONFIG_CHANGE_ERROR_COUNTER 0x0014
+/*TAS List update pending flag*/
+#define TAS_CONFIG_PENDING 0x0018
+/*TAS list update trigger flag*/
+#define TAS_CONFIG_CHANGE 0x0019
+/*List length for new TAS schedule*/
+#define TAS_ADMIN_LIST_LENGTH 0x001A
+/*Currently active TAS list index*/
+#define TAS_ACTIVE_LIST_INDEX 0x001B
+/*Cycle time for the new TAS schedule*/
+#define TAS_ADMIN_CYCLE_TIME 0x001C
+/*Cycle counts remaining till the TAS list update*/
+#define TAS_CONFIG_CHANGE_CYCLE_COUNT 0x0020
+/*Base Flow ID for sending packets to Host for Slice0*/
+#define PSI_L_REGULAR_FLOW_ID_BASE_OFFSET 0x0024
+/*Same as PSI_L_REGULAR_FLOW_ID_BASE_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PSI_L_REGULAR_FLOW_ID_BASE_OFFSET PSI_L_REGULAR_FLOW_ID_BASE_OFFSET
+/*Base Flow ID for sending mgmt and Tx TS to Host for Slice0*/
+#define PSI_L_MGMT_FLOW_ID_OFFSET 0x0026
+/*Same as PSI_L_MGMT_FLOW_ID_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PSI_L_MGMT_FLOW_ID_BASE_OFFSET PSI_L_MGMT_FLOW_ID_OFFSET
+/*Queue number for Special packets written here*/
+#define SPL_PKT_DEFAULT_PRIORITY 0x0028
+/*Express Preemptible Queue Mask*/
+#define EXPRESS_PRE_EMPTIVE_Q_MASK 0x0029
+/*Port1/Port2 Default Queue number for untagged packets, only 1B is used*/
+#define QUEUE_NUM_UNTAGGED 0x002A
+/*Stores the table used for priority regeneration. 1B per PCP/Queue*/
+#define PORT_Q_PRIORITY_REGEN_OFFSET 0x002C
+/*For marking packet as priority/express (this feature is disabled) or cut-through/S&F. One per slice*/
+#define EXPRESS_PRE_EMPTIVE_Q_MAP 0x0034
+/*Stores the table used for priority mapping. 1B per PCP/Queue*/
+#define PORT_Q_PRIORITY_MAPPING_OFFSET 0x003C
+/*TAS gate mask for windows list0*/
+#define TAS_GATE_MASK_LIST0 0x0100
+/*TAS gate mask for windows list1*/
+#define TAS_GATE_MASK_LIST1 0x0350
+/*Memory to Enable/Disable Preemption on TX side*/
+#define PRE_EMPTION_ENABLE_TX 0x05A0
+/*Active State of Preemption on TX side*/
+#define PRE_EMPTION_ACTIVE_TX 0x05A1
+/*Memory to Enable/Disable Verify State Machine Preemption*/
+#define PRE_EMPTION_ENABLE_VERIFY 0x05A2
+/*Verify Status of State Machine*/
+#define PRE_EMPTION_VERIFY_STATUS 0x05A3
+/*Non Final Fragment Size supported by Link Partner*/
+#define PRE_EMPTION_ADD_FRAG_SIZE_REMOTE 0x05A4
+/*Non Final Fragment Size supported by Firmware*/
+#define PRE_EMPTION_ADD_FRAG_SIZE_LOCAL 0x05A6
+/*Time in ms the State machine waits for respond packet*/
+#define PRE_EMPTION_VERIFY_TIME 0x05A8
+/*Memory used for R30 related management commands*/
+#define MGR_R30_CMD_OFFSET 0x05AC
+/*HW Buffer Pool0 base address*/
+#define BUFFER_POOL_0_ADDR_OFFSET 0x05BC
+/*16B for Host Egress MSMC Q (Pre-emptible) context*/
+#define HOST_RX_Q_PRE_CONTEXT_OFFSET 0x0684
+/*Buffer for 8 FDB entries to be added by 'Add Multiple FDB entries IOCTL*/
+#define FDB_CMD_BUFFER 0x0894
+
+/* Memory Usage of : DMEM1
+ *
+ */
+
+/* Memory Usage of : PA_STAT
+ *
+ */
+
+/*Start of 32 bits PA_STAT counters*/
+#define PA_STAT_32b_START_OFFSET 0x0080
+
+#endif /* __NET_TI_ICSSG_SWITCH_MAP_H */