Dynamically applying DTBO / swapping DTB at boot with UEFI

We are in exactly the same situation as this user: Dynamic DTB/DTBO loading (and my impression is that a lot of other devs are in the same shoes as well).

We also need to swap DTB or apply a different DTBO at boot time (not compile time) according to a value read from an EEPROM connected through I2C. This was easy to do with U-Boot but now that you switched to UEFI that makes things a lot more complicated.

It looks like NVIDIA is not supporting that even though this is (apparently) quite a common request. So we have a few options, neither really easy:

  1. Write ourselves a UEFI application to do that by leveraging the I2C DXE driver
  2. Port U-Boot ourselves to the Jetson ORIN
  3. Rely on exotic solutions like kexec to re-run the same kernel with updated DTB

So my questions are:

  1. Is there any official NVIDIA way to deal with this use case?
  2. Is the TegraI2c UEFI driver tested or even used anywhere if we want to write a UEFI app for that ourselves?
  3. Any other suggestion?
1 Like

Hi ccaione,

Are you using the devkit or custom board?
What’s your Jetpack version in use?

We would suggest using overlay dtb for your use case.
Overlay dtb would be applied according to the MOEDL/SKU ID in EEPROM.

For example, UEFI will check if ids in board_config match the ID in EEPROM.

/dts-v1/;
/plugin/;
 
 / {
 	overlay-name = "Tegra234 p3701-0000-as-p3767-0004 Emulation Overlay";
 
 	fragment-t234-p3701-0000-as-p3767-0004@0 {
 		target-path = "/";
 		board_config {
 			ids = "3701-0000-*", "3701-0005-*";
 		};

We are using a devkit Jetson ORIN with a custom board connected to the 40-pin header. The EEPROM is on this extension board on the I2C5 bus.

We are using JetPack 5.1.2.

Unfortunately this is not going to work. Please correct if I’m wrong but that is not going to work if the EEPROM is on the I2C bus exposed by the 40-pin header.

Do you mean that you are using AGX Orin devkit and connect your EEPROM module to 40-pins header?
Or you are using AGX Orin module on custom carrier board and your EEPROM is on this board?
What do you mean about “custom board”?

For the current mechanism we’ve implemented, it is read from the EEPROM in the module.

Correct.

No, the custom board is a board carrying an EEPROM (and a lot more) with a 40-pin female header that is connected to the 40-pin male header of the ORIN. We are not using any ORIN module or carrier board.

This is exactly why that solution is not going to work for us and it looks like there is not an available solution either since the switch to UEFI.

Yes, it seems we don’t support reading external EEPROM and load different dtb.
You may need to check UEFI source and write the driver for your use case.
We would suggest using dtb overlay for different module, which is what we’ve done for several kinds of modules.

Yeah, but the I2C UEFI driver seems at least to be there? In ComponentList · NVIDIA/edk2-nvidia Wiki · GitHub I see TegraI2c that is supposedly an I2C DXE driver that can be used to access the external EEPROM?

Do you know how mature is that? It doesn’t seem to be used anywhere at all.

The other solution I was investigating was kexec but I’m getting a lot of trouble since the rebooted kernel seems to not be fully functional but NVIDIA is indeed shipping a tegra234-p3701-0000-p3737-0000-kexec.dtb so I think someone is internally using that?

Yeah, the problem is doing that at run-time and not compile-time.

With this approach, we also do it in runtime that i will load different dtb when you switch to another module.

It seems no one is using this dtb and the nodes inside are all disabled.

@KevinFFF can you confirm whether the I2C UEFI driver is usable to interface with the EEPROM on the I2C bus on the 40-pins header?

We can read eeprom from an i2c bus as long as it’s specified in dtb.

Yes, I’m experimenting with that and adding my EEPROM to the eeprom-manager node it seems indeed that when the I2C DXE driver is probed, it accesses the EEPROM and tries to read the content.

The problem I’m facing now is that I get a ValidateEepromData: Invalid size in eeprom 0 even though I’m using a valid EEPROM layout (I have copied onto my external EEPROM the content of the Cvm EEPROM that it is correct).

My EEPROM is way bigger so I’m trying to understand where is the problem.

@KevinFFF is there any specific configuration for the EEPROM that are required?

The problem I’m facing is that when the I2C DXE driver is reading from my EEPROM it is skipping the first byte. I’m using an ATMEL 24c256.

So if this is the content of my EEPROM (hexdump, first 8 bytes):

0000000    0201 0403 0605 0807 xxxx

The I2C DXE driver is reading the first 8 bytes as follows (dumped from the I2C DXE driver):

0302 0504 0706 xx08

Is the I2C DXE driver able to deal with all the EEPROMs or does it expect something more specific?

Sorry that we’ve not verified this use case and also this module.
Have you tried to store your data from the second byte if the first byte is skipped?

You may need to check I2C DXE which is the open source driver in UEFI.

Yes, skipping the first byte it works fine.

Does it meet your requirement if the data could be read correctly?

Kind of. I can read data correctly but the general behaviour is a bit erratic. For example sometimes on reboot the I2C DXE driver fails to read the EEPROM again. In general it seems that the driver is not production ready I’d say.

There is no update from you for a period, assuming this is not an issue any more.
Hence we are closing this topic. If need further support, please open a new one.
Thanks

How’s the fail rate?
Have you tried to measure the I2C signal to check if there’s any waveform in failed case?