[flashrom] [PATCH] WIP: Add support for continious SPI reads

Urja Rannikko urjaman at gmail.com
Fri Aug 28 08:02:02 CEST 2015


Hi,

I'll make a note here that at one point i was trying to go through all
the SPI chips noting their
read length limitations if any, (i might reformat what i've checked
and send it one day but it got really boring fast, i've checked Amic
to gigadevice i think), but to summarize almost all of the of SPI
chips i checked support unlimited roll-around reads, except AT25F512
that doesnt do the rollower part (still can read 64k of the 64k chip
in one go if you start at 0). Somebody could start from gigadevice and
check the rest to be safe.

The second note is that serprog already implements this as a
performance hack (shrug).

And a comment on the patch: I'd rather flag the ones (if they exist)
that dont support read through the whole array (no wrap needed, even
the AT25F512 is fine for this) than do something as extensive as here
where the end result would be to have 99% of the chips flagged with a
"this chip is normal".




On Thu, Aug 27, 2015 at 11:28 PM, Nico Huber <nico.h at gmx.de> wrote:
> Rebased this old, rotting patch. Not tested in the last two years, but
> might help to speed up some things (ftdi got pretty fast with this).
>
> It has to be enabled per chip (see WINBOND/W25Q64.V for example).
> ---
>  chipdrivers.h |  1 +
>  cli_common.c  | 14 +++++++++++---
>  flash.h       | 23 ++++++++++++++---------
>  flashchips.c  |  4 ++--
>  spi.c         |  5 ++++-
>  spi25.c       | 18 ++++++++++++++++++
>  6 files changed, 50 insertions(+), 15 deletions(-)
>
> diff --git a/chipdrivers.h b/chipdrivers.h
> index cac94f3..f79195c 100644
> --- a/chipdrivers.h
> +++ b/chipdrivers.h
> @@ -59,6 +59,7 @@ int spi_byte_program(struct flashctx *flash, unsigned int addr, uint8_t databyte
>  int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len);
>  int spi_nbyte_read(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
>  int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
> +int spi_read_unbound(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
>  int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
>
>  /* spi25_statusreg.c */
> diff --git a/cli_common.c b/cli_common.c
> index 71cc2dd..289d56a 100644
> --- a/cli_common.c
> +++ b/cli_common.c
> @@ -73,17 +73,22 @@ void print_chip_support_status(const struct flashchip *chip)
>         if ((chip->tested.probe == BAD) || (chip->tested.probe == NT) ||
>             (chip->tested.read == BAD)  || (chip->tested.read == NT) ||
>             (chip->tested.erase == BAD) || (chip->tested.erase == NT) ||
> -           (chip->tested.write == BAD) || (chip->tested.write == NT)){
> +           (chip->tested.write == BAD) || (chip->tested.write == NT) ||
> +           ((chip->feature_bits & FEATURE_UNBOUND_READ) &&
> +            chip->tested.uread == BAD || chip->tested.uread == NT)) {
>                 msg_cinfo("===\n");
>                 if ((chip->tested.probe == BAD) ||
>                     (chip->tested.read == BAD) ||
>                     (chip->tested.erase == BAD) ||
> -                   (chip->tested.write == BAD)) {
> +                   (chip->tested.write == BAD) ||
> +                   ((chip->feature_bits & FEATURE_UNBOUND_READ) && chip->tested.uread == BAD)) {
>                         msg_cinfo("This flash part has status NOT WORKING for operations:");
>                         if (chip->tested.probe == BAD)
>                                 msg_cinfo(" PROBE");
>                         if (chip->tested.read == BAD)
>                                 msg_cinfo(" READ");
> +                       if ((chip->feature_bits & FEATURE_UNBOUND_READ) && chip->tested.uread == BAD)
> +                               msg_cinfo(" UNBOUND_READ");
>                         if (chip->tested.erase == BAD)
>                                 msg_cinfo(" ERASE");
>                         if (chip->tested.write == BAD)
> @@ -93,12 +98,15 @@ void print_chip_support_status(const struct flashchip *chip)
>                 if ((chip->tested.probe == NT) ||
>                     (chip->tested.read == NT) ||
>                     (chip->tested.erase == NT) ||
> -                   (chip->tested.write == NT)) {
> +                   (chip->tested.write == NT) ||
> +                   ((chip->feature_bits & FEATURE_UNBOUND_READ) && chip->tested.uread == NT)) {
>                         msg_cinfo("This flash part has status UNTESTED for operations:");
>                         if (chip->tested.probe == NT)
>                                 msg_cinfo(" PROBE");
>                         if (chip->tested.read == NT)
>                                 msg_cinfo(" READ");
> +                       if ((chip->feature_bits & FEATURE_UNBOUND_READ) && chip->tested.uread == NT)
> +                               msg_cinfo(" UNBOUND_READ");
>                         if (chip->tested.erase == NT)
>                                 msg_cinfo(" ERASE");
>                         if (chip->tested.write == NT)
> diff --git a/flash.h b/flash.h
> index 2c2839f..b3962ee 100644
> --- a/flash.h
> +++ b/flash.h
> @@ -122,6 +122,7 @@ enum write_granularity {
>  #define FEATURE_WRSR_EITHER    (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN)
>  #define FEATURE_OTP            (1 << 8)
>  #define FEATURE_QPI            (1 << 9)
> +#define FEATURE_UNBOUND_READ   (1 << 10)
>
>  enum test_state {
>         OK = 0,
> @@ -131,17 +132,20 @@ enum test_state {
>         NA,     /* Not applicable (e.g. write support on ROM chips) */
>  };
>
> -#define TEST_UNTESTED  (struct tested){ .probe = NT, .read = NT, .erase = NT, .write = NT }
> +#define TEST_UNTESTED  (struct tested){ .probe = NT, .read = NT, .uread = NT, .erase = NT, .write = NT }
>
> -#define TEST_OK_PROBE  (struct tested){ .probe = OK, .read = NT, .erase = NT, .write = NT }
> -#define TEST_OK_PR     (struct tested){ .probe = OK, .read = OK, .erase = NT, .write = NT }
> -#define TEST_OK_PRE    (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = NT }
> -#define TEST_OK_PREW   (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK }
> +#define TEST_OK_PROBE  (struct tested){ .probe = OK, .read = NT, .uread = NT, .erase = NT, .write = NT }
> +#define TEST_OK_PR     (struct tested){ .probe = OK, .read = OK, .uread = NT, .erase = NT, .write = NT }
> +#define TEST_OK_PRU    (struct tested){ .probe = OK, .read = OK, .uread = OK, .erase = NT, .write = NT }
> +#define TEST_OK_PRE    (struct tested){ .probe = OK, .read = OK, .uread = NT, .erase = OK, .write = NT }
> +#define TEST_OK_PRUE   (struct tested){ .probe = OK, .read = OK, .uread = OK, .erase = OK, .write = NT }
> +#define TEST_OK_PREW   (struct tested){ .probe = OK, .read = OK, .uread = NT, .erase = OK, .write = OK }
> +#define TEST_OK_PRUEW  (struct tested){ .probe = OK, .read = OK, .uread = OK, .erase = OK, .write = OK }
>
> -#define TEST_BAD_PROBE (struct tested){ .probe = BAD, .read = NT, .erase = NT, .write = NT }
> -#define TEST_BAD_PR    (struct tested){ .probe = BAD, .read = BAD, .erase = NT, .write = NT }
> -#define TEST_BAD_PRE   (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = NT }
> -#define TEST_BAD_PREW  (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD }
> +#define TEST_BAD_PROBE (struct tested){ .probe = BAD, .read = NT, .uread = NT, .erase = NT, .write = NT }
> +#define TEST_BAD_PR    (struct tested){ .probe = BAD, .read = BAD, .uread = NT, .erase = NT, .write = NT }
> +#define TEST_BAD_PRE   (struct tested){ .probe = BAD, .read = BAD, .uread = NT, .erase = BAD, .write = NT }
> +#define TEST_BAD_PREW  (struct tested){ .probe = BAD, .read = BAD, .uread = NT, .erase = BAD, .write = BAD }
>
>  struct flashctx;
>  typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
> @@ -170,6 +174,7 @@ struct flashchip {
>         struct tested {
>                 enum test_state probe;
>                 enum test_state read;
> +               enum test_state uread;
>                 enum test_state erase;
>                 enum test_state write;
>         } tested;
> diff --git a/flashchips.c b/flashchips.c
> index 574ad74..be6383b 100644
> --- a/flashchips.c
> +++ b/flashchips.c
> @@ -13961,8 +13961,8 @@ const struct flashchip flashchips[] = {
>                 .page_size      = 256,
>                 /* supports SFDP */
>                 /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
> -               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP,
> -               .tested         = TEST_OK_PREW,
> +               .feature_bits   = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_UNBOUND_READ,
> +               .tested         = TEST_OK_PRUEW,
>                 .probe          = probe_spi_rdid,
>                 .probe_timing   = TIMING_ZERO,
>                 .block_erasers  =
> diff --git a/spi.c b/spi.c
> index 894f73f..a7da50a 100644
> --- a/spi.c
> +++ b/spi.c
> @@ -85,7 +85,10 @@ int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
>                          "flashrom at flashrom.org\n", __func__);
>                 return 1;
>         }
> -       return spi_read_chunked(flash, buf, start, len, max_data);
> +       if (flash->chip->feature_bits & FEATURE_UNBOUND_READ)
> +               return spi_read_unbound(flash, buf, start, len, max_data);
> +       else
> +               return spi_read_chunked(flash, buf, start, len, max_data);
>  }
>
>  int default_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
> diff --git a/spi25.c b/spi25.c
> index af4b6db..34fd7d5 100644
> --- a/spi25.c
> +++ b/spi25.c
> @@ -978,6 +978,24 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
>  }
>
>  /*
> + * Read a part of the flash chip.
> + * Ignore pages as we shall read the data continuously. The only bound is the chunksize.
> + */
> +int spi_read_unbound(struct flashctx *flash, uint8_t *buf, unsigned int start,
> +                    unsigned int len, unsigned int chunksize)
> +{
> +       int rc = 0;
> +       unsigned int i;
> +
> +       for (i = start; i < (start + len); i += chunksize) {
> +               rc = spi_nbyte_read(flash, i, buf + (i - start), min(chunksize, start + len - i));
> +               if (rc)
> +                       break;
> +       }
> +       return rc;
> +}
> +
> +/*
>   * Write a part of the flash chip.
>   * FIXME: Use the chunk code from Michael Karcher instead.
>   * Each page is written separately in chunks with a maximum size of chunksize.
> --
> 2.4.6
>
>
> _______________________________________________
> flashrom mailing list
> flashrom at flashrom.org
> http://www.flashrom.org/mailman/listinfo/flashrom



-- 
Urja Rannikko




More information about the flashrom mailing list