linux-sunxi / sunxi-tools

A collection of command line tools for ARM devices with Allwinner SoCs.
http://linux-sunxi.org/
GNU General Public License v2.0
579 stars 421 forks source link

fel: relax SCTLR check #111

Closed nunojpg closed 6 years ago

nunojpg commented 6 years ago

On a H2+ (Orange Pi Zero), if I enter fel mode by entering "go 0xFFFF0020" on u-boot cmd line, then sunxi-fel fails with this error:

"Unexpected SCTLR (00C5287A)"

This does not happen when I enter fel mode directly on power-on (no sd card for eg).

I've attempted to remove this check and sunxi-fel can work fine without it (tested uboot command successfully).

I suggest SCTLR check is relaxed.

ssvb commented 6 years ago

Why are you doing this? Can you describe your use case? Is it a mainline U-Boot or a variant of U-Boot from the Allwinner's firmware?

The reason for having this safety check there is to ensure that we have a predictable state of the CPU and peripherals. We can surely downgrade this error to a warning message, but at least keeping a warning message is necessary for troubleshooting purposes.

wens commented 6 years ago

Maybe we could add a U-boot command that properly drops down / jumps to FEL mode, instead of just "go [FEL mode start address]"

ssvb commented 6 years ago

I basically wonder whether @nunojpg's use case is testing/development of U-Boot or jailbreaking Android firmware.

If it's the former, then this is not a very good idea in general: https://www.denx.de/wiki/DULG/CanUBootBeConfiguredSuchThatItCanBeStartedInRAM

But if it's the latter, then we can maybe think about something to make it easier.

wens commented 6 years ago

If it's the latter then my proposal is irrelevant.

nunojpg commented 6 years ago

Hi,

I'm using u-boot mainline (2018.05-rc1 with some minor patches). When I have a valid sd card on the orange pi zero it will not start in FEL mode, so I need u-boot to be able to programatically switch to FEL mode by using go 0xFFFF0020.

This is used as a recover mode.

@wens What can I do beside "go 0xFFFF0020" to get to a cleaner FEL state?

ssvb commented 6 years ago

I see, thanks. If you have U-Boot already running, then why don't you use DFU or Fastboot for recovery (flashing a new image to MMC)? It should be much faster than FEL.

As for a clean switch to FEL mode from U-Boot. It is probably possible to use one of the data registers from the RTC domain for storing a boot state code. Then write some magic value to this register and reset the SoC. Then the SPL part of U-Boot can check this magic value very early (before initializing any peripherals), clear the data register and pass control to 0xFFFF0020.

A GPIO FEL button is another possible solution, but it can't be used with the stock unmodified Orange Pi Zero.

wens commented 6 years ago

The magic value in RTC domain is pretty much what Allwinner's boot0 / U-boot uses. Their U-boot has an "efex" command that resets the system into FEL mode.

nunojpg commented 6 years ago

My current recovery setup is:

@ssvb I decided to use mass storage and not fastboot or dfu because it seems to be the easier way to flash a .img to the sd card, including u-boot on the boot sector and all partitions. AFAIK (and I don't know much :D), with fastboot or dfu It's not very easy or possible to create the partitions or write without partitions (boot sector). I would prefer to be wrong.

@wens Ok, so I should look up how to use the RTC registers to reboot into FEL. So far I've only confirmed I'm able to reset by triggering the watchdog (afaik what the reset command on mainline u-boot also does. Are you awaer of a efex patch for mainline?

ssvb commented 6 years ago

@wens Oh, that's nice. No need to reinvent anything new. And it's good to know that this approach has been already tested.

@nunojpg Out of curiosity, are you using a jumper for shorting some GPIO pins or is it a button? If you are already using GPIO, then you can check its state very early in the SPL. As an example, you can have a look at the https://github.com/linux-sunxi/sunxi-tools/blob/master/uart0-helloworld-sdboot.c sample program. This code can be reduced to only keep a basic GPIO functionality and strip everything else. Then you can implement a single function, which would check the GPIO state and either jump to 0xFFFF0020 or return back to the caller. This function can be added to the U-Boot SPL. If I remember correctly, @apritzel was experimenting with this stuff some time ago.

apritzel commented 6 years ago

Yeah, I had some patch for the SPL to enter FEL mode when a GPIO was pulled low. But as this wasn't working with the AArch64 SPL on the 64-bit SoCs, I didn't pursue this further. But I remember having tested it successfully on the OPI-Zero with a simple switch on pin PL7. I can try to dig out this patch tonight. Another thing I currently use is some kind of pre-firmware tool on SPI flash: It loads something which waits three seconds for a key press (over serial). If it times out, it loads the actual SPL from the SPI (@1MB) and proceeds normally. If one pressed a key, it presents a command prompt, from where I can enter FEL mode easily.

nunojpg commented 6 years ago

@apritzel Yes, some patch for mainline SPL would be greatly appreciated.

ssvb commented 6 years ago

@apritzel My understanding is that the GPIO button check can (and should) be done as the very first thing in the SPL, so it may happen before switching to the 64-bit mode. But again, we will have a toolchain problem to compile this tiny bit of code, unless it is just injected as a blob of hex data.

apritzel commented 6 years ago

@nunojpg I dug out the patch yesterday and put it here. Not tested, but at least it applies cleanly. You need to add something like CONFIG_SUNXI_FEL_BUTTON_PIN="PL7" to your defconfig.

@ssvb Well, that would be one possibility, but it's a bit hairy, especially when it comes to configurability (translating from PL7 to the GPIO number). But be my guest ;-) I got quite far with switching back to AArch32 from the SPL - that actually works (I can execute ARM code again). But then branching back to the BROM's FEL routine didn't work, I guess because some state isn't the same, as we enabled the MMU in AArch64. I tried the usual D$/I$ cache clean/invalidate, but that didn't help either. Not sure I covered the TLBs, but that might not matter with a 1:1 mapping. So I guess it would be more worthwhile to fix this, as this would give us a FEL compatible stock SPL, so we can use the normal build for initialising the DRAM and would support FEL boot easily.

ssvb commented 6 years ago

@apritzel Don't we also need to configure pull-up for this GPIO pin before reading it? Otherwise the result may be unpredictable if the pin is floating.

For example, I know that there were a few incidents when poorly designed boards did not handle the FEL pin properly (yeah, this is not GPIO but the idea is still the same) and this resulted in a sporadically "non-booting" board:

apritzel commented 6 years ago

@ssvb Right, I thought I did this in the patch, but that was apparently a different version (just found this one in an old branch). Also I connected a switch with a pull-up resistor. But yes, we should pull this up in the code.

nunojpg commented 6 years ago

@apritzel your patched worked perfectly for me, thansk.

About the later comments, how does it change to enable a pull-up if you don't give it time to settle? is a few CPU clocks enough in comparison with the port pin capacitance?

hramrach commented 2 years ago

Is there a source where the efex command is implamented?

apritzel commented 2 years ago

@hramrach if you are thinking about a mainline U-Boot command to enter FEL mode: existing source would be specific to the BSP U-Boot version, and due to the different firmware design cannot easily be applied to mainline U-Boot. We tossed around some ideas to have such a "felreset" command in mainline, but it's not trivial, and there would need to be a few variants, as different SoC (generations) require different hacks. In general FEL mode is entered by branching to 0xffff0020 (older SoCs, <=H3) or 0x00000020 (newer SoCs, 64-bit and newer 32-bit). But the rest of the system must be in a certain state, so the easiest and most reliable is to reset the SoC and let it enter FEL mode, for instance via some standby hook. This is comparably easy on new SoCs like the H616, but tricky on older ones. Are you looking at a certain SoC? Maybe we can try to start implementing this there? You could also join the #linux-sunxi IRC channel on OFTC to discuss this.

hramrach commented 2 years ago

What I am looking for is an implementation that works, it does not have to be on mainline u-boot.

The comments here talk about setting a register in RTC and branching to the FEL address early in SPL so I would like to see the code for setting the register on different SoC generations. I do not want to reinvent that.

There is similar downstream functionality for Rockchip SoCs, and I want to see if this can be reasonably generalized.

I have an Orange Pi Zero somewhere around.