[PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash

Bin Meng via qemu development posted 10 patches 2 months, 1 week ago
Maintainers: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>, Alistair Francis <alistair@alistair23.me>, Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>, "Cédric Le Goater" <clg@kaod.org>, Peter Maydell <peter.maydell@linaro.org>, Steven Lee <steven_lee@aspeedtech.com>, Troy Lee <leetroy@gmail.com>, Jamin Lin <jamin_lin@aspeedtech.com>, Kane Chen <kane_chen@aspeedtech.com>, Andrew Jeffery <andrew@codeconstruct.com.au>, Joel Stanley <joel@jms.id.au>, Tyrone Ting <kfting@nuvoton.com>, Hao Wu <wuhaotsh@google.com>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>
[PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Bin Meng 2 months, 1 week ago
Spansion flashes expose the number of dummy clock cycles through CR2V
register [1]. The value is a cycle count, not a byte count, so the
m25p80 model has to convert it to the number of whole SSI transfer
bytes consumed while collecting read command data.

Add a helper that multiplies the CR2V dummy cycle count by the phase
width and rounds up non-byte-aligned counts, matching the byte-oriented
SSI model. The default eight-cycle configuration keeps the same byte
counts as before.

[1] https://www.infineon.com/assets/row/public/documents/10/49/infineon-s25fs128s-s25fs256s-1-datasheet-en.pdf

Fixes: cf6f1efe0b57 ("m25p80: Fast read commands family changes")
Signed-off-by: Bin Meng <bin.meng@processmission.com>
Tested-by: Cédric Le Goater <clg@redhat.com>

---

Changes in v2:
- change spansion_extract_cfg_num_dummies() to spansion_extract_cfg_dummy_bytes()
  to avoid confusion
- use assert() when the dummy bit count is not byte-aligned

 hw/block/m25p80.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index d7a9d79373..545e0b5728 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -1057,6 +1057,23 @@ static uint8_t macronix_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
     return dummy_bits / 8;
 }
 
+static uint8_t spansion_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
+{
+    uint8_t dummy_bits;
+
+    dummy_bits = extract32(s->spansion_cr2v, SPANSION_DUMMY_CLK_POS,
+                            SPANSION_DUMMY_CLK_LEN);
+    dummy_bits *= bus_width;
+
+    /*
+     * Assert that the dummy bit count is byte-aligned
+     * as SSI core can only consume whole dummy bytes.
+     */
+    assert(dummy_bits % 8 == 0);
+
+    return dummy_bits / 8;
+}
+
 static void decode_fast_read_cmd(Flash *s)
 {
     s->needed_bytes = get_addr_length(s);
@@ -1075,10 +1092,7 @@ static void decode_fast_read_cmd(Flash *s)
         s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 1);
         break;
     case MAN_SPANSION:
-        s->needed_bytes += extract32(s->spansion_cr2v,
-                                    SPANSION_DUMMY_CLK_POS,
-                                    SPANSION_DUMMY_CLK_LEN
-                                    );
+        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 1);
         break;
     case MAN_ISSI:
         /*
@@ -1111,10 +1125,7 @@ static void decode_dio_read_cmd(Flash *s)
         break;
     case MAN_SPANSION:
         s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += extract32(s->spansion_cr2v,
-                                    SPANSION_DUMMY_CLK_POS,
-                                    SPANSION_DUMMY_CLK_LEN
-                                    );
+        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 2);
         break;
     case MAN_NUMONYX:
         s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
@@ -1151,10 +1162,7 @@ static void decode_qio_read_cmd(Flash *s)
         break;
     case MAN_SPANSION:
         s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
-        s->needed_bytes += extract32(s->spansion_cr2v,
-                                    SPANSION_DUMMY_CLK_POS,
-                                    SPANSION_DUMMY_CLK_LEN
-                                    );
+        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 4);
         break;
     case MAN_NUMONYX:
         s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
-- 
2.53.0


Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Philippe Mathieu-Daudé 2 months, 1 week ago
On 7/7/26 10:34, Bin Meng wrote:
> Spansion flashes expose the number of dummy clock cycles through CR2V
> register [1]. The value is a cycle count, not a byte count, so the
> m25p80 model has to convert it to the number of whole SSI transfer
> bytes consumed while collecting read command data.
> 
> Add a helper that multiplies the CR2V dummy cycle count by the phase
> width and rounds up non-byte-aligned counts, matching the byte-oriented
> SSI model. The default eight-cycle configuration keeps the same byte
> counts as before.
> 
> [1] https://www.infineon.com/assets/row/public/documents/10/49/infineon-s25fs128s-s25fs256s-1-datasheet-en.pdf
> 
> Fixes: cf6f1efe0b57 ("m25p80: Fast read commands family changes")
> Signed-off-by: Bin Meng <bin.meng@processmission.com>
> Tested-by: Cédric Le Goater <clg@redhat.com>
> 
> ---
> 
> Changes in v2:
> - change spansion_extract_cfg_num_dummies() to spansion_extract_cfg_dummy_bytes()
>    to avoid confusion
> - use assert() when the dummy bit count is not byte-aligned
> 
>   hw/block/m25p80.c | 32 ++++++++++++++++++++------------
>   1 file changed, 20 insertions(+), 12 deletions(-)
> 
> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> index d7a9d79373..545e0b5728 100644
> --- a/hw/block/m25p80.c
> +++ b/hw/block/m25p80.c
> @@ -1057,6 +1057,23 @@ static uint8_t macronix_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
>       return dummy_bits / 8;
>   }
>   
> +static uint8_t spansion_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
> +{
> +    uint8_t dummy_bits;
> +
> +    dummy_bits = extract32(s->spansion_cr2v, SPANSION_DUMMY_CLK_POS,
> +                            SPANSION_DUMMY_CLK_LEN);
> +    dummy_bits *= bus_width;
> +
> +    /*
> +     * Assert that the dummy bit count is byte-aligned
> +     * as SSI core can only consume whole dummy bytes.
> +     */
> +    assert(dummy_bits % 8 == 0);
> +
> +    return dummy_bits / 8;
> +}
> +
>   static void decode_fast_read_cmd(Flash *s)
>   {
>       s->needed_bytes = get_addr_length(s);
> @@ -1075,10 +1092,7 @@ static void decode_fast_read_cmd(Flash *s)
>           s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 1);
>           break;
>       case MAN_SPANSION:
> -        s->needed_bytes += extract32(s->spansion_cr2v,
> -                                    SPANSION_DUMMY_CLK_POS,
> -                                    SPANSION_DUMMY_CLK_LEN
> -                                    );
> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 1);
>           break;
>       case MAN_ISSI:
>           /*
> @@ -1111,10 +1125,7 @@ static void decode_dio_read_cmd(Flash *s)
>           break;
>       case MAN_SPANSION:
>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
> -        s->needed_bytes += extract32(s->spansion_cr2v,
> -                                    SPANSION_DUMMY_CLK_POS,
> -                                    SPANSION_DUMMY_CLK_LEN
> -                                    );
> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 2);
>           break;
>       case MAN_NUMONYX:
>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
> @@ -1151,10 +1162,7 @@ static void decode_qio_read_cmd(Flash *s)
>           break;
>       case MAN_SPANSION:
>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
> -        s->needed_bytes += extract32(s->spansion_cr2v,
> -                                    SPANSION_DUMMY_CLK_POS,
> -                                    SANSION_DUMMY_CLK_LEN
> -                                    );
> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 4);
>           break;
>       case MAN_NUMONYX:
>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);

This breaks the test_arm_emcraft_sf2 functional test:

not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2


Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Cédric Le Goater 2 months, 1 week ago
On 7/7/26 14:34, Philippe Mathieu-Daudé wrote:
> On 7/7/26 10:34, Bin Meng wrote:
>> Spansion flashes expose the number of dummy clock cycles through CR2V
>> register [1]. The value is a cycle count, not a byte count, so the
>> m25p80 model has to convert it to the number of whole SSI transfer
>> bytes consumed while collecting read command data.
>>
>> Add a helper that multiplies the CR2V dummy cycle count by the phase
>> width and rounds up non-byte-aligned counts, matching the byte-oriented
>> SSI model. The default eight-cycle configuration keeps the same byte
>> counts as before.
>>
>> [1] https://www.infineon.com/assets/row/public/documents/10/49/infineon-s25fs128s-s25fs256s-1-datasheet-en.pdf
>>
>> Fixes: cf6f1efe0b57 ("m25p80: Fast read commands family changes")
>> Signed-off-by: Bin Meng <bin.meng@processmission.com>
>> Tested-by: Cédric Le Goater <clg@redhat.com>
>>
>> ---
>>
>> Changes in v2:
>> - change spansion_extract_cfg_num_dummies() to spansion_extract_cfg_dummy_bytes()
>>    to avoid confusion
>> - use assert() when the dummy bit count is not byte-aligned
>>
>>   hw/block/m25p80.c | 32 ++++++++++++++++++++------------
>>   1 file changed, 20 insertions(+), 12 deletions(-)
>>
>> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
>> index d7a9d79373..545e0b5728 100644
>> --- a/hw/block/m25p80.c
>> +++ b/hw/block/m25p80.c
>> @@ -1057,6 +1057,23 @@ static uint8_t macronix_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
>>       return dummy_bits / 8;
>>   }
>> +static uint8_t spansion_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
>> +{
>> +    uint8_t dummy_bits;
>> +
>> +    dummy_bits = extract32(s->spansion_cr2v, SPANSION_DUMMY_CLK_POS,
>> +                            SPANSION_DUMMY_CLK_LEN);
>> +    dummy_bits *= bus_width;
>> +
>> +    /*
>> +     * Assert that the dummy bit count is byte-aligned
>> +     * as SSI core can only consume whole dummy bytes.
>> +     */
>> +    assert(dummy_bits % 8 == 0);
>> +
>> +    return dummy_bits / 8;
>> +}
>> +
>>   static void decode_fast_read_cmd(Flash *s)
>>   {
>>       s->needed_bytes = get_addr_length(s);
>> @@ -1075,10 +1092,7 @@ static void decode_fast_read_cmd(Flash *s)
>>           s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 1);
>>           break;
>>       case MAN_SPANSION:
>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>> -                                    SPANSION_DUMMY_CLK_POS,
>> -                                    SPANSION_DUMMY_CLK_LEN
>> -                                    );
>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 1);
>>           break;
>>       case MAN_ISSI:
>>           /*
>> @@ -1111,10 +1125,7 @@ static void decode_dio_read_cmd(Flash *s)
>>           break;
>>       case MAN_SPANSION:
>>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>> -                                    SPANSION_DUMMY_CLK_POS,
>> -                                    SPANSION_DUMMY_CLK_LEN
>> -                                    );
>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 2);
>>           break;
>>       case MAN_NUMONYX:
>>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
>> @@ -1151,10 +1162,7 @@ static void decode_qio_read_cmd(Flash *s)
>>           break;
>>       case MAN_SPANSION:
>>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>> -                                    SPANSION_DUMMY_CLK_POS,
>> -                                    SANSION_DUMMY_CLK_LEN
>> -                                    );
>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 4);
>>           break;
>>       case MAN_NUMONYX:
>>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
> 
> This breaks the test_arm_emcraft_sf2 functional test:
> 
> not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2
> 


No problem on my side.

C.


Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Cédric Le Goater 2 months, 1 week ago
>> This breaks the test_arm_emcraft_sf2 functional test:
>>
>> not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2
>>
> 
> 
> No problem on my side.
> 
Sorry. you are right ! It fails too.

So we have a machine using a Spansion flash.

     spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */


C.
Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Cédric Le Goater 2 months, 1 week ago
Bin, Philippe,

On 7/7/26 16:05, Cédric Le Goater wrote:
> 
>>> This breaks the test_arm_emcraft_sf2 functional test:
>>>
>>> not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2
>>>
>>
>>
>> No problem on my side.
>>
> Sorry. you are right ! It fails too.
> 
> So we have a machine using a Spansion flash.
> 
>      spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */
> 
> 
> C.


Here is the fix. Feel free to merge in patch 4.

Thanks,

C.

 From 17ae23e5bc3629a5a301f14f47125f6f685ca9d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= <clg@redhat.com>
Date: Tue, 7 Jul 2026 16:23:29 +0200
Subject: [PATCH] hw/arm/msf2-som: Fix spansion-cr2nv value for S25FL128S
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The emcraft-sf2 board set spansion-cr2nv to 1, which the old m25p80
code treated as a byte count. With the dummy cycle to byte conversion
fix, CR2V=1 at SPI x1 is 1 bit, not byte-aligned, and triggers an
assertion. Use the S25FL128S default of 0x8 (8 cycles = 1 byte at
SPI x1), preserving the same runtime behavior.

Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
  hw/arm/msf2-som.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
index caf6e7e1ad7d..1ada1a136130 100644
--- a/hw/arm/msf2-som.c
+++ b/hw/arm/msf2-som.c
@@ -84,7 +84,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
      /* Attach SPI flash to SPI0 controller */
      spi_bus = qdev_get_child_bus(dev, "spi0");
      spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */
-    qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1);
+    qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 0x8);
      if (dinfo) {
          qdev_prop_set_drive_err(spi_flash, "drive",
                                  blk_by_legacy_dinfo(dinfo), &error_fatal);
-- 
2.54.0


Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Philippe Mathieu-Daudé 2 months, 1 week ago
On 7/7/26 16:26, Cédric Le Goater wrote:

>  From 17ae23e5bc3629a5a301f14f47125f6f685ca9d9 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= <clg@redhat.com>
> Date: Tue, 7 Jul 2026 16:23:29 +0200
> Subject: [PATCH] hw/arm/msf2-som: Fix spansion-cr2nv value for S25FL128S
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> The emcraft-sf2 board set spansion-cr2nv to 1, which the old m25p80
> code treated as a byte count. With the dummy cycle to byte conversion
> fix, CR2V=1 at SPI x1 is 1 bit, not byte-aligned, and triggers an
> assertion. Use the S25FL128S default of 0x8 (8 cycles = 1 byte at
> SPI x1), preserving the same runtime behavior.
> 
> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> ---
>   hw/arm/msf2-som.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)


Tested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Bin Meng 2 months, 1 week ago
Hi Cédric,

On Tue, Jul 7, 2026 at 10:27 PM Cédric Le Goater <clg@redhat.com> wrote:
>
> Bin, Philippe,
>
> On 7/7/26 16:05, Cédric Le Goater wrote:
> >
> >>> This breaks the test_arm_emcraft_sf2 functional test:
> >>>
> >>> not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2
> >>>
> >>
> >>
> >> No problem on my side.
> >>
> > Sorry. you are right ! It fails too.
> >
> > So we have a machine using a Spansion flash.
> >
> >      spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */
> >
> >
> > C.
>
>
> Here is the fix. Feel free to merge in patch 4.

