Skip to content

snagrecover: support SPL mode on STM32MP1 - #108

Merged
rgantois merged 2 commits into
bootlin:mainfrom
mfuzzey:stm32mp1-spl
Oct 16, 2026
Merged

rgantois merged 2 commits into
bootlin:mainfrom
mfuzzey:stm32mp1-spl

Conversation

@MartinFuzzey

Copy link
Copy Markdown
Contributor

Normally STM32MP1 uses TF-A as the first stage bootloader but it
is also possible to use SPL instead.

Enable this by using a configuration file like:
first_stage: spl

    spl:
      path: u-boot-2024/out/flb_std_stm32mp15/u-boot-spl.stm32

    u-boot:
      path: u-boot-2024/out/flb_std_stm32mp15/u-boot.img

The "first_stage" property defaults to tf-a so as to not break existing tf-a
configurations.

@rgantois rgantois left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Martin, thanks for the contribution!

I've left a couple of comments.

Comment thread docs/snagrecover.md Outdated
to use u-boot SPL, wrapped in a ST header as the first stage.

**fip:** Contains at least U-Boot with an stm32 image header. Usually the
The mode is specified by one of "first_stage: tf-a" or "first_stage: spl" in the configuration file (defaults to tf-a)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this first_stage argument really necessary? I think we could just pick tf-a if it's in the config, and spl if tf-a isn't there.

Comment thread src/snagrecover/firmware/firmware.py Outdated
# ROM or TF-A too). I have also used plain dfu-util which uses a first index
# of zero too.
# But keep the existing behaviour unless uploading to SPL in case there is
# some weird edge case somewhere.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stm32 argument was introduced because when I reverse engineered STCubeProgrammer USB packet dumps, I noticed that USB requests started from 2 instead of 0. I didn't find any docs about this either.

I've just tested recover of an STM32MP1 DK2 without the stm32=True option and indeed it seems to work without issues.

So I'm okay with dropping the stm32 logic in DFU(), but without leaving any dead code lying around.

@MartinFuzzey

MartinFuzzey commented Oct 2, 2026 via email

Copy link
Copy Markdown
Contributor Author

@rgantois

rgantois commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Hi Romain,
On Fri, 2 Oct 2026 at 12:13, Romain Gantois @.***> wrote: Is this first_stage argument really necessary? I think we could just pick tf-a if it's in the config, and spl if tf-a isn't there.
I wondered about this too. Indeed it is not strictly necessary and we could do it that way. But one advantage of my way is having a common configuration file for both modes and setting the mode from the command line via the dict parameter. Eg this works even without first_stage in the yaml file (which could have both spl and tf-a binaries listed) $ snagrecover -s stm32mp15 -f snagboot/opr-snag.yaml -F "{'first_stage': 'spl'}" That does display a warning though [WARNING] You passed firmware configuration via files AND direct CLI arguments!

Why not, but I still want users to be able to use the SPL flow without having to specify the first_stage parameter. So the logic would be something like:

If only tf-a or only spl is there, then use that one. If both of them are used, then required first_stage to be specified.

The DFU constuctor has an optional argument "stm32", defaulting to True,
which causes the block number in the USB requests to start from 2 instead of 0.

This was done because reverse engineering of the STCubeProgrammer
USB packet dumps showed it used 2 based indices but this is not
actually required (tested), nor is documented anywhere.

This is problematic for 2 reasons:
* It requires all the non STM32 users of DFU to use stm32=False
* For the upcoming support of SPL rather than TF-A on stm32 we must start
  from block 0 since the u-boot SPL DFU protocol errors out with
  an unexpected block number if we start with 2.

So drop the stm32 constructor argument completely and alwys use zero
based packet indices.
Normally STM32MP1 uses TF-A as the first stage bootloader but it
is also possible to use SPL instead.

Enable this by using a configuration file like:
	spl:
	  path: u-boot-2024/out/flb_std_stm32mp15/u-boot-spl.stm32

	u-boot:
	  path: u-boot-2024/out/flb_std_stm32mp15/u-boot.img

It is also possible to specify both TF-A and SPL in the configuration file,
in which case an additional "first_stage" property is required:
	first_stage: spl

	tf-a:
	  path: ./tf-a-stm32mp157f-dk2.stm32

	spl:
	  path: u-boot-2024/out/flb_std_stm32mp15/u-boot-spl.stm32

	fip:
	  path: ./fip.bin

	u-boot:
	  path: u-boot-2024/out/flb_std_stm32mp15/u-boot.img

Alternatively the first_stage property may be omitted from the config
file and supplied on the command line by adding
	-F "{'first_stage': 'spl'}"
@MartinFuzzey
MartinFuzzey force-pushed the stm32mp1-spl branch 2 times, most recently from 86ff764 to fb1e986 Compare October 15, 2026 12:08
@MartinFuzzey

Copy link
Copy Markdown
Contributor Author

first_stage is now optional if only one of "tf-a" / "spl" is specified

@rgantois

Copy link
Copy Markdown
Collaborator

Thanks a lot!

@rgantois
rgantois merged commit c5c3e76 into bootlin:main Oct 16, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants