Imho such thing like setting mac address should be done generic and the tlv_eeprom goes in this direction…seems having less code than the starfive aproach.
TLV_EEPROM it’s ONIE (Open Network Install Environment)
Onie installer it’s standart for whitebox switches I can prepare a special onie image.
And the whole installation will be done with one command. For example.
onie-nos-install https://example.com/filogic/arm64-bananapi_bpi_r4-r0.bin
ok, i tested with my “junk” data on eeprom - no error
fine so far, how is the tlv be initialized?
BPI-R4> i2c dev 2
Setting bus to 2
BPI-R4> tlv_eeprom read
EEPROM data loaded from device to memory.
tlv_eeprom - Display and program the system EEPROM data block.
Usage:
tlv_eeprom [read|write|set <type_code> <string_value>|erase|list]
tlv_eeprom
- With no arguments display the current contents.
tlv_eeprom dev [dev]
- List devices or set current EEPROM device.
tlv_eeprom read
- Load EEPROM data from device to memory.
tlv_eeprom write
- Write the EEPROM data to persistent storage.
tlv_eeprom set <type_code> <string_value>
- Set a field to a value.
- If no string_value, field is deleted.
- Use 'tlv_eeprom write' to make changes permanent.
tlv_eeprom erase
- Reset the in memory EEPROM data.
- Use 'tlv_eeprom read' to refresh the in memory EEPROM data.
- Use 'tlv_eeprom write' to make changes permanent.
tlv_eeprom list
- List the understood TLV codes and names.
BPI-R4> i2c bus
Bus 0: i2c@11004000
Bus 1: i2c@11005000 (active 1)
70: i2c-mux@70, offset len 1, flags 0
Bus 2: i2c@11005000->i2c-mux@70->i2c@0 (active 2)
57: eeprom@57, offset len 1, flags 0
i guess tlv_eeprom read only lists content if there is valid data.so i guess i need tlv_eeprom erase and then write the fields one-by-one,right?
BPI-R4> tlv_eeprom erase
EEPROM data in memory reset.
BPI-R4> tlv_eeprom set 0x2A 3
BPI-R4> tlv_eeprom set 0x24 F2:B8:7B:4D:00:01
BPI-R4> tlv_eeprom write
Programming passed.
BPI-R4> tlv_eeprom dev
BPI-R4>
imho the eeprom should be listed here, right?
BPI-R4> tlv_eeprom
TLV: 0
TlvInfo Header:
Id String: TlvInfo
Version: 1
Total Length: 18
TLV Name Code Len Value
-------------------- ---- --- -----
MAC Addresses 0x2A 2 3
Base MAC Address 0x24 6 F2:B8:7B:4D:00:01
CRC-32 0xFE 4 0x75E88454
Checksum is valid.
thought it is memory only but display with i2c command shows it on the eeprom
BPI-R4> i2c md 0x57 0 0x20
0000: 54 6c 76 49 6e 66 6f 00 01 00 12 2a 02 00 03 24 TlvInfo....*...$
0010: 06 f2 b8 7b 4d 00 01 fe 04 75 e8 84 54 ff ff ff ...{M....u..T...
seems always <code> <len bytes> <data>
but looks like the data is not applied yet (maybe needs reset), but after i did this (and loaded the tlv_eeprom binary) i got an endless loop (seems not stopping based on the mac-count field)
## Error inserting "eth1274add" variable, errno=12
## Error inserting "eth1275add" variable, errno=12
## Error inserting "eth1276add" variable, errno=12
## Error inserting "eth1277add" variable, errno=12
so something is wrong in the startup-code…i can see the eeprom-data with tlv_eeprom and mac-addresses are set.
BPI-R4> tlv_eeprom
TLV: 0
TlvInfo Header:
Id String: TlvInfo
Version: 1
Total Length: 18
TLV Name Code Len Value
-------------------- ---- --- -----
MAC Addresses 0x2A 2 3
Base MAC Address 0x24 6 F2:B8:7B:4D:00:01
CRC-32 0xFE 4 0x75E88454
Checksum is valid.
BPI-R4> printenv ethaddr
ethaddr=F2:B8:7B:4D:00:01
BPI-R4> printenv eth2addr
eth2addr=F2:B8:7B:4D:00:03
BPI-R4> printenv eth1addr
eth1addr=F2:B8:7B:4D:00:02
I guess set_mac is called before setting the length. but order seems right…
parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry, td); //read data from eeprom to memory
set_mac_addr(td); //loop through (i = 0; i < td->maclen;), maclen should be 3
currently adding some debug-code and limiting the maclen before the loop ![]()
looks like first it is set correctly, but after loading the mac address the length is set to 1278…maybe some memory corruption/overflow?
Not completely understood the code. Maybe it is important in which order the fields are written? I have first set the mac count an then the base mac
No. The order of the fields is not important.
That’s for sure! Most likely, more Fields are needed.
But I’m not sure about that.
Let’s check now.
But if mac address is first
all works correctly