Thanks for the quick fix.

>
> Thanks,
>
> C.
>
>  From 17ae23e5bc3629a5a301f14f47125f6f685ca9d9 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= <clg@redhat.com>
> Date: Tue, 7 Jul 2026 16:23:29 +0200
> Subject: [PATCH] hw/arm/msf2-som: Fix spansion-cr2nv value for S25FL128S
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
>
> The emcraft-sf2 board set spansion-cr2nv to 1, which the old m25p80
> code treated as a byte count. With the dummy cycle to byte conversion
> fix, CR2V=1 at SPI x1 is 1 bit, not byte-aligned, and triggers an
> assertion. Use the S25FL128S default of 0x8 (8 cycles = 1 byte at
> SPI x1), preserving the same runtime behavior.
>
> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> ---
>   hw/arm/msf2-som.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
> index caf6e7e1ad7d..1ada1a136130 100644
> --- a/hw/arm/msf2-som.c
> +++ b/hw/arm/msf2-som.c
> @@ -84,7 +84,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
>       /* Attach SPI flash to SPI0 controller */
>       spi_bus = qdev_get_child_bus(dev, "spi0");
>       spi_flash = qdev_new("s25sl12801"); /* Spansion S25FL128SDPBHICO */
> -    qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1);
> +    qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 0x8);

Indeed the default reset value of cr2nv[3:0] is 8 according to the
flash datasheet.

Reviewed-by: Bin Meng <bin.meng@processmission.com>

