Skip to content

added support for SPI Flashes > 16MB using extended address register#247

Open
MT522 wants to merge 1 commit into
linux-sunxi:masterfrom
MT522:master
Open

added support for SPI Flashes > 16MB using extended address register#247
MT522 wants to merge 1 commit into
linux-sunxi:masterfrom
MT522:master

Conversation

@MT522

@MT522 MT522 commented Jun 23, 2026

Copy link
Copy Markdown

SPI NOR Flashes support address spaces larger than 16MB using an extended address register.

This code switches banks automatically based on the destination address if > 16MB.

After read/write operation, the bank safely switches back to 0.

@apritzel

Copy link
Copy Markdown
Contributor

Can you say which board uses a SPI NOR flash bigger than 128Mbit? I think all the boards I have seen use NAND SPI for sizes beyond 16MB, and then they typically go much bigger. So what is the use case here?

And how universal is the extended address register and the bank switching? The idea of this code, in connection with the BootROM, is to stay simple and support a common subset of commands, that are universally usable across different chips. If this is too special, I wonder if using U-Boot's far more elaborate SPI flash support would be preferable, to keep this code here simple and lean.

And looking at the code: the diff is hardly readable, it's hard to see what's refactored and what's new code. Can you please try to move the bank switching code into a separate function, and call this from the existing code? So that most of the existing code stays in place, and is just extended by calls to new functions, when needed? If you need refactorings, please do them first in separate patches.

@ssvb

ssvb commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

I think it makes sense to strictly avoid using any extended bank switching commands for reading/writing below 16MB. But we can do something else after crossing this boundary (without breaking compatibility with smaller SPI NOR chips).

@MT522

MT522 commented Jun 29, 2026 via email

Copy link
Copy Markdown
Author

@Icenowy

Icenowy commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

I don't think bank switch or ENTER_4BYTE should be used on V3s, because the BootROM isn't aware of these things, and an unexpected SoC reset without Flash reset will send the system to hell.

@ssvb

ssvb commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

my current patch does not sabatoge support for smaller chips. It just inspects the destination address. Should it be larger than 16MB, it sends the SPI command to switch banks and wraps the address back around 0.

I skimmed through your patch and noticed:

    uint8_t current_bank = 0xFF;
    // <skipped>
    if (target_bank != current_bank) {

My understanding (without testing it with a real device) is that if the bank is 0 (accessing below 16MB), then the code guarded by the if statement is executed due to having the initial value set to 0xFF.

@MT522

MT522 commented Jun 29, 2026

Copy link
Copy Markdown
Author

I don't think bank switch or ENTER_4BYTE should be used on V3s, because the BootROM isn't aware of these things, and an unexpected SoC reset without Flash reset will send the system to hell.

you are correct. That's why we resort to the extended address register to switch banks instead of ENTER_4BYTE.

By the way, note how the bank automatically switches back to 0 after a read/write operation.

The only issue I have not targeted in this patch, is the SoC resetting while programming the higher bytes of the chip. This would retain the bit set in the extended address register.

@MT522

MT522 commented Jun 29, 2026

Copy link
Copy Markdown
Author

my current patch does not sabatoge support for smaller chips. It just inspects the destination address. Should it be larger than 16MB, it sends the SPI command to switch banks and wraps the address back around 0.

I skimmed through your patch and noticed:

    uint8_t current_bank = 0xFF;
    // <skipped>
    if (target_bank != current_bank) {

My understanding (without testing it with a real device) is that if the bank is 0 (accessing below 16MB), then the code guarded by the if statement is executed due to having the initial value set to 0xFF.

Actually, quite on the opposite.

The code inside the if statement is always executed. I didn't implement a function to first read the current_bank and skip the block completely if need be (could be added in the future). I just put a dummy value 0xFF inside it at the beginning of the function.

Should you look inside the block, you'll see that a WREAR command is issued which sets the current bank of the device to the target bank.

So for example if your address is somewhere below 0x1000000, it will reset the EAR. otherwise, the register is set.

Also, note that at the end of the function, no matter a read/write operation, the EAR is reset back to 0. This is put there to make sure the next time the SoC powers on and the U-boot tries reading data from the flash, it reads at the correct bank 1 rather than retrieving invalid data sitting at addresses > 0x1000000

@ssvb

ssvb commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

My understanding (without testing it with a real device) is that if the bank is 0 (accessing below 16MB), then the code guarded by the if statement is executed due to having the initial value set to 0xFF.

Actually, quite on the opposite.

The code inside the if statement is always executed.

My comment says that the code inside of the if statement is always executed. So you just confirmed what I said.

Should you look inside the block, you'll see that a WREAR command is issued which sets the current bank of the device to the target bank. So for example if your address is somewhere below 0x1000000, it will reset the EAR. otherwise, the register is set.

And how can we be sure that this is compatible with all older small SPI NOR flash chips? There are many dirt cheap SPI NOR chips sold on Aliexpress or Ebay, which only pretend to be Winbond (sold as WinDbond) and other brand names. Each and every of them may differ in subtle ways. See https://linux-sunxi.org/Bootable_SPI_flash#25Q128FV as an example. If the concept of banks switching is not implemented (since there's no need for that when the size is small) and the relevant commands are not supported, then your patch will ruin someone's day. That's the rationale for #247 (comment)

What's the default bank setup after reset on your hardware? I mean, if you switch bank beyond 16MB, does this setup persist after reset?

@MT522

MT522 commented Jun 29, 2026

Copy link
Copy Markdown
Author

My understanding (without testing it with a real device) is that if the bank is 0 (accessing below 16MB), then the code guarded by the if statement is executed due to having the initial value set to 0xFF.

Actually, quite on the opposite.
The code inside the if statement is always executed.

My comment says that the code inside of the if statement is always executed. So you just confirmed what I said.

Should you look inside the block, you'll see that a WREAR command is issued which sets the current bank of the device to the target bank. So for example if your address is somewhere below 0x1000000, it will reset the EAR. otherwise, the register is set.

And how can we be sure that this is compatible with all older small SPI NOR flash chips? There are many dirt cheap SPI NOR chips sold on Aliexpress or Ebay, which only pretend to be Winbond (sold as WinDbond) and other brand names. Each and every of them may differ in subtle ways. See https://linux-sunxi.org/Bootable_SPI_flash#25Q128FV as an example. If the concept of banks switching is not implemented (since there's no need for that when the size is small) and the relevant commands are not supported, then your patch will ruin someone's day. That's the rationale for #247 (comment)

What's the default bank setup after reset on your hardware? I mean, if you switch bank beyond 16MB, does this setup persist after reset?

One may never change the bank indefinitely. It only sets to bank to 1 during the current operation. It always switches back to 0 at the end.

@apritzel

apritzel commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

I was working on a Lichee PI Zero board, and I have soldered a 512Mbit SPI NOR flash onto it myself. As for the U-Boot SPI flash interface, you are completely right. there is no argue in that. I just found it a little bit tedious in my project to flash the U-boot once using the sunxi-fel tools and then use the u-boot interface itself to program the rest of the chip.

You wouldn't need to flash U-Boot, all can stay in RAM, and you control it via a shell script on the host side:

sunxi-fel uboot u-boot-sunxi-with-spl.bin write 0x41a00000 spiflash.img write 0x41900000 uboot_flash_scr.txt

This writes the payload into DRAM, then executes the uploaded U-Boot script, which can do the flash writing. The only downside is that you cannot write the whole 64MB, since not all RAM is available, though you can split it up in chunks and stuff them into the available gaps, then write them separately. And you can flash the first 16MB from sunxi-fel. This would work today without any code changes.

If you still want the support, please clean up the patch, and try to address the comments.

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.

4 participants