mtd: spi-nor: flash_info db overhaul
Tudor Ambarus
tudor.ambarus at linaro.org
Mon Jul 17 07:55:38 PDT 2023
On 7/17/23 14:51, Michael Walle wrote:
> Hi,
>
> I'm planning to do a makeover of how the in-kernel flash database of
> the SPI-NOR parts are represented. It all started with the quest for
> dropping unneeded properties like size and sector_size for newer
> flashes which already contains self describing tables within the flash
> itself :)
>
> Soon additional drawbacks (or maybe legacy features :) were discovered:
> * the SNOR_IDs are hardcoded to either 3 or 6 bytes. But with the dawn
> of continuation codes, these IDs have a flexible length.
> Fun fact, we have one flash with a correct continuation code,
> "is25cd512" with id 0x7f9d20, 0x7f9d is the vendor id and 0x20 the
> device id, which is just one byte for this flash. First, I though that
> was a mistake, but actually it is in line with the datasheet. Apparently,
> the vendor is afraid of spi code which only supports 3 id bytes :) The
> same is true for "pm25lq032".
> * all the macros contain a trailing comma, and thus the trailing comma
> is omitted in the flash db which makes is somewhat inconsistent if you
> also want to use non-macro entires, like ".fixups = fixup,"
> * macros which just returns their argument, e.g.
> #define NO_SFDP_FLAGS(x) .no_sfdp_flags = (x),
> * newer flashes only need the id, a name and some flags, thus INFO()
> has a lot of empty fields,
> * newer flashes need to explicitly specify PARSE_SFDP.
>
> Goals I'd like to achieve:
> * first and formost, new flash entries should be as slim as possible,
> * the id should have a flexible length,
> * same (consistent) format for legacy flash entries and newer ones,
> * no overuse of macros
>
>
> Here are some old examples:
> { "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512)
> NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
> FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
> MFR_FLAGS(USE_FSR)
> }, // (1)
> { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512)
> NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
> MFR_FLAGS(USE_FSR)
> }, // (2)
> { "w25q512nwq", INFO(0xef6020, 0, 0, 0)
> PARSE_SFDP
> OTP_INFO(256, 3, 0x1000, 0x1000)
> }, // (3)
> { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256)
> PARSE_SFDP
> FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
> NO_SFDP_FLAGS(SECT_4K)
> }, // (4)
>
> Here's the (idea of the) final version:
> {
> .id = SNOR_ID(0x20, 0xba, 0x19, 0x10, 0x44, 0x00),
> .name = "mt25ql256a",
> .size = SZ_32M,
> .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
> .fixup_flags = SPI_NOR_4B_OPCODES,
> .mfr_flags = USE_FSR,
> } (1)
> {
> .id = SNOR_ID(0x20, 0xbb, 0x19),
> .name = "n25q256ax1",
> .size = SZ_32M,
> .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
> .mfr_flags = USE_FSR,
> } (2)
> {
> .id = SNOR_ID(0xef, 0x60, 0x20),
> .name = "w25q512nwq",
> .otp_org = SNOR_OTP_ORG(256, 3, 0x1000, 0x1000),
> // or maybe just .otp = SNOR_OTP(),
I like SNOR_OTP.
> } (3)
> {
> .id = SNOR_ID(0xef, 0x40, 0x18),
> .name = "w25q128",
> .size = SZ_16M,
> .force_sfdp = true,
> .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB,
> .no_sfdp_flags = SECT_4K,
> }, // (4)
>
> The full template would be:
> {
> .id = SNOR_ID(),
> .name = ,
> .size = , // will replace n_sectors
> .sector_size = , // if 0, SZ_64K is assumed, otherwise has to be set
> .n_banks = , // if 0, 1 is assumed, otherwise has to be set
> .page_size = , // if 0, 256 is assumed, otherwise has to be set
> .addr_nbytes = , // addr_nbytes is already special, see spi_nor_set_addr_nbytes()
> .flags = ,
> .no_sfdp_flags = ,
> .mfr_flags = ,
> .otp_org = SNOR_OTP_ORG()
> .fixups = .
> .fixup_flags = ,
> .force_sfdp = , // see below!
> }
>
> The only mandatory field is .id because that is the key into
> the db entry. Of course, with the dawn of the generic spi flash
> driver, an entry with no additional flags doesn't make any sense.
> Therefore, I'd expect an entry to have at least .*flags or
> .otp_org set.
Right, the goal is to define a flash by name, id, and everything else that
can't be discovered when parsing SFDP.
>
> Alternatively, the second key is the name for legacy flashes which
> are looked up by the name instead of the id. If we ever need to
> resort to individual DT compatibles, I'd use a new .compatible entry
> for that like everywhere else in the kernel.
>
> One word on .parse_sfdp (@Tudor this is new, so let me know). Because
> I want new entries as slim as possible and I expect that all new flashes
> will support SFDP, I'd like to get rid of the mandatory
> ".parse_sfdp = true" line. The first idea was to just invert the logic
> and have a .no_sfdp which will need to be set to true for all the old
> flashes. But I think we can do better. We can assume that each entry
> with .size != 0 (or .n_sectors in the old format) will implicitly be
> ".no_sfdp = true" (or parse_sfdp = false in the old format). There is
the assumption will work indeed.
> of course one exception to this rule. Flashes with the same ID where
> one supports SFDP and one doesn't. In the end the outcome is the same,
> we need to force SFDP parsing even if .size non-zero. Thus for this
> case, we need a .force_sfdp = true entry. See also example (4) above.
>
I wouldn't introduce a new member just for exceptions. How about setting
.parse_sfdp = true at definition only in this case and add a comment on
top of it saying that we force sfdp parsing to differentiate between the
flashes.
> I've already had a talk with Tudor about that topic. Does anyone else
> have thoughts on it?
>
I confirm that I agree with the changes proposed.
Cheers,
ta
More information about the linux-mtd
mailing list