>       if (dinfo) {
>           qdev_prop_set_drive_err(spi_flash, "drive",
>                                   blk_by_legacy_dinfo(dinfo), &error_fatal);
> --

Regards,
Bin
Re: [PATCH v2 04/10] hw/block: m25p80: Fix dummy byte handling for Spansion flash
Posted by Philippe Mathieu-Daudé 2 months, 1 week ago
On 7/7/26 14:51, Cédric Le Goater wrote:
> On 7/7/26 14:34, Philippe Mathieu-Daudé wrote:
>> On 7/7/26 10:34, Bin Meng wrote:
>>> Spansion flashes expose the number of dummy clock cycles through CR2V
>>> register [1]. The value is a cycle count, not a byte count, so the
>>> m25p80 model has to convert it to the number of whole SSI transfer
>>> bytes consumed while collecting read command data.
>>>
>>> Add a helper that multiplies the CR2V dummy cycle count by the phase
>>> width and rounds up non-byte-aligned counts, matching the byte-oriented
>>> SSI model. The default eight-cycle configuration keeps the same byte
>>> counts as before.
>>>
>>> [1] https://www.infineon.com/assets/row/public/documents/10/49/ 
>>> infineon-s25fs128s-s25fs256s-1-datasheet-en.pdf
>>>
>>> Fixes: cf6f1efe0b57 ("m25p80: Fast read commands family changes")
>>> Signed-off-by: Bin Meng <bin.meng@processmission.com>
>>> Tested-by: Cédric Le Goater <clg@redhat.com>
>>>
>>> ---
>>>
>>> Changes in v2:
>>> - change spansion_extract_cfg_num_dummies() to 
>>> spansion_extract_cfg_dummy_bytes()
>>>    to avoid confusion
>>> - use assert() when the dummy bit count is not byte-aligned
>>>
>>>   hw/block/m25p80.c | 32 ++++++++++++++++++++------------
>>>   1 file changed, 20 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
>>> index d7a9d79373..545e0b5728 100644
>>> --- a/hw/block/m25p80.c
>>> +++ b/hw/block/m25p80.c
>>> @@ -1057,6 +1057,23 @@ static uint8_t 
>>> macronix_extract_cfg_dummy_bytes(Flash *s, uint8_t bus_width)
>>>       return dummy_bits / 8;
>>>   }
>>> +static uint8_t spansion_extract_cfg_dummy_bytes(Flash *s, uint8_t 
>>> bus_width)
>>> +{
>>> +    uint8_t dummy_bits;
>>> +
>>> +    dummy_bits = extract32(s->spansion_cr2v, SPANSION_DUMMY_CLK_POS,
>>> +                            SPANSION_DUMMY_CLK_LEN);
>>> +    dummy_bits *= bus_width;
>>> +
>>> +    /*
>>> +     * Assert that the dummy bit count is byte-aligned
>>> +     * as SSI core can only consume whole dummy bytes.
>>> +     */
>>> +    assert(dummy_bits % 8 == 0);
>>> +
>>> +    return dummy_bits / 8;
>>> +}
>>> +
>>>   static void decode_fast_read_cmd(Flash *s)
>>>   {
>>>       s->needed_bytes = get_addr_length(s);
>>> @@ -1075,10 +1092,7 @@ static void decode_fast_read_cmd(Flash *s)
>>>           s->needed_bytes += macronix_extract_cfg_dummy_bytes(s, 1);
>>>           break;
>>>       case MAN_SPANSION:
>>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>>> -                                    SPANSION_DUMMY_CLK_POS,
>>> -                                    SPANSION_DUMMY_CLK_LEN
>>> -                                    );
>>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 1);
>>>           break;
>>>       case MAN_ISSI:
>>>           /*
>>> @@ -1111,10 +1125,7 @@ static void decode_dio_read_cmd(Flash *s)
>>>           break;
>>>       case MAN_SPANSION:
>>>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
>>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>>> -                                    SPANSION_DUMMY_CLK_POS,
>>> -                                    SPANSION_DUMMY_CLK_LEN
>>> -                                    );
>>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 2);
>>>           break;
>>>       case MAN_NUMONYX:
>>>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
>>> @@ -1151,10 +1162,7 @@ static void decode_qio_read_cmd(Flash *s)
>>>           break;
>>>       case MAN_SPANSION:
>>>           s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
>>> -        s->needed_bytes += extract32(s->spansion_cr2v,
>>> -                                    SPANSION_DUMMY_CLK_POS,
>>> -                                    SANSION_DUMMY_CLK_LEN
>>> -                                    );
>>> +        s->needed_bytes += spansion_extract_cfg_dummy_bytes(s, 4);
>>>           break;
>>>       case MAN_NUMONYX:
>>>           s->needed_bytes += numonyx_extract_cfg_dummy_bytes(s);
>>
>> This breaks the test_arm_emcraft_sf2 functional test:
>>
>> not ok 1 test_emcraft_sf2.EmcraftSf2Machine.test_arm_emcraft_sf2
>>
> 
> 
> No problem on my side.

Odd, I can reliably reproduce... I queued the rest (except the docs/
one which lacked a SPDX license tag which I couldn't add myself).

I'll let the remaining 2 via your aspeed tree (this one is a fix
anyway).

Thanks,

Phil.