I’m fix this error.
I read the values incorrectly.
tlv_eeprom_fix_read.patch (2,6 КБ)
Now it’s work correctly
have applied the patch manually because i did some cleanup before…can you verify it is right? only compile-tested yet, will do function test later
All correctly. The patch has been applied correctly.
ok, yes quick-tested it with my already written eeprom, works now
eth1addr=F2:B8:7B:4D:00:02
eth2addr=F2:B8:7B:4D:00:03
ethaddr=F2:B8:7B:4D:00:01
maybe we should add a normal printf to show, that mac is loaded from eeprom (and applied)? btw. is mac also used for uboot or only inserted into linux devicetree?
currently only this is shown:
BPI-R4> fatload usb 0:1 $loadaddr u-boot-eeprom.bin
911952 bytes read in 81 ms (10.7 MiB/s)
BPI-R4> go $loadaddr
## Starting application at 0x46000000 ...
U-Boot 2025.04-bpi-eeprom-00036-gb649d849e4dc-dirty (Jun 09 2025 - 10:41:05 +0200)
CPU: MediaTek MT7988
Model: mt7988-rfb
DRAM: 4 GiB
Core: 57 devices, 23 uclasses, devicetree: separate
MMC: mmc@11230000: 0
Loading Environment from nowhere... OK
In: serial@11000000
Out: serial@11000000
Err: serial@11000000
=> board_late_init...
bootmedia:sd
Net: MediaTek MT7988 built-in switch
eth0: ethernet@15110100
Hit any key to stop autoboot: 0
BPI-R4>
Maybe later. I need to prepare a new image taking into account these changes.
If anyone is interested
This my image of vyos for bpi-r4
with tlv_eeprom and kernel 6.12-main from @frank-w
login/password of image is vyos/vyos
docs of vyos https://docs.vyos.io
Have you tested if your original order works too?
Yes. It’s worked fine.
Interesting discussions, folks.
Share one piece of my finding. Enable CONFIG_ID_EEPROM=y. Then u-boot will automatically read and initialise MACs from the TLV values.
The new tlv_data.{ch} code is not required.
I enabled tlv_eeprom on my build of the stock OpenWrt. BPI-R4 instantly looks more sophisticated. ![]()
Do you still have that VyOS image available somewhere?
The link returns a 404.
Yes
You have image for R3 Or R4 ??
what have you set as CONFIG_SYS_EEPROM_BUS_NUM?
currently i have added i2c1 and i2c2, where i2c2 has the pcamux behind with the eeprom-chip.
does 0 enumerate all i2c busses? i2c0 is not enabled so busnum=0 should be i2c1 where no eeprom is there. in linux the mux creates additional busses where the bus-number could be 1 (i2c2) or 2 (mux-channel 0)
looks like this option can be omitted
BPI-R4> tlv_eeprom
TLV: 0
TlvInfo Header:
Id String: TlvInfo
Version: 1
Total Length: 18
TLV Name Code Len Value
-------------------- ---- --- -----
MAC Addresses 0x2A 2 3
Base MAC Address 0x24 6 F2:B8:7B:4D:00:01
CRC-32 0xFE 4 0x75E88454
Checksum is valid.
and also booted kernel received adresses for all macs
3: eth0: <BROADCAST,MULTICAST> mtu 1504 qdisc noop state DOWN group default qlen 1000
link/ether f2:b8:7b:4d:00:01 brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether f2:b8:7b:4d:00:02 brd ff:ff:ff:ff:ff:ff
5: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether f2:b8:7b:4d:00:03 brd ff:ff:ff:ff:ff:ff
have reverted the tlv-code patch and just enabled the ID_EEPROM option and chainloaded uboot from my existing
CONFIG_SYS_EEPROM_BUS_NUM=0
It is the default in stock OpenWrt Snapshot.
Here is my output of “i2c bus”
BPI-R4> i2c bus
Bus 0: i2c@11004000
Bus 1: i2c@11005000 (active 1)
70: i2c-mux@70, offset len 1, flags 0
Bus 2: i2c@11005000->i2c-mux@70->i2c@0 (active 2)
57: eeprom@57, offset len 1, flags 0
Bus 3: i2c@11005000->i2c-mux@70->i2c@1
Bus 4: i2c@11005000->i2c-mux@70->i2c@3
Yes thats what i tried to say. I understood CONFIG_SYS_EEPROM_BUS_NUM option as “on which bus is the eeprom”,so i guessed 0 is wrong because eeprom is on muxed bus 2. But 0 does work,so it looks like this option can be ignored (leaving on default 0).
I never looked into the details of CONFIG_SYS_EEPROM_BUS_NUM.
0 could be just default and means scan all buses. Just a guess.








