背景

设备上一共有四个网口,一个是原生的mac,另外三个是USB扩展的RTL8152,为了生产时候方便mac地址统一,所以需要所有的mac地址都存在一个存储空间里,然后四个mac去获取设置。这里比较简单的是将ethaddr这些参数在uboot通过bootargs传递给内核驱动。设备上有一个eeprom,可以把mac存储在里面,uboot启动时候去读取,然后设置到环境变量,再传递给内核的mac驱动。

uboot修改

1.增加ID_EEPROM支持

参考uboot源码中其他平台现有的实现,将u-boot/board/freescale/common下的sys_eeprom.c和eeprom.h拷贝到u-boot/board/rockchip/evb_rv1126目录下,然后在该目录下修改Kconfig,增加内容如下

+config ID_EEPROM
+        bool "support ID eeprom"
+        default y
+        help
+          Say Y here to add support for Sample
+          at Reset Utility. You need this only if
+          you work on a Marvell development board.
+          If not, keep this off to reduce code size
+
+config SYS_I2C_EEPROM_CCID
+        bool "support I2C_EEPROM_ID"
+        default y
+        help
+          Say Y here to add support for Sample
+          at Reset Utility. You need this only if
+          you work on a Marvell development board.
+          If not, keep this off to reduce code size
+
+config SYS_I2C_EEPROM_NXID
+        bool "support I2C_EEPROM_NXID"
+        default y
+        help
+          Say Y here to add support for Sample
+          at Reset Utility. You need this only if
+          you work on a Marvell development board.
+          If not, keep this off to reduce code size

接着在Makefile中增加 obj-$(CONFIG_ID_EEPROM) += sys_eeprom.o

2.配置相关config选项

eeprom的型号为AT24C512,地址长度为2个字节。RK在eMMC的首部保留了一块用于存储序列号、MAC等自定义内容的Vendor Storage存储空间,这里不需要用到,配置项中去掉。

-CONFIG_ROCKCHIP_VENDOR_PARTITION=y
+# CONFIG_ROCKCHIP_VENDOR_PARTITION is not set
+CONFIG_ID_EEPROM=y
+CONFIG_SYS_I2C_EEPROM_CCID=y
+# CONFIG_SYS_I2C_EEPROM_NXID is not set
+CONFIG_CMD_I2C=y
+CONFIG_SPL_I2C_SUPPORT=y
-CONFIG_NET_RANDOM_ETHADDR=y
+# CONFIG_NET_RANDOM_ETHADDR is not set
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_I2C_DEFAULT_BUS_NUMBER=0x2
+CONFIG_I2C_EEPROM=y
+CONFIG_SYS_I2C_EEPROM_ADDR=0x51
+CONFIG_SYS_I2C_EEPROM_BUS=2
+CONFIG_SYS_EEPROM_SIZE=65536
+CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=1024
+CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=5
+CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
+CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW=0x2

3.修改相关驱动

因为eeprom的地址是两个字节,页大小是128个字节的,所以这里要修改一些相关驱动的参数。

1)sys_eeprom.c

2)rv1126-u-boot.dtsi
+&i2c2 {
+       u-boot,dm-spl;
+        clock-frequency = <400000>;
+        status = "okay";
+
+       at24:at24@51 {
+        compatible = "atmel,24c512";
+        reg = <0x51>;
+        pagesize = <128>;
+       };
+};
3)cmd/i2c.c
 #ifdef CONFIG_DM_I2C
-#define DEFAULT_ADDR_LEN       (-1)
+#define DEFAULT_ADDR_LEN       2
 #else
-#define DEFAULT_ADDR_LEN       1
+#define DEFAULT_ADDR_LEN       2
 #endif
4)i2c-uclass-compat.c

5)rv1126_common.h

4.bootargs参数传递

修改u-boot/arch/arm/lib/bootm.c文件,找到boot_prep_linux函数,此函数可以读取bootargs中的参数并保存到指定位置,在uboot启动完成跳转到内核时把参数传递到内核的bootargs里,uboot阶段还没传递进去,所以在uboot中,查看bootargs时看不到相关的变量传递。具体修改如下

内核修改

1.rk-mac驱动修改

修改drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c文件,找到rk_get_eth_addr函数,从中可以看到原来mac地址是从Vendor Storage获取的,如果没有再使用随机的mac地址,以下为原函数

void rk_get_eth_addr(void *priv, unsigned char *addr)
{
        int ret;
        struct rk_priv_data *bsp_priv = priv;
        struct device *dev = &bsp_priv->pdev->dev;
   
        rk_devinfo_get_eth_mac(addr);
        if (is_valid_ether_addr(addr))
                goto out;

        ret = rk_vendor_read(LAN_MAC_ID, addr, 6);
        if (ret != 6 || is_zero_ether_addr(addr)) {
                dev_err(dev, "%s: rk_vendor_read eth mac address failed (%d)",
                                        __func__, ret);
                random_ether_addr(addr);
                dev_err(dev, "%s: generate random eth mac address: %02x:%02x:%02x:%02x:%02x:%02x",
                                        __func__, addr[0], addr[1], addr[2],
                                        addr[3], addr[4], addr[5]);
                ret = rk_vendor_write(LAN_MAC_ID, addr, 6);
                if (ret != 0)
                        dev_err(dev, "%s: rk_vendor_write eth mac address failed (%d)",
                                        __func__, ret);
        }

out:
        dev_err(dev, "%s: mac address: %02x:%02x:%02x:%02x:%02x:%02x",
                                __func__, addr[0], addr[1], addr[2],
                                addr[3], addr[4], addr[5]);
  
}

将此部分注释掉,使用 __setup 函数来获取bootargs中的eth1addr参数,然后传递给mac进行设置,具体实现如下

2.修改rtl8152驱动

首先先从realtek官网下载8152最新的linux驱动,官网地址为[https://www.realtek.com/zh/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software](),目前为止linux驱动最新版本为2.16.1,解压后将r8152.c和compatibility.h上传到kernel/drivers/net/usb目录下,接着修改r8152.c中的mac获取方式,因为设备上有三个8152,所以这里用一个变量mac_num区分加载顺序,方便设置mac地址,具体修改如下

实现验证

在uboot中可以用mac命令写入eeprom并保存

系统起来后查看cmdline是否传入bootargs成功

ifconfig查看是否正确设置mac地址

至此已实现需要的功能,RV1126原生mac和外扩的三个8152均使用了eeprom里的mac地址进行设置,且一一对应。另外可以在系统上写个应用,通过应用写到eeprom中,不用在uboot中进行mac的设置命令。

如果觉得我的文章对你有用,请随意赞赏