[PATCH] mtd: spi-nor: spansion: Add SMPT fixup for S25FS512S

Tudor Ambarus tudor.ambarus at linaro.org
Mon Oct 13 08:41:48 PDT 2025



On 10/12/25 5:19 PM, Marek Vasut wrote:
> Hello Tudor,

Hello!

>>>>> diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
>>>>> index d6c92595f6bc..d446d12371e1 100644
>>>>> --- a/drivers/mtd/spi-nor/spansion.c
>>>>> +++ b/drivers/mtd/spi-nor/spansion.c
>>>>> @@ -757,6 +757,31 @@ static const struct spi_nor_fixups s25fs_s_nor_fixups = {
>>>>>        .post_bfpt = s25fs_s_nor_post_bfpt_fixups,
>>>>>    };
>>>>>    +static int s25fs512s_nor_post_smpt_fixups(struct spi_nor *nor, u8 *smpt)
>>>>> +{
>>>>> +    /*
>>>>> +     * The S25FS512S chip datasheet rev.O Table 71 on page 153
>>>>> +     * JEDEC Sector Map Parameter Dword-6 Config. Detect-3 does
>>>>> +     * use CR3NV bit 1 to discern 64kiB/256kiB uniform sectors
>>>>> +     * device configuration, however according to section 7.5.5.1
>>>>> +     * Configuration Register 3 Non-volatile (CR3NV) page 61, the
>>>>> +     * CR3NV bit 1 is RFU Reserved for Future Use, and is set to
>>>>> +     * 0 on newly manufactured devices, which means 64kiB sectors.
>>>>> +     * Since the device does not support 64kiB uniform sectors in
>>>>> +     * any configuration, parsing SMPT table cannot find a valid
>>>>> +     * sector map entry and fails. Fix this up by setting SMPT
>>>>> +     * configuration index bit 0, which is populated exactly by
>>>>> +     * the CR3NV bit 1 being 1.
>>>>> +     */
>>>>> +    *smpt |= BIT(0);
>>>>
>>>> Please help me understand this. Maybe a link to your revision of
>>>> datasheet would help me.
>>>
>>> https://www.infineon.com/assets/row/public/documents/10/49/infineon-s25fs512s-512-mb-1-datasheet-en.pdf
>>>
>>> SMPT values:
>>>
>>> i=0 smpt[i]=08ff65fc
>>> i=1 smpt[i]=00000004
>>> i=2 smpt[i]=04ff65fc
>>> i=3 smpt[i]=00000002
>>> i=4 smpt[i]=02ff65fd
>>> i=5 smpt[i]=00000004
>>> i=6 smpt[i]=ff0201fe
>>> i=7 smpt[i]=00007ff1
>>> i=8 smpt[i]=00037ff4
>>> i=9 smpt[i]=03fbfff4
>>> i=10 smpt[i]=ff0203fe
>>> i=11 smpt[i]=03fbfff4
>>> i=12 smpt[i]=00037ff4
>>> i=13 smpt[i]=00007ff1
>>> i=14 smpt[i]=ff0005ff
>>> i=15 smpt[i]=03fffff4
>>>
>>
>> thanks!
>>
>>>> In the flash datasheets that I see, there shall
>>>> be a "Sector Map Parameter Table Notes" where a "Sector Map Parameter"
>>>> table is described showing an Index Value constructed by the CRxNV[y]
>>>> return values. That index value is the map_id in the code.
>>>>
>>>> By reading your description I understand CR3NV[1] has value zero as it
>>>> is marked as RFU, but at the same time that bit is expected in SMPT to
>>>> always have value 1. That's why datasheets like this one [1] in their
>>>> "Table 70. Sector Map Parameter" do not describe CR3NV[1] at all, and
>>>> define the index value as CR3NV[3] << 2 | CR1NV[2] << 1 | 1.
>>>
>>> Where does this last part "define the index value as CR3NV[3] << 2 | CR1NV[2] << 1 | 1" come from ?
>>
>> In your datasheet flavor, from "Table 70 Sector map parameter", page 152,
>> "Index Value" column. I deduced the formula by using the CR3NV[3] and
>> CR1NV[2] values. The datasheet says:
>>
>> "When more than one configuration bit must be read, all the bits are
>> concatenated into an index value that is used to select the current address map."
>>
>> and that the "the following MSb to LSb order to form the configuration map
>> index value:
>> • CR3NV[3] — 0 = Hybrid Architecture, 1 = Uniform Architecture
>> • CR1NV[2] — 0 = 4 KB parameter sectors at bottom, 1 = 4 KB sectors at top
>> "
>>
>> The "Index Value" shall be the map_id that you passed in the code:
>> spi_nor_post_smpt_fixups(nor, &map_id);
>>
>> Can you please print the map_id value that you obtain without updating it?
> 
> 0x4

This translates to CR3NV[3] = 1, CR1NV[2] = 0,  CR3NV[1] = 0.
> 
>> Let's also print the values of CR3NV and CR1NV.
> 
> Both 0x0 and 0x0 .

But here CR3NV is 0, it contradicts the result from above.

Maybe it's the same problem that Takahiro identified: the flash needs
8 dummy cycles, but the code uses zero dummy cycles, resulting in
reading garbage data, depending on whether your IO lines are pulled up/down
or floating.

Can you redo the test with the following please?

diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 21727f9a4ac6..85443c903e59 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -752,7 +752,7 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt,
 
                read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
                nor->addr_nbytes = spi_nor_smpt_addr_nbytes(nor, smpt[i]);
-               nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
+               nor->read_dummy = 8;
                nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
                addr = smpt[i + 1];
 
@@ -767,6 +767,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt,
                 * Configuration that is currently in use.
                 */
                map_id = map_id << 1 | !!(*buf & read_data_mask);
+               dev_err(nor->dev, "i = %d, buf = %02x, map_id = %02x\n",
+                       i, buf[0], map_id);
        }
 
Cheers,
ta



More information about the linux-mtd mailing list