From 024c46aeabf4264b85c7d527e1d1525ab5697078 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 19 Jan 2024 08:02:26 +0100 Subject: [PATCH] linux-iot2050: Re-add support for SR1.0 prueth to the 6.1-cip kernel This is widely a backport for current under-review upstream patches to re-add SR1.0 prueth support. Signed-off-by: Jan Kiszka --- ...fig-add-SR1.0-specific-configuration.patch | 108 +++ ...eth-add-SR1.0-specific-configuration.patch | 77 +++ ...ssg-classifier-Add-support-for-SR1.0.patch | 203 ++++++ ...fig-Add-SR1.0-configuration-function.patch | 161 +++++ ...htool-Adjust-channel-count-for-SR1.0.patch | 49 ++ ...eth-Add-necessary-functions-for-SR1..patch | 301 +++++++++ ...ssg-prueth-Wire-up-support-for-SR1.0.patch | 613 ++++++++++++++++++ ...0093-net-ti-icss_iep-Add-SR1-support.patch | 209 ++++++ ...2050-Add-icssg-prueth-nodes-for-PG1-.patch | 67 ++ 9 files changed, 1788 insertions(+) create mode 100644 recipes-kernel/linux/files/patches-6.1/0086-net-ti-icssg-config-add-SR1.0-specific-configuration.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0087-net-ti-icssg-prueth-add-SR1.0-specific-configuration.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0088-net-ti-icssg-classifier-Add-support-for-SR1.0.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0089-net-ti-icssg-config-Add-SR1.0-configuration-function.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0090-net-ti-icssg-ethtool-Adjust-channel-count-for-SR1.0.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0091-net-ti-iccsg-prueth-Add-necessary-functions-for-SR1..patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0092-net-ti-icssg-prueth-Wire-up-support-for-SR1.0.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0093-net-ti-icss_iep-Add-SR1-support.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0094-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch diff --git a/recipes-kernel/linux/files/patches-6.1/0086-net-ti-icssg-config-add-SR1.0-specific-configuration.patch b/recipes-kernel/linux/files/patches-6.1/0086-net-ti-icssg-config-add-SR1.0-specific-configuration.patch new file mode 100644 index 000000000..21a1c0cfa --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0086-net-ti-icssg-config-add-SR1.0-specific-configuration.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:14:56 +0100 +Subject: [PATCH] net: ti: icssg-config: add SR1.0-specific configuration bits + +Add required definitions and structures to properly describe +SR1.0 devices where they differ from SR2.0. + +Based on the work of Roger Quadros, Murali Karicheri and +Grygorii Strashko in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_config.h | 55 ++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h +index 43eb0922172a..65539fec5e58 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_config.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.h +@@ -23,14 +23,23 @@ struct icssg_flow_cfg { + #define PRUETH_NAV_SW_DATA_SIZE 16 /* SW related data size */ + #define PRUETH_MAX_TX_DESC 512 + #define PRUETH_MAX_RX_DESC 512 ++#define PRUETH_MAX_RX_FLOWS_SR1 4 /* excluding default flow */ + #define PRUETH_MAX_RX_FLOWS 1 /* excluding default flow */ ++#define PRUETH_RX_FLOW_DATA_SR1 3 /* highest priority flow */ + #define PRUETH_RX_FLOW_DATA 0 + ++/* SR1.0 only */ ++#define PRUETH_MAX_RX_MGM_DESC 8 ++#define PRUETH_MAX_RX_MGM_FLOWS 2 /* excluding default flow */ ++#define PRUETH_RX_MGM_FLOW_RESPONSE 0 ++#define PRUETH_RX_MGM_FLOW_TIMESTAMP 1 ++ + #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_SR1 (SZ_64K + SZ_32K + SZ_2K) /* 0x1880 x 8 x 2 */ + #define MSMC_RAM_SIZE \ + (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \ + PRUETH_EMAC_RX_CTX_BUF_SIZE * 2)) +@@ -94,6 +103,13 @@ enum icssg_port_state_cmd { + #define EMAC_ACCEPT_TAG 0xfffe0002 + #define EMAC_ACCEPT_PRIOR 0xfffc0000 + ++#define PRUETH_NUM_BUF_POOLS_SR1 16 ++#define PRUETH_EMAC_BUF_POOL_START_SR1 8 ++#define PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1 128 ++#define PRUETH_EMAC_BUF_SIZE_SR1 1536 ++#define PRUETH_EMAC_NUM_BUF_SR1 4 ++#define PRUETH_EMAC_BUF_POOL_SIZE_SR1 (PRUETH_EMAC_NUM_BUF_SR1 * \ ++ PRUETH_EMAC_BUF_SIZE_SR1) + /* Config area lies in DRAM */ + #define ICSSG_CONFIG_OFFSET 0x0 + +@@ -101,6 +117,45 @@ enum icssg_port_state_cmd { + #define ICSSG_CONFIG_OFFSET_SLICE0 0 + #define ICSSG_CONFIG_OFFSET_SLICE1 0x8000 + ++struct icssg_config_sr1 { ++ __le32 status; /* Firmware status */ ++ __le32 addr_lo; /* MSMC Buffer pool base address low. */ ++ __le32 addr_hi; /* MSMC Buffer pool base address high. Must be 0 */ ++ __le32 tx_buf_sz[16]; /* Array of buffer pool sizes */ ++ __le32 num_tx_threads; /* Number of active egress threads, 1 to 4 */ ++ __le32 tx_rate_lim_en; /* Bitmask: Egress rate limit en per thread */ ++ __le32 rx_flow_id; /* RX flow id for first rx ring */ ++ __le32 rx_mgr_flow_id; /* RX flow id for the first management ring */ ++ __le32 flags; /* TBD */ ++ __le32 n_burst; /* for debug */ ++ __le32 rtu_status; /* RTU status */ ++ __le32 info; /* reserved */ ++ __le32 reserve; ++ __le32 rand_seed; /* Used for the random number generation at fw */ ++} __packed; ++ ++/* SR1.0 shutdown command to stop processing at firmware. ++ * Command format : 0x8101ss00. ss - sequence number. Currently not used ++ * by driver. ++ */ ++#define ICSSG_SHUTDOWN_CMD 0x81010000 ++ ++/* SR1.0 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_NUM_NORMAL_PDS 64 + #define ICSSG_NUM_SPECIAL_PDS 16 + diff --git a/recipes-kernel/linux/files/patches-6.1/0087-net-ti-icssg-prueth-add-SR1.0-specific-configuration.patch b/recipes-kernel/linux/files/patches-6.1/0087-net-ti-icssg-prueth-add-SR1.0-specific-configuration.patch new file mode 100644 index 000000000..e0dcf1cd0 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0087-net-ti-icssg-prueth-add-SR1.0-specific-configuration.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:14:57 +0100 +Subject: [PATCH] net: ti: icssg-prueth: add SR1.0-specific configuration bits + +Add fields to differentiate between SR1.0 and SR2.0 in the driver +as well as the structures necessary to program SR1.0. + +Based on the work of Roger Quadros in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index 8b6d6b497010..1bdd3d301fde 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -127,6 +127,7 @@ struct prueth_rx_chn { + + /* data for each emac port */ + struct prueth_emac { ++ bool is_sr1; + bool fw_running; + struct prueth *prueth; + struct net_device *ndev; +@@ -155,6 +156,10 @@ struct prueth_emac { + int rx_flow_id_base; + int tx_ch_num; + ++ /* SR1.0 Management channel */ ++ struct prueth_rx_chn rx_mgm_chn; ++ int rx_mgm_flow_id_base; ++ + spinlock_t lock; /* serialize access */ + + /* TX HW Timestamping */ +@@ -182,10 +187,12 @@ struct prueth_emac { + * struct prueth_pdata - PRUeth platform data + * @fdqring_mode: Free desc queue mode + * @quirk_10m_link_issue: 10M link detect errata ++ * @is_sr1: device is SR1.0 + */ + struct prueth_pdata { + enum k3_ring_mode fdqring_mode; + u32 quirk_10m_link_issue:1; ++ u32 is_sr1:1; + }; + + /** +@@ -224,6 +231,7 @@ struct prueth { + struct device_node *eth_node[PRUETH_NUM_MACS]; + struct prueth_emac *emac[PRUETH_NUM_MACS]; + struct net_device *registered_netdevs[PRUETH_NUM_MACS]; ++ struct icssg_config_sr1 config[PRUSS_NUM_PRUS]; + struct regmap *miig_rt; + struct regmap *mii_rt; + +@@ -236,6 +244,13 @@ struct prueth { + struct icss_iep *iep1; + }; + ++struct emac_tx_ts_response_sr1 { ++ u32 lo_ts; ++ u32 hi_ts; ++ u32 reserved; ++ u32 cookie; ++}; ++ + struct emac_tx_ts_response { + u32 reserved[2]; + u32 cookie; diff --git a/recipes-kernel/linux/files/patches-6.1/0088-net-ti-icssg-classifier-Add-support-for-SR1.0.patch b/recipes-kernel/linux/files/patches-6.1/0088-net-ti-icssg-classifier-Add-support-for-SR1.0.patch new file mode 100644 index 000000000..7313a4867 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0088-net-ti-icssg-classifier-Add-support-for-SR1.0.patch @@ -0,0 +1,203 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:14:58 +0100 +Subject: [PATCH] net: ti: icssg-classifier: Add support for SR1.0 + +Add the functions to program the SR1.0 packet classifier. + +Based on the work of Roger Quadros in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + .../net/ethernet/ti/icssg/icssg_classifier.c | 113 ++++++++++++++++-- + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 2 +- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 6 +- + 3 files changed, 110 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_classifier.c b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +index 6df53ab17fbc..d7288eb6c0fd 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_classifier.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +@@ -274,6 +274,16 @@ static void rx_class_set_or(struct regmap *miig_rt, int slice, int n, + regmap_write(miig_rt, offset, data); + } + ++static u32 rx_class_get_or(struct regmap *miig_rt, int slice, int n) ++{ ++ u32 offset, val; ++ ++ offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); ++ regmap_read(miig_rt, offset, &val); ++ ++ return val; ++} ++ + void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac) + { + regmap_write(miig_rt, MAC_INTERFACE_0, (u32)(mac[0] | mac[1] << 8 | +@@ -288,6 +298,26 @@ void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac) + regmap_write(miig_rt, offs[slice].mac1, (u32)(mac[4] | mac[5] << 8)); + } + ++static void icssg_class_ft1_add_mcast(struct regmap *miig_rt, int slice, ++ int slot, const u8 *addr, const u8 *mask) ++{ ++ int i; ++ u32 val; ++ ++ WARN(slot >= FT1_NUM_SLOTS, "invalid slot: %d\n", slot); ++ ++ rx_class_ft1_set_da(miig_rt, slice, slot, addr); ++ rx_class_ft1_set_da_mask(miig_rt, slice, slot, mask); ++ rx_class_ft1_cfg_set_type(miig_rt, slice, slot, FT1_CFG_TYPE_EQ); ++ ++ /* Enable the FT1 slot in OR enable for all classifiers */ ++ for (i = 0; i < ICSSG_NUM_CLASSIFIERS_IN_USE; i++) { ++ val = rx_class_get_or(miig_rt, slice, i); ++ val |= RX_CLASS_FT_FT1_MATCH(slot); ++ rx_class_set_or(miig_rt, slice, i, val); ++ } ++} ++ + /* disable all RX traffic */ + void icssg_class_disable(struct regmap *miig_rt, int slice) + { +@@ -331,30 +361,95 @@ void icssg_class_disable(struct regmap *miig_rt, int slice) + regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); + } + +-void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti) ++void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti, ++ bool is_sr1) + { ++ int classifiers_in_use = is_sr1 ? ICSSG_NUM_CLASSIFIERS_IN_USE : 1; + u32 data; ++ int n; + + /* 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; ++ for (n = 0; n < 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; ++ /* multicast */ ++ if (allmulti) ++ data |= RX_CLASS_FT_MC; + +- rx_class_set_or(miig_rt, slice, 0, data); ++ 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, 0, RX_CLASS_SEL_TYPE_OR_OR_AND); ++ /* 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); + } + ++void icssg_class_promiscuous_sr1(struct regmap *miig_rt, int slice) ++{ ++ u32 data, offset; ++ int n; ++ ++ /* defaults */ ++ icssg_class_disable(miig_rt, slice); ++ ++ /* Setup Classifier */ ++ for (n = 0; n < ICSSG_NUM_CLASSIFIERS_IN_USE; n++) { ++ /* set RAW_MASK to bypass filters */ ++ offset = RX_CLASS_GATES_N_REG(slice, n); ++ regmap_read(miig_rt, offset, &data); ++ data |= RX_CLASS_GATES_RAW_MASK; ++ regmap_write(miig_rt, offset, data); ++ } ++} ++ ++void icssg_class_add_mcast_sr1(struct regmap *miig_rt, int slice, ++ struct net_device *ndev) ++{ ++ u8 sr_addr[6] = { 0x01, 0x80, 0xc2, 0, 0, 0 }; ++ u8 cb_addr[6] = { 0x01, 0x00, 0x5e, 0, 0, 0 }; ++ u8 mask_addr[6] = { 0, 0, 0, 0, 0, 0xff }; ++ struct netdev_hw_addr *ha; ++ int slot = 2; ++ ++ rx_class_ft1_set_start_len(miig_rt, slice, 0, 6); ++ /* reserve first 2 slots for ++ * 1) 01-80-C2-00-00-XX Known Service Ethernet Multicast addresses ++ * 2) 01-00-5e-00-00-XX Local Network Control Block ++ * (224.0.0.0 - 224.0.0.255 (224.0.0/24)) ++ */ ++ icssg_class_ft1_add_mcast(miig_rt, slice, 0, sr_addr, mask_addr); ++ icssg_class_ft1_add_mcast(miig_rt, slice, 1, cb_addr, mask_addr); ++ mask_addr[5] = 0; ++ netdev_for_each_mc_addr(ha, ndev) { ++ /* skip addresses matching reserved slots */ ++ if (!memcmp(sr_addr, ha->addr, 5) || ++ !memcmp(cb_addr, ha->addr, 5)) { ++ netdev_dbg(ndev, "mcast skip %pM\n", ha->addr); ++ continue; ++ } ++ ++ if (slot >= FT1_NUM_SLOTS) { ++ netdev_dbg(ndev, ++ "can't add more than %d MC addresses, enabling allmulti\n", ++ FT1_NUM_SLOTS); ++ icssg_class_default(miig_rt, slice, 1, true); ++ break; ++ } ++ ++ netdev_dbg(ndev, "mcast add %pM\n", ha->addr); ++ icssg_class_ft1_add_mcast(miig_rt, slice, slot, ++ ha->addr, mask_addr); ++ slot++; ++ } ++} ++ + /* required for SAV check */ + void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr) + { +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 2b22e98dd677..1f38e115e227 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1329,7 +1329,7 @@ static int emac_ndo_open(struct net_device *ndev) + icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); + icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); + +- icssg_class_default(prueth->miig_rt, slice, 0); ++ icssg_class_default(prueth->miig_rt, slice, 0, emac->is_sr1); + + /* Notify the stack of the actual queue counts. */ + ret = netif_set_real_num_tx_queues(ndev, num_data_chn); +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index 1bdd3d301fde..c2221db25950 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -277,7 +277,11 @@ extern const struct ethtool_ops icssg_ethtool_ops; + 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, const 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_class_default(struct regmap *miig_rt, int slice, bool allmulti, ++ bool is_sr1); ++void icssg_class_promiscuous_sr1(struct regmap *miig_rt, int slice); ++void icssg_class_add_mcast_sr1(struct regmap *miig_rt, int slice, ++ struct net_device *ndev); + void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr); + + /* config helpers */ diff --git a/recipes-kernel/linux/files/patches-6.1/0089-net-ti-icssg-config-Add-SR1.0-configuration-function.patch b/recipes-kernel/linux/files/patches-6.1/0089-net-ti-icssg-config-Add-SR1.0-configuration-function.patch new file mode 100644 index 000000000..c9ad815c7 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0089-net-ti-icssg-config-Add-SR1.0-configuration-function.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:14:59 +0100 +Subject: [PATCH] net: ti: icssg-config: Add SR1.0 configuration functions + +The SR1.0 firmware needs to configured differently from the +current SR2.0 firmware. Add the necessary functions. + +Based on the work of Roger Quadros, Vignesh Raghavendra +and Grygorii Strashko in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_config.c | 86 ++++++++++++++++++-- + 1 file changed, 81 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c +index c1da70f247d4..a013851de30a 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_config.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.c +@@ -18,6 +18,8 @@ + */ + + /* IPG is in core_clk cycles */ ++#define MII_RT_TX_IPG_100M_SR1 0x166 ++#define MII_RT_TX_IPG_1G_SR1 0x1a + #define MII_RT_TX_IPG_100M 0x17 + #define MII_RT_TX_IPG_1G 0xb + +@@ -205,14 +207,20 @@ void icssg_config_ipg(struct prueth_emac *emac) + + switch (emac->speed) { + case SPEED_1000: +- icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_1G); ++ icssg_mii_update_ipg(prueth->mii_rt, slice, ++ prueth->pdata.is_sr1 ? ++ MII_RT_TX_IPG_1G_SR1 : MII_RT_TX_IPG_1G); + break; + case SPEED_100: +- icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); ++ icssg_mii_update_ipg(prueth->mii_rt, slice, ++ prueth->pdata.is_sr1 ? ++ MII_RT_TX_IPG_100M_SR1 : MII_RT_TX_IPG_100M); + break; + case SPEED_10: +- /* IPG for 10M is same as 100M */ +- icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); ++ /* Firmware hardcodes IPG for SR1. SR2 same as 100M */ ++ if (!prueth->pdata.is_sr1) ++ icssg_mii_update_ipg(prueth->mii_rt, slice, ++ MII_RT_TX_IPG_100M); + break; + default: + /* Other links speeds not supported */ +@@ -221,6 +229,56 @@ void icssg_config_ipg(struct prueth_emac *emac) + } + } + ++/* SR1: Set buffer sizes for the pools. There are 8 internal queues ++ * implemented in firmware, but only 4 tx channels/threads in the Egress ++ * direction to firmware. Need a high priority queue for management ++ * messages since they shouldn't be blocked even during high traffic ++ * situation. So use Q0-Q2 as data queues and Q3 as management queue ++ * in the max case. However for ease of configuration, use the max ++ * data queue + 1 for management message if we are not using max ++ * case. ++ * ++ * Allocate 4 MTU buffers per data queue. Firmware requires ++ * pool sizes to be set for internal queues. Set the upper 5 queue ++ * pool size to min size of 128 bytes since there are only 3 tx ++ * data channels and management queue requires only minimum buffer. ++ * i.e lower queues are used by driver and highest priority queue ++ * from that is used for management message. ++ */ ++ ++static int emac_egress_buf_pool_size[] = { ++ PRUETH_EMAC_BUF_POOL_SIZE_SR1, PRUETH_EMAC_BUF_POOL_SIZE_SR1, ++ PRUETH_EMAC_BUF_POOL_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, ++ PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, ++ PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1, PRUETH_EMAC_BUF_POOL_MIN_SIZE_SR1}; ++ ++static void icssg_config_sr1(struct prueth *prueth, struct prueth_emac *emac, ++ int slice) ++{ ++ struct icssg_config_sr1 *config; ++ void __iomem *va; ++ int i, index; ++ ++ va = prueth->shram.va + slice * ICSSG_CONFIG_OFFSET_SLICE1; ++ config = &prueth->config[slice]; ++ memset(config, 0, sizeof(*config)); ++ config->addr_lo = cpu_to_le32(lower_32_bits(prueth->msmcram.pa)); ++ config->addr_hi = cpu_to_le32(upper_32_bits(prueth->msmcram.pa)); ++ config->num_tx_threads = 0; ++ config->rx_flow_id = emac->rx_flow_id_base; /* flow id for host port */ ++ config->rx_mgr_flow_id = emac->rx_mgm_flow_id_base; /* for mgm ch */ ++ config->rand_seed = get_random_u32(); ++ ++ for (i = PRUETH_EMAC_BUF_POOL_START_SR1; i < PRUETH_NUM_BUF_POOLS_SR1; i++) { ++ index = i - PRUETH_EMAC_BUF_POOL_START_SR1; ++ config->tx_buf_sz[i] = cpu_to_le32(emac_egress_buf_pool_size[index]); ++ } ++ ++ memcpy_toio(va, &prueth->config[slice], sizeof(prueth->config[slice])); ++ ++ emac->speed = SPEED_1000; ++} ++ + static void emac_r30_cmd_init(struct prueth_emac *emac) + { + struct icssg_r30_cmd __iomem *p; +@@ -331,6 +389,11 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice) + struct icssg_flow_cfg __iomem *flow_cfg; + int ret; + ++ if (prueth->pdata.is_sr1) { ++ icssg_config_sr1(prueth, emac, slice); ++ return 0; ++ } ++ + icssg_init_emac_mode(prueth); + + memset_io(config, 0, TAS_GATE_MASK_LIST0); +@@ -435,19 +498,32 @@ int emac_set_port_state(struct prueth_emac *emac, + + void icssg_config_half_duplex(struct prueth_emac *emac) + { ++ struct icssg_config_sr1 *config; ++ void __iomem *va; ++ int slice; + u32 val; + + if (!emac->half_duplex) + return; + + val = get_random_u32(); +- writel(val, emac->dram.va + HD_RAND_SEED_OFFSET); ++ if (emac->is_sr1) { ++ slice = prueth_emac_slice(emac); ++ va = emac->prueth->shram.va + slice * ICSSG_CONFIG_OFFSET_SLICE1; ++ config = (struct icssg_config_sr1 *)va; ++ writel(val, &config->rand_seed); ++ } else { ++ writel(val, emac->dram.va + HD_RAND_SEED_OFFSET); ++ } + } + + void icssg_config_set_speed(struct prueth_emac *emac) + { + u8 fw_speed; + ++ if (emac->is_sr1) ++ return; ++ + switch (emac->speed) { + case SPEED_1000: + fw_speed = FW_LINK_SPEED_1G; diff --git a/recipes-kernel/linux/files/patches-6.1/0090-net-ti-icssg-ethtool-Adjust-channel-count-for-SR1.0.patch b/recipes-kernel/linux/files/patches-6.1/0090-net-ti-icssg-ethtool-Adjust-channel-count-for-SR1.0.patch new file mode 100644 index 000000000..1384d9bae --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0090-net-ti-icssg-ethtool-Adjust-channel-count-for-SR1.0.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:15:00 +0100 +Subject: [PATCH] net: ti: icssg-ethtool: Adjust channel count for SR1.0 + +SR1.0 uses the highest priority channel to transmit control +messages to the firmware. Take this into account when computing +channels. + +Based on the work of Roger Quadros in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +index a27ec1dcc8d5..29e67526fa22 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +@@ -141,6 +141,9 @@ static int emac_set_channels(struct net_device *ndev, + return -EBUSY; + + emac->tx_ch_num = ch->tx_count; ++ /* highest channel number for management messaging on SR1 */ ++ if (emac->is_sr1) ++ emac->tx_ch_num++; + + return 0; + } +@@ -151,9 +154,12 @@ static void emac_get_channels(struct net_device *ndev, + struct prueth_emac *emac = netdev_priv(ndev); + + ch->max_rx = 1; +- ch->max_tx = PRUETH_MAX_TX_QUEUES; ++ /* SR1 use high priority channel for management messages */ ++ ch->max_tx = emac->is_sr1 ? PRUETH_MAX_TX_QUEUES - 1 : ++ PRUETH_MAX_TX_QUEUES; + ch->rx_count = 1; +- ch->tx_count = emac->tx_ch_num; ++ ch->tx_count = emac->is_sr1 ? emac->tx_ch_num - 1 : ++ emac->tx_ch_num; + } + + static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = { diff --git a/recipes-kernel/linux/files/patches-6.1/0091-net-ti-iccsg-prueth-Add-necessary-functions-for-SR1..patch b/recipes-kernel/linux/files/patches-6.1/0091-net-ti-iccsg-prueth-Add-necessary-functions-for-SR1..patch new file mode 100644 index 000000000..d99a70e78 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0091-net-ti-iccsg-prueth-Add-necessary-functions-for-SR1..patch @@ -0,0 +1,301 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:15:01 +0100 +Subject: [PATCH] net: ti: iccsg-prueth: Add necessary functions for SR1.0 + support + +Add functions required to correctly program the SR1.0 firmware for +network operation. + +Based on the work of Roger Quadros, Vignesh Raghavendra and +Grygorii Strashko in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 255 +++++++++++++++++++ + 1 file changed, 255 insertions(+) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 1f38e115e227..c7fd31c985b4 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -616,6 +616,101 @@ static int emac_get_tx_ts(struct prueth_emac *emac, + return 0; + } + ++static int emac_send_command_sr1(struct prueth_emac *emac, u32 cmd) ++{ ++ dma_addr_t desc_dma, buf_dma; ++ struct prueth_tx_chn *tx_chn; ++ struct cppi5_host_desc_t *first_desc; ++ u32 *data = emac->cmd_data; ++ u32 pkt_len = sizeof(emac->cmd_data); ++ void **swdata; ++ int ret = 0; ++ u32 *epib; ++ ++ netdev_dbg(emac->ndev, "Sending cmd %x\n", cmd); ++ ++ /* only one command at a time allowed to firmware */ ++ mutex_lock(&emac->cmd_lock); ++ data[0] = cpu_to_le32(cmd); ++ ++ /* highest priority channel for management messages */ ++ tx_chn = &emac->tx_chns[emac->tx_ch_num - 1]; ++ ++ /* Map the linear buffer */ ++ buf_dma = dma_map_single(tx_chn->dma_dev, data, pkt_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { ++ netdev_err(emac->ndev, "cmd %x: failed to map cmd buffer\n", cmd); ++ ret = -EINVAL; ++ goto err_unlock; ++ } ++ ++ first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); ++ if (!first_desc) { ++ netdev_err(emac->ndev, "cmd %x: failed to allocate descriptor\n", cmd); ++ dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); ++ ret = -ENOMEM; ++ goto err_unlock; ++ } ++ ++ cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, ++ PRUETH_NAV_PS_DATA_SIZE); ++ cppi5_hdesc_set_pkttype(first_desc, PRUETH_PKT_TYPE_CMD); ++ epib = first_desc->epib; ++ epib[0] = 0; ++ epib[1] = 0; ++ ++ cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); ++ swdata = cppi5_hdesc_get_swdata(first_desc); ++ *swdata = data; ++ ++ cppi5_hdesc_set_pktlen(first_desc, pkt_len); ++ desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); ++ ++ /* send command */ ++ reinit_completion(&emac->cmd_complete); ++ ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); ++ if (ret) { ++ netdev_err(emac->ndev, "cmd %x: push failed: %d\n", cmd, ret); ++ goto free_desc; ++ } ++ ret = wait_for_completion_timeout(&emac->cmd_complete, msecs_to_jiffies(100)); ++ if (!ret) ++ netdev_err(emac->ndev, "cmd %x: completion timeout\n", cmd); ++ ++ mutex_unlock(&emac->cmd_lock); ++ ++ return ret; ++free_desc: ++ prueth_xmit_free(tx_chn, first_desc); ++err_unlock: ++ mutex_unlock(&emac->cmd_lock); ++ ++ return ret; ++} ++ ++static void emac_change_port_speed_duplex_sr1(struct prueth_emac *emac) ++{ ++ u32 cmd = ICSSG_PSTATE_SPEED_DUPLEX_CMD, val; ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ ++ /* only full duplex supported for now */ ++ if (emac->duplex != DUPLEX_FULL) ++ return; ++ ++ val = icssg_rgmii_get_speed(prueth->miig_rt, slice); ++ /* firmware expects full duplex settings in bit 2-1 */ ++ val <<= 1; ++ cmd |= val; ++ ++ val = icssg_rgmii_get_fullduplex(prueth->miig_rt, slice); ++ /* firmware expects full duplex settings in bit 3 */ ++ val <<= 3; ++ cmd |= val; ++ ++ emac_send_command_sr1(emac, cmd); ++} ++ + static void tx_ts_work(struct prueth_emac *emac) + { + struct skb_shared_hwtstamps ssh; +@@ -873,6 +968,141 @@ static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++/* get one packet from requested flow_id ++ * ++ * Returns skb pointer if packet found else NULL ++ * Caller must free the returned skb. ++ */ ++static struct sk_buff *prueth_process_rx_mgm(struct prueth_emac *emac, ++ u32 flow_id) ++{ ++ struct prueth_rx_chn *rx_chn = &emac->rx_mgm_chn; ++ struct net_device *ndev = emac->ndev; ++ struct cppi5_host_desc_t *desc_rx; ++ struct sk_buff *skb, *new_skb; ++ dma_addr_t desc_dma, buf_dma; ++ u32 buf_dma_len, pkt_len; ++ void **swdata; ++ int ret; ++ ++ ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); ++ if (ret) { ++ if (ret != -ENODATA) ++ netdev_err(ndev, "rx mgm pop: failed: %d\n", ret); ++ return NULL; ++ } ++ ++ if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown */ ++ return NULL; ++ ++ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); ++ ++ /* Fix FW bug about incorrect PSDATA size */ ++ if (cppi5_hdesc_get_psdata_size(desc_rx) != PRUETH_NAV_PS_DATA_SIZE) { ++ cppi5_hdesc_update_psdata_size(desc_rx, ++ PRUETH_NAV_PS_DATA_SIZE); ++ } ++ ++ swdata = cppi5_hdesc_get_swdata(desc_rx); ++ skb = *swdata; ++ cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); ++ pkt_len = cppi5_hdesc_get_pktlen(desc_rx); ++ ++ dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); ++ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); ++ ++ new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE); ++ /* if allocation fails we drop the packet but push the ++ * descriptor back to the ring with old skb to prevent a stall ++ */ ++ if (!new_skb) { ++ netdev_err(ndev, ++ "skb alloc failed, dropped mgm pkt from flow %d\n", ++ flow_id); ++ new_skb = skb; ++ skb = NULL; /* return NULL */ ++ } else { ++ /* return the filled skb */ ++ skb_put(skb, pkt_len); ++ } ++ ++ /* queue another DMA */ ++ ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_mgm_chn); ++ if (WARN_ON(ret < 0)) ++ dev_kfree_skb_any(new_skb); ++ ++ return skb; ++} ++ ++static void prueth_tx_ts_sr1(struct prueth_emac *emac, ++ struct emac_tx_ts_response_sr1 *tsr) ++{ ++ u64 ns; ++ struct skb_shared_hwtstamps ssh; ++ struct sk_buff *skb; ++ ++ ns = (u64)tsr->hi_ts << 32 | tsr->lo_ts; ++ ++ if (tsr->cookie >= PRUETH_MAX_TX_TS_REQUESTS) { ++ netdev_dbg(emac->ndev, "Invalid TX TS cookie 0x%x\n", ++ tsr->cookie); ++ return; ++ } ++ ++ skb = emac->tx_ts_skb[tsr->cookie]; ++ emac->tx_ts_skb[tsr->cookie] = NULL; /* free slot */ ++ ++ memset(&ssh, 0, sizeof(ssh)); ++ ssh.hwtstamp = ns_to_ktime(ns); ++ ++ skb_tstamp_tx(skb, &ssh); ++ dev_consume_skb_any(skb); ++} ++ ++static irqreturn_t prueth_rx_mgm_ts_thread_sr1(int irq, void *dev_id) ++{ ++ struct prueth_emac *emac = dev_id; ++ struct sk_buff *skb; ++ ++ skb = prueth_process_rx_mgm(emac, PRUETH_RX_MGM_FLOW_TIMESTAMP); ++ if (!skb) ++ return IRQ_NONE; ++ ++ prueth_tx_ts_sr1(emac, (void *)skb->data); ++ dev_kfree_skb_any(skb); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t prueth_rx_mgm_rsp_thread(int irq, void *dev_id) ++{ ++ struct prueth_emac *emac = dev_id; ++ struct sk_buff *skb; ++ u32 rsp; ++ ++ skb = prueth_process_rx_mgm(emac, PRUETH_RX_MGM_FLOW_RESPONSE); ++ if (!skb) ++ return IRQ_NONE; ++ ++ /* Process command response */ ++ rsp = le32_to_cpu(*(u32 *)skb->data); ++ if ((rsp & 0xffff0000) == ICSSG_SHUTDOWN_CMD) { ++ netdev_dbg(emac->ndev, ++ "f/w Shutdown cmd resp %x\n", rsp); ++ complete(&emac->cmd_complete); ++ } else if ((rsp & 0xffff0000) == ++ ICSSG_PSTATE_SPEED_DUPLEX_CMD) { ++ netdev_dbg(emac->ndev, ++ "f/w Speed/Duplex cmd rsp %x\n", ++ rsp); ++ complete(&emac->cmd_complete); ++ } ++ ++ dev_kfree_skb_any(skb); ++ ++ return IRQ_HANDLED; ++} ++ + static irqreturn_t prueth_rx_irq(int irq, void *dev_id) + { + struct prueth_emac *emac = dev_id; +@@ -1517,6 +1747,31 @@ static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) + ndev->stats.tx_errors++; + } + ++static void emac_ndo_set_rx_mode_sr1(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ bool promisc = ndev->flags & IFF_PROMISC; ++ bool allmulti = ndev->flags & IFF_ALLMULTI; ++ ++ if (promisc) { ++ icssg_class_promiscuous_sr1(prueth->miig_rt, slice); ++ return; ++ } ++ ++ if (allmulti) { ++ icssg_class_default(prueth->miig_rt, slice, 1, true); ++ return; ++ } ++ ++ icssg_class_default(prueth->miig_rt, slice, 0, true); ++ if (!netdev_mc_empty(ndev)) { ++ /* program multicast address list into Classifier */ ++ icssg_class_add_mcast_sr1(prueth->miig_rt, slice, ndev); ++ } ++} ++ + static void emac_ndo_set_rx_mode_work(struct work_struct *work) + { + struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work); diff --git a/recipes-kernel/linux/files/patches-6.1/0092-net-ti-icssg-prueth-Wire-up-support-for-SR1.0.patch b/recipes-kernel/linux/files/patches-6.1/0092-net-ti-icssg-prueth-Wire-up-support-for-SR1.0.patch new file mode 100644 index 000000000..b220e9b6d --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0092-net-ti-icssg-prueth-Wire-up-support-for-SR1.0.patch @@ -0,0 +1,613 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diogo Ivo +Date: Wed, 17 Jan 2024 17:15:02 +0100 +Subject: [PATCH] net: ti: icssg-prueth: Wire up support for SR1.0 + +Add the function calls to enable operation for SR1.0. + +Based on the work of Roger Quadros, Vignesh Raghavendra and +Grygorii Strashko in TI's 5.10 SDK [1]. + +[1]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/?h=ti-linux-5.10.y + +Co-developed-by: Jan Kiszka +Signed-off-by: Jan Kiszka +Signed-off-by: Diogo Ivo +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 299 +++++++++++++++---- + 1 file changed, 239 insertions(+), 60 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index c7fd31c985b4..e8d5406fcdbb 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -169,6 +169,13 @@ static int emac_tx_complete_packets(struct prueth_emac *emac, int chn, + desc_dma); + swdata = cppi5_hdesc_get_swdata(desc_tx); + ++ /* was this command's TX complete? */ ++ if (emac->is_sr1 && *(swdata) == emac->cmd_data) { ++ prueth_xmit_free(tx_chn, desc_tx); ++ budget++; /* not a data packet */ ++ continue; ++ } ++ + skb = *(swdata); + prueth_xmit_free(tx_chn, desc_tx); + +@@ -344,6 +351,7 @@ static int prueth_init_rx_chns(struct prueth_emac *emac, + struct net_device *ndev = emac->ndev; + u32 fdqring_id, hdesc_size; + int i, ret = 0, slice; ++ int flow_id_base; + + slice = prueth_emac_slice(emac); + if (slice < 0) +@@ -384,8 +392,14 @@ static int prueth_init_rx_chns(struct prueth_emac *emac, + goto fail; + } + +- emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); +- netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base); ++ flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); ++ if (!strcmp(name, "rxmgm")) { ++ emac->rx_mgm_flow_id_base = flow_id_base; ++ netdev_dbg(ndev, "mgm flow id base = %d\n", flow_id_base); ++ } else { ++ emac->rx_flow_id_base = flow_id_base; ++ netdev_dbg(ndev, "flow id base = %d\n", flow_id_base); ++ } + + fdqring_id = K3_RINGACC_RING_ID_ANY; + for (i = 0; i < rx_cfg.flow_id_num; i++) { +@@ -494,10 +508,14 @@ static void emac_rx_timestamp(struct prueth_emac *emac, + struct skb_shared_hwtstamps *ssh; + u64 ns; + +- u32 hi_sw = readl(emac->prueth->shram.va + +- TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); +- ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0], +- IEP_DEFAULT_CYCLE_TIME_NS); ++ if (emac->is_sr1) { ++ ns = (u64)psdata[1] << 32 | psdata[0]; ++ } else { ++ u32 hi_sw = readl(emac->prueth->shram.va + ++ TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); ++ ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0], ++ IEP_DEFAULT_CYCLE_TIME_NS); ++ } + + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); +@@ -1119,6 +1137,17 @@ struct icssg_firmwares { + char *txpru; + }; + ++static struct icssg_firmwares icssg_emac_firmwares_sr1[] = { ++ { ++ .pru = "ti-pruss/am65x-pru0-prueth-fw.elf", ++ .rtu = "ti-pruss/am65x-rtu0-prueth-fw.elf", ++ }, ++ { ++ .pru = "ti-pruss/am65x-pru1-prueth-fw.elf", ++ .rtu = "ti-pruss/am65x-rtu1-prueth-fw.elf", ++ } ++}; ++ + static struct icssg_firmwares icssg_emac_firmwares[] = { + { + .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", +@@ -1138,7 +1167,8 @@ static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac) + struct device *dev = prueth->dev; + int slice, ret; + +- firmwares = icssg_emac_firmwares; ++ firmwares = prueth->pdata.is_sr1 ? icssg_emac_firmwares_sr1 ++ : icssg_emac_firmwares; + + slice = prueth_emac_slice(emac); + if (slice < 0) { +@@ -1164,11 +1194,15 @@ static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac) + goto halt_pru; + } + +- ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru); +- ret = rproc_boot(prueth->txpru[slice]); +- if (ret) { +- dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret); +- goto halt_rtu; ++ if (!emac->is_sr1) { ++ ret = rproc_set_firmware(prueth->txpru[slice], ++ firmwares[slice].txpru); ++ ret = rproc_boot(prueth->txpru[slice]); ++ if (ret) { ++ dev_err(dev, "failed to boot TX_PRU%d: %d\n", ++ slice, ret); ++ goto halt_rtu; ++ } + } + + emac->fw_running = 1; +@@ -1201,7 +1235,8 @@ static void prueth_emac_stop(struct prueth_emac *emac) + } + + emac->fw_running = 0; +- rproc_shutdown(prueth->txpru[slice]); ++ if (!emac->is_sr1) ++ rproc_shutdown(prueth->txpru[slice]); + rproc_shutdown(prueth->rtu[slice]); + rproc_shutdown(prueth->pru[slice]); + } +@@ -1269,11 +1304,15 @@ static void emac_adjust_link(struct net_device *ndev) + icssg_config_ipg(emac); + spin_unlock_irqrestore(&emac->lock, flags); + icssg_config_set_speed(emac); +- emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD); ++ if (!emac->is_sr1) ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD); + +- } else { ++ } else if (!emac->is_sr1) { + emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE); + } ++ ++ if (emac->is_sr1 && emac->link) ++ emac_change_port_speed_duplex_sr1(emac); + } + + if (emac->link) { +@@ -1288,8 +1327,10 @@ static void emac_adjust_link(struct net_device *ndev) + static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget) + { + struct prueth_emac *emac = prueth_napi_to_emac(napi_rx); +- int rx_flow = PRUETH_RX_FLOW_DATA; +- int flow = PRUETH_MAX_RX_FLOWS; ++ int rx_flow = emac->is_sr1 ? ++ PRUETH_RX_FLOW_DATA_SR1 : PRUETH_RX_FLOW_DATA; ++ int flow = emac->is_sr1 ? ++ PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS; + int num_rx = 0; + int cur_budget; + int ret; +@@ -1553,11 +1594,19 @@ static int emac_ndo_open(struct net_device *ndev) + memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS); + } + ++ if (emac->is_sr1) { ++ /* For SR1, high priority channel is used exclusively for ++ * management messages. Do reduce number of data channels. ++ */ ++ num_data_chn--; ++ } ++ + /* set h/w MAC as user might have re-configured */ + ether_addr_copy(emac->mac_addr, ndev->dev_addr); + + icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); +- icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); ++ if (!emac->is_sr1) ++ icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); + + icssg_class_default(prueth->miig_rt, slice, 0, emac->is_sr1); + +@@ -1575,7 +1624,8 @@ static int emac_ndo_open(struct net_device *ndev) + return ret; + } + +- max_rx_flows = PRUETH_MAX_RX_FLOWS; ++ max_rx_flows = emac->is_sr1 ? ++ PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS; + ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx", + max_rx_flows, PRUETH_MAX_RX_DESC); + if (ret) { +@@ -1583,12 +1633,24 @@ static int emac_ndo_open(struct net_device *ndev) + goto cleanup_tx; + } + ++ if (emac->is_sr1) { ++ ret = prueth_init_rx_chns(emac, &emac->rx_mgm_chn, "rxmgm", ++ PRUETH_MAX_RX_MGM_FLOWS, ++ PRUETH_MAX_RX_MGM_DESC); ++ if (ret) { ++ dev_err(dev, "failed to init rx mgmt channel: %d\n", ++ ret); ++ goto cleanup_rx; ++ } ++ } ++ + ret = prueth_ndev_add_tx_napi(emac); + if (ret) +- goto cleanup_rx; ++ goto cleanup_rx_mgm; + + /* we use only the highest priority flow for now i.e. @irq[3] */ +- rx_flow = PRUETH_RX_FLOW_DATA; ++ rx_flow = emac->is_sr1 ? ++ PRUETH_RX_FLOW_DATA_SR1 : PRUETH_RX_FLOW_DATA; + ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq, + IRQF_TRIGGER_HIGH, dev_name(dev), emac); + if (ret) { +@@ -1596,31 +1658,66 @@ static int emac_ndo_open(struct net_device *ndev) + goto cleanup_napi; + } + ++ if (!emac->is_sr1) ++ goto skip_mgm_irq; ++ ++ ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE], ++ NULL, prueth_rx_mgm_rsp_thread, ++ IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ dev_name(dev), emac); ++ if (ret) { ++ dev_err(dev, "unable to request RX Management RSP IRQ\n"); ++ goto free_rx_irq; ++ } ++ ++ ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP], ++ NULL, prueth_rx_mgm_ts_thread_sr1, ++ IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ++ dev_name(dev), emac); ++ if (ret) { ++ dev_err(dev, "unable to request RX Management TS IRQ\n"); ++ goto free_rx_mgm_rsp_irq; ++ } ++ ++skip_mgm_irq: + /* reset and start PRU firmware */ + ret = prueth_emac_start(prueth, emac); + if (ret) +- goto free_rx_irq; ++ goto free_rx_mgmt_ts_irq; + + icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu); + +- if (!prueth->emacs_initialized) { ++ if (!emac->is_sr1 && !prueth->emacs_initialized) { + ret = icss_iep_init(emac->iep, &prueth_iep_clockops, + emac, IEP_DEFAULT_CYCLE_TIME_NS); + } + +- ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq, +- IRQF_ONESHOT, dev_name(dev), emac); +- if (ret) +- goto stop; ++ if (!emac->is_sr1) { ++ ret = request_threaded_irq(emac->tx_ts_irq, NULL, ++ prueth_tx_ts_irq, IRQF_ONESHOT, ++ dev_name(dev), emac); ++ if (ret) ++ goto stop; ++ } + + /* Prepare RX */ + ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE); + if (ret) + goto free_tx_ts_irq; + ++ if (emac->is_sr1) { ++ ret = prueth_prepare_rx_chan(emac, &emac->rx_mgm_chn, 64); ++ if (ret) ++ goto reset_rx_chn; ++ ++ ret = k3_udma_glue_enable_rx_chn(emac->rx_mgm_chn.rx_chn); ++ if (ret) ++ goto reset_rx_chn; ++ } ++ + ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn); + if (ret) +- goto reset_rx_chn; ++ goto reset_rx_mgm_chn; + + for (i = 0; i < emac->tx_ch_num; i++) { + ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn); +@@ -1647,16 +1744,33 @@ static int emac_ndo_open(struct net_device *ndev) + * any SKB for completion. So set false to free_skb + */ + prueth_reset_tx_chan(emac, i, false); ++reset_rx_mgm_chn: ++ if (emac->is_sr1) ++ prueth_reset_rx_chan(&emac->rx_mgm_chn, ++ PRUETH_MAX_RX_MGM_FLOWS, true); + reset_rx_chn: + prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false); + free_tx_ts_irq: +- free_irq(emac->tx_ts_irq, emac); ++ if (!emac->is_sr1) ++ free_irq(emac->tx_ts_irq, emac); + stop: + prueth_emac_stop(emac); ++free_rx_mgmt_ts_irq: ++ if (emac->is_sr1) ++ free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP], ++ emac); ++free_rx_mgm_rsp_irq: ++ if (emac->is_sr1) ++ free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE], ++ emac); + free_rx_irq: + free_irq(emac->rx_chns.irq[rx_flow], emac); + cleanup_napi: + prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); ++cleanup_rx_mgm: ++ if (emac->is_sr1) ++ prueth_cleanup_rx_chns(emac, &emac->rx_mgm_chn, ++ PRUETH_MAX_RX_MGM_FLOWS); + cleanup_rx: + prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); + cleanup_tx: +@@ -1677,7 +1791,8 @@ static int emac_ndo_stop(struct net_device *ndev) + { + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; +- int rx_flow = PRUETH_RX_FLOW_DATA; ++ int rx_flow = emac->is_sr1 ? PRUETH_RX_FLOW_DATA_SR1 : ++ PRUETH_RX_FLOW_DATA; + int max_rx_flows; + int ret, i; + +@@ -1690,6 +1805,9 @@ static int emac_ndo_stop(struct net_device *ndev) + + icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac)); + ++ if (emac->is_sr1) ++ emac_send_command_sr1(emac, ICSSG_SHUTDOWN_CMD); ++ + atomic_set(&emac->tdown_cnt, emac->tx_ch_num); + /* ensure new tdown_cnt value is visible */ + smp_mb__after_atomic(); +@@ -1707,10 +1825,17 @@ static int emac_ndo_stop(struct net_device *ndev) + for (i = 0; i < emac->tx_ch_num; i++) + napi_disable(&emac->tx_chns[i].napi_tx); + +- max_rx_flows = PRUETH_MAX_RX_FLOWS; ++ max_rx_flows = emac->is_sr1 ? ++ PRUETH_MAX_RX_FLOWS_SR1 : PRUETH_MAX_RX_FLOWS; + k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true); + + prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true); ++ if (emac->is_sr1) { ++ /* Teardown RX MGM channel */ ++ k3_udma_glue_tdown_rx_chn(emac->rx_mgm_chn.rx_chn, true); ++ prueth_reset_rx_chan(&emac->rx_mgm_chn, ++ PRUETH_MAX_RX_MGM_FLOWS, true); ++ } + + napi_disable(&emac->napi_rx); + +@@ -1722,18 +1847,28 @@ static int emac_ndo_stop(struct net_device *ndev) + /* stop PRUs */ + prueth_emac_stop(emac); + +- if (prueth->emacs_initialized == 1) ++ if (!emac->is_sr1 && prueth->emacs_initialized == 1) + icss_iep_exit(emac->iep); + + /* stop PRUs */ + prueth_emac_stop(emac); + +- free_irq(emac->tx_ts_irq, emac); ++ if (!emac->is_sr1) ++ free_irq(emac->tx_ts_irq, emac); + ++ if (emac->is_sr1) { ++ free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP], ++ emac); ++ free_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE], ++ emac); ++ } + free_irq(emac->rx_chns.irq[rx_flow], emac); + prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); + prueth_cleanup_tx_chns(emac); + ++ if (emac->is_sr1) ++ prueth_cleanup_rx_chns(emac, &emac->rx_mgm_chn, ++ PRUETH_MAX_RX_MGM_FLOWS); + prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); + prueth_cleanup_tx_chns(emac); + +@@ -1814,7 +1949,10 @@ static void emac_ndo_set_rx_mode(struct net_device *ndev) + { + struct prueth_emac *emac = netdev_priv(ndev); + +- queue_work(emac->cmd_wq, &emac->rx_mode_work); ++ if (emac->is_sr1) ++ emac_ndo_set_rx_mode_sr1(ndev); ++ else ++ queue_work(emac->cmd_wq, &emac->rx_mode_work); + } + + static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr) +@@ -1994,6 +2132,10 @@ static int prueth_netdev_init(struct prueth *prueth, + if (mac == PRUETH_MAC_INVALID) + return -EINVAL; + ++ /* Use 1 channel for management messages on SR1 */ ++ if (prueth->pdata.is_sr1) ++ num_tx_chn--; ++ + ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn); + if (!ndev) + return -ENOMEM; +@@ -2021,7 +2163,15 @@ static int prueth_netdev_init(struct prueth *prueth, + goto free_wq; + } + ++ emac->is_sr1 = prueth->pdata.is_sr1; + emac->tx_ch_num = 1; ++ if (emac->is_sr1) { ++ /* use a dedicated high priority channel for management ++ * messages which is +1 of highest priority data channel. ++ */ ++ emac->tx_ch_num++; ++ goto skip_irq; ++ } + + irq_name = "tx_ts0"; + if (emac->port_id == PRUETH_PORT_MII1) +@@ -2032,6 +2182,7 @@ static int prueth_netdev_init(struct prueth *prueth, + goto free; + } + ++skip_irq: + SET_NETDEV_DEV(ndev, prueth->dev); + spin_lock_init(&emac->lock); + mutex_init(&emac->cmd_lock); +@@ -2158,7 +2309,7 @@ static int prueth_get_cores(struct prueth *prueth, int slice) + idx = 0; + break; + case ICSS_SLICE1: +- idx = 3; ++ idx = prueth->pdata.is_sr1 ? 2 : 3; + break; + default: + return -EINVAL; +@@ -2180,6 +2331,9 @@ static int prueth_get_cores(struct prueth *prueth, int slice) + return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice); + } + ++ if (prueth->pdata.is_sr1) ++ return 0; ++ + idx++; + prueth->txpru[slice] = pru_rproc_get(np, idx, NULL); + if (IS_ERR(prueth->txpru[slice])) { +@@ -2336,14 +2490,20 @@ static int prueth_probe(struct platform_device *pdev) + goto put_mem; + } + +- msmc_ram_size = MSMC_RAM_SIZE; ++ msmc_ram_size = prueth->pdata.is_sr1 ? MSMC_RAM_SIZE_SR1 : MSMC_RAM_SIZE; + +- /* NOTE: FW bug needs buffer base to be 64KB aligned */ +- prueth->msmcram.va = +- (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool, +- msmc_ram_size, +- gen_pool_first_fit_align, +- &gp_data); ++ if (prueth->pdata.is_sr1) { ++ prueth->msmcram.va = ++ (void __iomem *)gen_pool_alloc(prueth->sram_pool, ++ msmc_ram_size); ++ } else { ++ /* NOTE: FW bug needs buffer base to be 64KB aligned */ ++ prueth->msmcram.va = ++ (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool, ++ msmc_ram_size, ++ gen_pool_first_fit_align, ++ &gp_data); ++ } + + if (!prueth->msmcram.va) { + ret = -ENOMEM; +@@ -2357,17 +2517,19 @@ static int prueth_probe(struct platform_device *pdev) + dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa, + prueth->msmcram.va, prueth->msmcram.size); + +- prueth->iep0 = icss_iep_get_idx(np, 0); +- if (IS_ERR(prueth->iep0)) { +- ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n"); +- prueth->iep0 = NULL; +- goto free_pool; +- } ++ if (!prueth->pdata.is_sr1) { ++ prueth->iep0 = icss_iep_get_idx(np, 0); ++ if (IS_ERR(prueth->iep0)) { ++ ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n"); ++ prueth->iep0 = NULL; ++ goto free_pool; ++ } + +- prueth->iep1 = icss_iep_get_idx(np, 1); +- if (IS_ERR(prueth->iep1)) { +- ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n"); +- goto put_iep0; ++ prueth->iep1 = icss_iep_get_idx(np, 1); ++ if (IS_ERR(prueth->iep1)) { ++ ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n"); ++ goto put_iep0; ++ } + } + + if (prueth->pdata.quirk_10m_link_issue) { +@@ -2389,7 +2551,8 @@ static int prueth_probe(struct platform_device *pdev) + if (of_find_property(eth0_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC0]->half_duplex = 1; + +- prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; ++ if (!prueth->pdata.is_sr1) ++ prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; + } + + if (eth1_node) { +@@ -2403,7 +2566,8 @@ static int prueth_probe(struct platform_device *pdev) + if (of_find_property(eth1_node, "ti,half-duplex-capable", NULL)) + prueth->emac[PRUETH_MAC1]->half_duplex = 1; + +- prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; ++ if (!prueth->pdata.is_sr1) ++ prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; + } + + /* register the network devices */ +@@ -2464,10 +2628,13 @@ static int prueth_probe(struct platform_device *pdev) + exit_iep: + if (prueth->pdata.quirk_10m_link_issue) + icss_iep_exit_fw(prueth->iep1); +- icss_iep_put(prueth->iep1); ++ ++ if (!prueth->pdata.is_sr1) ++ icss_iep_put(prueth->iep1); + + put_iep0: +- icss_iep_put(prueth->iep0); ++ if (!prueth->pdata.is_sr1) ++ icss_iep_put(prueth->iep0); + prueth->iep0 = NULL; + prueth->iep1 = NULL; + +@@ -2518,15 +2685,21 @@ static void prueth_remove(struct platform_device *pdev) + prueth_netdev_exit(prueth, eth_node); + } + +- if (prueth->pdata.quirk_10m_link_issue) ++ if (prueth->pdata.is_sr1) { ++ icss_iep_exit(prueth->iep1); ++ icss_iep_exit(prueth->iep0); ++ } else if (prueth->pdata.quirk_10m_link_issue) { + icss_iep_exit_fw(prueth->iep1); ++ } + +- icss_iep_put(prueth->iep1); +- icss_iep_put(prueth->iep0); ++ if (!prueth->pdata.is_sr1) { ++ icss_iep_put(prueth->iep1); ++ icss_iep_put(prueth->iep0); ++ } + + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, +- MSMC_RAM_SIZE); ++ prueth->pdata.is_sr1 ? MSMC_RAM_SIZE_SR1 : MSMC_RAM_SIZE); + + pruss_release_mem_region(prueth->pruss, &prueth->shram); + +@@ -2595,12 +2768,18 @@ static const struct dev_pm_ops prueth_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume) + }; + ++static const struct prueth_pdata am654_icssg_pdata_sr1 = { ++ .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, ++ .is_sr1 = 1, ++}; ++ + static const struct prueth_pdata am654_icssg_pdata = { + .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, + .quirk_10m_link_issue = 1, + }; + + static const struct of_device_id prueth_dt_match[] = { ++ { .compatible = "ti,am654-sr1-icssg-prueth", .data = &am654_icssg_pdata_sr1 }, + { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata }, + { /* sentinel */ } + }; diff --git a/recipes-kernel/linux/files/patches-6.1/0093-net-ti-icss_iep-Add-SR1-support.patch b/recipes-kernel/linux/files/patches-6.1/0093-net-ti-icss_iep-Add-SR1-support.patch new file mode 100644 index 000000000..43a9026f5 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0093-net-ti-icss_iep-Add-SR1-support.patch @@ -0,0 +1,209 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Fri, 3 Nov 2023 12:18:44 +0100 +Subject: [PATCH] net: ti: icss_iep: Add SR1 support + +This brings SR1 support to the Industrial Ethernet Peripheral driver so +that PTP and PPS is working with that revision as well. + +Forward-ported from the TI SDK. + +Signed-off-by: Jan Kiszka +--- + drivers/net/ethernet/ti/icssg/icss_iep.c | 116 ++++++++++++++++++++++- + 1 file changed, 114 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c +index 4cf2a52e4378..b208042c381a 100644 +--- a/drivers/net/ethernet/ti/icssg/icss_iep.c ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.c +@@ -32,6 +32,7 @@ + + #define IEP_GLOBAL_STATUS_CNT_OVF BIT(0) + ++#define CMP_INDEX(sync) ((sync) + 1) + #define IEP_CMP_CFG_SHADOW_EN BIT(17) + #define IEP_CMP_CFG_CMP0_RST_CNT_EN BIT(0) + #define IEP_CMP_CFG_CMP_EN(cmp) (GENMASK(16, 1) & (1 << ((cmp) + 1))) +@@ -122,6 +123,7 @@ struct icss_iep { + int cap_cmp_irq; + u64 period; + u32 latch_enable; ++ struct hrtimer sync_timer; + }; + + /** +@@ -560,6 +562,8 @@ static int icss_iep_perout_enable(struct icss_iep *iep, + goto exit; + + spin_lock_irqsave(&iep->irq_lock, flags); ++ if (iep->cap_cmp_irq) ++ hrtimer_cancel(&iep->sync_timer); + ret = icss_iep_perout_enable_hw(iep, req, on); + if (!ret) + iep->perout_enabled = !!on; +@@ -571,6 +575,80 @@ static int icss_iep_perout_enable(struct icss_iep *iep, + return ret; + } + ++static irqreturn_t icss_iep_cap_cmp_handler(int irq, void *dev_id) ++{ ++ struct icss_iep *iep = (struct icss_iep *)dev_id; ++ unsigned int val, index = 0, i, sts; ++ struct ptp_clock_event pevent; ++ irqreturn_t ret = IRQ_NONE; ++ unsigned long flags; ++ u64 ns, ns_next; ++ ++ spin_lock_irqsave(&iep->irq_lock, flags); ++ ++ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP_STAT_REG]); ++ if (val & BIT(CMP_INDEX(index))) { ++ writel(BIT(CMP_INDEX(index)), ++ iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP_STAT_REG]); ++ ++ if (!iep->pps_enabled && !iep->perout_enabled) ++ goto do_latch; ++ ++ ns = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP1_REG0]); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) { ++ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP1_REG1]); ++ ns |= (u64)val << 32; ++ } ++ /* set next event */ ++ ns_next = ns + iep->period; ++ writel(lower_32_bits(ns_next), ++ iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP1_REG0]); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ writel(upper_32_bits(ns_next), ++ iep->base + iep->plat_data->reg_offs[ICSS_IEP_CMP1_REG1]); ++ ++ pevent.pps_times.ts_real = ns_to_timespec64(ns); ++ pevent.type = PTP_CLOCK_PPSUSR; ++ pevent.index = index; ++ ptp_clock_event(iep->ptp_clock, &pevent); ++ dev_dbg(iep->dev, "IEP:pps ts: %llu next:%llu:\n", ns, ns_next); ++ ++ hrtimer_start(&iep->sync_timer, ms_to_ktime(110), /* 100ms + buffer */ ++ HRTIMER_MODE_REL); ++ ++ ret = IRQ_HANDLED; ++ } ++ ++do_latch: ++ sts = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_CAPTURE_STAT_REG]); ++ if (!sts) ++ goto cap_cmp_exit; ++ ++ for (i = 0; i < iep->ptp_info.n_ext_ts; i++) { ++ if (sts & IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(i * 2)) { ++ ns = readl(iep->base + ++ iep->plat_data->reg_offs[ICSS_IEP_CAP6_RISE_REG0 + ++ (i * 2)]); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) { ++ val = readl(iep->base + ++ iep->plat_data->reg_offs[ICSS_IEP_CAP6_RISE_REG0 + ++ (i * 2) + 1]); ++ ns |= (u64)val << 32; ++ } ++ pevent.timestamp = ns; ++ pevent.type = PTP_CLOCK_EXTTS; ++ pevent.index = i; ++ ptp_clock_event(iep->ptp_clock, &pevent); ++ dev_dbg(iep->dev, "IEP:extts index=%d ts: %llu\n", i, ns); ++ ret = IRQ_HANDLED; ++ } ++ } ++ ++cap_cmp_exit: ++ spin_unlock_irqrestore(&iep->irq_lock, flags); ++ return ret; ++} ++ + static int icss_iep_pps_enable(struct icss_iep *iep, int on) + { + struct ptp_clock_request rq; +@@ -601,6 +679,8 @@ static int icss_iep_pps_enable(struct icss_iep *iep, int on) + rq.perout.start.nsec = 0; + ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); + } else { ++ if (iep->cap_cmp_irq) ++ hrtimer_cancel(&iep->sync_timer); + ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); + } + +@@ -676,6 +756,18 @@ static struct ptp_clock_info icss_iep_ptp_info = { + .enable = icss_iep_ptp_enable, + }; + ++static enum hrtimer_restart icss_iep_sync0_work(struct hrtimer *timer) ++{ ++ struct icss_iep *iep = container_of(timer, struct icss_iep, sync_timer); ++ ++ writel(0, iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); ++ writel(IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN, ++ iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); ++ writel(1, iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC0_STAT_REG]); ++ ++ return HRTIMER_NORESTART; ++} ++ + struct icss_iep *icss_iep_get_idx(struct device_node *np, int idx) + { + struct platform_device *pdev; +@@ -724,6 +816,8 @@ void icss_iep_put(struct icss_iep *iep) + iep->client_np = NULL; + device_unlock(iep->dev); + put_device(iep->dev); ++ if (iep->cap_cmp_irq) ++ hrtimer_cancel(&iep->sync_timer); + } + EXPORT_SYMBOL_GPL(icss_iep_put); + +@@ -774,12 +868,12 @@ int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops, + !(iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)) + goto skip_perout; + +- if (iep->ops && iep->ops->perout_enable) { ++ if (iep->cap_cmp_irq || (iep->ops && iep->ops->perout_enable)) { + iep->ptp_info.n_per_out = 1; + iep->ptp_info.pps = 1; + } + +- if (iep->ops && iep->ops->extts_enable) ++ if (iep->cap_cmp_irq || (iep->ops && iep->ops->extts_enable)) + iep->ptp_info.n_ext_ts = 2; + + skip_perout: +@@ -817,6 +911,7 @@ static int icss_iep_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct icss_iep *iep; + struct clk *iep_clk; ++ int ret; + + iep = devm_kzalloc(dev, sizeof(*iep), GFP_KERNEL); + if (!iep) +@@ -827,6 +922,23 @@ static int icss_iep_probe(struct platform_device *pdev) + if (IS_ERR(iep->base)) + return -ENODEV; + ++ iep->cap_cmp_irq = platform_get_irq_byname_optional(pdev, "iep_cap_cmp"); ++ if (iep->cap_cmp_irq < 0) { ++ if (iep->cap_cmp_irq == -EPROBE_DEFER) ++ return iep->cap_cmp_irq; ++ iep->cap_cmp_irq = 0; ++ } else { ++ ret = devm_request_irq(dev, iep->cap_cmp_irq, ++ icss_iep_cap_cmp_handler, IRQF_TRIGGER_HIGH, ++ "iep_cap_cmp", iep); ++ if (ret) { ++ dev_err(iep->dev, "Request irq failed for cap_cmp %d\n", ret); ++ return ret; ++ } ++ hrtimer_init(&iep->sync_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ iep->sync_timer.function = icss_iep_sync0_work; ++ } ++ + iep_clk = devm_clk_get(dev, NULL); + if (IS_ERR(iep_clk)) + return PTR_ERR(iep_clk); diff --git a/recipes-kernel/linux/files/patches-6.1/0094-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch b/recipes-kernel/linux/files/patches-6.1/0094-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch new file mode 100644 index 000000000..00ed368e4 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0094-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Thu, 2 Nov 2023 21:25:23 +0100 +Subject: [PATCH] arm64: dts: ti: iot2050: Add icssg-prueth nodes for PG1 + devices + +Enable prueth for SR1-based IOT2050 variants in their device trees now +that the driver supports this. + +Signed-off-by: Jan Kiszka +--- + .../dts/ti/k3-am65-iot2050-common-pg1.dtsi | 42 +++++++++++++++++-- + 1 file changed, 39 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi +index 1d1979859583..84018bd74737 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi +@@ -46,9 +46,45 @@ &tx_pru2_1 { + }; + + &icssg0_eth { +- status = "disabled"; ++ compatible = "ti,am654-sr1-icssg-prueth"; ++ ++ ti,prus = <&pru0_0>, <&rtu0_0>, <&pru0_1>, <&rtu0_1>; ++ firmware-name = "ti-pruss/am65x-pru0-prueth-fw.elf", ++ "ti-pruss/am65x-rtu0-prueth-fw.elf", ++ "ti-pruss/am65x-pru1-prueth-fw.elf", ++ "ti-pruss/am65x-rtu1-prueth-fw.elf"; ++ ++ ti,pruss-gp-mux-sel = <2>, /* MII mode */ ++ <2>, ++ <2>, /* MII mode */ ++ <2>; ++ ++ dmas = <&main_udmap 0xc100>, /* egress slice 0 */ ++ <&main_udmap 0xc101>, /* egress slice 0 */ ++ <&main_udmap 0xc102>, /* egress slice 0 */ ++ <&main_udmap 0xc103>, /* egress slice 0 */ ++ <&main_udmap 0xc104>, /* egress slice 1 */ ++ <&main_udmap 0xc105>, /* egress slice 1 */ ++ <&main_udmap 0xc106>, /* egress slice 1 */ ++ <&main_udmap 0xc107>, /* egress slice 1 */ ++ <&main_udmap 0x4100>, /* ingress slice 0 */ ++ <&main_udmap 0x4101>, /* ingress slice 1 */ ++ <&main_udmap 0x4102>, /* mgmnt rsp slice 0 */ ++ <&main_udmap 0x4103>; /* mgmnt rsp slice 1 */ ++ dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", ++ "tx1-0", "tx1-1", "tx1-2", "tx1-3", ++ "rx0", "rx1", ++ "rxmgm0", "rxmgm1"; + }; + +-&icssg0_mdio { +- status = "disabled"; ++&icssg0_iep0 { ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <7 7 8>; ++ interrupt-names = "iep_cap_cmp"; ++}; ++ ++&icssg0_iep1 { ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <56 8 9>; ++ interrupt-names = "iep_cap_cmp"; + };