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.

AM335x MAC addresses and TI's CPSW Ethernet driver

Other Parts Discussed in Thread: AM3358, AM3352

I noticed that our board, which has an AM3358 on it, is booting up with a random MAC address assigned to the network interface every time. We're using the kernel and filesystems that are provided with the TI Sitara SDK version 7.

The AM3358 has unique MAC addresses programmed into the control module according to this post and this post.

So, why does the CPSW driver supplied with TI not use these programmed MAC addresses?

I know that the MAC addresses can be passed to the CPSW driver via the device tree, but this would seem to imply that the device tree would have to be customized for every individual device and that obviously isn't a desired solution. I suppose a variation of this would be to have u-boot read the MAC addresses and modify the device tree on the fly... (I removed all of the Ethernet stuff from u-boot since our board will never be booted via Ethernet).

It's possible for me to modify the CPSW driver to use the programmed MAC addresses, but I first want to know if there is a more convenient solution that I'm not aware of.

  • After further looking it appears the solution is really in one of those other posts. I'm guessing that all I have to do is add a few lines to my u-boot board initialization to copy the values from the eFuse registers into the MAC registers. I'll see how that goes...

    I'm just amazed that the CPSW driver would fall back to a random address instead of querying the device.
  • Hi Steve,

    This is a strange observation. The CPSW driver should copy the MAC addresses from the mac_id[1:0]_[lo:hi] registers to the P[2:]1_SA_[LO:HI] registers. I will ask the Ethernet experts what might be the reason for this behavior.

  • Instead of modifying u-boot to copy those registers, I simply used devmem2 to read the values and then write them into P[12]_SA[HI:LO].

    However, when I brought the interface up, they were overwritten by a random MAC address...

    I'm now just waiting to hear back from your Ethernet experts. Thanks Biser.

  • Biser,

    Any word yet on what the expected behavior of the driver is and the recommended solution for the problem I'm experiencing?
  • No feedback yet. It will be posted directly here when available.

  • To be honest I thought the Linux CPSW driver did read the MAC addresses also. Looking at the code that you mentioned it is not. After thinking about it the basic reason would be for customers that don’t want to use the TI mac addresses supplied from u-boot could replace that code with populating MAC addresses of their choosing. As pointed out device tree could be used from the linux level but also pointed out this is far from ideal. The solution you alluded to modifying u-boot to read the registers is the one I would recommend. For completeness since I think you have already figured this out is that u-boot reads the EMAC registers and then sets the u-boot environment in board_eth_init() in board/ti/am335x
  • What is the exact mechanism u-boot uses to pass the MAC address to the CPSW driver? I set u-boot's ethaddr variable, and sure enough that information got passed through to Linux.

  • I think I might see what is happening in u-boot. In your board/ti/am335x/board.c file there is the routine board_eth_init. It reads the MAC addresses from the ROM and sets the environment variables ethaddr and eth1addr. Then if you look in common/fdt_support.c you can see the routine fdt_fixup_ethernet. I think the routine runs after the .dtb file loads (or maybe at bootz command) and copies the ethaddr and eth1addr variable to the flattened device triee in memory. Then when you boot your kernel, it will pick up those values from the device tree. I was looking at code from the SDK 8 release.

    Steve K.

  • Awesome, thanks for providing this information! That was something I thought I might have to implement myself - modifying the device tree at boot time. I'm glad I inquired about this so I didn't re-invent the wheel.
  • Hi Steve,

    Our board is based on AM3352 (TI SDK kernel - 3.14.43) and also we are facing same issue " random MAC address assignment by cpsw driver".
    It will be very needful if you share with us how you have managed to solved this.

    We want to read MAC from EEPROM.

    Thanks in advance.

    Regards,
    Somanath
  • It's been a very long time, and I don't remember how all this works. However, here is code in my u-boot board.c file that I believe does what you need. In this case, I'm reading the fuses, but if you want to read from an EEPROM that should work too. I think the important part is telling Linux what the MAC addresses should be. I believe the eth_setenv_enetaddr() call sets a u-boot variable, that then "magically" gets picked up by the kernel. I think. It's been a while... :)

    static void set_mac_variable(const char* var, uint32_t lo_addr, uint32_t hi_addr)
    {
    	uint8_t mac_addr[6];
    	uint32_t mac_hi, mac_lo;
    
    	/* try reading mac address from efuse */
    	mac_lo = readl(lo_addr);
    	mac_hi = readl(hi_addr);
    	mac_addr[0] = mac_hi & 0xFF;
    	mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    	mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
    	mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
    	mac_addr[4] = mac_lo & 0xFF;
    	mac_addr[5] = (mac_lo & 0xFF00) >> 8;
    
    	if (is_valid_ether_addr(mac_addr))
    		eth_setenv_enetaddr(var, mac_addr);
    }
    
    #define MAC_ID0_LO 0x44e10630
    #define MAC_ID0_HI 0x44e10634
    #define MAC_ID1_LO 0x44e10638
    #define MAC_ID1_HI 0x44e1063c
    
    #ifdef CONFIG_BOARD_LATE_INIT
    int board_late_init(void)
    {
    	set_mac_variable("ethaddr", MAC_ID0_LO, MAC_ID0_HI);	
    	set_mac_variable("eth1addr", MAC_ID1_LO, MAC_ID1_HI);	
    
    	return 0;
    }
    #endif

  • Thanks Steve for sharing your resolution. Your help is much appreciated.
    As you said ""magically" gets picked up by the kernel", it seems working :)
  • The random mac address assignment happens when the kernel is not passed the mac addresses during boot.

    For the TI SDKs the board/ti/am335x/board.c in the u-boot source tree provided with the SDK has a function called board_eth_init. This function reads the MACs IDs of the part and then sets u-boot environment variables that get applied to the DTB passed to the kernel.

    Implementing an EEPROM and reading MAC addresses from is possible, but it is the responsiblity of the system developer. Based on your question though did you implement a I2C EEPROM like TI did for board identification?

    Could you attach your board.c file?