• RK3566设置以太网MAC地址


    1.遇到的问题

            此次购买了10块RK3566的核心板,收到后发现以太网的MAC地址全是一样的,然后尝试使用工具自行设置MAC地址。

    使用RKDevInfoWriteTool工具(使用方法参照:RKDevInfoWriteTool使用指南 - V1.2.5.pdf)给主板设置LAN MAC地址,但是主板启动后读取的MAC地址不是设置的MAC地址:

    让主板进入Loader模式,启动RKDevInfoWriteTool工具,勾选LAN后面的复选框,勾选单次读取,点击读取,读取出的MAC地址是12个字节,猜想可能系统默认有两个gmac(RK3568有2个GMAC,RK3566只有1个GMAC,GMAC1。),前面6字节是gmac0的地址,后面6字节是gmac1的地址,所以加起来12字节。通过ifconfig指令获取eth0的mac地址为026E784A75A6,为后面6字节。

    点击左上角的设置,进入设置页面:

     将8CAE49610002作为MAC地址写入设备,如果选择“自增”的形式这里不能写入12字节,会提示MAC地址不符合规范。

    写入之后再读取,LAN:的内容变为8CAE49610003,重启设备再次进入LOADER模式之后再读取,LAN:的内容变为了8CAE49610002A66AE16D2872。

     重启正常进入系统之后通过ifconfig指令获取eth0 的mac地址为A66AE16D2872,如下所示:

     

    2.分析系统启动读取MAC地址的过程

    系统启动时会在uboot过程中获取存储在vendor storage中的ETH MAC地址传给内核。

     uboot启动过程中执行..\x3566_linux_v1.2.0\u-boot\arch\arm\mach-rockchip\board.c中board_late_init()函数进行平台late初始化,函数实现如下:

    1. int board_late_init(void)
    2. {
    3.     rockchip_set_ethaddr();
    4.     rockchip_set_serialno();
    5.     setup_download_mode();
    6. #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0)
    7.     setup_boot_mode();
    8. #endif
    9. #ifdef CONFIG_ROCKCHIP_USB_BOOT
    10.     boot_from_udisk();
    11. #endif
    12. #ifdef CONFIG_DM_CHARGE_DISPLAY
    13.     charge_display();
    14. #endif
    15. #ifdef CONFIG_DRM_ROCKCHIP
    16.     rockchip_show_logo();
    17. #endif
    18. #ifdef CONFIG_ROCKCHIP_EINK_DISPLAY
    19.     rockchip_eink_show_uboot_logo();
    20. #endif
    21.     env_fixup();
    22.     soc_clk_dump();
    23.     cmdline_handle();
    24. #ifdef CONFIG_AMP
    25.     amp_cpus_on();
    26. #endif
    27.     return rk_board_late_init();
    28. }

    board_late_init()函数调用rockchip_set_ethaddr()进行eth mac地址的设置,函数实现如下:

    1. #define MAX_ETHERNET 0x2
    2. static int rockchip_set_ethaddr(void)
    3. {
    4. #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
    5. char buf[ARP_HLEN_ASCII + 1], mac[16];
    6. u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
    7. int ret, i;
    8. bool need_write = false, randomed = false;
    9. ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
    10. for (i = 0; i < MAX_ETHERNET; i++) {
    11. if (ret <= 0 || !is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
    12. if (!randomed) {
    13. net_random_ethaddr(ðaddr[i * ARP_HLEN]);
    14. randomed = true;
    15. } else {
    16. if (i > 0) {
    17. memcpy(ðaddr[i * ARP_HLEN],
    18. ðaddr[(i - 1) * ARP_HLEN],
    19. ARP_HLEN);
    20. ethaddr[i * ARP_HLEN] |= 0x02;
    21. ethaddr[i * ARP_HLEN] += (i << 2);
    22. }
    23. }
    24. need_write = true;
    25. }
    26. if (is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
    27. sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);
    28. if (i == 0)
    29. memcpy(mac, "ethaddr", sizeof("ethaddr"));
    30. else
    31. sprintf(mac, "eth%daddr", i);
    32. env_set(mac, buf);
    33. }
    34. }
    35. if (need_write) {
    36. ret = vendor_storage_write(LAN_MAC_ID,
    37. ethaddr, sizeof(ethaddr));
    38. if (ret < 0)
    39. printf("%s: vendor_storage_write failed %d\n",
    40. __func__, ret);
    41. }
    42. #endif
    43. return 0;
    44. }
    1. 定义MAX_ETHERNET为0x02,表示有两个ETH网卡。
    2. 从vendor storage区域LAN_MAC_ID处读取12字节的内容,接下来判断是否读取成功和依次判断前6字节和后6字节是否为合法的eth地址。
    3. 若读取失败或前6字节不是有效的eth地址,则随机生成一个mac地址。
    4. 若读取失败或后6字节不是有效的eth地址,则将前6字节的内容拷贝到后6字节区域,然后将后6字节的第0字节的内容与0x02想或,然后再加4,按照这个规则可以猜测第一次读取的LAN的内容FE6E784A75A6026E784A75A6的前6字节是由系统随机生成的,后6字节是按规则生成的。
    5. 若修改过ethaddr的内容,则将need_write赋值为true,在后面的执行中将ethaddr的内容重新写入vendor storage区域。
    6. 使用sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);语句将ethaddr[]中的内容格式化为冒号分割的MAC字符串存入buf,如8C:AE:49:61:00:02,把前6字节设置为ethaddr变量的内容,后6字节设置为eth1addr变量的内容。

    3.设置MAC地址的方法

    RK3566虽然只有一个gmac,但是是gmac1,只写入6字节的MAC地址会被默认为gmac0,所以需要写入12字节的MAC,然后系统取后6字节作为gmac1的MAC地址,系统启动后通过ifconfig才能获取到正确的MAC地址。但是通过LAN无法写入12字节,会提示"获取LAN MAC失败!!!",如下所示:

    目前想到的解决方案是给Vendor storage区新增一个ID用来存储两个以太网的MAC地址,编号为18,因为从vendor.h文件中看到0~17已有定义:

    1. #define RSV_ID 0
    2. #define SN_ID 1
    3. #define WIFI_MAC_ID 2
    4. #define LAN_MAC_ID 3
    5. #define BT_MAC_ID 4
    6. #define HDCP_14_HDMI_ID 5
    7. #define HDCP_14_DP_ID 6
    8. #define HDCP_2X_ID 7
    9. #define DRM_KEY_ID 8
    10. #define PLAYREADY_CERT_ID 9
    11. #define ATTENTION_KEY_ID 10
    12. #define PLAYREADY_ROOT_KEY_0_ID 11
    13. #define PLAYREADY_ROOT_KEY_1_ID 12
    14. #define SENSOR_CALIBRATION_ID 13
    15. #define IMEI_ID 15
    16. #define LAN_RGMII_DL_ID 16
    17. #define EINK_VCOM_ID 17

    再修改下static int rockchip_set_ethaddr(void)函数,如下所示:

    1. static int rockchip_set_ethaddr(void)
    2. {
    3. #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
    4. char buf[ARP_HLEN_ASCII + 1], mac[16];
    5. u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
    6. int ret, i;
    7. bool need_write = false, randomed = false;
    8. // ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
    9. ret = vendor_storage_read(18, ethaddr, sizeof(ethaddr));
    10. for (i = 0; i < MAX_ETHERNET; i++) {
    11. if (ret <= 0 || !is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
    12. if (!randomed) {
    13. net_random_ethaddr(ðaddr[i * ARP_HLEN]);
    14. randomed = true;
    15. } else {
    16. if (i > 0) {
    17. memcpy(ðaddr[i * ARP_HLEN],
    18. ðaddr[(i - 1) * ARP_HLEN],
    19. ARP_HLEN);
    20. ethaddr[i * ARP_HLEN] |= 0x02;
    21. ethaddr[i * ARP_HLEN] += (i << 2);
    22. }
    23. }
    24. need_write = true;
    25. }
    26. if (is_valid_ethaddr(ðaddr[i * ARP_HLEN])) {
    27. sprintf(buf, "%pM", ðaddr[i * ARP_HLEN]);
    28. if (i == 0)
    29. memcpy(mac, "ethaddr", sizeof("ethaddr"));
    30. else
    31. sprintf(mac, "eth%daddr", i);
    32. env_set(mac, buf);
    33. }
    34. }
    35. if (need_write) {
    36. // ret = vendor_storage_write(LAN_MAC_ID,
    37. // ethaddr, sizeof(ethaddr));
    38. ret = vendor_storage_write(18,
    39. ethaddr, sizeof(ethaddr));
    40. if (ret < 0)
    41. printf("%s: vendor_storage_write failed %d\n",
    42. __func__, ret);
    43. }
    44. #endif
    45. return 0;
    46. }

    修改完成之后,重新编译uboot,然后烧写到主板。

    重启主板进入loader模式,使用RKDevInfoWriteTool工具向vendor storage ID为18的区域写入两个MAC地址,操作如下所示:

     手动输入,ID为18,二进制,然后点保存回到主界面:

     填写内容后再写入,前6字节可以填写任意内容,后6字节内容为MAC地址。

    写入之后重启主板,正常启动之后,通过ifconfig命令查询到eth0的mac地址为:8C:AE:49:61:00:03

    1. eth0 Link encap:Ethernet HWaddr 8C:AE:49:61:00:03
    2. UP BROADCAST MULTICAST MTU:1500 Metric:1
    3. RX packets:0 errors:0 dropped:0 overruns:0 frame:0
    4. TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
    5. collisions:0 txqueuelen:1000
    6. RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
    7. Interrupt:35

    问题暂时解决,如有更好的方法,请不吝赐教!

  • 相关阅读:
    【计算机网络】成功解决 ARP项添加失败:请求的操作需要提升
    Launcher3介绍
    阿里P9被转载上100W次的Java面试题!已助我拿下12家大厂offer!
    git新建仓库上传项目步骤
    Flink中的状态一致性
    Linux发行版---常用命令操作快速熟悉
    rust类型
    30天啃透这份Framework 源码手册直接面进大厂
    实现 easyExcel 导入导出自定义字典转换器
    hive安装部署
  • 原文地址:https://blog.csdn.net/professionalmcu/article/details/126137210