This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[FAQ] How to boot SK-AM62B/SK-AM62A via Ethernet and flash U-boot and Linux binaries into eMMC via Ethernet ?

Other Parts Discussed in Thread: SK-AM62B

How do I boot an SK-AM62B or SK-AM62A using Ethernet and subsequently flash the required U-boot binaries and Kernel, DTB, and root filesystem to eMMC?


The solution is divided into two sections:

1) This section describes how to boot into U-boot, via Ethernet boot mode.

2) This section describes how to flash required U-boot binaries and filesystem into eMMC, and completely boot Linux from EMMC, using Ethernet to flash images.




  • How to boot SK-AM62B/SK-AM62A into U-boot using Ethernet as primary boot mode?

    ***IMPORTANT NOTES ***

    SK-AM62B: Booting via Ethernet is not recommended for production purposes and should only really be used for development. The reason is because of Errata i2329 which mentions that there is no workaround to guarantee the primary Ethernet boot mode is successful.

    SK-AM62A: On SDK v9.1, booting via Ethernet is not supported out-of-the-box despite what is indicated by the SDK documentation. There is a patch that could be applied in order to get booting via Ethernet working which can find in this E2E thread: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1307981/sk-am62a-lp-rgmii-boot-mode-problem/4968147#4968147 

    1. Build the u-boot binaries (tiboot3.bin, tispl.bin, u-boot.img) with the ethboot defconfig

    Follow the steps indicated in https://software-dl.ti.com/processor-sdk-linux-rt/esd/AM62X/latest/exports/docs/linux/Foundational_Components/U-Boot/UG-Network-K3.html?highlight=am62x_evm_r5_ethboot_defconfig#booting-over-ethernet-ethernet-rgmii 

    Make sure to build with "am62x_evm_r5_ethboot_defconfig" instead of the default "am62x_evm_r5_defconfig". You can change this by going into "Rules.make" in the top-level directory of your SDK installation and changing "UBOOT_MACHINE_R5=am62x_evm_r5_defconfig".

    Afterwards, to build the u-boot binaries just enter "make u-boot" in the top-level directory of your SDK installation. Details on how to build u-boot binaries can also be found at our Linux Academy

    Key Notes:

    • You may find the following error message when you attempt to build the u-boot binaries. If you see this, add "CONFIG_SYSCON=y" and "CONFIG_SPL_SYSCON=y" to the ethboot defconfig. If you see this replace /drivers/net/ti/am65-cpsw-nuss.c with this version: 
      7028.am65-cpsw-nuss.c
      // SPDX-License-Identifier: GPL-2.0+
      /*
       * Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
       *
       * Copyright (C) 2019, Texas Instruments, Incorporated
       *
       */
      
      #include <common.h>
      #include <malloc.h>
      #include <asm/cache.h>
      #include <asm/io.h>
      #include <asm/processor.h>
      #include <clk.h>
      #include <dm.h>
      #include <dm/device_compat.h>
      #include <dm/lists.h>
      #include <dm/pinctrl.h>
      #include <dma-uclass.h>
      #include <dm/of_access.h>
      #include <miiphy.h>
      #include <net.h>
      #include <phy.h>
      #include <power-domain.h>
      #include <soc.h>
      #include <linux/bitops.h>
      #include <linux/soc/ti/ti-udma.h>
      
      #include "cpsw_mdio.h"
      
      #define AM65_CPSW_CPSWNU_MAX_PORTS 9
      
      #define AM65_CPSW_SS_BASE		0x0
      #define AM65_CPSW_SGMII_BASE	0x100
      #define AM65_CPSW_MDIO_BASE	0xf00
      #define AM65_CPSW_XGMII_BASE	0x2100
      #define AM65_CPSW_CPSW_NU_BASE	0x20000
      #define AM65_CPSW_CPSW_NU_ALE_BASE 0x1e000
      
      #define AM65_CPSW_CPSW_NU_PORTS_OFFSET	0x1000
      #define AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET	0x330
      
      #define AM65_CPSW_MDIO_BUS_FREQ_DEF 1000000
      
      #define AM65_CPSW_CTL_REG			0x4
      #define AM65_CPSW_STAT_PORT_EN_REG	0x14
      #define AM65_CPSW_PTYPE_REG		0x18
      
      #define AM65_CPSW_CTL_REG_P0_ENABLE			BIT(2)
      #define AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE		BIT(13)
      #define AM65_CPSW_CTL_REG_P0_RX_PAD			BIT(14)
      
      #define AM65_CPSW_P0_FLOW_ID_REG			0x8
      #define AM65_CPSW_PN_RX_MAXLEN_REG		0x24
      #define AM65_CPSW_PN_REG_SA_L			0x308
      #define AM65_CPSW_PN_REG_SA_H			0x30c
      
      #define AM65_CPSW_ALE_CTL_REG			0x8
      #define AM65_CPSW_ALE_CTL_REG_ENABLE		BIT(31)
      #define AM65_CPSW_ALE_CTL_REG_RESET_TBL		BIT(30)
      #define AM65_CPSW_ALE_CTL_REG_BYPASS		BIT(4)
      #define AM65_CPSW_ALE_PN_CTL_REG(x)		(0x40 + (x) * 4)
      #define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD	0x3
      #define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY	BIT(11)
      
      #define AM65_CPSW_ALE_THREADMAPDEF_REG		0x134
      #define AM65_CPSW_ALE_DEFTHREAD_EN		BIT(15)
      
      #define AM65_CPSW_MACSL_CTL_REG			0x0
      #define AM65_CPSW_MACSL_CTL_REG_IFCTL_A		BIT(15)
      #define AM65_CPSW_MACSL_CTL_EXT_EN		BIT(18)
      #define AM65_CPSW_MACSL_CTL_REG_GIG		BIT(7)
      #define AM65_CPSW_MACSL_CTL_REG_GMII_EN		BIT(5)
      #define AM65_CPSW_MACSL_CTL_REG_LOOPBACK	BIT(1)
      #define AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX	BIT(0)
      #define AM65_CPSW_MACSL_RESET_REG		0x8
      #define AM65_CPSW_MACSL_RESET_REG_RESET		BIT(0)
      #define AM65_CPSW_MACSL_STATUS_REG		0x4
      #define AM65_CPSW_MACSL_RESET_REG_PN_IDLE	BIT(31)
      #define AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE	BIT(30)
      #define AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE	BIT(29)
      #define AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE	BIT(28)
      #define AM65_CPSW_MACSL_RESET_REG_IDLE_MASK \
      	(AM65_CPSW_MACSL_RESET_REG_PN_IDLE | \
      	 AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE | \
      	 AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE | \
      	 AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE)
      
      #define AM65_CPSW_CPPI_PKT_TYPE			0x7
      
      struct am65_cpsw_port {
      	fdt_addr_t	port_base;
      	fdt_addr_t	macsl_base;
      	bool		disabled;
      	u32		mac_control;
      };
      
      struct am65_cpsw_common {
      	struct udevice		*dev;
      	fdt_addr_t		ss_base;
      	fdt_addr_t		cpsw_base;
      	fdt_addr_t		mdio_base;
      	fdt_addr_t		ale_base;
      	fdt_addr_t		gmii_sel;
      	fdt_addr_t		mac_efuse;
      
      	struct clk		fclk;
      	struct power_domain	pwrdmn;
      
      	u32			port_num;
      	struct am65_cpsw_port	ports[AM65_CPSW_CPSWNU_MAX_PORTS];
      
      	struct mii_dev		*bus;
      	u32			bus_freq;
      
      	struct dma		dma_tx;
      	struct dma		dma_rx;
      	u32			rx_next;
      	u32			rx_pend;
      	bool			started;
      };
      
      struct am65_cpsw_priv {
      	struct udevice		*dev;
      	struct am65_cpsw_common	*cpsw_common;
      	u32			port_id;
      
      	struct phy_device	*phydev;
      	bool			has_phy;
      	ofnode			phy_node;
      	u32			phy_addr;
      
      	bool			mdio_manual_mode;
      };
      
      #ifdef PKTSIZE_ALIGN
      #define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
      #else
      #define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN)
      #endif
      
      #ifdef PKTBUFSRX
      #define UDMA_RX_DESC_NUM PKTBUFSRX
      #else
      #define UDMA_RX_DESC_NUM 4
      #endif
      
      #define mac_hi(mac)	(((mac)[0] << 0) | ((mac)[1] << 8) |    \
      			 ((mac)[2] << 16) | ((mac)[3] << 24))
      #define mac_lo(mac)	(((mac)[4] << 0) | ((mac)[5] << 8))
      
      static void am65_cpsw_set_sl_mac(struct am65_cpsw_port *slave,
      				 unsigned char *addr)
      {
      	writel(mac_hi(addr),
      	       slave->port_base + AM65_CPSW_PN_REG_SA_H);
      	writel(mac_lo(addr),
      	       slave->port_base + AM65_CPSW_PN_REG_SA_L);
      }
      
      int am65_cpsw_macsl_reset(struct am65_cpsw_port *slave)
      {
      	u32 i = 100;
      
      	/* Set the soft reset bit */
      	writel(AM65_CPSW_MACSL_RESET_REG_RESET,
      	       slave->macsl_base + AM65_CPSW_MACSL_RESET_REG);
      
      	while ((readl(slave->macsl_base + AM65_CPSW_MACSL_RESET_REG) &
      		AM65_CPSW_MACSL_RESET_REG_RESET) && i--)
      		cpu_relax();
      
      	/* Timeout on the reset */
      	return i;
      }
      
      static int am65_cpsw_macsl_wait_for_idle(struct am65_cpsw_port *slave)
      {
      	u32 i = 100;
      
      	while ((readl(slave->macsl_base + AM65_CPSW_MACSL_STATUS_REG) &
      		AM65_CPSW_MACSL_RESET_REG_IDLE_MASK) && i--)
      		cpu_relax();
      
      	return i;
      }
      
      static int am65_cpsw_update_link(struct am65_cpsw_priv *priv)
      {
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      	struct am65_cpsw_port *port = &common->ports[priv->port_id];
      	struct phy_device *phy = priv->phydev;
      	u32 mac_control = 0;
      
      	if (phy->link) { /* link up */
      		mac_control = /*AM65_CPSW_MACSL_CTL_REG_LOOPBACK |*/
      			      AM65_CPSW_MACSL_CTL_REG_GMII_EN;
      		if (phy->speed == 1000)
      			mac_control |= AM65_CPSW_MACSL_CTL_REG_GIG;
      		if (phy->speed == 10 && phy_interface_is_rgmii(phy))
      			/* Can be used with in band mode only */
      			mac_control |= AM65_CPSW_MACSL_CTL_EXT_EN;
      		if (phy->duplex == DUPLEX_FULL)
      			mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX;
      		if (phy->speed == 100)
      			mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A;
      	}
      
      	if (mac_control == port->mac_control)
      		goto out;
      
      	if (mac_control) {
      		printf("link up on port %d, speed %d, %s duplex\n",
      		       priv->port_id, phy->speed,
      		       (phy->duplex == DUPLEX_FULL) ? "full" : "half");
      	} else {
      		printf("link down on port %d\n", priv->port_id);
      	}
      
      	writel(mac_control, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
      	port->mac_control = mac_control;
      
      out:
      	return phy->link;
      }
      
      #define AM65_GMII_SEL_PORT_OFFS(x)	(0x4 * ((x) - 1))
      
      #define AM65_GMII_SEL_MODE_MII		0
      #define AM65_GMII_SEL_MODE_RMII		1
      #define AM65_GMII_SEL_MODE_RGMII	2
      
      #define AM65_GMII_SEL_RGMII_IDMODE	BIT(4)
      
      static void am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
      				  phy_interface_t phy_mode, int slave)
      {
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      	fdt_addr_t gmii_sel = common->gmii_sel + AM65_GMII_SEL_PORT_OFFS(slave);
      	u32 reg;
      	u32 mode = 0;
      	bool rgmii_id = false;
      
      	reg = readl(gmii_sel);
      
      	dev_dbg(common->dev, "old gmii_sel: %08x\n", reg);
      
      	switch (phy_mode) {
      	case PHY_INTERFACE_MODE_RMII:
      		mode = AM65_GMII_SEL_MODE_RMII;
      		break;
      
      	case PHY_INTERFACE_MODE_RGMII:
      	case PHY_INTERFACE_MODE_RGMII_RXID:
      		mode = AM65_GMII_SEL_MODE_RGMII;
      		break;
      
      	case PHY_INTERFACE_MODE_RGMII_ID:
      	case PHY_INTERFACE_MODE_RGMII_TXID:
      		mode = AM65_GMII_SEL_MODE_RGMII;
      		rgmii_id = true;
      		break;
      
      	default:
      		dev_warn(common->dev,
      			 "Unsupported PHY mode: %u. Defaulting to MII.\n",
      			 phy_mode);
      		/* fallthrough */
      	case PHY_INTERFACE_MODE_MII:
      		mode = AM65_GMII_SEL_MODE_MII;
      		break;
      	};
      
      	if (rgmii_id)
      		mode |= AM65_GMII_SEL_RGMII_IDMODE;
      
      	reg = mode;
      	dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
      		phy_mode, reg);
      	writel(reg, gmii_sel);
      
      	reg = readl(gmii_sel);
      	if (reg != mode)
      		dev_err(common->dev,
      			"gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n",
      			mode, reg);
      }
      
      static int am65_cpsw_start(struct udevice *dev)
      {
      	struct eth_pdata *pdata = dev_get_plat(dev);
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      	struct am65_cpsw_port *port = &common->ports[priv->port_id];
      	struct am65_cpsw_port *port0 = &common->ports[0];
      	struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
      	int ret, i;
      
      	ret = power_domain_on(&common->pwrdmn);
      	if (ret) {
      		dev_err(dev, "power_domain_on() failed %d\n", ret);
      		goto out;
      	}
      
      	ret = clk_enable(&common->fclk);
      	if (ret) {
      		dev_err(dev, "clk enabled failed %d\n", ret);
      		goto err_off_pwrdm;
      	}
      
      	common->rx_next = 0;
      	common->rx_pend = 0;
      	ret = dma_get_by_name(common->dev, "tx0", &common->dma_tx);
      	if (ret) {
      		dev_err(dev, "TX dma get failed %d\n", ret);
      		goto err_off_clk;
      	}
      	ret = dma_get_by_name(common->dev, "rx", &common->dma_rx);
      	if (ret) {
      		dev_err(dev, "RX dma get failed %d\n", ret);
      		goto err_free_tx;
      	}
      
      	for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
      		ret = dma_prepare_rcv_buf(&common->dma_rx,
      					  net_rx_packets[i],
      					  UDMA_RX_BUF_SIZE);
      		if (ret) {
      			dev_err(dev, "RX dma add buf failed %d\n", ret);
      			goto err_free_tx;
      		}
      	}
      
      	ret = dma_enable(&common->dma_tx);
      	if (ret) {
      		dev_err(dev, "TX dma_enable failed %d\n", ret);
      		goto err_free_rx;
      	}
      	ret = dma_enable(&common->dma_rx);
      	if (ret) {
      		dev_err(dev, "RX dma_enable failed %d\n", ret);
      		goto err_dis_tx;
      	}
      
      	/* Control register */
      	writel(AM65_CPSW_CTL_REG_P0_ENABLE |
      	       AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE |
      	       AM65_CPSW_CTL_REG_P0_RX_PAD,
      	       common->cpsw_base + AM65_CPSW_CTL_REG);
      
      	/* disable priority elevation */
      	writel(0, common->cpsw_base + AM65_CPSW_PTYPE_REG);
      
      	/* enable statistics */
      	writel(BIT(0) | BIT(priv->port_id),
      	       common->cpsw_base + AM65_CPSW_STAT_PORT_EN_REG);
      
      	/* Port 0  length register */
      	writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
      
      	/* set base flow_id */
      	dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data);
      	writel(dma_rx_cfg_data->flow_id_base,
      	       port0->port_base + AM65_CPSW_P0_FLOW_ID_REG);
      	dev_info(dev, "K3 CPSW: rflow_id_base: %u\n",
      		 dma_rx_cfg_data->flow_id_base);
      
      	/* Reset and enable the ALE */
      	writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL |
      	       AM65_CPSW_ALE_CTL_REG_BYPASS,
      	       common->ale_base + AM65_CPSW_ALE_CTL_REG);
      
      	/* port 0 put into forward mode */
      	writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
      	       common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
      
      	writel(AM65_CPSW_ALE_DEFTHREAD_EN,
      	       common->ale_base + AM65_CPSW_ALE_THREADMAPDEF_REG);
      
      	/* PORT x configuration */
      
      	/* Port x Max length register */
      	writel(PKTSIZE_ALIGN, port->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
      
      	/* Port x set mac */
      	am65_cpsw_set_sl_mac(port, pdata->enetaddr);
      
      	/* Port x ALE: mac_only, Forwarding */
      	writel(AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY |
      	       AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
      	       common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
      
      	port->mac_control = 0;
      	if (!am65_cpsw_macsl_reset(port)) {
      		dev_err(dev, "mac_sl reset failed\n");
      		ret = -EFAULT;
      		goto err_dis_rx;
      	}
      
      	ret = phy_startup(priv->phydev);
      	if (ret) {
      		dev_err(dev, "phy_startup failed\n");
      		goto err_dis_rx;
      	}
      
      	ret = am65_cpsw_update_link(priv);
      	if (!ret) {
      		ret = -ENODEV;
      		goto err_phy_shutdown;
      	}
      
      	common->started = true;
      
      	return 0;
      
      err_phy_shutdown:
      	phy_shutdown(priv->phydev);
      err_dis_rx:
      	/* disable ports */
      	writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
      	writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
      	if (!am65_cpsw_macsl_wait_for_idle(port))
      		dev_err(dev, "mac_sl idle timeout\n");
      	writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
      	writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
      	writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
      
      	dma_disable(&common->dma_rx);
      err_dis_tx:
      	dma_disable(&common->dma_tx);
      err_free_rx:
      	dma_free(&common->dma_rx);
      err_free_tx:
      	dma_free(&common->dma_tx);
      err_off_clk:
      	clk_disable(&common->fclk);
      err_off_pwrdm:
      	power_domain_off(&common->pwrdmn);
      out:
      	dev_err(dev, "%s end error\n", __func__);
      
      	return ret;
      }
      
      static int am65_cpsw_send(struct udevice *dev, void *packet, int length)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      	struct ti_udma_drv_packet_data packet_data;
      	int ret;
      
      	packet_data.pkt_type = AM65_CPSW_CPPI_PKT_TYPE;
      	packet_data.dest_tag = priv->port_id;
      	ret = dma_send(&common->dma_tx, packet, length, &packet_data);
      	if (ret) {
      		dev_err(dev, "TX dma_send failed %d\n", ret);
      		return ret;
      	}
      
      	return 0;
      }
      
      static int am65_cpsw_recv(struct udevice *dev, int flags, uchar **packetp)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      
      	/* try to receive a new packet */
      	return dma_receive(&common->dma_rx, (void **)packetp, NULL);
      }
      
      static int am65_cpsw_free_pkt(struct udevice *dev, uchar *packet, int length)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*common = priv->cpsw_common;
      	int ret;
      
      	if (length > 0) {
      		u32 pkt = common->rx_next % UDMA_RX_DESC_NUM;
      
      		ret = dma_prepare_rcv_buf(&common->dma_rx,
      					  net_rx_packets[pkt],
      					  UDMA_RX_BUF_SIZE);
      		if (ret)
      			dev_err(dev, "RX dma free_pkt failed %d\n", ret);
      		common->rx_next++;
      	}
      
      	return 0;
      }
      
      static void am65_cpsw_stop(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common *common = priv->cpsw_common;
      	struct am65_cpsw_port *port = &common->ports[priv->port_id];
      
      	if (!common->started)
      		return;
      
      	phy_shutdown(priv->phydev);
      
      	writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
      	writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
      	if (!am65_cpsw_macsl_wait_for_idle(port))
      		dev_err(dev, "mac_sl idle timeout\n");
      	writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
      	writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
      	writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
      
      	dma_disable(&common->dma_tx);
      	dma_free(&common->dma_tx);
      
      	dma_disable(&common->dma_rx);
      	dma_free(&common->dma_rx);
      
      	common->started = false;
      }
      
      static int am65_cpsw_read_rom_hwaddr(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common *common = priv->cpsw_common;
      	struct eth_pdata *pdata = dev_get_plat(dev);
      	u32 mac_hi, mac_lo;
      
      	if (common->mac_efuse == FDT_ADDR_T_NONE)
      		return -1;
      
      	mac_lo = readl(common->mac_efuse);
      	mac_hi = readl(common->mac_efuse + 4);
      	pdata->enetaddr[0] = (mac_hi >> 8) & 0xff;
      	pdata->enetaddr[1] = mac_hi & 0xff;
      	pdata->enetaddr[2] = (mac_lo >> 24) & 0xff;
      	pdata->enetaddr[3] = (mac_lo >> 16) & 0xff;
      	pdata->enetaddr[4] = (mac_lo >> 8) & 0xff;
      	pdata->enetaddr[5] = mac_lo & 0xff;
      
      	return 0;
      }
      
      static const struct eth_ops am65_cpsw_ops = {
      	.start		= am65_cpsw_start,
      	.send		= am65_cpsw_send,
      	.recv		= am65_cpsw_recv,
      	.free_pkt	= am65_cpsw_free_pkt,
      	.stop		= am65_cpsw_stop,
      	.read_rom_hwaddr = am65_cpsw_read_rom_hwaddr,
      };
      
      static const struct soc_attr k3_mdio_soc_data[] = {
      	{ .family = "AM62X", .revision = "SR1.0" },
      	{ .family = "AM64X", .revision = "SR1.0" },
      	{ .family = "AM64X", .revision = "SR2.0" },
      	{ .family = "AM65X", .revision = "SR1.0" },
      	{ .family = "AM65X", .revision = "SR2.0" },
      	{ .family = "J7200", .revision = "SR1.0" },
      	{ .family = "J7200", .revision = "SR2.0" },
      	{ .family = "J721E", .revision = "SR1.0" },
      	{ .family = "J721E", .revision = "SR1.1" },
      	{ .family = "J721S2", .revision = "SR1.0" },
      	{ /* sentinel */ },
      };
      
      static ofnode am65_cpsw_find_mdio(ofnode parent)
      {
      	ofnode node;
      
      	ofnode_for_each_subnode(node, parent)
      		if (ofnode_device_is_compatible(node, "ti,cpsw-mdio"))
      			return node;
      
      	return ofnode_null();
      }
      
      static int am65_cpsw_mdio_setup(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*cpsw_common = priv->cpsw_common;
      	struct udevice *mdio_dev;
      	ofnode mdio;
      	int ret;
      
      	mdio = am65_cpsw_find_mdio(dev_ofnode(cpsw_common->dev));
      	if (!ofnode_valid(mdio))
      		return 0;
      
      	/*
      	 * The MDIO controller is represented in the DT binding by a
      	 * subnode of the MAC controller.
      	 *
      	 * We don't have a DM driver for the MDIO device yet, and thus any
      	 * pinctrl setting on its node will be ignored.
      	 *
      	 * However, we do need to make sure the pins states tied to the
      	 * MDIO node are configured properly. Fortunately, the core DM
      	 * does that for use when we get a device, so we can work around
      	 * that whole issue by just requesting a dummy MDIO driver to
      	 * probe, and our pins will get muxed.
      	 */
      	ret = uclass_get_device_by_ofnode(UCLASS_MDIO, mdio, &mdio_dev);
      	if (ret)
      		return ret;
      
      	return 0;
      }
      
      static int am65_cpsw_mdio_init(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common	*cpsw_common = priv->cpsw_common;
      	int ret;
      
      	if (!priv->has_phy || cpsw_common->bus)
      		return 0;
      
      	ret = am65_cpsw_mdio_setup(dev);
      	if (ret)
      		return ret;
      
      	cpsw_common->bus = cpsw_mdio_init(dev->name,
      					  cpsw_common->mdio_base,
      					  cpsw_common->bus_freq,
      					  clk_get_rate(&cpsw_common->fclk),
      					  priv->mdio_manual_mode);
      	if (!cpsw_common->bus)
      		return -EFAULT;
      
      	return 0;
      }
      
      static int am65_cpsw_phy_init(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
      	struct eth_pdata *pdata = dev_get_plat(dev);
      	struct phy_device *phydev;
      	u32 supported = PHY_GBIT_FEATURES;
      	int ret;
      
      	phydev = phy_connect(cpsw_common->bus,
      			     priv->phy_addr,
      			     priv->dev,
      			     pdata->phy_interface);
      
      	if (!phydev) {
      		dev_err(dev, "phy_connect() failed\n");
      		return -ENODEV;
      	}
      
      	phydev->supported &= supported;
      	if (pdata->max_speed) {
      		ret = phy_set_supported(phydev, pdata->max_speed);
      		if (ret)
      			return ret;
      	}
      	phydev->advertising = phydev->supported;
      
      	if (ofnode_valid(priv->phy_node))
      		phydev->node = priv->phy_node;
      
      	priv->phydev = phydev;
      	ret = phy_config(phydev);
      	if (ret < 0)
      		pr_err("phy_config() failed: %d", ret);
      
      	return ret;
      }
      
      static int am65_cpsw_ofdata_parse_phy(struct udevice *dev)
      {
      	struct eth_pdata *pdata = dev_get_plat(dev);
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct ofnode_phandle_args out_args;
      	int ret = 0;
      
      	dev_read_u32(dev, "reg", &priv->port_id);
      
      	pdata->phy_interface = dev_read_phy_mode(dev);
      	if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
      		dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id);
      		return -EINVAL;
      	}
      
      	dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed);
      	if (pdata->max_speed)
      		dev_err(dev, "Port %u speed froced to %uMbit\n",
      			priv->port_id, pdata->max_speed);
      
      	priv->has_phy  = true;
      	ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "phy-handle",
      					     NULL, 0, 0, &out_args);
      	if (ret) {
      		dev_err(dev, "can't parse phy-handle port %u (%d)\n",
      			priv->port_id, ret);
      		priv->has_phy  = false;
      		ret = 0;
      	}
      
      	priv->phy_node = out_args.node;
      	if (priv->has_phy) {
      		ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr);
      		if (ret) {
      			dev_err(dev, "failed to get phy_addr port %u (%d)\n",
      				priv->port_id, ret);
      			goto out;
      		}
      	}
      
      out:
      	return ret;
      }
      
      static int am65_cpsw_port_probe(struct udevice *dev)
      {
      	struct am65_cpsw_priv *priv = dev_get_priv(dev);
      	struct eth_pdata *pdata = dev_get_plat(dev);
      	struct am65_cpsw_common *cpsw_common;
      	char portname[15];
      	int ret;
      
      	priv->dev = dev;
      
      	cpsw_common = dev_get_priv(dev->parent);
      	priv->cpsw_common = cpsw_common;
      
      	sprintf(portname, "%s%s", dev->parent->name, dev->name);
      	device_set_name(dev, portname);
      
      	priv->mdio_manual_mode = false;
      	if (soc_device_match(k3_mdio_soc_data))
      		priv->mdio_manual_mode = true;
      
      	ret = am65_cpsw_ofdata_parse_phy(dev);
      	if (ret)
      		goto out;
      
      	am65_cpsw_gmii_sel_k3(priv, pdata->phy_interface, priv->port_id);
      
      	ret = am65_cpsw_mdio_init(dev);
      	if (ret)
      		goto out;
      
      	ret = am65_cpsw_phy_init(dev);
      	if (ret)
      		goto out;
      out:
      	return ret;
      }
      
      static int am65_cpsw_probe_nuss(struct udevice *dev)
      {
      	struct am65_cpsw_common *cpsw_common = dev_get_priv(dev);
      	ofnode ports_np, node;
      	int ret, i;
      	struct udevice *port_dev;
      
      	cpsw_common->dev = dev;
      	cpsw_common->ss_base = dev_read_addr(dev);
      	if (cpsw_common->ss_base == FDT_ADDR_T_NONE)
      		return -EINVAL;
      	cpsw_common->mac_efuse = devfdt_get_addr_name(dev, "mac_efuse");
      	/* no err check - optional */
      
      	ret = power_domain_get_by_index(dev, &cpsw_common->pwrdmn, 0);
      	if (ret) {
      		dev_err(dev, "failed to get pwrdmn: %d\n", ret);
      		return ret;
      	}
      
      	ret = clk_get_by_name(dev, "fck", &cpsw_common->fclk);
      	if (ret) {
      		power_domain_free(&cpsw_common->pwrdmn);
      		dev_err(dev, "failed to get clock %d\n", ret);
      		return ret;
      	}
      
      	cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE;
      	cpsw_common->ale_base = cpsw_common->cpsw_base +
      				AM65_CPSW_CPSW_NU_ALE_BASE;
      	cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE;
      
      	ports_np = dev_read_subnode(dev, "ethernet-ports");
      	if (!ofnode_valid(ports_np)) {
      		ret = -ENOENT;
      		goto out;
      	}
      
      	ofnode_for_each_subnode(node, ports_np) {
      		const char *node_name;
      		u32 port_id;
      		bool disabled;
      
      		node_name = ofnode_get_name(node);
      
      		disabled = !ofnode_is_enabled(node);
      
      		ret = ofnode_read_u32(node, "reg", &port_id);
      		if (ret) {
      			dev_err(dev, "%s: failed to get port_id (%d)\n",
      				node_name, ret);
      			goto out;
      		}
      
      		if (port_id >= AM65_CPSW_CPSWNU_MAX_PORTS) {
      			dev_err(dev, "%s: invalid port_id (%d)\n",
      				node_name, port_id);
      			ret = -EINVAL;
      			goto out;
      		}
      		cpsw_common->port_num++;
      
      		if (!port_id)
      			continue;
      
      		cpsw_common->ports[port_id].disabled = disabled;
      		if (disabled)
      			continue;
      
      		ret = device_bind_driver_to_node(dev, "am65_cpsw_nuss_port", ofnode_get_name(node), node, &port_dev);
      		if (ret)
      			dev_err(dev, "Failed to bind to %s node\n", ofnode_get_name(node));
      	}
      
      	for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) {
      		struct am65_cpsw_port *port = &cpsw_common->ports[i];
      
      		port->port_base = cpsw_common->cpsw_base +
      				  AM65_CPSW_CPSW_NU_PORTS_OFFSET +
      				  (i * AM65_CPSW_CPSW_NU_PORTS_OFFSET);
      		port->macsl_base = port->port_base +
      				   AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET;
      	}
      
      	node = dev_read_subnode(dev, "cpsw-phy-sel");
      	if (!ofnode_valid(node)) {
      		dev_err(dev, "can't find cpsw-phy-sel\n");
      		ret = -ENOENT;
      		goto out;
      	}
      
      	cpsw_common->gmii_sel = ofnode_get_addr(node);
      	if (cpsw_common->gmii_sel == FDT_ADDR_T_NONE) {
      		dev_err(dev, "failed to get gmii_sel base\n");
      		goto out;
      	}
      
      	cpsw_common->bus_freq =
      			dev_read_u32_default(dev, "bus_freq",
      					     AM65_CPSW_MDIO_BUS_FREQ_DEF);
      
      	dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n",
      		 readl(cpsw_common->ss_base),
      		 readl(cpsw_common->cpsw_base),
      		 readl(cpsw_common->ale_base),
      		 cpsw_common->port_num,
      		 cpsw_common->bus_freq);
      
      out:
      	clk_free(&cpsw_common->fclk);
      	power_domain_free(&cpsw_common->pwrdmn);
      	return ret;
      }
      
      static const struct udevice_id am65_cpsw_nuss_ids[] = {
      	{ .compatible = "ti,am654-cpsw-nuss" },
      	{ .compatible = "ti,j721e-cpsw-nuss" },
      	{ .compatible = "ti,am642-cpsw-nuss" },
      	{ }
      };
      
      U_BOOT_DRIVER(am65_cpsw_nuss) = {
      	.name	= "am65_cpsw_nuss",
      	.id	= UCLASS_MISC,
      	.of_match = am65_cpsw_nuss_ids,
      	.probe	= am65_cpsw_probe_nuss,
      	.priv_auto = sizeof(struct am65_cpsw_common),
      };
      
      U_BOOT_DRIVER(am65_cpsw_nuss_port) = {
      	.name	= "am65_cpsw_nuss_port",
      	.id	= UCLASS_ETH,
      	.probe	= am65_cpsw_port_probe,
      	.ops	= &am65_cpsw_ops,
      	.priv_auto	= sizeof(struct am65_cpsw_priv),
      	.plat_auto	= sizeof(struct eth_pdata),
      	.flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
      };
      
      static const struct udevice_id am65_cpsw_mdio_ids[] = {
      	{ .compatible = "ti,cpsw-mdio" },
      	{ }
      };
      
      U_BOOT_DRIVER(am65_cpsw_mdio) = {
      	.name		= "am65_cpsw_mdio",
      	.id		= UCLASS_MDIO,
      	.of_match	= am65_cpsw_mdio_ids,
      };
      
       
      • /home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/k3r5-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-oe-eabi/arm-oe-eabi-ld.bfd: drivers/net/ti/am65-cpsw-nuss.o: in function `am65_cpsw_am654_get_efuse_macid':
        /home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/board-support/ti-u-boot-2023.04+gitAUTOINC+b0d717b732-gb0d717b732/drivers/net/ti/am65-cpsw-nuss.c:550: undefined reference to `syscon_regmap_lookup_by_phandle'
        make[3]: *** [/home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/board-support/ti-u-boot-2023.04+gitAUTOINC+b0d717b732-gb0d717b732/scripts/Makefile.spl:527: spl/u-boot-spl] Error 1
        make[2]: *** [/home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/board-support/ti-u-boot-2023.04+gitAUTOINC+b0d717b732-gb0d717b732/Makefile:2043: spl/u-boot-spl] Error 2
        make[2]: Leaving directory '/home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/board-support/u-boot-build/r5'
        make[1]: *** [Makefile:177: sub-make] Error 2
        make[1]: Leaving directory '/home/a0500327/Documents/ti-processor-sdk-linux-rt-am62xx-evm-09.01.00.08/board-support/ti-u-boot-2023.04+gitAUTOINC+b0d717b732-gb0d717b732'
        make: *** [makerules/Makefile_u-boot:28: u-boot-r5] Error 2
    • If you see the following output in the EVM console, you may need to replace <u-boot-dir>/configs/am62x_evm_a53_defconfig with the following file
      • 7433.am62x_evm_a53_defconfig 
      • U-Boot 2023.04-dirty (Apr 18 2024 - 13:38:04 -0500)
        
        SoC:   AM62X SR1.0 HS-FS
        Model: Texas Instruments AM625 SK
        EEPROM not available at 80, trying to read at 81
        Board: AM62B-SKEVM rev A
        DRAM:  no bloblist found!2 GiB
        Core:  72 devices, 32 uclasses, devicetree: separate
        MMC:   mmc@fa10000: 0, mmc@fa00000: 1
        Loading Environment from nowhere... OK
        In:    serial
        Out:   serial
        Err:   serial
        Net:   eth0: ethernet@8000000port@1
        Hit any key to stop autoboot:  0 
        MMC: no card present
        SD/MMC found on device 1
        MMC: no card present
        ** Bad device specification mmc 1 **
        Couldn't find partition mmc 1
        Can't set block device
        MMC: no card present
        ** Bad device specification mmc 1 **
        Couldn't find partition mmc 1
        Can't set block device
        MMC: no card present
        ** Bad device specification mmc 1 **
        ## Error: "main_cpsw0_qsgmii_phyinit" not defined
        MMC: no card present
        ** Bad device specification mmc 1 **
        Couldn't find partition mmc 1:2
        Can't set block device
        MMC: no card present
        ** Bad device specification mmc 1 **
        Couldn't find partition mmc 1:2
        Can't set block device
        libfdt fdt_check_header(): FDT_ERR_BADMAGIC
        No FDT memory address configured. Please configure
        the FDT address via "fdt addr <address>" command.
        Aborting!
        Bad Linux ARM64 Image magic!
        switch to partitions #0, OK
        mmc0(part 0) is current device
        ** No partition table - mmc 0 **
        Couldn't find partition mmc 0:1
        MMC: no card present
        starting USB...
        Bus usb@31100000: generic_phy_get_bulk : no phys property
        Register 1000840 NbrPorts 1
        Starting the controller
        USB XHCI 1.10
        scanning bus usb@31100000 for devices... 1 USB Device(s) found
               scanning usb for storage devices... 0 Storage Device(s) found
        
        Device 0: unknown device
        link up on port 1, speed 1000, full duplex
        BOOTP broadcast 1
        DHCP client bound to address 172.168.1.170 (2 ms)
        *** Warning: no boot file name; using 'ACA801AA.img'
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'ACA801AA.img'.
        Load address: 0x82000000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        missing environment variable: pxeuuid
        Retrieving file: pxelinux.cfg/01-1c-63-49-0f-61-14
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/01-1c-63-49-0f-61-14'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA801AA
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA801AA'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA801A
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA801A'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA801
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA801'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA80
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA80'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA8
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA8'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/ACA
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/ACA'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/AC
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/AC'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/A
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/A'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/default-arm-k3-am62x
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/default-arm-k3-am62x'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/default-arm-k3
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/default-arm-k3'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/default-arm
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/default-arm'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Retrieving file: pxelinux.cfg/default
        link up on port 1, speed 1000, full duplex
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'pxelinux.cfg/default'.
        Load address: 0x80100000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        Config file not found
        link up on port 1, speed 1000, full duplex
        BOOTP broadcast 1
        DHCP client bound to address 172.168.1.170 (3 ms)
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'boot.scr.uimg'.
        Load address: 0x80000000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        link up on port 1, speed 1000, full duplex
        BOOTP broadcast 1
        DHCP client bound to address 172.168.1.170 (3 ms)
        Using ethernet@8000000port@1 device
        TFTP from server 172.168.1.1; our IP address is 172.168.1.170
        Filename 'boot.scr.uimg'.
        Load address: 0x82000000
        Loading: *
        TFTP error: 'File not found' (1)
        Not retrying...
        am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
        => 
    • You may find the following error when attempting to boot into U-boot after setting up the BOOTP/DHCP server and TFTP server on your host PC and configuring the board to Ethernet as primary boot mode. If you see this, you may need to use the patches provided at this site in order to rebuilt your u-boot binaries for boot via Ethernet to work. These patches have not yet been upstreamed as of SDK release 9.1.
      • This error should no longer be seen as the am65-cpsw-nuss.c replacement should have fixed the "No ethernet found." issue.
      • U-Boot SPL 2023.04-dirty (Jan 30 2024 - 14:21:23 -0600)
        SYSFW ABI: 3.1 (firmware rev 0x0009 '9.1.8--v09.01.08 (Kool Koala)')
        alloc space exhausted
        am65_cpsw_nuss ethernet@8000000: Failed to bind to port@1 node
        Failed to probe am65_cpsw_nuss driver
        SPL initial stack usage: 13384 bytes
        Trying to boot from eth device
        Loading Environment from nowhere... OK
        No ethernet found.
        No Ethernet devices found
        SPL: failed to boot from all boot devices
        ### ERROR ### Please RESET the board ### 

    2. Change bootswitches to Ethernet as primary bootmode and UART as secondary bootmode.

    Make sure to use only RGMII1 (eth0), port closest to the USB Type-A socket. 

    Primary Bootmode = Ethernet

    Secondary Bootmode = UART

    SW1 [0-7] (right switch in the picture below) = 11000100

    SW2 [8-15] = 00110000

    3. Set up TFTP server and DHCP server on your host PC

    Setup the tftp server by following the steps in https://help.ubuntu.com/community/TFTP or https://www.addictivetips.com/ubuntu-linux-tips/set-up-a-tftp-server-on-ubuntu-server/ 

    Check the status of the of the tftp server by running "sudo service tftpd-hpa status" or "sudo systemctl status xinetd.service" and make sure it is active.

    Add the u-boot binaries that you built in step 1 to the /tftpboot directory you created by following the steps to set up tftp server.

    Set up the dhcp server by following the steps in https://help.ubuntu.com/community/isc-dhcp-server

    Use the ISC dhcp example host entry in https://software-dl.ti.com/processor-sdk-linux-rt/esd/AM62X/latest/exports/docs/linux/Foundational_Components/U-Boot/UG-Network-K3.html?highlight=am62x_evm_r5_ethboot_defconfig#booting-over-ethernet-ethernet-rgmii to add to your /etc/dhcp/dhcpd.conf file. Make sure to change the range of IP addresses to the IP addresses in your network.

    Troubleshooting tips:

    • Check using Wireshark on host PC ethernet interface connected to the board and expect to see the following for establishment of BOOTP request and reply and the TFTP read request, data packets and acknowledgements.
    • If the following is seen instead where it stalls at TFTP read request, it might be blocked by a firewall. If so, try running "sudo ufw allow <port number used in tftpserver setup>/udp" and rerun dhcp and tftp server
      • Ex: "sudo ufw allow 69/udp"

    4. Load the u-boot binaries via tftp and boot into U-boot environment

    Power cycle the board and you should see something like the following

  • How to flash to eMMC via Ethernet on SK-AM62B/ SK-AM62A

    1. Create an uEnv.txt for flashing to eMMC

    The commands for flashing in U-boot can be automated upon booting into U-boot environment.

    The main instructions for "flash via Ethernet" can be found in https://software-dl.ti.com/processor-sdk-linux-rt/esd/AM62X/latest/exports/docs/linux/Foundational_Components/Tools/Flash_via_Ethernet.html. However, as of SDK release v9.1, the uEnv.txt provided in  <TI_SDK_PATH>/bin/Ethernet_flash/am62xx-evm/ needs some modifications in order to work. Please refer to the solution in https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1324308/sk-am62b-p1-issue-with-ethernet-booting---need-assistance for the required modifications.

    Make sure to put your uEnv.txt into the /tftpboot directory of your host PC so that it can also be loaded via TFTP

    Key Note:

    • When changing to eMMC boot mode in step 5, you will not be able to boot into Linux using the U-boot binaries built from ethboot defconfig. In order to boot into Linux in step 5, after booting into U-boot environment using ethernet boot mode, you must change the u-boot binaries that get loaded via the commands in uEnv.txt to the pre-built u-boot binaries. The pre-built u-boot binaries can be found in <TISDK>/board-support/prebuilt-images/am62xx-evm/.
    • This is a bit of a hassle, so overall we do not recommend booting via Ethernet boot mode. It is much easier and more reliable to boot from SD card and load the binaries from there.

    2. Convert the target .tar.xz image to an .ext4 image format and place this image into the /tftpboot directory of your host PC

    The general steps are as follows

    $ cd <path-ti-psdk>/filesystem
    $ dd if=/dev/null of=tisdk-base.ext4 bs=1M seek=300
    $ mkfs.ext4 -F rootfs.ext4
    $ mkdir mnt_fs
    $ sudo mount -t ext4 rootfs.ext4 mnt_fs
    $ cd mnt_fs
    $ sudo tar xvf ../<target image name>.tar.xz
    $ cd ..
    $ sudo umount mnt_fs

    Key Notes:

    • Flashing via ethernet first loads the .ext4 image into DDR which limits the size of the file to the DDR size (~2GB). If the .ext4 image is larger than DDR size, flashing via ethernet will not work. Keep in mind that the default TISDK image is around 5GB so flashing the default image provided on the product page is not possible.
    • You may also find the following error message if the default loadaddr of 0x82000000 is at a location that does not provide large enough continuous memory to contain the size of the .ext4 image. 
    • You can use "bdinfo" in the U-boot command line to see reserved memory locations and look for an address that will provide enough continuous memory
    • You can change the loadaddr by "setenv loadaddr <new address>" or adding "loadaddr=<new address>" to your uEnv.txt
    • TFTP error: trying to overwrite reserved memory...
      am65_cpsw_nuss_port ethernet@8000000port@1: RX dma free_pkt failed -22
      => 
    • In the picture above, if the default loadaddr of 0x82000000 is used, there is only continuous memory form 0x82000000 to 0x9ca00000 available. This is about 446 Mb of free space. 

    3. Once all u-boot binaries and your .ext4 file gets flashed to eMMC, you should check if the filesystem got written to the correct partition.

    Run "ls mmc 0:1" and you should see something similar to below.

             ##############################################  0 Bytes
             1.6 MiB/s
    done
    Bytes transferred = 943718400 (38400000 hex)
    => mmc write ${loadaddr} 0x22 0x1c2000
    
    MMC write: dev # 0, block # 34, count 1843200 ... 1843200 blocks written: OK
    => ls mmc 0:1
    <DIR>       4096 .
    <DIR>       4096 ..
    <DIR>      16384 lost+found
    <DIR>       4096 bin
    <DIR>       4096 boot
    <DIR>       4096 dev
    <DIR>       4096 etc
    <DIR>       4096 home
    <DIR>       4096 lib
    <SYM>         19 linuxrc
    <DIR>       4096 media
    <DIR>       4096 mnt
    <DIR>       4096 proc
    <DIR>       4096 run
    <DIR>       4096 sbin
    <DIR>       4096 srv
    <DIR>       4096 sys
    <DIR>       4096 tmp
    <DIR>       4096 usr
    <DIR>       4096 var

    Key notes:

    4. To boot into Linux, run the following commands in the U-boot command line

    => setenv mmcdev 0
    => setenv bootpart 0:1
    => run distro_bootcmd

    "run distro_bootcmd" is required instead of "boot" because the u-boot binaries were built with ethboot defconfig rather than the default pre-built u-boot binaries.

    The default u-boot build does not contain "saveenv" to save these environment variables, so every time you boot the board, you must stop in U-boot environment and run these commands. If you want to enable "saveenv", you can find details on the solution to this thread: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1324442/am625-change-saveenv-mmc-location/5040438#5040438 

    5. Verify that you can boot into Linux via eMMC boot mode.

    Make sure to run the following commands to give ROM access to the eMMC boot partition (this only needs to be done once) before changing the boot switches to eMMC boot mode

    => mmc partconf 0 1 1 1
    => mmc bootbus 0 2 0 0

    Change the boot switches to eMMC boot mode using the configuration found on our Linux Academy

    Power cycle the board and you will automatically boot into Linux.