aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/net/pfe_eth
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/net/pfe_eth')
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/Kconfig12
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/Makefile13
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_cmd.c500
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_driver.c645
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_eth.c295
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_firmware.c399
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_hw.c1000
-rw-r--r--roms/u-boot/drivers/net/pfe_eth/pfe_mdio.c291
8 files changed, 3155 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/net/pfe_eth/Kconfig b/roms/u-boot/drivers/net/pfe_eth/Kconfig
new file mode 100644
index 000000000..a13b331a5
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/Kconfig
@@ -0,0 +1,12 @@
+menuconfig FSL_PFE
+ bool "NXP PFE Ethernet driver"
+ help
+ This driver provides support for NXP's Packet Forwarding Engine.
+
+if FSL_PFE
+
+config SYS_FSL_PFE_ADDR
+ hex "PFE base address"
+ default 0x04000000
+
+endif
diff --git a/roms/u-boot/drivers/net/pfe_eth/Makefile b/roms/u-boot/drivers/net/pfe_eth/Makefile
new file mode 100644
index 000000000..ab5a7b2c7
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2015-2016 Freescale Semiconductor, Inc.
+# Copyright 2017 NXP
+#
+
+# Layerscape PFE driver
+obj-y += pfe_cmd.o \
+ pfe_driver.o \
+ pfe_eth.o \
+ pfe_firmware.o \
+ pfe_hw.o \
+ pfe_mdio.o
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_cmd.c b/roms/u-boot/drivers/net/pfe_eth/pfe_cmd.c
new file mode 100644
index 000000000..364750f65
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_cmd.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+/*
+ * @file
+ * @brief PFE utility commands
+ */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <net/pfe_eth/pfe_eth.h>
+
+static inline void pfe_command_help(void)
+{
+ printf("Usage: pfe [pe | status | expt ] <options>\n");
+}
+
+static void pfe_command_pe(int argc, char *const argv[])
+{
+ if (argc >= 3 && strcmp(argv[2], "pmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ int id;
+ u32 addr;
+ u32 size;
+ u32 val;
+
+ if (argc == 7) {
+ num = simple_strtoul(argv[6], NULL, 0);
+ } else if (argc == 6) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe pmem read <id> <addr> [<num>]\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ addr = simple_strtoul(argv[5], NULL, 16);
+ size = 4;
+
+ for (i = 0; i < num; i++, addr += 4) {
+ val = pe_pmem_read(id, addr, size);
+ val = be32_to_cpu(val);
+ if (!(i & 3))
+ printf("%08x: ", addr);
+ printf("%08x%s", val, i == num - 1 || (i & 3)
+ == 3 ? "\n" : " ");
+ }
+
+ } else {
+ printf("Usage: pfe pe pmem read <parameters>\n");
+ }
+ } else if (argc >= 3 && strcmp(argv[2], "dmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ int id;
+ u32 addr;
+ u32 size;
+ u32 val;
+
+ if (argc == 7) {
+ num = simple_strtoul(argv[6], NULL, 0);
+ } else if (argc == 6) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe dmem read <id> <addr> [<num>]\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ addr = simple_strtoul(argv[5], NULL, 16);
+ size = 4;
+
+ for (i = 0; i < num; i++, addr += 4) {
+ val = pe_dmem_read(id, addr, size);
+ val = be32_to_cpu(val);
+ if (!(i & 3))
+ printf("%08x: ", addr);
+ printf("%08x%s", val, i == num - 1 || (i & 3)
+ == 3 ? "\n" : " ");
+ }
+
+ } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
+ int id;
+ u32 val;
+ u32 addr;
+ u32 size;
+
+ if (argc != 7) {
+ printf("Usage: pfe pe dmem write <id> <val> <addr>\n");
+ return;
+ }
+
+ id = simple_strtoul(argv[4], NULL, 0);
+ val = simple_strtoul(argv[5], NULL, 16);
+ val = cpu_to_be32(val);
+ addr = simple_strtoul(argv[6], NULL, 16);
+ size = 4;
+ pe_dmem_write(id, val, addr, size);
+ } else {
+ printf("Usage: pfe pe dmem [read | write] <parameters>\n");
+ }
+ } else if (argc >= 3 && strcmp(argv[2], "lmem") == 0) {
+ if (argc >= 4 && strcmp(argv[3], "read") == 0) {
+ int i;
+ int num;
+ u32 val;
+ u32 offset;
+
+ if (argc == 6) {
+ num = simple_strtoul(argv[5], NULL, 0);
+ } else if (argc == 5) {
+ num = 1;
+ } else {
+ printf("Usage: pfe pe lmem read <offset> [<num>]\n");
+ return;
+ }
+
+ offset = simple_strtoul(argv[4], NULL, 16);
+
+ for (i = 0; i < num; i++, offset += 4) {
+ pe_lmem_read(&val, 4, offset);
+ val = be32_to_cpu(val);
+ printf("%08x%s", val, i == num - 1 || (i & 7)
+ == 7 ? "\n" : " ");
+ }
+
+ } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
+ u32 val;
+ u32 offset;
+
+ if (argc != 6) {
+ printf("Usage: pfe pe lmem write <val> <offset>\n");
+ return;
+ }
+
+ val = simple_strtoul(argv[4], NULL, 16);
+ val = cpu_to_be32(val);
+ offset = simple_strtoul(argv[5], NULL, 16);
+ pe_lmem_write(&val, 4, offset);
+ } else {
+ printf("Usage: pfe pe lmem [read | write] <parameters>\n");
+ }
+ } else {
+ if (strcmp(argv[2], "help") != 0)
+ printf("Unknown option: %s\n", argv[2]);
+
+ printf("Usage: pfe pe <parameters>\n");
+ }
+}
+
+#define NUM_QUEUES 16
+
+/*
+ * qm_read_drop_stat
+ * This function is used to read the drop statistics from the TMU
+ * hw drop counter. Since the hw counter is always cleared afer
+ * reading, this function maintains the previous drop count, and
+ * adds the new value to it. That value can be retrieved by
+ * passing a pointer to it with the total_drops arg.
+ *
+ * @param tmu TMU number (0 - 3)
+ * @param queue queue number (0 - 15)
+ * @param total_drops pointer to location to store total drops (or NULL)
+ * @param do_reset if TRUE, clear total drops after updating
+ *
+ */
+u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset)
+{
+ static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES];
+ u32 val;
+
+ writel((tmu << 8) | queue, TMU_TEQ_CTRL);
+ writel((tmu << 8) | queue, TMU_LLM_CTRL);
+ val = readl(TMU_TEQ_DROP_STAT);
+ qtotal[tmu][queue] += val;
+ if (total_drops)
+ *total_drops = qtotal[tmu][queue];
+ if (do_reset)
+ qtotal[tmu][queue] = 0;
+ return val;
+}
+
+static ssize_t tmu_queue_stats(char *buf, int tmu, int queue)
+{
+ ssize_t len = 0;
+ u32 drops;
+
+ printf("%d-%02d, ", tmu, queue);
+
+ drops = qm_read_drop_stat(tmu, queue, NULL, 0);
+
+ /* Select queue */
+ writel((tmu << 8) | queue, TMU_TEQ_CTRL);
+ writel((tmu << 8) | queue, TMU_LLM_CTRL);
+
+ printf("(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n",
+ drops, readl(TMU_TEQ_TRANS_STAT),
+ readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR),
+ readl(TMU_LLM_QUE_DROPCNT));
+
+ return len;
+}
+
+static ssize_t tmu_queues(char *buf, int tmu)
+{
+ ssize_t len = 0;
+ int queue;
+
+ for (queue = 0; queue < 16; queue++)
+ len += tmu_queue_stats(buf + len, tmu, queue);
+
+ return len;
+}
+
+static inline void hif_status(void)
+{
+ printf("hif:\n");
+
+ printf(" tx curr bd: %x\n", readl(HIF_TX_CURR_BD_ADDR));
+ printf(" tx status: %x\n", readl(HIF_TX_STATUS));
+ printf(" tx dma status: %x\n", readl(HIF_TX_DMA_STATUS));
+
+ printf(" rx curr bd: %x\n", readl(HIF_RX_CURR_BD_ADDR));
+ printf(" rx status: %x\n", readl(HIF_RX_STATUS));
+ printf(" rx dma status: %x\n", readl(HIF_RX_DMA_STATUS));
+
+ printf("hif nocopy:\n");
+
+ printf(" tx curr bd: %x\n", readl(HIF_NOCPY_TX_CURR_BD_ADDR));
+ printf(" tx status: %x\n", readl(HIF_NOCPY_TX_STATUS));
+ printf(" tx dma status: %x\n", readl(HIF_NOCPY_TX_DMA_STATUS));
+
+ printf(" rx curr bd: %x\n", readl(HIF_NOCPY_RX_CURR_BD_ADDR));
+ printf(" rx status: %x\n", readl(HIF_NOCPY_RX_STATUS));
+ printf(" rx dma status: %x\n", readl(HIF_NOCPY_RX_DMA_STATUS));
+}
+
+static void gpi(int id, void *base)
+{
+ u32 val;
+
+ printf("%s%d:\n", __func__, id);
+
+ printf(" tx under stick: %x\n", readl(base + GPI_FIFO_STATUS));
+ val = readl(base + GPI_FIFO_DEBUG);
+ printf(" tx pkts: %x\n", (val >> 23) & 0x3f);
+ printf(" rx pkts: %x\n", (val >> 18) & 0x3f);
+ printf(" tx bytes: %x\n", (val >> 9) & 0x1ff);
+ printf(" rx bytes: %x\n", (val >> 0) & 0x1ff);
+ printf(" overrun: %x\n", readl(base + GPI_OVERRUN_DROPCNT));
+}
+
+static void bmu(int id, void *base)
+{
+ printf("%s%d:\n", __func__, id);
+
+ printf(" buf size: %x\n", (1 << readl(base + BMU_BUF_SIZE)));
+ printf(" buf count: %x\n", readl(base + BMU_BUF_CNT));
+ printf(" buf rem: %x\n", readl(base + BMU_REM_BUF_CNT));
+ printf(" buf curr: %x\n", readl(base + BMU_CURR_BUF_CNT));
+ printf(" free err: %x\n", readl(base + BMU_FREE_ERR_ADDR));
+}
+
+#define PESTATUS_ADDR_CLASS 0x800
+#define PEMBOX_ADDR_CLASS 0x890
+#define PESTATUS_ADDR_TMU 0x80
+#define PEMBOX_ADDR_TMU 0x290
+#define PESTATUS_ADDR_UTIL 0x0
+
+static void pfe_pe_status(int argc, char *const argv[])
+{
+ int do_clear = 0;
+ u32 id;
+ u32 dmem_addr;
+ u32 cpu_state;
+ u32 activity_counter;
+ u32 rx;
+ u32 tx;
+ u32 drop;
+ char statebuf[5];
+ u32 class_debug_reg = 0;
+
+ if (argc == 4 && strcmp(argv[3], "clear") == 0)
+ do_clear = 1;
+
+ for (id = CLASS0_ID; id < MAX_PE; id++) {
+ if (id >= TMU0_ID) {
+ if (id == TMU2_ID)
+ continue;
+ if (id == TMU0_ID)
+ printf("tmu:\n");
+ dmem_addr = PESTATUS_ADDR_TMU;
+ } else {
+ if (id == CLASS0_ID)
+ printf("class:\n");
+ dmem_addr = PESTATUS_ADDR_CLASS;
+ class_debug_reg = readl(CLASS_PE0_DEBUG + id * 4);
+ }
+
+ cpu_state = pe_dmem_read(id, dmem_addr, 4);
+ dmem_addr += 4;
+ memcpy(statebuf, (char *)&cpu_state, 4);
+ statebuf[4] = '\0';
+ activity_counter = pe_dmem_read(id, dmem_addr, 4);
+ dmem_addr += 4;
+ rx = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+ tx = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+ drop = pe_dmem_read(id, dmem_addr, 4);
+ if (do_clear)
+ pe_dmem_write(id, 0, dmem_addr, 4);
+ dmem_addr += 4;
+
+ if (id >= TMU0_ID) {
+ printf("%d: state=%4s ctr=%08x rx=%x qstatus=%x\n",
+ id - TMU0_ID, statebuf,
+ cpu_to_be32(activity_counter),
+ cpu_to_be32(rx), cpu_to_be32(tx));
+ } else {
+ printf("%d: pc=1%04x ldst=%04x state=%4s ctr=%08x rx=%x tx=%x drop=%x\n",
+ id - CLASS0_ID, class_debug_reg & 0xFFFF,
+ class_debug_reg >> 16,
+ statebuf, cpu_to_be32(activity_counter),
+ cpu_to_be32(rx), cpu_to_be32(tx),
+ cpu_to_be32(drop));
+ }
+ }
+}
+
+static void pfe_command_status(int argc, char *const argv[])
+{
+ if (argc >= 3 && strcmp(argv[2], "pe") == 0) {
+ pfe_pe_status(argc, argv);
+ } else if (argc == 3 && strcmp(argv[2], "bmu") == 0) {
+ bmu(1, BMU1_BASE_ADDR);
+ bmu(2, BMU2_BASE_ADDR);
+ } else if (argc == 3 && strcmp(argv[2], "hif") == 0) {
+ hif_status();
+ } else if (argc == 3 && strcmp(argv[2], "gpi") == 0) {
+ gpi(0, EGPI1_BASE_ADDR);
+ gpi(1, EGPI2_BASE_ADDR);
+ gpi(3, HGPI_BASE_ADDR);
+ } else if (argc == 3 && strcmp(argv[2], "tmu0_queues") == 0) {
+ tmu_queues(NULL, 0);
+ } else if (argc == 3 && strcmp(argv[2], "tmu1_queues") == 0) {
+ tmu_queues(NULL, 1);
+ } else if (argc == 3 && strcmp(argv[2], "tmu3_queues") == 0) {
+ tmu_queues(NULL, 3);
+ } else {
+ printf("Usage: pfe status [pe <clear> | bmu | gpi | hif | tmuX_queues ]\n");
+ }
+}
+
+#define EXPT_DUMP_ADDR 0x1fa8
+#define EXPT_REG_COUNT 20
+static const char *register_names[EXPT_REG_COUNT] = {
+ " pc", "ECAS", " EID", " ED",
+ " sp", " r1", " r2", " r3",
+ " r4", " r5", " r6", " r7",
+ " r8", " r9", " r10", " r11",
+ " r12", " r13", " r14", " r15"
+};
+
+static void pfe_command_expt(int argc, char *const argv[])
+{
+ unsigned int id, i, val, addr;
+
+ if (argc == 3) {
+ id = simple_strtoul(argv[2], NULL, 0);
+ addr = EXPT_DUMP_ADDR;
+ printf("Exception information for PE %d:\n", id);
+ for (i = 0; i < EXPT_REG_COUNT; i++) {
+ val = pe_dmem_read(id, addr, 4);
+ val = be32_to_cpu(val);
+ printf("%s:%08x%s", register_names[i], val,
+ (i & 3) == 3 ? "\n" : " ");
+ addr += 4;
+ }
+ } else {
+ printf("Usage: pfe expt <id>\n");
+ }
+}
+
+#ifdef PFE_RESET_WA
+/*This function sends a dummy packet to HIF through TMU3 */
+static void send_dummy_pkt_to_hif(void)
+{
+ u32 buf;
+ static u32 dummy_pkt[] = {
+ 0x4200800a, 0x01000003, 0x00018100, 0x00000000,
+ 0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
+ 0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
+ 0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
+
+ /*Allocate BMU2 buffer */
+ buf = readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
+
+ debug("Sending a dummy pkt to HIF %x\n", buf);
+ buf += 0x80;
+ memcpy((void *)DDR_PFE_TO_VIRT(buf), dummy_pkt, sizeof(dummy_pkt));
+
+ /*Write length and pkt to TMU*/
+ writel(0x03000042, TMU_PHY_INQ_PKTPTR);
+ writel(buf, TMU_PHY_INQ_PKTINFO);
+}
+
+void pfe_command_stop(int argc, char *const argv[])
+{
+ int pfe_pe_id, hif_stop_loop = 10;
+ u32 rx_status;
+
+ printf("Stopping PFE...\n");
+
+ /*Mark all descriptors as LAST_BD */
+ hif_rx_desc_disable();
+
+ /*If HIF Rx BDP is busy send a dummy packet */
+ do {
+ rx_status = readl(HIF_RX_STATUS);
+ if (rx_status & BDP_CSR_RX_DMA_ACTV)
+ send_dummy_pkt_to_hif();
+ udelay(10);
+ } while (hif_stop_loop--);
+
+ if (readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
+ printf("Unable to stop HIF\n");
+
+ /*Disable Class PEs */
+ for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
+ /*Inform PE to stop */
+ pe_dmem_write(pfe_pe_id, cpu_to_be32(1), PEMBOX_ADDR_CLASS, 4);
+ udelay(10);
+
+ /*Read status */
+ if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_CLASS + 4, 4))
+ printf("Failed to stop PE%d\n", pfe_pe_id);
+ }
+
+ /*Disable TMU PEs */
+ for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
+ if (pfe_pe_id == TMU2_ID)
+ continue;
+
+ /*Inform PE to stop */
+ pe_dmem_write(pfe_pe_id, 1, PEMBOX_ADDR_TMU, 4);
+ udelay(10);
+
+ /*Read status */
+ if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_TMU + 4, 4))
+ printf("Failed to stop PE%d\n", pfe_pe_id);
+ }
+}
+#endif
+
+static int pfe_command(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if (argc == 1 || strcmp(argv[1], "help") == 0) {
+ pfe_command_help();
+ return CMD_RET_SUCCESS;
+ }
+
+ if (strcmp(argv[1], "pe") == 0) {
+ pfe_command_pe(argc, argv);
+ } else if (strcmp(argv[1], "status") == 0) {
+ pfe_command_status(argc, argv);
+ } else if (strcmp(argv[1], "expt") == 0) {
+ pfe_command_expt(argc, argv);
+#ifdef PFE_RESET_WA
+ } else if (strcmp(argv[1], "stop") == 0) {
+ pfe_command_stop(argc, argv);
+#endif
+ } else {
+ printf("Unknown option: %s\n", argv[1]);
+ pfe_command_help();
+ return CMD_RET_FAILURE;
+ }
+ return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+ pfe, 7, 1, pfe_command,
+ "Performs PFE lib utility functions",
+ "Usage:\n"
+ "pfe <options>"
+);
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_driver.c b/roms/u-boot/drivers/net/pfe_eth/pfe_driver.c
new file mode 100644
index 000000000..6f443b4ea
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_driver.c
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <log.h>
+#include <malloc.h>
+#include <linux/delay.h>
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_firmware.h>
+
+static struct tx_desc_s *g_tx_desc;
+static struct rx_desc_s *g_rx_desc;
+
+/*
+ * HIF Rx interface function
+ * Reads the rx descriptor from the current location (rx_to_read).
+ * - If the descriptor has a valid data/pkt, then get the data pointer
+ * - check for the input rx phy number
+ * - increment the rx data pointer by pkt_head_room_size
+ * - decrement the data length by pkt_head_room_size
+ * - handover the packet to caller.
+ *
+ * @param[out] pkt_ptr - Pointer to store rx packet
+ * @param[out] phy_port - Pointer to store recv phy port
+ *
+ * @return -1 if no packet, else return length of packet.
+ */
+int pfe_recv(uchar **pkt_ptr, int *phy_port)
+{
+ struct rx_desc_s *rx_desc = g_rx_desc;
+ struct buf_desc *bd;
+ int len = 0;
+
+ struct hif_header_s *hif_header;
+
+ bd = rx_desc->rx_base + rx_desc->rx_to_read;
+
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return len; /* No pending Rx packet */
+
+ /* this len include hif_header(8 bytes) */
+ len = readl(&bd->ctrl) & 0xFFFF;
+
+ hif_header = (struct hif_header_s *)DDR_PFE_TO_VIRT(readl(&bd->data));
+
+ /* Get the receive port info from the packet */
+ debug("Pkt received:");
+ debug(" Pkt ptr(%p), len(%d), gemac_port(%d) status(%08x)\n",
+ hif_header, len, hif_header->port_no, readl(&bd->status));
+#ifdef DEBUG
+ {
+ int i;
+ unsigned char *p = (unsigned char *)hif_header;
+
+ for (i = 0; i < len; i++) {
+ if (!(i % 16))
+ printf("\n");
+ printf(" %02x", p[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+ *pkt_ptr = (uchar *)(hif_header + 1);
+ *phy_port = hif_header->port_no;
+ len -= sizeof(struct hif_header_s);
+
+ return len;
+}
+
+/*
+ * HIF function to check the Rx done
+ * This function will check the rx done indication of the current rx_to_read
+ * locations
+ * if success, moves the rx_to_read to next location.
+ */
+int pfe_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct rx_desc_s *rx_desc = g_rx_desc;
+ struct buf_desc *bd;
+
+ debug("%s:rx_base: %p, rx_to_read: %d\n", __func__, rx_desc->rx_base,
+ rx_desc->rx_to_read);
+
+ bd = rx_desc->rx_base + rx_desc->rx_to_read;
+
+ /* reset the control field */
+ writel((MAX_FRAME_SIZE | BD_CTRL_LIFM | BD_CTRL_DESC_EN
+ | BD_CTRL_DIR), &bd->ctrl);
+ writel(0, &bd->status);
+
+ debug("Rx Done : status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* Give START_STROBE to BDP to fetch the descriptor __NOW__,
+ * BDP need not wait for rx_poll_cycle time to fetch the descriptor,
+ * In idle state (ie., no rx pkt), BDP will not fetch
+ * the descriptor even if strobe is given.
+ */
+ writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+
+ /* increment the rx_to_read index to next location */
+ rx_desc->rx_to_read = (rx_desc->rx_to_read + 1)
+ & (rx_desc->rx_ring_size - 1);
+
+ debug("Rx next pkt location: %d\n", rx_desc->rx_to_read);
+
+ return 0;
+}
+
+/*
+ * HIF Tx interface function
+ * This function sends a single packet to PFE from HIF interface.
+ * - No interrupt indication on tx completion.
+ * - Data is copied to tx buffers before tx descriptor is updated
+ * and TX DMA is enabled.
+ *
+ * @param[in] phy_port Phy port number to send out this packet
+ * @param[in] data Pointer to the data
+ * @param[in] length Length of the ethernet packet to be transferred.
+ *
+ * @return -1 if tx Q is full, else returns the tx location where the pkt is
+ * placed.
+ */
+int pfe_send(int phy_port, void *data, int length)
+{
+ struct tx_desc_s *tx_desc = g_tx_desc;
+ struct buf_desc *bd;
+ struct hif_header_s hif_header;
+ u8 *tx_buf_va;
+
+ debug("%s:pkt: %p, len: %d, tx_base: %p, tx_to_send: %d\n", __func__,
+ data, length, tx_desc->tx_base, tx_desc->tx_to_send);
+
+ bd = tx_desc->tx_base + tx_desc->tx_to_send;
+
+ /* check queue-full condition */
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return -1;
+
+ /* PFE checks for min pkt size */
+ if (length < MIN_PKT_SIZE)
+ length = MIN_PKT_SIZE;
+
+ tx_buf_va = (void *)DDR_PFE_TO_VIRT(readl(&bd->data));
+ debug("%s: tx_buf_va: %p, tx_buf_pa: %08x\n", __func__, tx_buf_va,
+ readl(&bd->data));
+
+ /* Fill the gemac/phy port number to send this packet out */
+ memset(&hif_header, 0, sizeof(struct hif_header_s));
+ hif_header.port_no = phy_port;
+
+ memcpy(tx_buf_va, (u8 *)&hif_header, sizeof(struct hif_header_s));
+ memcpy(tx_buf_va + sizeof(struct hif_header_s), data, length);
+ length += sizeof(struct hif_header_s);
+
+#ifdef DEBUG
+ {
+ int i;
+ unsigned char *p = (unsigned char *)tx_buf_va;
+
+ for (i = 0; i < length; i++) {
+ if (!(i % 16))
+ printf("\n");
+ printf("%02x ", p[i]);
+ }
+ }
+#endif
+
+ debug("Tx Done: status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* fill the tx desc */
+ writel((u32)(BD_CTRL_DESC_EN | BD_CTRL_LIFM | (length & 0xFFFF)),
+ &bd->ctrl);
+ writel(0, &bd->status);
+
+ writel((HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB), HIF_TX_CTRL);
+
+ udelay(100);
+
+ return tx_desc->tx_to_send;
+}
+
+/*
+ * HIF function to check the Tx done
+ * This function will check the tx done indication of the current tx_to_send
+ * locations
+ * if success, moves the tx_to_send to next location.
+ *
+ * @return -1 if TX ownership bit is not cleared by hw.
+ * else on success (tx done completion) return zero.
+ */
+int pfe_tx_done(void)
+{
+ struct tx_desc_s *tx_desc = g_tx_desc;
+ struct buf_desc *bd;
+
+ debug("%s:tx_base: %p, tx_to_send: %d\n", __func__, tx_desc->tx_base,
+ tx_desc->tx_to_send);
+
+ bd = tx_desc->tx_base + tx_desc->tx_to_send;
+
+ /* check queue-full condition */
+ if (readl(&bd->ctrl) & BD_CTRL_DESC_EN)
+ return -1;
+
+ /* reset the control field */
+ writel(0, &bd->ctrl);
+ writel(0, &bd->status);
+
+ debug("Tx Done : status: %08x, ctrl: %08x\n", readl(&bd->status),
+ readl(&bd->ctrl));
+
+ /* increment the txtosend index to next location */
+ tx_desc->tx_to_send = (tx_desc->tx_to_send + 1)
+ & (tx_desc->tx_ring_size - 1);
+
+ debug("Tx next pkt location: %d\n", tx_desc->tx_to_send);
+
+ return 0;
+}
+
+/*
+ * Helper function to dump Rx descriptors.
+ */
+static inline void hif_rx_desc_dump(void)
+{
+ struct buf_desc *bd_va;
+ int i;
+ struct rx_desc_s *rx_desc;
+
+ if (!g_rx_desc) {
+ printf("%s: HIF Rx desc no init\n", __func__);
+ return;
+ }
+
+ rx_desc = g_rx_desc;
+ bd_va = rx_desc->rx_base;
+
+ debug("HIF rx desc: base_va: %p, base_pa: %08x\n", rx_desc->rx_base,
+ rx_desc->rx_base_pa);
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ debug("status: %08x, ctrl: %08x, data: %08x, next: 0x%08x\n",
+ readl(&bd_va->status),
+ readl(&bd_va->ctrl),
+ readl(&bd_va->data),
+ readl(&bd_va->next));
+ bd_va++;
+ }
+}
+
+/*
+ * This function mark all Rx descriptors as LAST_BD.
+ */
+void hif_rx_desc_disable(void)
+{
+ int i;
+ struct rx_desc_s *rx_desc;
+ struct buf_desc *bd_va;
+
+ if (!g_rx_desc) {
+ printf("%s: HIF Rx desc not initialized\n", __func__);
+ return;
+ }
+
+ rx_desc = g_rx_desc;
+ bd_va = rx_desc->rx_base;
+
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ writel(readl(&bd_va->ctrl) | BD_CTRL_LAST_BD, &bd_va->ctrl);
+ bd_va++;
+ }
+}
+
+/*
+ * HIF Rx Desc initialization function.
+ */
+static int hif_rx_desc_init(struct pfe_ddr_address *pfe_addr)
+{
+ u32 ctrl;
+ struct buf_desc *bd_va;
+ struct buf_desc *bd_pa;
+ struct rx_desc_s *rx_desc;
+ u32 rx_buf_pa;
+ int i;
+
+ /* sanity check */
+ if (g_rx_desc) {
+ printf("%s: HIF Rx desc re-init request\n", __func__);
+ return 0;
+ }
+
+ rx_desc = (struct rx_desc_s *)malloc(sizeof(struct rx_desc_s));
+ if (!rx_desc) {
+ printf("%s: Memory allocation failure\n", __func__);
+ return -ENOMEM;
+ }
+ memset(rx_desc, 0, sizeof(struct rx_desc_s));
+
+ /* init: Rx ring buffer */
+ rx_desc->rx_ring_size = HIF_RX_DESC_NT;
+
+ /* NOTE: must be 64bit aligned */
+ bd_va = (struct buf_desc *)(pfe_addr->ddr_pfe_baseaddr
+ + RX_BD_BASEADDR);
+ bd_pa = (struct buf_desc *)(pfe_addr->ddr_pfe_phys_baseaddr
+ + RX_BD_BASEADDR);
+
+ rx_desc->rx_base = bd_va;
+ rx_desc->rx_base_pa = (unsigned long)bd_pa;
+
+ rx_buf_pa = pfe_addr->ddr_pfe_phys_baseaddr + HIF_RX_PKT_DDR_BASEADDR;
+
+ debug("%s: Rx desc base: %p, base_pa: %08x, desc_count: %d\n",
+ __func__, rx_desc->rx_base, rx_desc->rx_base_pa,
+ rx_desc->rx_ring_size);
+
+ memset(bd_va, 0, sizeof(struct buf_desc) * rx_desc->rx_ring_size);
+
+ ctrl = (MAX_FRAME_SIZE | BD_CTRL_DESC_EN | BD_CTRL_DIR | BD_CTRL_LIFM);
+
+ for (i = 0; i < rx_desc->rx_ring_size; i++) {
+ writel((unsigned long)(bd_pa + 1), &bd_va->next);
+ writel(ctrl, &bd_va->ctrl);
+ writel(rx_buf_pa + (i * MAX_FRAME_SIZE), &bd_va->data);
+ bd_va++;
+ bd_pa++;
+ }
+ --bd_va;
+ writel((u32)rx_desc->rx_base_pa, &bd_va->next);
+
+ writel(rx_desc->rx_base_pa, HIF_RX_BDP_ADDR);
+ writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+
+ g_rx_desc = rx_desc;
+
+ return 0;
+}
+
+/*
+ * Helper function to dump Tx Descriptors.
+ */
+static inline void hif_tx_desc_dump(void)
+{
+ struct tx_desc_s *tx_desc;
+ int i;
+ struct buf_desc *bd_va;
+
+ if (!g_tx_desc) {
+ printf("%s: HIF Tx desc no init\n", __func__);
+ return;
+ }
+
+ tx_desc = g_tx_desc;
+ bd_va = tx_desc->tx_base;
+
+ debug("HIF tx desc: base_va: %p, base_pa: %08x\n", tx_desc->tx_base,
+ tx_desc->tx_base_pa);
+
+ for (i = 0; i < tx_desc->tx_ring_size; i++)
+ bd_va++;
+}
+
+/*
+ * HIF Tx descriptor initialization function.
+ */
+static int hif_tx_desc_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct buf_desc *bd_va;
+ struct buf_desc *bd_pa;
+ int i;
+ struct tx_desc_s *tx_desc;
+ u32 tx_buf_pa;
+
+ /* sanity check */
+ if (g_tx_desc) {
+ printf("%s: HIF Tx desc re-init request\n", __func__);
+ return 0;
+ }
+
+ tx_desc = (struct tx_desc_s *)malloc(sizeof(struct tx_desc_s));
+ if (!tx_desc) {
+ printf("%s:%d:Memory allocation failure\n", __func__,
+ __LINE__);
+ return -ENOMEM;
+ }
+ memset(tx_desc, 0, sizeof(struct tx_desc_s));
+
+ /* init: Tx ring buffer */
+ tx_desc->tx_ring_size = HIF_TX_DESC_NT;
+
+ /* NOTE: must be 64bit aligned */
+ bd_va = (struct buf_desc *)(pfe_addr->ddr_pfe_baseaddr
+ + TX_BD_BASEADDR);
+ bd_pa = (struct buf_desc *)(pfe_addr->ddr_pfe_phys_baseaddr
+ + TX_BD_BASEADDR);
+
+ tx_desc->tx_base_pa = (unsigned long)bd_pa;
+ tx_desc->tx_base = bd_va;
+
+ debug("%s: Tx desc_base: %p, base_pa: %08x, desc_count: %d\n",
+ __func__, tx_desc->tx_base, tx_desc->tx_base_pa,
+ tx_desc->tx_ring_size);
+
+ memset(bd_va, 0, sizeof(struct buf_desc) * tx_desc->tx_ring_size);
+
+ tx_buf_pa = pfe_addr->ddr_pfe_phys_baseaddr + HIF_TX_PKT_DDR_BASEADDR;
+
+ for (i = 0; i < tx_desc->tx_ring_size; i++) {
+ writel((unsigned long)(bd_pa + 1), &bd_va->next);
+ writel(tx_buf_pa + (i * MAX_FRAME_SIZE), &bd_va->data);
+ bd_va++;
+ bd_pa++;
+ }
+ --bd_va;
+ writel((u32)tx_desc->tx_base_pa, &bd_va->next);
+
+ writel(tx_desc->tx_base_pa, HIF_TX_BDP_ADDR);
+
+ g_tx_desc = tx_desc;
+
+ return 0;
+}
+
+/*
+ * PFE/Class initialization.
+ */
+static void pfe_class_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct class_cfg class_cfg = {
+ .route_table_baseaddr = pfe_addr->ddr_pfe_phys_baseaddr +
+ ROUTE_TABLE_BASEADDR,
+ .route_table_hash_bits = ROUTE_TABLE_HASH_BITS,
+ };
+
+ class_init(&class_cfg);
+
+ debug("class init complete\n");
+}
+
+/*
+ * PFE/TMU initialization.
+ */
+static void pfe_tmu_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct tmu_cfg tmu_cfg = {
+ .llm_base_addr = pfe_addr->ddr_pfe_phys_baseaddr
+ + TMU_LLM_BASEADDR,
+ .llm_queue_len = TMU_LLM_QUEUE_LEN,
+ };
+
+ tmu_init(&tmu_cfg);
+
+ debug("tmu init complete\n");
+}
+
+/*
+ * PFE/BMU (both BMU1 & BMU2) initialization.
+ */
+static void pfe_bmu_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct bmu_cfg bmu1_cfg = {
+ .baseaddr = CBUS_VIRT_TO_PFE(LMEM_BASE_ADDR +
+ BMU1_LMEM_BASEADDR),
+ .count = BMU1_BUF_COUNT,
+ .size = BMU1_BUF_SIZE,
+ };
+
+ struct bmu_cfg bmu2_cfg = {
+ .baseaddr = pfe_addr->ddr_pfe_phys_baseaddr + BMU2_DDR_BASEADDR,
+ .count = BMU2_BUF_COUNT,
+ .size = BMU2_BUF_SIZE,
+ };
+
+ bmu_init(BMU1_BASE_ADDR, &bmu1_cfg);
+ debug("bmu1 init: done\n");
+
+ bmu_init(BMU2_BASE_ADDR, &bmu2_cfg);
+ debug("bmu2 init: done\n");
+}
+
+/*
+ * PFE/GPI initialization function.
+ * - egpi1, egpi2, egpi3, hgpi
+ */
+static void pfe_gpi_init(struct pfe_ddr_address *pfe_addr)
+{
+ struct gpi_cfg egpi1_cfg = {
+ .lmem_rtry_cnt = EGPI1_LMEM_RTRY_CNT,
+ .tmlf_txthres = EGPI1_TMLF_TXTHRES,
+ .aseq_len = EGPI1_ASEQ_LEN,
+ };
+
+ struct gpi_cfg egpi2_cfg = {
+ .lmem_rtry_cnt = EGPI2_LMEM_RTRY_CNT,
+ .tmlf_txthres = EGPI2_TMLF_TXTHRES,
+ .aseq_len = EGPI2_ASEQ_LEN,
+ };
+
+ struct gpi_cfg hgpi_cfg = {
+ .lmem_rtry_cnt = HGPI_LMEM_RTRY_CNT,
+ .tmlf_txthres = HGPI_TMLF_TXTHRES,
+ .aseq_len = HGPI_ASEQ_LEN,
+ };
+
+ gpi_init(EGPI1_BASE_ADDR, &egpi1_cfg);
+ debug("GPI1 init complete\n");
+
+ gpi_init(EGPI2_BASE_ADDR, &egpi2_cfg);
+ debug("GPI2 init complete\n");
+
+ gpi_init(HGPI_BASE_ADDR, &hgpi_cfg);
+ debug("HGPI init complete\n");
+}
+
+/*
+ * PFE/HIF initialization function.
+ */
+static int pfe_hif_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ hif_tx_disable();
+ hif_rx_disable();
+
+ ret = hif_tx_desc_init(pfe_addr);
+ if (ret)
+ return ret;
+ ret = hif_rx_desc_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ hif_init();
+
+ hif_tx_enable();
+ hif_rx_enable();
+
+ hif_rx_desc_dump();
+ hif_tx_desc_dump();
+
+ debug("HIF init complete\n");
+ return ret;
+}
+
+/*
+ * PFE initialization
+ * - Firmware loading (CLASS-PE and TMU-PE)
+ * - BMU1 and BMU2 init
+ * - GEMAC init
+ * - GPI init
+ * - CLASS-PE init
+ * - TMU-PE init
+ * - HIF tx and rx descriptors init
+ *
+ * @param[in] edev Pointer to eth device structure.
+ *
+ * @return 0, on success.
+ */
+static int pfe_hw_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ debug("%s: start\n", __func__);
+
+ writel(0x3, CLASS_PE_SYS_CLK_RATIO);
+ writel(0x3, TMU_PE_SYS_CLK_RATIO);
+ writel(0x3, UTIL_PE_SYS_CLK_RATIO);
+ udelay(10);
+
+ pfe_class_init(pfe_addr);
+
+ pfe_tmu_init(pfe_addr);
+
+ pfe_bmu_init(pfe_addr);
+
+ pfe_gpi_init(pfe_addr);
+
+ ret = pfe_hif_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ bmu_enable(BMU1_BASE_ADDR);
+ debug("bmu1 enabled\n");
+
+ bmu_enable(BMU2_BASE_ADDR);
+ debug("bmu2 enabled\n");
+
+ debug("%s: done\n", __func__);
+
+ return ret;
+}
+
+/*
+ * PFE driver init function.
+ * - Initializes pfe_lib
+ * - pfe hw init
+ * - fw loading and enables PEs
+ * - should be executed once.
+ *
+ * @param[in] pfe Pointer the pfe control block
+ */
+int pfe_drv_init(struct pfe_ddr_address *pfe_addr)
+{
+ int ret = 0;
+
+ pfe_lib_init();
+
+ ret = pfe_hw_init(pfe_addr);
+ if (ret)
+ return ret;
+
+ /* Load the class,TM, Util fw.
+ * By now pfe is:
+ * - out of reset + disabled + configured.
+ * Fw loading should be done after pfe_hw_init()
+ */
+ /* It loads default inbuilt sbl firmware */
+ pfe_firmware_init();
+
+ return ret;
+}
+
+/*
+ * PFE remove function
+ * - stops PEs
+ * - frees tx/rx descriptor resources
+ * - should be called once.
+ *
+ * @param[in] pfe Pointer to pfe control block.
+ */
+int pfe_eth_remove(struct udevice *dev)
+{
+ if (g_tx_desc)
+ free(g_tx_desc);
+
+ if (g_rx_desc)
+ free(g_rx_desc);
+
+ pfe_firmware_exit();
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_eth.c b/roms/u-boot/drivers/net/pfe_eth/pfe_eth.c
new file mode 100644
index 000000000..0c27a668b
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_eth.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/platform_data/pfe_dm_eth.h>
+#include <net.h>
+#include <linux/delay.h>
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_mdio.h>
+
+struct gemac_s gem_info[] = {
+ /* PORT_0 configuration */
+ {
+ /* GEMAC config */
+ .gemac_speed = PFE_MAC_SPEED_1000M,
+ .gemac_duplex = DUPLEX_FULL,
+
+ /* phy iface */
+ .phy_address = CONFIG_PFE_EMAC1_PHY_ADDR,
+ .phy_mode = PHY_INTERFACE_MODE_SGMII,
+ },
+ /* PORT_1 configuration */
+ {
+ /* GEMAC config */
+ .gemac_speed = PFE_MAC_SPEED_1000M,
+ .gemac_duplex = DUPLEX_FULL,
+
+ /* phy iface */
+ .phy_address = CONFIG_PFE_EMAC2_PHY_ADDR,
+ .phy_mode = PHY_INTERFACE_MODE_RGMII_ID,
+ },
+};
+
+static inline void pfe_gemac_enable(void *gemac_base)
+{
+ writel(readl(gemac_base + EMAC_ECNTRL_REG) |
+ EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+
+static inline void pfe_gemac_disable(void *gemac_base)
+{
+ writel(readl(gemac_base + EMAC_ECNTRL_REG) &
+ ~EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+
+static inline void pfe_gemac_set_speed(void *gemac_base, u32 speed)
+{
+ struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
+ u32 ecr = readl(gemac_base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_SPEED;
+ u32 rcr = readl(gemac_base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_RMII_10T;
+ u32 rgmii_pcr = in_be32(&scfg->rgmiipcr) &
+ ~(SCFG_RGMIIPCR_SETSP_1000M | SCFG_RGMIIPCR_SETSP_10M);
+
+ if (speed == _1000BASET) {
+ ecr |= EMAC_ECNTRL_SPEED;
+ rgmii_pcr |= SCFG_RGMIIPCR_SETSP_1000M;
+ } else if (speed != _100BASET) {
+ rcr |= EMAC_RCNTRL_RMII_10T;
+ rgmii_pcr |= SCFG_RGMIIPCR_SETSP_10M;
+ }
+
+ writel(ecr, gemac_base + EMAC_ECNTRL_REG);
+ out_be32(&scfg->rgmiipcr, rgmii_pcr | SCFG_RGMIIPCR_SETFD);
+
+ /* remove loop back */
+ rcr &= ~EMAC_RCNTRL_LOOP;
+ /* enable flow control */
+ rcr |= EMAC_RCNTRL_FCE;
+
+ /* Enable MII mode */
+ rcr |= EMAC_RCNTRL_MII_MODE;
+
+ writel(rcr, gemac_base + EMAC_RCNTRL_REG);
+
+ /* Enable Tx full duplex */
+ writel(readl(gemac_base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_FDEN,
+ gemac_base + EMAC_TCNTRL_REG);
+}
+
+static int pfe_eth_write_hwaddr(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct gemac_s *gem = priv->gem;
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ uchar *mac = pdata->enetaddr;
+
+ writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
+ gem->gemac_base + EMAC_PHY_ADDR_LOW);
+ writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, gem->gemac_base +
+ EMAC_PHY_ADDR_HIGH);
+ return 0;
+}
+
+/** Stops or Disables GEMAC pointing to this eth iface.
+ *
+ * @param[in] edev Pointer to eth device structure.
+ *
+ * @return none
+ */
+static inline void pfe_eth_stop(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+
+ pfe_gemac_disable(priv->gem->gemac_base);
+
+ gpi_disable(priv->gem->egpi_base);
+}
+
+static int pfe_eth_start(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct gemac_s *gem = priv->gem;
+ int speed;
+
+ /* set ethernet mac address */
+ pfe_eth_write_hwaddr(dev);
+
+ writel(EMAC_TFWR, gem->gemac_base + EMAC_TFWR_STR_FWD);
+ writel(EMAC_RX_SECTION_FULL_32, gem->gemac_base + EMAC_RX_SECTIOM_FULL);
+ writel(EMAC_TRUNC_FL_16K, gem->gemac_base + EMAC_TRUNC_FL);
+ writel(EMAC_TX_SECTION_EMPTY_30, gem->gemac_base
+ + EMAC_TX_SECTION_EMPTY);
+ writel(EMAC_MIBC_NO_CLR_NO_DIS, gem->gemac_base
+ + EMAC_MIB_CTRL_STS_REG);
+
+#ifdef CONFIG_PHYLIB
+ /* Start up the PHY */
+ if (phy_startup(priv->phydev)) {
+ printf("Could not initialize PHY %s\n",
+ priv->phydev->dev->name);
+ return -1;
+ }
+ speed = priv->phydev->speed;
+ printf("Speed detected %x\n", speed);
+ if (priv->phydev->duplex == DUPLEX_HALF) {
+ printf("Half duplex not supported\n");
+ return -1;
+ }
+#endif
+
+ pfe_gemac_set_speed(gem->gemac_base, speed);
+
+ /* Enable GPI */
+ gpi_enable(gem->egpi_base);
+
+ /* Enable GEMAC */
+ pfe_gemac_enable(gem->gemac_base);
+
+ return 0;
+}
+
+static int pfe_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct pfe_eth_dev *priv = (struct pfe_eth_dev *)dev_get_priv(dev);
+
+ int rc;
+ int i = 0;
+
+ rc = pfe_send(priv->gemac_port, packet, length);
+
+ if (rc < 0) {
+ printf("Tx Queue full\n");
+ return rc;
+ }
+
+ while (1) {
+ rc = pfe_tx_done();
+ if (rc == 0)
+ break;
+
+ udelay(100);
+ i++;
+ if (i == 30000) {
+ printf("Tx timeout, send failed\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int pfe_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ uchar *pkt_buf;
+ int len;
+ int phy_port;
+
+ len = pfe_recv(&pkt_buf, &phy_port);
+
+ if (len == 0)
+ return -EAGAIN; /* no packet in rx */
+ else if (len < 0)
+ return -EAGAIN;
+
+ debug("Rx pkt: pkt_buf(0x%p), phy_port(%d), len(%d)\n", pkt_buf,
+ phy_port, len);
+ if (phy_port != priv->gemac_port) {
+ printf("Rx pkt not on expected port\n");
+ return -EAGAIN;
+ }
+
+ *packetp = pkt_buf;
+
+ return len;
+}
+
+static int pfe_eth_probe(struct udevice *dev)
+{
+ struct pfe_eth_dev *priv = dev_get_priv(dev);
+ struct pfe_ddr_address pfe_addr;
+ struct pfe_eth_pdata *pdata = dev_get_plat(dev);
+ int ret = 0;
+ static int init_done;
+
+ if (!init_done) {
+ pfe_addr.ddr_pfe_baseaddr =
+ (void *)pdata->pfe_ddr_addr.ddr_pfe_baseaddr;
+ pfe_addr.ddr_pfe_phys_baseaddr =
+ (unsigned long)pdata->pfe_ddr_addr.ddr_pfe_phys_baseaddr;
+
+ debug("ddr_pfe_baseaddr: %p, ddr_pfe_phys_baseaddr: %08x\n",
+ pfe_addr.ddr_pfe_baseaddr,
+ (u32)pfe_addr.ddr_pfe_phys_baseaddr);
+
+ ret = pfe_drv_init(&pfe_addr);
+ if (ret)
+ return ret;
+
+ init_pfe_scfg_dcfg_regs();
+ init_done = 1;
+ }
+
+ priv->gemac_port = pdata->pfe_eth_pdata_mac.phy_interface;
+ priv->gem = &gem_info[priv->gemac_port];
+ priv->dev = dev;
+
+ switch (priv->gemac_port) {
+ case EMAC_PORT_0:
+ default:
+ priv->gem->gemac_base = EMAC1_BASE_ADDR;
+ priv->gem->egpi_base = EGPI1_BASE_ADDR;
+ break;
+ case EMAC_PORT_1:
+ priv->gem->gemac_base = EMAC2_BASE_ADDR;
+ priv->gem->egpi_base = EGPI2_BASE_ADDR;
+ break;
+ }
+
+ ret = pfe_eth_board_init(dev);
+ if (ret)
+ return ret;
+
+#if defined(CONFIG_PHYLIB)
+ ret = pfe_phy_configure(priv, pdata->pfe_eth_pdata_mac.phy_interface,
+ gem_info[priv->gemac_port].phy_address);
+#endif
+ return ret;
+}
+
+static int pfe_eth_bind(struct udevice *dev)
+{
+ struct pfe_eth_pdata *pdata = dev_get_plat(dev);
+ char name[20];
+
+ sprintf(name, "pfe_eth%u", pdata->pfe_eth_pdata_mac.phy_interface);
+
+ return device_set_name(dev, name);
+}
+
+static const struct eth_ops pfe_eth_ops = {
+ .start = pfe_eth_start,
+ .send = pfe_eth_send,
+ .recv = pfe_eth_recv,
+ .free_pkt = pfe_eth_free_pkt,
+ .stop = pfe_eth_stop,
+ .write_hwaddr = pfe_eth_write_hwaddr,
+};
+
+U_BOOT_DRIVER(pfe_eth) = {
+ .name = "pfe_eth",
+ .id = UCLASS_ETH,
+ .bind = pfe_eth_bind,
+ .probe = pfe_eth_probe,
+ .remove = pfe_eth_remove,
+ .ops = &pfe_eth_ops,
+ .priv_auto = sizeof(struct pfe_eth_dev),
+ .plat_auto = sizeof(struct pfe_eth_pdata)
+};
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_firmware.c b/roms/u-boot/drivers/net/pfe_eth/pfe_firmware.c
new file mode 100644
index 000000000..ac86e33c5
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_firmware.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017,2021 NXP
+ */
+
+/*
+ * @file
+ * Contains all the functions to handle parsing and loading of PE firmware
+ * files.
+ */
+
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <image.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/bitops.h>
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe_firmware.h>
+#include <spi_flash.h>
+#ifdef CONFIG_CHAIN_OF_TRUST
+#include <fsl_validate.h>
+#endif
+
+#define PFE_FIRMWARE_FIT_CNF_NAME "config@1"
+
+static const void *pfe_fit_addr;
+#ifdef CONFIG_CHAIN_OF_TRUST
+static const void *pfe_esbc_hdr_addr;
+#endif
+
+/*
+ * PFE elf firmware loader.
+ * Loads an elf firmware image into a list of PE's (specified using a bitmask)
+ *
+ * @param pe_mask Mask of PE id's to load firmware to
+ * @param pfe_firmware Pointer to the firmware image
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_load_elf(int pe_mask, uint8_t *pfe_firmware)
+{
+ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)pfe_firmware;
+ Elf32_Half sections = be16_to_cpu(elf_hdr->e_shnum);
+ Elf32_Shdr *shdr = (Elf32_Shdr *)(pfe_firmware +
+ be32_to_cpu(elf_hdr->e_shoff));
+ int id, section;
+ int ret;
+
+ debug("%s: no of sections: %d\n", __func__, sections);
+
+ /* Some sanity checks */
+ if (strncmp((char *)&elf_hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG)) {
+ printf("%s: incorrect elf magic number\n", __func__);
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) {
+ printf("%s: incorrect elf class(%x)\n", __func__,
+ elf_hdr->e_ident[EI_CLASS]);
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+ printf("%s: incorrect elf data(%x)\n", __func__,
+ elf_hdr->e_ident[EI_DATA]);
+ return -1;
+ }
+
+ if (be16_to_cpu(elf_hdr->e_type) != ET_EXEC) {
+ printf("%s: incorrect elf file type(%x)\n", __func__,
+ be16_to_cpu(elf_hdr->e_type));
+ return -1;
+ }
+
+ for (section = 0; section < sections; section++, shdr++) {
+ if (!(be32_to_cpu(shdr->sh_flags) & (SHF_WRITE | SHF_ALLOC |
+ SHF_EXECINSTR)))
+ continue;
+ for (id = 0; id < MAX_PE; id++)
+ if (pe_mask & BIT(id)) {
+ ret = pe_load_elf_section(id,
+ pfe_firmware, shdr);
+ if (ret < 0)
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ return ret;
+}
+
+/*
+ * Get PFE firmware from FIT image
+ *
+ * @param data pointer to PFE firmware
+ * @param size pointer to size of the firmware
+ * @param fw_name pfe firmware name, either class or tmu
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_get_fw(const void **data,
+ size_t *size, char *fw_name)
+{
+ int conf_node_off, fw_node_off;
+ char *conf_node_name = NULL;
+ char *desc;
+ int ret = 0;
+
+ conf_node_name = PFE_FIRMWARE_FIT_CNF_NAME;
+
+ conf_node_off = fit_conf_get_node(pfe_fit_addr, conf_node_name);
+ if (conf_node_off < 0) {
+ printf("PFE Firmware: %s: no such config\n", conf_node_name);
+ return -ENOENT;
+ }
+
+ fw_node_off = fit_conf_get_prop_node(pfe_fit_addr, conf_node_off,
+ fw_name);
+ if (fw_node_off < 0) {
+ printf("PFE Firmware: No '%s' in config\n",
+ fw_name);
+ return -ENOLINK;
+ }
+
+ if (!(fit_image_verify(pfe_fit_addr, fw_node_off))) {
+ printf("PFE Firmware: Bad firmware image (bad CRC)\n");
+ return -EINVAL;
+ }
+
+ if (fit_image_get_data(pfe_fit_addr, fw_node_off, data, size)) {
+ printf("PFE Firmware: Can't get %s subimage data/size",
+ fw_name);
+ return -ENOENT;
+ }
+
+ ret = fit_get_desc(pfe_fit_addr, fw_node_off, &desc);
+ if (ret)
+ printf("PFE Firmware: Can't get description\n");
+ else
+ printf("%s\n", desc);
+
+ return ret;
+}
+
+/*
+ * Check PFE FIT image
+ *
+ * @return 0 on success, a negative value on error
+ */
+static int pfe_fit_check(void)
+{
+ int ret = 0;
+
+ ret = fdt_check_header(pfe_fit_addr);
+ if (ret) {
+ printf("PFE Firmware: Bad firmware image (not a FIT image)\n");
+ return ret;
+ }
+
+ if (fit_check_format(pfe_fit_addr, IMAGE_SIZE_INVAL)) {
+ printf("PFE Firmware: Bad firmware image (bad FIT header)\n");
+ ret = -1;
+ return ret;
+ }
+
+ return ret;
+}
+
+int pfe_spi_flash_init(void)
+{
+ struct spi_flash *pfe_flash;
+ struct udevice *new;
+ int ret = 0;
+ void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH);
+
+ if (!addr)
+ return -ENOMEM;
+
+ ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
+ CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ,
+ CONFIG_ENV_SPI_MODE,
+ &new);
+ if (ret) {
+ printf("SF: failed to probe spi\n");
+ free(addr);
+ device_remove(new, DM_REMOVE_NORMAL);
+ return ret;
+ }
+
+
+ pfe_flash = dev_get_uclass_priv(new);
+ if (!pfe_flash) {
+ printf("SF: probe for pfe failed\n");
+ free(addr);
+ device_remove(new, DM_REMOVE_NORMAL);
+ return -ENODEV;
+ }
+
+ ret = spi_flash_read(pfe_flash,
+ CONFIG_SYS_LS_PFE_FW_ADDR,
+ CONFIG_SYS_LS_PFE_FW_LENGTH,
+ addr);
+ if (ret) {
+ printf("SF: read for pfe failed\n");
+ free(addr);
+ spi_flash_free(pfe_flash);
+ return ret;
+ }
+
+#ifdef CONFIG_CHAIN_OF_TRUST
+ void *hdr_addr = malloc(CONFIG_SYS_LS_PFE_ESBC_LENGTH);
+
+ if (!hdr_addr) {
+ free(addr);
+ spi_flash_free(pfe_flash);
+ return -ENOMEM;
+ }
+
+ ret = spi_flash_read(pfe_flash,
+ CONFIG_SYS_LS_PFE_ESBC_ADDR,
+ CONFIG_SYS_LS_PFE_ESBC_LENGTH,
+ hdr_addr);
+ if (ret) {
+ printf("SF: failed to read pfe esbc header\n");
+ free(addr);
+ free(hdr_addr);
+ spi_flash_free(pfe_flash);
+ return ret;
+ }
+
+ pfe_esbc_hdr_addr = hdr_addr;
+#endif
+ pfe_fit_addr = addr;
+ spi_flash_free(pfe_flash);
+
+ return ret;
+}
+
+/*
+ * PFE firmware initialization.
+ * Loads different firmware files from FIT image.
+ * Initializes PE IMEM/DMEM and UTIL-PE DDR
+ * Initializes control path symbol addresses (by looking them up in the elf
+ * firmware files
+ * Takes PE's out of reset
+ *
+ * @return 0 on success, a negative value on error
+ */
+int pfe_firmware_init(void)
+{
+#define PFE_KEY_HASH NULL
+ char *pfe_firmware_name;
+ const void *raw_image_addr;
+ size_t raw_image_size = 0;
+ u8 *pfe_firmware;
+#ifdef CONFIG_CHAIN_OF_TRUST
+ uintptr_t pfe_esbc_hdr = 0;
+ uintptr_t pfe_img_addr = 0;
+#endif
+ int ret = 0;
+ int fw_count, max_fw_count;
+ const char *p;
+
+ ret = pfe_spi_flash_init();
+ if (ret)
+ goto err;
+
+ ret = pfe_fit_check();
+ if (ret)
+ goto err;
+
+#ifdef CONFIG_CHAIN_OF_TRUST
+ pfe_esbc_hdr = (uintptr_t)pfe_esbc_hdr_addr;
+ pfe_img_addr = (uintptr_t)pfe_fit_addr;
+ if (fsl_check_boot_mode_secure() != 0) {
+ /*
+ * In case of failure in validation, fsl_secboot_validate
+ * would not return back in case of Production environment
+ * with ITS=1. In Development environment (ITS=0 and
+ * SB_EN=1), the function may return back in case of
+ * non-fatal failures.
+ */
+ ret = fsl_secboot_validate(pfe_esbc_hdr,
+ PFE_KEY_HASH,
+ &pfe_img_addr);
+ if (ret != 0)
+ printf("PFE firmware(s) validation failed\n");
+ else
+ printf("PFE firmware(s) validation Successful\n");
+ }
+#endif
+
+ p = env_get("load_util");
+ if (!p) {
+ max_fw_count = 2;
+ } else {
+ max_fw_count = simple_strtoul(p, NULL, 10);
+ if (max_fw_count)
+ max_fw_count = 3;
+ else
+ max_fw_count = 2;
+ }
+
+ for (fw_count = 0; fw_count < max_fw_count; fw_count++) {
+ switch (fw_count) {
+ case 0:
+ pfe_firmware_name = "class_slowpath";
+ break;
+ case 1:
+ pfe_firmware_name = "tmu_slowpath";
+ break;
+ case 2:
+ pfe_firmware_name = "util_slowpath";
+ break;
+ }
+
+ if (pfe_get_fw(&raw_image_addr, &raw_image_size,
+ pfe_firmware_name)) {
+ printf("%s firmware couldn't be found in FIT image\n",
+ pfe_firmware_name);
+ break;
+ }
+ pfe_firmware = malloc(raw_image_size);
+ if (!pfe_firmware)
+ return -ENOMEM;
+ memcpy((void *)pfe_firmware, (void *)raw_image_addr,
+ raw_image_size);
+
+ switch (fw_count) {
+ case 0:
+ env_set_addr("class_elf_firmware", pfe_firmware);
+ env_set_addr("class_elf_size", (void *)raw_image_size);
+ break;
+ case 1:
+ env_set_addr("tmu_elf_firmware", pfe_firmware);
+ env_set_addr("tmu_elf_size", (void *)raw_image_size);
+ break;
+ case 2:
+ env_set_addr("util_elf_firmware", pfe_firmware);
+ env_set_addr("util_elf_size", (void *)raw_image_size);
+ break;
+ }
+ }
+
+ raw_image_addr = NULL;
+ pfe_firmware = NULL;
+ raw_image_size = 0;
+ for (fw_count = 0; fw_count < 2; fw_count++) {
+ if (fw_count == 0)
+ pfe_firmware_name = "class";
+ else if (fw_count == 1)
+ pfe_firmware_name = "tmu";
+
+ pfe_get_fw(&raw_image_addr, &raw_image_size, pfe_firmware_name);
+ pfe_firmware = malloc(raw_image_size);
+ if (!pfe_firmware)
+ return -ENOMEM;
+ memcpy((void *)pfe_firmware, (void *)raw_image_addr,
+ raw_image_size);
+
+ if (fw_count == 0)
+ ret = pfe_load_elf(CLASS_MASK, pfe_firmware);
+ else if (fw_count == 1)
+ ret = pfe_load_elf(TMU_MASK, pfe_firmware);
+
+ if (ret < 0) {
+ printf("%s: %s firmware load failed\n", __func__,
+ pfe_firmware_name);
+ goto err;
+ }
+ debug("%s: %s firmware loaded\n", __func__, pfe_firmware_name);
+ free(pfe_firmware);
+ }
+
+ tmu_enable(0xb);
+ class_enable();
+ gpi_enable(HGPI_BASE_ADDR);
+
+err:
+ return ret;
+}
+
+/*
+ * PFE firmware cleanup
+ * Puts PE's in reset
+ */
+void pfe_firmware_exit(void)
+{
+ debug("%s\n", __func__);
+
+ class_disable();
+ tmu_disable(0xf);
+ hif_tx_disable();
+ hif_rx_disable();
+}
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_hw.c b/roms/u-boot/drivers/net/pfe_eth/pfe_hw.c
new file mode 100644
index 000000000..722f5c238
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_hw.c
@@ -0,0 +1,1000 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+#include <log.h>
+#include <linux/bitops.h>
+#include <net/pfe_eth/pfe_eth.h>
+#include <net/pfe_eth/pfe/pfe_hw.h>
+
+static struct pe_info pe[MAX_PE];
+
+/*
+ * Initializes the PFE library.
+ * Must be called before using any of the library functions.
+ */
+void pfe_lib_init(void)
+{
+ int pfe_pe_id;
+
+ for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
+ pe[pfe_pe_id].dmem_base_addr =
+ (u32)CLASS_DMEM_BASE_ADDR(pfe_pe_id);
+ pe[pfe_pe_id].pmem_base_addr =
+ (u32)CLASS_IMEM_BASE_ADDR(pfe_pe_id);
+ pe[pfe_pe_id].pmem_size = (u32)CLASS_IMEM_SIZE;
+ pe[pfe_pe_id].mem_access_wdata =
+ (void *)CLASS_MEM_ACCESS_WDATA;
+ pe[pfe_pe_id].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
+ pe[pfe_pe_id].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
+ }
+
+ for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
+ if (pfe_pe_id == TMU2_ID)
+ continue;
+ pe[pfe_pe_id].dmem_base_addr =
+ (u32)TMU_DMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
+ pe[pfe_pe_id].pmem_base_addr =
+ (u32)TMU_IMEM_BASE_ADDR(pfe_pe_id - TMU0_ID);
+ pe[pfe_pe_id].pmem_size = (u32)TMU_IMEM_SIZE;
+ pe[pfe_pe_id].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
+ pe[pfe_pe_id].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
+ pe[pfe_pe_id].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
+ }
+}
+
+/*
+ * Writes a buffer to PE internal memory from the host
+ * through indirect access registers.
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] mem_access_addr DMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_mem_memcpy_to32(int id, u32 mem_access_addr, const void *src,
+ unsigned int len)
+{
+ u32 offset = 0, val, addr;
+ unsigned int len32 = len >> 2;
+ int i;
+
+ addr = mem_access_addr | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_BYTE_ENABLE(0, 4);
+
+ for (i = 0; i < len32; i++, offset += 4, src += 4) {
+ val = *(u32 *)src;
+ writel(cpu_to_be32(val), pe[id].mem_access_wdata);
+ writel(addr + offset, pe[id].mem_access_addr);
+ }
+
+ len = (len & 0x3);
+ if (len) {
+ val = 0;
+
+ addr = (mem_access_addr | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_BYTE_ENABLE(0, len)) + offset;
+
+ for (i = 0; i < len; i++, src++)
+ val |= (*(u8 *)src) << (8 * i);
+
+ writel(cpu_to_be32(val), pe[id].mem_access_wdata);
+ writel(addr, pe[id].mem_access_addr);
+ }
+}
+
+/*
+ * Writes a buffer to PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] dst DMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_dmem_memcpy_to32(int id, u32 dst, const void *src,
+ unsigned int len)
+{
+ pe_mem_memcpy_to32(id, pe[id].dmem_base_addr | dst | PE_MEM_ACCESS_DMEM,
+ src, len);
+}
+
+/*
+ * Writes a buffer to PE internal program memory (PMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., TMU3_ID)
+ * @param[in] dst PMEM destination address (must be 32bit
+ * aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void pe_pmem_memcpy_to32(int id, u32 dst, const void *src,
+ unsigned int len)
+{
+ pe_mem_memcpy_to32(id, pe[id].pmem_base_addr | (dst & (pe[id].pmem_size
+ - 1)) | PE_MEM_ACCESS_IMEM, src, len);
+}
+
+/*
+ * Reads PE internal program memory (IMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., TMU3_ID)
+ * @param[in] addr PMEM read address (must be aligned on size)
+ * @param[in] size Number of bytes to read (maximum 4, must not
+ * cross 32bit boundaries)
+ * @return the data read (in PE endianness, i.e BE).
+ */
+u32 pe_pmem_read(int id, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ addr = pe[id].pmem_base_addr | ((addr & ~0x3) & (pe[id].pmem_size - 1))
+ | PE_MEM_ACCESS_READ | PE_MEM_ACCESS_IMEM |
+ PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ writel(addr, pe[id].mem_access_addr);
+ val = be32_to_cpu(readl(pe[id].mem_access_rdata));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * Writes PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] val Value to write (in PE endianness, i.e BE)
+ * @param[in] addr DMEM write address (must be aligned on size)
+ * @param[in] size Number of bytes to write (maximum 4, must not
+ * cross 32bit boundaries)
+ */
+void pe_dmem_write(int id, u32 val, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+
+ addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_WRITE |
+ PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ /* Indirect access interface is byte swapping data being written */
+ writel(cpu_to_be32(val << (offset << 3)), pe[id].mem_access_wdata);
+ writel(addr, pe[id].mem_access_addr);
+}
+
+/*
+ * Reads PE internal data memory (DMEM) from the host
+ * through indirect access registers.
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] addr DMEM read address (must be aligned on size)
+ * @param[in] size Number of bytes to read (maximum 4, must not
+ * cross 32bit boundaries)
+ * @return the data read (in PE endianness, i.e BE).
+ */
+u32 pe_dmem_read(int id, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ addr = pe[id].dmem_base_addr | (addr & ~0x3) | PE_MEM_ACCESS_READ |
+ PE_MEM_ACCESS_DMEM | PE_MEM_ACCESS_BYTE_ENABLE(offset, size);
+
+ writel(addr, pe[id].mem_access_addr);
+
+ /* Indirect access interface is byte swapping data being read */
+ val = be32_to_cpu(readl(pe[id].mem_access_rdata));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * This function is used to write to CLASS internal bus peripherals (ccu,
+ * pe-lem) from the host
+ * through indirect access registers.
+ * @param[in] val value to write
+ * @param[in] addr Address to write to (must be aligned on size)
+ * @param[in] size Number of bytes to write (1, 2 or 4)
+ *
+ */
+static void class_bus_write(u32 val, u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+
+ writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
+
+ addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | PE_MEM_ACCESS_WRITE |
+ (size << 24);
+
+ writel(cpu_to_be32(val << (offset << 3)), CLASS_BUS_ACCESS_WDATA);
+ writel(addr, CLASS_BUS_ACCESS_ADDR);
+}
+
+/*
+ * Reads from CLASS internal bus peripherals (ccu, pe-lem) from the host
+ * through indirect access registers.
+ * @param[in] addr Address to read from (must be aligned on size)
+ * @param[in] size Number of bytes to read (1, 2 or 4)
+ * @return the read data
+ */
+static u32 class_bus_read(u32 addr, u8 size)
+{
+ u32 offset = addr & 0x3;
+ u32 mask = 0xffffffff >> ((4 - size) << 3);
+ u32 val;
+
+ writel((addr & CLASS_BUS_ACCESS_BASE_MASK), CLASS_BUS_ACCESS_BASE);
+
+ addr = (addr & ~CLASS_BUS_ACCESS_BASE_MASK) | (size << 24);
+
+ writel(addr, CLASS_BUS_ACCESS_ADDR);
+ val = be32_to_cpu(readl(CLASS_BUS_ACCESS_RDATA));
+
+ return (val >> (offset << 3)) & mask;
+}
+
+/*
+ * Writes data to the cluster memory (PE_LMEM)
+ * @param[in] dst PE LMEM destination address (must be 32bit aligned)
+ * @param[in] src Buffer source address
+ * @param[in] len Number of bytes to copy
+ */
+static void class_pe_lmem_memcpy_to32(u32 dst, const void *src,
+ unsigned int len)
+{
+ u32 len32 = len >> 2;
+ int i;
+
+ for (i = 0; i < len32; i++, src += 4, dst += 4)
+ class_bus_write(*(u32 *)src, dst, 4);
+
+ if (len & 0x2) {
+ class_bus_write(*(u16 *)src, dst, 2);
+ src += 2;
+ dst += 2;
+ }
+
+ if (len & 0x1) {
+ class_bus_write(*(u8 *)src, dst, 1);
+ src++;
+ dst++;
+ }
+}
+
+/*
+ * Writes value to the cluster memory (PE_LMEM)
+ * @param[in] dst PE LMEM destination address (must be 32bit aligned)
+ * @param[in] val Value to write
+ * @param[in] len Number of bytes to write
+ */
+static void class_pe_lmem_memset(u32 dst, int val, unsigned int len)
+{
+ u32 len32 = len >> 2;
+ int i;
+
+ val = val | (val << 8) | (val << 16) | (val << 24);
+
+ for (i = 0; i < len32; i++, dst += 4)
+ class_bus_write(val, dst, 4);
+
+ if (len & 0x2) {
+ class_bus_write(val, dst, 2);
+ dst += 2;
+ }
+
+ if (len & 0x1) {
+ class_bus_write(val, dst, 1);
+ dst++;
+ }
+}
+
+/*
+ * Reads data from the cluster memory (PE_LMEM)
+ * @param[out] dst pointer to the source buffer data are copied to
+ * @param[in] len length in bytes of the amount of data to read
+ * from cluster memory
+ * @param[in] offset offset in bytes in the cluster memory where data are
+ * read from
+ */
+void pe_lmem_read(u32 *dst, u32 len, u32 offset)
+{
+ u32 len32 = len >> 2;
+ int i = 0;
+
+ for (i = 0; i < len32; dst++, i++, offset += 4)
+ *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, 4);
+
+ if (len & 0x03)
+ *dst = class_bus_read(PE_LMEM_BASE_ADDR + offset, (len & 0x03));
+}
+
+/*
+ * Writes data to the cluster memory (PE_LMEM)
+ * @param[in] src pointer to the source buffer data are copied from
+ * @param[in] len length in bytes of the amount of data to write to the
+ * cluster memory
+ * @param[in] offset offset in bytes in the cluster memory where data are
+ * written to
+ */
+void pe_lmem_write(u32 *src, u32 len, u32 offset)
+{
+ u32 len32 = len >> 2;
+ int i = 0;
+
+ for (i = 0; i < len32; src++, i++, offset += 4)
+ class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, 4);
+
+ if (len & 0x03)
+ class_bus_write(*src, PE_LMEM_BASE_ADDR + offset, (len &
+ 0x03));
+}
+
+/*
+ * Loads an elf section into pmem
+ * Code needs to be at least 16bit aligned and only PROGBITS sections are
+ * supported
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID, ...,
+ * TMU3_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_pmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x1) {
+ printf("%s: load address(%x) is not 16bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ if (size & 0x1) {
+ printf("%s: load size(%x) is not 16bit aligned\n", __func__,
+ size);
+ return -1;
+ }
+
+ debug("pmem pe%d @%x len %d\n", id, addr, size);
+ switch (type) {
+ case SHT_PROGBITS:
+ pe_pmem_memcpy_to32(id, addr, data + offset, size);
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into dmem
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_dmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+ u32 size32 = size >> 2;
+ int i;
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x3) {
+ printf("%s: load address(%x) is not 32bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ switch (type) {
+ case SHT_PROGBITS:
+ debug("dmem pe%d @%x len %d\n", id, addr, size);
+ pe_dmem_memcpy_to32(id, addr, data + offset, size);
+ break;
+
+ case SHT_NOBITS:
+ debug("dmem zero pe%d @%x len %d\n", id, addr, size);
+ for (i = 0; i < size32; i++, addr += 4)
+ pe_dmem_write(id, 0, addr, 4);
+
+ if (size & 0x3)
+ pe_dmem_write(id, 0, addr, size & 0x3);
+
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into DDR
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_ddr_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+ u32 flags = be32_to_cpu(shdr->sh_flags);
+
+ switch (type) {
+ case SHT_PROGBITS:
+ debug("ddr pe%d @%x len %d\n", id, addr, size);
+ if (flags & SHF_EXECINSTR) {
+ if (id <= CLASS_MAX_ID) {
+ /* DO the loading only once in DDR */
+ if (id == CLASS0_ID) {
+ debug(
+ "%s: load address(%x) and elf file address(%lx) rcvd\n"
+ , __func__, addr,
+ (unsigned long)data + offset);
+ if (((unsigned long)(data + offset)
+ & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr,
+ (unsigned long)data +
+ offset);
+
+ return -1;
+ }
+
+ if (addr & 0x1) {
+ printf(
+ "%s: load address(%x) is not 16bit aligned\n"
+ , __func__, addr);
+ return -1;
+ }
+
+ if (size & 0x1) {
+ printf(
+ "%s: load length(%x) is not 16bit aligned\n"
+ , __func__, size);
+ return -1;
+ }
+
+ memcpy((void *)DDR_PFE_TO_VIRT(addr),
+ data + offset, size);
+ }
+ } else {
+ printf(
+ "%s: unsupported ddr section type(%x) for PE(%d)\n"
+ , __func__, type, id);
+ return -1;
+ }
+
+ } else {
+ memcpy((void *)DDR_PFE_TO_VIRT(addr), data + offset,
+ size);
+ }
+
+ break;
+
+ case SHT_NOBITS:
+ debug("ddr zero pe%d @%x len %d\n", id, addr, size);
+ memset((void *)DDR_PFE_TO_VIRT(addr), 0, size);
+
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into pe lmem
+ * Data needs to be at least 32bit aligned, NOBITS sections are correctly
+ * initialized to 0
+ *
+ * @param[in] id PE identification (CLASS0_ID,..., CLASS5_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+static int pe_load_pe_lmem_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 offset = be32_to_cpu(shdr->sh_offset);
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+ u32 type = be32_to_cpu(shdr->sh_type);
+
+ if (id > CLASS_MAX_ID) {
+ printf("%s: unsupported pe-lmem section type(%x) for PE(%d)\n",
+ __func__, type, id);
+ return -1;
+ }
+
+ if (((unsigned long)(data + offset) & 0x3) != (addr & 0x3)) {
+ printf(
+ "%s: load address(%x) and elf file address(%lx) don't have the same alignment\n",
+ __func__, addr, (unsigned long)data + offset);
+
+ return -1;
+ }
+
+ if (addr & 0x3) {
+ printf("%s: load address(%x) is not 32bit aligned\n",
+ __func__, addr);
+ return -1;
+ }
+
+ debug("lmem pe%d @%x len %d\n", id, addr, size);
+
+ switch (type) {
+ case SHT_PROGBITS:
+ class_pe_lmem_memcpy_to32(addr, data + offset, size);
+ break;
+
+ case SHT_NOBITS:
+ class_pe_lmem_memset(addr, 0, size);
+ break;
+
+ default:
+ printf("%s: unsupported section type(%x)\n", __func__, type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Loads an elf section into a PE
+ * For now only supports loading a section to dmem (all PE's), pmem (class and
+ * tmu PE's), DDDR (util PE code)
+ * @param[in] id PE identification (CLASS0_ID, ..., TMU0_ID,
+ * ..., UTIL_ID)
+ * @param[in] data pointer to the elf firmware
+ * @param[in] shdr pointer to the elf section header
+ */
+int pe_load_elf_section(int id, const void *data, Elf32_Shdr *shdr)
+{
+ u32 addr = be32_to_cpu(shdr->sh_addr);
+ u32 size = be32_to_cpu(shdr->sh_size);
+
+ if (IS_DMEM(addr, size))
+ return pe_load_dmem_section(id, data, shdr);
+ else if (IS_PMEM(addr, size))
+ return pe_load_pmem_section(id, data, shdr);
+ else if (IS_PFE_LMEM(addr, size))
+ return 0;
+ else if (IS_PHYS_DDR(addr, size))
+ return pe_load_ddr_section(id, data, shdr);
+ else if (IS_PE_LMEM(addr, size))
+ return pe_load_pe_lmem_section(id, data, shdr);
+
+ printf("%s: unsupported memory range(%x)\n", __func__, addr);
+
+ return 0;
+}
+
+/**************************** BMU ***************************/
+/*
+ * Resets a BMU block.
+ * @param[in] base BMU block base address
+ */
+static inline void bmu_reset(void *base)
+{
+ writel(CORE_SW_RESET, base + BMU_CTRL);
+
+ /* Wait for self clear */
+ while (readl(base + BMU_CTRL) & CORE_SW_RESET)
+ ;
+}
+
+/*
+ * Enabled a BMU block.
+ * @param[in] base BMU block base address
+ */
+void bmu_enable(void *base)
+{
+ writel(CORE_ENABLE, base + BMU_CTRL);
+}
+
+/*
+ * Disables a BMU block.
+ * @param[in] base BMU block base address
+ */
+static inline void bmu_disable(void *base)
+{
+ writel(CORE_DISABLE, base + BMU_CTRL);
+}
+
+/*
+ * Sets the configuration of a BMU block.
+ * @param[in] base BMU block base address
+ * @param[in] cfg BMU configuration
+ */
+static inline void bmu_set_config(void *base, struct bmu_cfg *cfg)
+{
+ writel(cfg->baseaddr, base + BMU_UCAST_BASE_ADDR);
+ writel(cfg->count & 0xffff, base + BMU_UCAST_CONFIG);
+ writel(cfg->size & 0xffff, base + BMU_BUF_SIZE);
+
+ /* Interrupts are never used */
+ writel(0x0, base + BMU_INT_ENABLE);
+}
+
+/*
+ * Initializes a BMU block.
+ * @param[in] base BMU block base address
+ * @param[in] cfg BMU configuration
+ */
+void bmu_init(void *base, struct bmu_cfg *cfg)
+{
+ bmu_disable(base);
+
+ bmu_set_config(base, cfg);
+
+ bmu_reset(base);
+}
+
+/**************************** GPI ***************************/
+/*
+ * Resets a GPI block.
+ * @param[in] base GPI base address
+ */
+static inline void gpi_reset(void *base)
+{
+ writel(CORE_SW_RESET, base + GPI_CTRL);
+}
+
+/*
+ * Enables a GPI block.
+ * @param[in] base GPI base address
+ */
+void gpi_enable(void *base)
+{
+ writel(CORE_ENABLE, base + GPI_CTRL);
+}
+
+/*
+ * Disables a GPI block.
+ * @param[in] base GPI base address
+ */
+void gpi_disable(void *base)
+{
+ writel(CORE_DISABLE, base + GPI_CTRL);
+}
+
+/*
+ * Sets the configuration of a GPI block.
+ * @param[in] base GPI base address
+ * @param[in] cfg GPI configuration
+ */
+static inline void gpi_set_config(void *base, struct gpi_cfg *cfg)
+{
+ writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_ALLOC_CTRL), base
+ + GPI_LMEM_ALLOC_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_FREE_CTRL), base
+ + GPI_LMEM_FREE_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_ALLOC_CTRL), base
+ + GPI_DDR_ALLOC_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL), base
+ + GPI_DDR_FREE_ADDR);
+ writel(CBUS_VIRT_TO_PFE(CLASS_INQ_PKTPTR), base + GPI_CLASS_ADDR);
+ writel(DDR_HDR_SIZE, base + GPI_DDR_DATA_OFFSET);
+ writel(LMEM_HDR_SIZE, base + GPI_LMEM_DATA_OFFSET);
+ writel(0, base + GPI_LMEM_SEC_BUF_DATA_OFFSET);
+ writel(0, base + GPI_DDR_SEC_BUF_DATA_OFFSET);
+ writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, base + GPI_HDR_SIZE);
+ writel((DDR_BUF_SIZE << 16) | LMEM_BUF_SIZE, base + GPI_BUF_SIZE);
+
+ writel(((cfg->lmem_rtry_cnt << 16) | (GPI_DDR_BUF_EN << 1) |
+ GPI_LMEM_BUF_EN), base + GPI_RX_CONFIG);
+ writel(cfg->tmlf_txthres, base + GPI_TMLF_TX);
+ writel(cfg->aseq_len, base + GPI_DTX_ASEQ);
+
+ /*Make GPI AXI transactions non-bufferable */
+ writel(0x1, base + GPI_AXI_CTRL);
+}
+
+/*
+ * Initializes a GPI block.
+ * @param[in] base GPI base address
+ * @param[in] cfg GPI configuration
+ */
+void gpi_init(void *base, struct gpi_cfg *cfg)
+{
+ gpi_reset(base);
+
+ gpi_disable(base);
+
+ gpi_set_config(base, cfg);
+}
+
+/**************************** CLASSIFIER ***************************/
+/*
+ * Resets CLASSIFIER block.
+ */
+static inline void class_reset(void)
+{
+ writel(CORE_SW_RESET, CLASS_TX_CTRL);
+}
+
+/*
+ * Enables all CLASS-PE's cores.
+ */
+void class_enable(void)
+{
+ writel(CORE_ENABLE, CLASS_TX_CTRL);
+}
+
+/*
+ * Disables all CLASS-PE's cores.
+ */
+void class_disable(void)
+{
+ writel(CORE_DISABLE, CLASS_TX_CTRL);
+}
+
+/*
+ * Sets the configuration of the CLASSIFIER block.
+ * @param[in] cfg CLASSIFIER configuration
+ */
+static inline void class_set_config(struct class_cfg *cfg)
+{
+ if (PLL_CLK_EN == 0) {
+ /* Clock ratio: for 1:1 the value is 0 */
+ writel(0x0, CLASS_PE_SYS_CLK_RATIO);
+ } else {
+ /* Clock ratio: for 1:2 the value is 1 */
+ writel(0x1, CLASS_PE_SYS_CLK_RATIO);
+ }
+ writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, CLASS_HDR_SIZE);
+ writel(LMEM_BUF_SIZE, CLASS_LMEM_BUF_SIZE);
+ writel(CLASS_ROUTE_ENTRY_SIZE(CLASS_ROUTE_SIZE) |
+ CLASS_ROUTE_HASH_SIZE(cfg->route_table_hash_bits),
+ CLASS_ROUTE_HASH_ENTRY_SIZE);
+ writel(HASH_CRC_PORT_IP | QB2BUS_LE, CLASS_ROUTE_MULTI);
+
+ writel(cfg->route_table_baseaddr, CLASS_ROUTE_TABLE_BASE);
+ memset((void *)DDR_PFE_TO_VIRT(cfg->route_table_baseaddr), 0,
+ ROUTE_TABLE_SIZE);
+
+ writel(CLASS_PE0_RO_DM_ADDR0_VAL, CLASS_PE0_RO_DM_ADDR0);
+ writel(CLASS_PE0_RO_DM_ADDR1_VAL, CLASS_PE0_RO_DM_ADDR1);
+ writel(CLASS_PE0_QB_DM_ADDR0_VAL, CLASS_PE0_QB_DM_ADDR0);
+ writel(CLASS_PE0_QB_DM_ADDR1_VAL, CLASS_PE0_QB_DM_ADDR1);
+ writel(CBUS_VIRT_TO_PFE(TMU_PHY_INQ_PKTPTR), CLASS_TM_INQ_ADDR);
+
+ writel(23, CLASS_AFULL_THRES);
+ writel(23, CLASS_TSQ_FIFO_THRES);
+
+ writel(24, CLASS_MAX_BUF_CNT);
+ writel(24, CLASS_TSQ_MAX_CNT);
+
+ /*Make Class AXI transactions non-bufferable */
+ writel(0x1, CLASS_AXI_CTRL);
+
+ /*Make Util AXI transactions non-bufferable */
+ /*Util is disabled in U-boot, do it from here */
+ writel(0x1, UTIL_AXI_CTRL);
+}
+
+/*
+ * Initializes CLASSIFIER block.
+ * @param[in] cfg CLASSIFIER configuration
+ */
+void class_init(struct class_cfg *cfg)
+{
+ class_reset();
+
+ class_disable();
+
+ class_set_config(cfg);
+}
+
+/**************************** TMU ***************************/
+/*
+ * Enables TMU-PE cores.
+ * @param[in] pe_mask TMU PE mask
+ */
+void tmu_enable(u32 pe_mask)
+{
+ writel(readl(TMU_TX_CTRL) | (pe_mask & 0xF), TMU_TX_CTRL);
+}
+
+/*
+ * Disables TMU cores.
+ * @param[in] pe_mask TMU PE mask
+ */
+void tmu_disable(u32 pe_mask)
+{
+ writel(readl(TMU_TX_CTRL) & ~(pe_mask & 0xF), TMU_TX_CTRL);
+}
+
+/*
+ * Initializes TMU block.
+ * @param[in] cfg TMU configuration
+ */
+void tmu_init(struct tmu_cfg *cfg)
+{
+ int q, phyno;
+
+ /* keep in soft reset */
+ writel(SW_RESET, TMU_CTRL);
+
+ /*Make Class AXI transactions non-bufferable */
+ writel(0x1, TMU_AXI_CTRL);
+
+ /* enable EMAC PHY ports */
+ writel(0x3, TMU_SYS_GENERIC_CONTROL);
+
+ writel(750, TMU_INQ_WATERMARK);
+
+ writel(CBUS_VIRT_TO_PFE(EGPI1_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY0_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(EGPI2_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY1_INQ_ADDR);
+
+ writel(CBUS_VIRT_TO_PFE(HGPI_BASE_ADDR + GPI_INQ_PKTPTR),
+ TMU_PHY3_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(HIF_NOCPY_RX_INQ0_PKTPTR), TMU_PHY4_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(UTIL_INQ_PKTPTR), TMU_PHY5_INQ_ADDR);
+ writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL),
+ TMU_BMU_INQ_ADDR);
+
+ /* enabling all 10 schedulers [9:0] of each TDQ */
+ writel(0x3FF, TMU_TDQ0_SCH_CTRL);
+ writel(0x3FF, TMU_TDQ1_SCH_CTRL);
+ writel(0x3FF, TMU_TDQ3_SCH_CTRL);
+
+ if (PLL_CLK_EN == 0) {
+ /* Clock ratio: for 1:1 the value is 0 */
+ writel(0x0, TMU_PE_SYS_CLK_RATIO);
+ } else {
+ /* Clock ratio: for 1:2 the value is 1 */
+ writel(0x1, TMU_PE_SYS_CLK_RATIO);
+ }
+
+ /* Extra packet pointers will be stored from this address onwards */
+ debug("TMU_LLM_BASE_ADDR %x\n", cfg->llm_base_addr);
+ writel(cfg->llm_base_addr, TMU_LLM_BASE_ADDR);
+
+ debug("TMU_LLM_QUE_LEN %x\n", cfg->llm_queue_len);
+ writel(cfg->llm_queue_len, TMU_LLM_QUE_LEN);
+
+ writel(5, TMU_TDQ_IIFG_CFG);
+ writel(DDR_BUF_SIZE, TMU_BMU_BUF_SIZE);
+
+ writel(0x0, TMU_CTRL);
+
+ /* MEM init */
+ writel(MEM_INIT, TMU_CTRL);
+
+ while (!(readl(TMU_CTRL) & MEM_INIT_DONE))
+ ;
+
+ /* LLM init */
+ writel(LLM_INIT, TMU_CTRL);
+
+ while (!(readl(TMU_CTRL) & LLM_INIT_DONE))
+ ;
+
+ /* set up each queue for tail drop */
+ for (phyno = 0; phyno < 4; phyno++) {
+ if (phyno == 2)
+ continue;
+ for (q = 0; q < 16; q++) {
+ u32 qmax;
+
+ writel((phyno << 8) | q, TMU_TEQ_CTRL);
+ writel(BIT(22), TMU_TEQ_QCFG);
+
+ if (phyno == 3)
+ qmax = DEFAULT_TMU3_QDEPTH;
+ else
+ qmax = (q == 0) ? DEFAULT_Q0_QDEPTH :
+ DEFAULT_MAX_QDEPTH;
+
+ writel(qmax << 18, TMU_TEQ_HW_PROB_CFG2);
+ writel(qmax >> 14, TMU_TEQ_HW_PROB_CFG3);
+ }
+ }
+ writel(0x05, TMU_TEQ_DISABLE_DROPCHK);
+ writel(0, TMU_CTRL);
+}
+
+/**************************** HIF ***************************/
+/*
+ * Enable hif tx DMA and interrupt
+ */
+void hif_tx_enable(void)
+{
+ writel(HIF_CTRL_DMA_EN, HIF_TX_CTRL);
+}
+
+/*
+ * Disable hif tx DMA and interrupt
+ */
+void hif_tx_disable(void)
+{
+ u32 hif_int;
+
+ writel(0, HIF_TX_CTRL);
+
+ hif_int = readl(HIF_INT_ENABLE);
+ hif_int &= HIF_TXPKT_INT_EN;
+ writel(hif_int, HIF_INT_ENABLE);
+}
+
+/*
+ * Enable hif rx DMA and interrupt
+ */
+void hif_rx_enable(void)
+{
+ writel((HIF_CTRL_DMA_EN | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+}
+
+/*
+ * Disable hif rx DMA and interrupt
+ */
+void hif_rx_disable(void)
+{
+ u32 hif_int;
+
+ writel(0, HIF_RX_CTRL);
+
+ hif_int = readl(HIF_INT_ENABLE);
+ hif_int &= HIF_RXPKT_INT_EN;
+ writel(hif_int, HIF_INT_ENABLE);
+}
+
+/*
+ * Initializes HIF copy block.
+ */
+void hif_init(void)
+{
+ /* Initialize HIF registers */
+ writel(HIF_RX_POLL_CTRL_CYCLE << 16 | HIF_TX_POLL_CTRL_CYCLE,
+ HIF_POLL_CTRL);
+ /* Make HIF AXI transactions non-bufferable */
+ writel(0x1, HIF_AXI_CTRL);
+}
diff --git a/roms/u-boot/drivers/net/pfe_eth/pfe_mdio.c b/roms/u-boot/drivers/net/pfe_eth/pfe_mdio.c
new file mode 100644
index 000000000..3228b8df4
--- /dev/null
+++ b/roms/u-boot/drivers/net/pfe_eth/pfe_mdio.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/platform_data/pfe_dm_eth.h>
+#include <net.h>
+#include <linux/delay.h>
+#include <net/pfe_eth/pfe_eth.h>
+
+extern struct gemac_s gem_info[];
+#if defined(CONFIG_PHYLIB)
+
+#define MDIO_TIMEOUT 5000
+static int pfe_write_addr(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ void *reg_base = bus->priv;
+ u32 devadr;
+ u32 phy;
+ u32 reg_data;
+ int timeout = MDIO_TIMEOUT;
+
+ devadr = ((dev_addr & EMAC_MII_DATA_RA_MASK) << EMAC_MII_DATA_RA_SHIFT);
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ reg_data = (EMAC_MII_DATA_TA | phy | devadr | reg_addr);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ return 0;
+}
+
+static int pfe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr)
+{
+ void *reg_base = bus->priv;
+ u32 reg;
+ u32 phy;
+ u32 reg_data;
+ u16 val;
+ int timeout = MDIO_TIMEOUT;
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ } else {
+ pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
+ reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ }
+
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
+ EMAC_MII_DATA_TA | phy | reg);
+ else
+ reg_data = (EMAC_MII_DATA_OP_CL45_RD | EMAC_MII_DATA_TA |
+ phy | reg);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ val = (u16)readl(reg_base + EMAC_MII_DATA_REG);
+ debug("%s: %p phy: 0x%x reg:0x%08x val:%#x\n", __func__, reg_base,
+ phy_addr, reg_addr, val);
+
+ return val;
+}
+
+static int pfe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+ int reg_addr, u16 data)
+{
+ void *reg_base = bus->priv;
+ u32 reg;
+ u32 phy;
+ u32 reg_data;
+ int timeout = MDIO_TIMEOUT;
+
+ if (dev_addr == MDIO_DEVAD_NONE) {
+ reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ } else {
+ pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
+ reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
+ EMAC_MII_DATA_RA_SHIFT);
+ }
+
+ phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
+
+ if (dev_addr == MDIO_DEVAD_NONE)
+ reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
+ EMAC_MII_DATA_TA | phy | reg | data);
+ else
+ reg_data = (EMAC_MII_DATA_OP_CL45_WR | EMAC_MII_DATA_TA |
+ phy | reg | data);
+
+ writel(reg_data, reg_base + EMAC_MII_DATA_REG);
+
+ /*
+ * wait for the MII interrupt
+ */
+ while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
+ if (timeout-- <= 0) {
+ printf("Phy MDIO read/write timeout\n");
+ return -1;
+ }
+ }
+
+ /*
+ * clear MII interrupt
+ */
+ writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
+
+ debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phy_addr,
+ reg_addr, data);
+
+ return 0;
+}
+
+static void pfe_configure_serdes(struct pfe_eth_dev *priv)
+{
+ struct mii_dev bus;
+ int value, sgmii_2500 = 0;
+ struct gemac_s *gem = priv->gem;
+
+ if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500)
+ sgmii_2500 = 1;
+
+
+ /* PCS configuration done with corresponding GEMAC */
+ bus.priv = gem_info[priv->gemac_port].gemac_base;
+
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x0);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x1);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x2);
+ pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x3);
+
+ /* Reset serdes */
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x0, 0x8000);
+
+ /* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
+ value = PHY_SGMII_IF_MODE_SGMII;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_IF_MODE_AN;
+ else
+ value |= PHY_SGMII_IF_MODE_SGMII_GBT;
+
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
+
+ /* Dev ability according to SGMII specification */
+ value = PHY_SGMII_DEV_ABILITY_SGMII;
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
+
+ /* These values taken from validation team */
+ if (!sgmii_2500) {
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x0);
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0x400);
+ } else {
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x7);
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xa120);
+ }
+
+ /* Restart AN */
+ value = PHY_SGMII_CR_DEF_VAL;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_CR_RESET_AN;
+ /* Disable Auto neg for 2.5G SGMII as it doesn't support auto neg*/
+ if (sgmii_2500)
+ value &= ~PHY_SGMII_ENABLE_AN;
+ pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
+}
+
+int pfe_phy_configure(struct pfe_eth_dev *priv, int dev_id, int phy_id)
+{
+ struct phy_device *phydev = NULL;
+ struct udevice *dev = priv->dev;
+ struct gemac_s *gem = priv->gem;
+ struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+ if (!gem->bus)
+ return -1;
+
+ /* Configure SGMII PCS */
+ if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII ||
+ gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500) {
+ out_be32(&scfg->mdioselcr, 0x00000000);
+ pfe_configure_serdes(priv);
+ }
+
+ mdelay(100);
+
+ /* By this time on-chip SGMII initialization is done
+ * we can switch mdio interface to external PHYs
+ */
+ out_be32(&scfg->mdioselcr, 0x80000000);
+
+ phydev = phy_connect(gem->bus, phy_id, dev, gem->phy_mode);
+ if (!phydev) {
+ printf("phy_connect failed\n");
+ return -ENODEV;
+ }
+
+ phy_config(phydev);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+#endif
+
+struct mii_dev *pfe_mdio_init(struct pfe_mdio_info *mdio_info)
+{
+ struct mii_dev *bus;
+ int ret;
+ u32 mdio_speed;
+ u32 pclk = 250000000;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("mdio_alloc failed\n");
+ return NULL;
+ }
+ bus->read = pfe_phy_read;
+ bus->write = pfe_phy_write;
+
+ /* MAC1 MDIO used to communicate with external PHYS */
+ bus->priv = mdio_info->reg_base;
+ sprintf(bus->name, mdio_info->name);
+
+ /* configure mdio speed */
+ mdio_speed = (DIV_ROUND_UP(pclk, 4000000) << EMAC_MII_SPEED_SHIFT);
+ mdio_speed |= EMAC_HOLDTIME(0x5);
+ writel(mdio_speed, mdio_info->reg_base + EMAC_MII_CTRL_REG);
+
+ ret = mdio_register(bus);
+ if (ret) {
+ printf("mdio_register failed\n");
+ free(bus);
+ return NULL;
+ }
+ return bus;
+}
+
+void pfe_set_mdio(int dev_id, struct mii_dev *bus)
+{
+ gem_info[dev_id].bus = bus;
+}
+
+void pfe_set_phy_address_mode(int dev_id, int phy_id, int phy_mode)
+{
+ gem_info[dev_id].phy_address = phy_id;
+ gem_info[dev_id].phy_mode = phy_mode;
+}