mbox series

[v10,00/17] mtd: spi-nor: add xSPI Octal DTR support

Message ID 20200623183030.26591-1-p.yadav@ti.com
Headers show
Series mtd: spi-nor: add xSPI Octal DTR support | expand

Message

Pratyush Yadav June 23, 2020, 6:30 p.m. UTC
Hi,

This series adds support for octal DTR flashes in the spi-nor framework,
and then adds hooks for the Cypress Semper and Mircom Xcella flashes to
allow running them in octal DTR mode. This series assumes that the flash
is handed to the kernel in Legacy SPI mode.

Tested on TI J721e EVM with 1-bit ECC on the Cypress flash.

Changes in v10:
- Rebase on latest linux-next/master. Drop a couple patches that made it
  in the  previous release.

- Move the code that sets 20 dummy cycles for MT35XU512ABA to its octal
  enable function. This way, if the controller doesn't support 8D mode
  20 dummy cycles won't be used.

Changes in v9:
- Do not use '& 0xff' to get the opcode LSB in spi-mxic and
  spi-zynq-qspi. The cast to u8 will do that anyway.

- Do not use if (opcode) as a check for whether the command phase exists
  in spi-zynq-qspi because the opcode 0 can be valid. Use the new
  cmd.nbytes instead.

Changes in v8:
- Move controller changes in spi-mxic to the commit which introduces
  2-byte opcodes to avoid problems when bisecting.

- Replace usage of sizeof(op->cmd.opcode) with op->cmd.nbytes.

- Extract opcode in spi-zynq-qspi instead of using &op->cmd.opcode.

Changes in v7:
- Reject ops with more than 1 command byte in
  spi_mem_default_supports_op().

- Reject ops with more than 1 command byte in atmel and mtk controllers.

- Reject ops with 0 command bytes in spi_mem_check_op().

- Set cmd.nbytes to 1 when using SPI_MEM_OP_CMD().

- Avoid endianness problems in spi-mxic.

Changes in v6:
- Instead of hard-coding 8D-8D-8D Fast Read dummy cycles to 20, find
  them out from the Profile 1.0 table.

Changes in v5:
- Do not enable stateful X-X-X modes if the reset line is broken.

- Instead of setting SNOR_READ_HWCAPS_8_8_8_DTR from Profile 1.0 table
  parsing, do it in spi_nor_info_init_params() instead based on the
  SPI_NOR_OCTAL_DTR_READ flag instead.

- Set SNOR_HWCAPS_PP_8_8_8_DTR in s28hs post_sfdp hook since this
  capability is no longer set in Profile 1.0 parsing.

- Instead of just checking for spi_nor_get_protocol_width() in
  spi_nor_octal_dtr_enable(), make sure the protocol is
  SNOR_PROTO_8_8_8_DTR since get_protocol_width() only cares about data
  width.

- Drop flag SPI_NOR_SOFT_RESET. Instead, discover soft reset capability
  via BFPT.

- Do not make an invalid Quad Enable BFPT field a fatal error. Silently
  ignore it by assuming no quad enable bit is present.

- Set dummy cycles for Cypress Semper flash to 24 instead of 20. This
  allows for 200MHz operation in 8D mode compared to the 166MHz with 20.

- Rename spi_nor_cypress_octal_enable() to
  spi_nor_cypress_octal_dtr_enable().

- Update spi-mtk-nor.c to reject DTR ops since it doesn't call
  spi_mem_default_supports_op().

Changes in v4:
- Refactor the series to use the new spi-nor framework with the
  manufacturer-specific bits separated from the core.

- Add support for Micron MT35XU512ABA.

- Use cmd.nbytes as the criteria of whether the data phase exists or not
  instead of cmd.buf.in || cmd.buf.out in spi_nor_spimem_setup_op().

- Update Read FSR to use the same dummy cycles and address width as Read
  SR.

- Fix BFPT parsing stopping too early for JESD216 rev B flashes.

- Use 2 byte reads for Read SR and FSR commands in DTR mode.

Changes in v3:
- Drop the DT properties "spi-rx-dtr" and "spi-tx-dtr". Instead, if
  later a need is felt to disable DTR in case someone has a board with
  Octal DTR capable flash but does not support DTR transactions for some
  reason, a property like "spi-no-dtr" can be added.

- Remove mode bits SPI_RX_DTR and SPI_TX_DTR.

- Remove the Cadence Quadspi controller patch to un-block this series. I
  will submit it as a separate patch.

- Rebase on latest 'master' and fix merge conflicts.

- Update read and write dirmap templates to use DTR.

- Rename 'is_dtr' to 'dtr'.

- Make 'dtr' a bitfield.

- Reject DTR ops in spi_mem_default_supports_op().

- Update atmel-quadspi to reject DTR ops. All other controller drivers
  call spi_mem_default_supports_op() so they will automatically reject
  DTR ops.

- Add support for both enabling and disabling DTR modes.

- Perform a Software Reset on flashes that support it when shutting
  down.

- Disable Octal DTR mode on suspend, and re-enable it on resume.

- Drop enum 'spi_mem_cmd_ext' and make command opcode u16 instead.
  Update spi-nor to use the 2-byte command instead of the command
  extension. Since we still need a "extension type", mode that enum to
  spi-nor and name it 'spi_nor_cmd_ext'.

- Default variable address width to 3 to fix SMPT parsing.

- Drop non-volatile change to uniform sector mode and rely on parsing
  SMPT.

Changes in v2:
- Add DT properties "spi-rx-dtr" and "spi-tx-dtr" to allow expressing
  DTR capabilities.

- Set the mode bits SPI_RX_DTR and SPI_TX_DTR when we discover the DT
  properties "spi-rx-dtr" and spi-tx-dtr".

- spi_nor_cypress_octal_enable() was updating nor->params.read[] with
  the intention of setting the correct number of dummy cycles. But this
  function is called _after_ selecting the read so setting
  nor->params.read[] will have no effect. So, update nor->read_dummy
  directly.

- Fix spi_nor_spimem_check_readop() and spi_nor_spimem_check_pp()
  passing nor->read_proto and nor->write_proto to
  spi_nor_spimem_setup_op() instead of read->proto and pp->proto
  respectively.

- Move the call to cqspi_setup_opcode_ext() inside cqspi_enable_dtr().
  This avoids repeating the 'if (f_pdata->is_dtr)
  cqspi_setup_opcode_ext()...` snippet multiple times.

- Call the default 'supports_op()' from cqspi_supports_mem_op(). This
  makes sure the buswidth requirements are also enforced along with the
  DTR requirements.

- Drop the 'is_dtr' argument from spi_check_dtr_req(). We only call it
  when a phase is DTR so it is redundant.

Pratyush Yadav (17):
  spi: spi-mem: allow specifying whether an op is DTR or not
  spi: spi-mem: allow specifying a command's extension
  spi: atmel-quadspi: reject DTR ops
  spi: spi-mtk-nor: reject DTR ops
  mtd: spi-nor: add support for DTR protocol
  mtd: spi-nor: sfdp: get command opcode extension type from BFPT
  mtd: spi-nor: sfdp: parse xSPI Profile 1.0 table
  mtd: spi-nor: core: use dummy cycle and address width info from SFDP
  mtd: spi-nor: core: do 2 byte reads for SR and FSR in DTR mode
  mtd: spi-nor: core: enable octal DTR mode when possible
  mtd: spi-nor: sfdp: do not make invalid quad enable fatal
  mtd: spi-nor: sfdp: detect Soft Reset sequence support from BFPT
  mtd: spi-nor: core: perform a Soft Reset on shutdown
  mtd: spi-nor: core: disable Octal DTR mode on suspend.
  mtd: spi-nor: core: expose spi_nor_default_setup() in core.h
  mtd: spi-nor: spansion: add support for Cypress Semper flash
  mtd: spi-nor: micron-st: allow using MT35XU512ABA in Octal DTR mode

 drivers/mtd/spi-nor/core.c      | 446 +++++++++++++++++++++++++++-----
 drivers/mtd/spi-nor/core.h      |  22 ++
 drivers/mtd/spi-nor/micron-st.c | 103 +++++++-
 drivers/mtd/spi-nor/sfdp.c      | 131 +++++++++-
 drivers/mtd/spi-nor/sfdp.h      |   8 +
 drivers/mtd/spi-nor/spansion.c  | 166 ++++++++++++
 drivers/spi/atmel-quadspi.c     |   6 +
 drivers/spi/spi-mem.c           |  16 +-
 drivers/spi/spi-mtk-nor.c       |  10 +-
 drivers/spi/spi-mxic.c          |   3 +-
 drivers/spi/spi-zynq-qspi.c     |  11 +-
 include/linux/mtd/spi-nor.h     |  53 +++-
 include/linux/spi/spi-mem.h     |  14 +-
 13 files changed, 889 insertions(+), 100 deletions(-)

--
2.27.0

Comments

Tudor Ambarus July 8, 2020, 4:01 p.m. UTC | #1
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> 

> This table is indication that the flash is xSPI compliant and hence

> supports octal DTR mode. Extract information like the fast read opcode,

> dummy cycles, the number of dummy cycles needed for a Read Status

> Register command, and the number of address bytes needed for a Read

> Status Register command.

> 

> We don't know what speed the controller is running at. Find the fast

> read dummy cycles for the fastest frequency the flash can run at to be

> sure we are never short of dummy cycles. If nothing is available,

> default to 20. Flashes that use a different value should update it in

> their fixup hooks.

> 

> Since we want to set read settings, expose spi_nor_set_read_settings()

> in core.h.

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> ---

>  drivers/mtd/spi-nor/core.c |  2 +-

>  drivers/mtd/spi-nor/core.h | 10 ++++

>  drivers/mtd/spi-nor/sfdp.c | 98 ++++++++++++++++++++++++++++++++++++++

>  3 files changed, 109 insertions(+), 1 deletion(-)

> 

> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c

> index 22a3832b83a6..7d24e63fcca8 100644

> --- a/drivers/mtd/spi-nor/core.c

> +++ b/drivers/mtd/spi-nor/core.c

> @@ -2355,7 +2355,7 @@ static int spi_nor_check(struct spi_nor *nor)

>         return 0;

>  }

> 

> -static void

> +void

>  spi_nor_set_read_settings(struct spi_nor_read_command *read,

>                           u8 num_mode_clocks,

>                           u8 num_wait_states,

> diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h

> index de1e3917889f..7e6df8322da0 100644

> --- a/drivers/mtd/spi-nor/core.h

> +++ b/drivers/mtd/spi-nor/core.h

> @@ -192,6 +192,9 @@ struct spi_nor_locking_ops {

>   *

>   * @size:              the flash memory density in bytes.

>   * @page_size:         the page size of the SPI NOR flash memory.

> + * @rdsr_dummy:                dummy cycles needed for Read Status Register command.

> + * @rdsr_addr_nbytes:  dummy address bytes needed for Read Status Register

> + *                     command.

>   * @hwcaps:            describes the read and page program hardware

>   *                     capabilities.

>   * @reads:             read capabilities ordered by priority: the higher index

> @@ -214,6 +217,8 @@ struct spi_nor_locking_ops {

>  struct spi_nor_flash_parameter {

>         u64                             size;

>         u32                             page_size;

> +       u8                              rdsr_dummy;

> +       u8                              rdsr_addr_nbytes;

> 

>         struct spi_nor_hwcaps           hwcaps;

>         struct spi_nor_read_command     reads[SNOR_CMD_READ_MAX];

> @@ -424,6 +429,11 @@ ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,

> 

>  int spi_nor_hwcaps_read2cmd(u32 hwcaps);

>  u8 spi_nor_convert_3to4_read(u8 opcode);

> +void spi_nor_set_read_settings(struct spi_nor_read_command *read,

> +                             u8 num_mode_clocks,

> +                             u8 num_wait_states,

> +                             u8 opcode,

> +                             enum spi_nor_protocol proto);

>  void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode,

>                              enum spi_nor_protocol proto);

> 

> diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c

> index 3f709de5ea67..d5a24e61813c 100644

> --- a/drivers/mtd/spi-nor/sfdp.c

> +++ b/drivers/mtd/spi-nor/sfdp.c

> @@ -4,12 +4,15 @@

>   * Copyright (C) 2014, Freescale Semiconductor, Inc.

>   */

> 

> +#include <linux/bitfield.h>

>  #include <linux/slab.h>

>  #include <linux/sort.h>

>  #include <linux/mtd/spi-nor.h>

> 

>  #include "core.h"

> 

> +#define ROUND_UP_TO(x, y)      (((x) + (y) - 1) / (y) * (y))


you can use round_up()

> +

>  #define SFDP_PARAM_HEADER_ID(p)        (((p)->id_msb << 8) | (p)->id_lsb)

>  #define SFDP_PARAM_HEADER_PTP(p) \

>         (((p)->parameter_table_pointer[2] << 16) | \

> @@ -19,6 +22,7 @@

>  #define SFDP_BFPT_ID           0xff00  /* Basic Flash Parameter Table */

>  #define SFDP_SECTOR_MAP_ID     0xff81  /* Sector Map Table */

>  #define SFDP_4BAIT_ID          0xff84  /* 4-byte Address Instruction Table */

> +#define SFDP_PROFILE1_ID       0xff05  /* xSPI Profile 1.0 table. */

> 

>  #define SFDP_SIGNATURE         0x50444653U

> 

> @@ -66,6 +70,16 @@ struct sfdp_bfpt_erase {

>         u32                     shift;

>  };

> 

> +/* xSPI Profile 1.0 table (from JESD216D.01). */

> +#define PROFILE1_DWORD1_RD_FAST_CMD            GENMASK(15, 8)

> +#define PROFILE1_DWORD1_RDSR_DUMMY             BIT(28)

> +#define PROFILE1_DWORD1_RDSR_ADDR_BYTES                BIT(29)

> +#define PROFILE1_DWORD4_DUMMY_200MHZ           GENMASK(11, 7)

> +#define PROFILE1_DWORD5_DUMMY_166MHZ           GENMASK(31, 27)

> +#define PROFILE1_DWORD5_DUMMY_133MHZ           GENMASK(21, 17)

> +#define PROFILE1_DWORD5_DUMMY_100MHZ           GENMASK(11, 7)


we should order these macros in a consistent way. I see that previous macros
are declared in order starting from MSB to LSB.

> +#define PROFILE1_DUMMY_DEFAULT                 20


we need to explain why the default dummy value is 20.

How about declaring all these macros immediately above of spi_nor_parse_profile1()?

> +

>  #define SMPT_CMD_ADDRESS_LEN_MASK              GENMASK(23, 22)

>  #define SMPT_CMD_ADDRESS_LEN_0                 (0x0UL << 22)

>  #define SMPT_CMD_ADDRESS_LEN_3                 (0x1UL << 22)

> @@ -1106,6 +1120,86 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,

>         return ret;

>  }

> 

> +/**

> + * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table

> + * @nor:               pointer to a 'struct spi_nor'

> + * @param_header:      pointer to the 'struct sfdp_parameter_header' describing

> + *                     the 4-Byte Address Instruction Table length and version.

> + * @params:            pointer to the 'struct spi_nor_flash_parameter' to be.

> + *

> + * Return: 0 on success, -errno otherwise.

> + */

> +static int spi_nor_parse_profile1(struct spi_nor *nor,

> +                                 const struct sfdp_parameter_header *profile1_header,

> +                                 struct spi_nor_flash_parameter *params)

> +{

> +       u32 *table, opcode, addr;


s/table/dwords?

u8 opcode?

> +       size_t len;

> +       int ret, i;

> +       u8 dummy;

> +

> +       len = profile1_header->length * sizeof(*table);

> +       table = kmalloc(len, GFP_KERNEL);

> +       if (!table)

> +               return -ENOMEM;

> +

> +       addr = SFDP_PARAM_HEADER_PTP(profile1_header);

> +       ret = spi_nor_read_sfdp(nor, addr, len, table);

> +       if (ret)

> +               goto out;

> +

> +       /* Fix endianness of the table DWORDs. */

> +       for (i = 0; i < profile1_header->length; i++)

> +               table[i] = le32_to_cpu(table[i]);


le32_to_cpu_array(table, profile1_header->length);

> +

> +       /* Get 8D-8D-8D fast read opcode and dummy cycles. */

> +       opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]);

> +

> +       /*

> +        * We don't know what speed the controller is running at. Find the

> +        * dummy cycles for the fastest frequency the flash can run at to be

> +        * sure we are never short of dummy cycles. A value of 0 means the

> +        * frequency is not supported.

> +        *

> +        * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let

> +        * flashes set the correct value if needed in their fixup hooks.

> +        */

> +       dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]);

> +       if (!dummy)

> +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]);

> +       if (!dummy)

> +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]);

> +       if (!dummy)

> +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]);

> +       if (!dummy)

> +               dummy = PROFILE1_DUMMY_DEFAULT;

> +

> +       /* Round up to an even value to avoid tripping controllers up. */

> +       dummy = ROUND_UP_TO(dummy, 2);

> +

> +       /* Update the fast read settings. */

> +       spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],

> +                                 0, dummy, opcode,

> +                                 SNOR_PROTO_8_8_8_DTR);

> +

> +       /*

> +        * Set the Read Status Register dummy cycles and dummy address bytes.

> +        */


the comment can fit in a single line

> +       if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY)


I would move this above, where opcode is parsed from the same dword

> +               params->rdsr_dummy = 8;

> +       else

> +               params->rdsr_dummy = 4;

> +

> +       if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)

> +               params->rdsr_addr_nbytes = 4;

> +       else

> +               params->rdsr_addr_nbytes = 0;

> +

> +out:

> +       kfree(table);

> +       return ret;

> +}

> +

>  /**

>   * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.

>   * @nor:               pointer to a 'struct spi_nor'

> @@ -1207,6 +1301,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor,

>                         err = spi_nor_parse_4bait(nor, param_header, params);

>                         break;

> 

> +               case SFDP_PROFILE1_ID:

> +                       err = spi_nor_parse_profile1(nor, param_header, params);

> +                       break;

> +

>                 default:

>                         break;

>                 }

> --

> 2.27.0

>
Tudor Ambarus July 8, 2020, 4:03 p.m. UTC | #2
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> 

> The xSPI Profile 1.0 table specifies how many dummy cycles and address

> bytes are needed for the Read Status Register command in octal DTR mode.

> Use that information to send the correct Read SR command.

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> ---

>  drivers/mtd/spi-nor/core.c | 25 +++++++++++++++++++++++--

>  1 file changed, 23 insertions(+), 2 deletions(-)

> 

> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c

> index 7d24e63fcca8..f2748f1d9957 100644

> --- a/drivers/mtd/spi-nor/core.c

> +++ b/drivers/mtd/spi-nor/core.c

> @@ -357,6 +357,8 @@ int spi_nor_write_disable(struct spi_nor *nor)

>  static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

>  {

>         int ret;

> +       u8 addr_bytes = nor->params->rdsr_addr_nbytes;

> +       u8 dummy = nor->params->rdsr_dummy;


no need to introduce local variables for a single dereference

> 

>         if (nor->spimem) {

>                 struct spi_mem_op op =

> @@ -365,10 +367,21 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

>                                    SPI_MEM_OP_NO_DUMMY,

>                                    SPI_MEM_OP_DATA_IN(1, sr, 1));

> 

> +               if (spi_nor_protocol_is_dtr(nor->reg_proto)) {

> +                       op.addr.nbytes = addr_bytes;

> +                       op.addr.val = 0;


isn't addr already initialized to 0?

> +                       op.dummy.nbytes = dummy;

> +               }

> +

> +               spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);

> +

>                 ret = spi_mem_exec_op(nor->spimem, &op);

>         } else {

> -               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,

> -                                                   sr, 1);

> +               if (spi_nor_protocol_is_dtr(nor->reg_proto))

> +                       ret = -ENOTSUPP;

> +               else

> +                       ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,

> +                                                           sr, 1);

>         }


doesn't this belong to a previous patch?

> 

>         if (ret)

> @@ -388,6 +401,8 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

>  static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)

>  {

>         int ret;

> +       u8 addr_bytes = nor->params->rdsr_addr_nbytes;

> +       u8 dummy = nor->params->rdsr_dummy;

> 

>         if (nor->spimem) {

>                 struct spi_mem_op op =

> @@ -396,6 +411,12 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)

>                                    SPI_MEM_OP_NO_DUMMY,

>                                    SPI_MEM_OP_DATA_IN(1, fsr, 1));

> 

> +               if (spi_nor_protocol_is_dtr(nor->reg_proto)) {

> +                       op.addr.nbytes = addr_bytes;

> +                       op.addr.val = 0;

> +                       op.dummy.nbytes = dummy;

> +               }

> +

>                 spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);

> 

>                 ret = spi_mem_exec_op(nor->spimem, &op);

> --

> 2.27.0

>
Tudor Ambarus July 8, 2020, 4:22 p.m. UTC | #3
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> 

> Each phase is given a separate 'dtr' field so mixed protocols like

> 4S-4D-4D can be supported.

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>


Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>


> ---

>  drivers/spi/spi-mem.c       | 3 +++

>  include/linux/spi/spi-mem.h | 8 ++++++++

>  2 files changed, 11 insertions(+)

>
Tudor Ambarus July 13, 2020, 3:55 a.m. UTC | #4
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c

> index 9a86cc27fcc0..93e255287ab9 100644

> --- a/drivers/spi/spi-mem.c

> +++ b/drivers/spi/spi-mem.c

> @@ -156,6 +156,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,

>                                    op->data.dir == SPI_MEM_DATA_OUT))

>                 return false;

> 

> +       if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)

> +               return false;



I would put this check the first thing in the function to exit sooner
and avoid the rest of the checks, that would become superfluous.

Anyway this is just a nit.
Tudor Ambarus July 13, 2020, 6:15 a.m. UTC | #5
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> 

> In xSPI mode, flashes expect 2-byte opcodes. The second byte is called

> the "command extension". There can be 3 types of extensions in xSPI:

> repeat, invert, and hex. When the extension type is "repeat", the same

> opcode is sent twice. When it is "invert", the second byte is the

> inverse of the opcode. When it is "hex" an additional opcode byte based

> is sent with the command whose value can be anything.

> 

> So, make opcode a 16-bit value and add a 'nbytes', similar to how

> multiple address widths are handled.

> 

> Some places use sizeof(op->cmd.opcode). Replace them with op->cmd.nbytes

> 

> The spi-mxic and spi-zynq-qspi drivers directly use op->cmd.opcode as a

> buffer. Now that opcode is a 2-byte field, this can result in different

> behaviour depending on if the machine is little endian or big endian.

> Extract the opcode in a local 1-byte variable and use that as the buffer

> instead. Both these drivers would reject multi-byte opcodes in their

> supports_op() hook anyway, so we only need to worry about single-byte

> opcodes for now.

> 

> The above two changes are put in this commit to keep the series

> bisectable.

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> ---

>  drivers/spi/spi-mem.c       | 13 +++++++------

>  drivers/spi/spi-mtk-nor.c   |  4 ++--

>  drivers/spi/spi-mxic.c      |  3 ++-

>  drivers/spi/spi-zynq-qspi.c | 11 ++++++-----

>  include/linux/spi/spi-mem.h |  6 +++++-

>  5 files changed, 22 insertions(+), 15 deletions(-)

> 

> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c

> index 93e255287ab9..ef53290b7d24 100644

> --- a/drivers/spi/spi-mem.c

> +++ b/drivers/spi/spi-mem.c

> @@ -159,6 +159,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,

>         if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)

>                 return false;

> 

> +       if (op->cmd.nbytes != 1)

> +               return false;


I would put this imediately before:

if (spi_check_buswidth_req(mem, op->cmd.buswidth, true))  

to speed up the exit and avoid the rest of the checks that would
become superflous.


> +

>         return true;

>  }

>  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);

> @@ -173,7 +176,7 @@ static bool spi_mem_buswidth_is_valid(u8 buswidth)

> 

>  static int spi_mem_check_op(const struct spi_mem_op *op)

>  {

> -       if (!op->cmd.buswidth)

> +       if (!op->cmd.buswidth || !op->cmd.nbytes)


we would be more explicit with:
if (!op->cmd.buswidth || !op->cmd.nbytes || op->cmd.nbytes > 2)

With these addressed:

Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>


>                 return -EINVAL;

> 

>         if ((op->addr.nbytes && !op->addr.buswidth) ||

> @@ -309,8 +312,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)

>                         return ret;

>         }

> 

> -       tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +

> -                    op->dummy.nbytes;

> +       tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;

> 

>         /*

>          * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so

> @@ -325,7 +327,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)

> 

>         tmpbuf[0] = op->cmd.opcode;

>         xfers[xferpos].tx_buf = tmpbuf;

> -       xfers[xferpos].len = sizeof(op->cmd.opcode);

> +       xfers[xferpos].len = op->cmd.nbytes;

>         xfers[xferpos].tx_nbits = op->cmd.buswidth;

>         spi_message_add_tail(&xfers[xferpos], &msg);

>         xferpos++;

> @@ -427,8 +429,7 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)

>                 return ctlr->mem_ops->adjust_op_size(mem, op);

> 

>         if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {

> -               len = sizeof(op->cmd.opcode) + op->addr.nbytes +

> -                     op->dummy.nbytes;

> +               len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;

> 

>                 if (len > spi_max_transfer_size(mem->spi))

>                         return -EINVAL;

> diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c

> index 7bc302b50396..d5f393871619 100644

> --- a/drivers/spi/spi-mtk-nor.c

> +++ b/drivers/spi/spi-mtk-nor.c

> @@ -195,7 +195,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)

>                 }

>         }

> 

> -       len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes -

> +       len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -

>               op->dummy.nbytes;

>         if (op->data.nbytes > len)

>                 op->data.nbytes = len;

> @@ -219,7 +219,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,

>                                (op->dummy.buswidth == 0) &&

>                                (op->data.buswidth == 1);

>         }

> -       len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;

> +       len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;

>         if ((len > MTK_NOR_PRG_MAX_SIZE) ||

>             ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))

>                 return false;

> diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c

> index 69491f3a515d..8c630acb0110 100644

> --- a/drivers/spi/spi-mxic.c

> +++ b/drivers/spi/spi-mxic.c

> @@ -356,6 +356,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,

>         int nio = 1, i, ret;

>         u32 ss_ctrl;

>         u8 addr[8];

> +       u8 opcode = op->cmd.opcode;

> 

>         ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);

>         if (ret)

> @@ -393,7 +394,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,

>         writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,

>                mxic->regs + HC_CFG);

> 

> -       ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1);

> +       ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1);

>         if (ret)

>                 goto out;

> 

> diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c

> index 17641157354d..bbf3d90561f5 100644

> --- a/drivers/spi/spi-zynq-qspi.c

> +++ b/drivers/spi/spi-zynq-qspi.c

> @@ -527,20 +527,21 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,

>         struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master);

>         int err = 0, i;

>         u8 *tmpbuf;

> +       u8 opcode = op->cmd.opcode;

> 

>         dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",

> -               op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,

> +               opcode, op->cmd.buswidth, op->addr.buswidth,

>                 op->dummy.buswidth, op->data.buswidth);

> 

>         zynq_qspi_chipselect(mem->spi, true);

>         zynq_qspi_config_op(xqspi, mem->spi);

> 

> -       if (op->cmd.opcode) {

> +       if (op->cmd.nbytes) {

>                 reinit_completion(&xqspi->data_completion);

> -               xqspi->txbuf = (u8 *)&op->cmd.opcode;

> +               xqspi->txbuf = &opcode;

>                 xqspi->rxbuf = NULL;

> -               xqspi->tx_bytes = sizeof(op->cmd.opcode);

> -               xqspi->rx_bytes = sizeof(op->cmd.opcode);

> +               xqspi->tx_bytes = op->cmd.nbytes;

> +               xqspi->rx_bytes = op->cmd.nbytes;

>                 zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true);

>                 zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET,

>                                 ZYNQ_QSPI_IXR_RXTX_MASK);

> diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h

> index e3dcb956bf61..159463cc659c 100644

> --- a/include/linux/spi/spi-mem.h

> +++ b/include/linux/spi/spi-mem.h

> @@ -17,6 +17,7 @@

>         {                                                       \

>                 .buswidth = __buswidth,                         \

>                 .opcode = __opcode,                             \

> +               .nbytes = 1,                                    \

>         }

> 

>  #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth)           \

> @@ -69,6 +70,8 @@ enum spi_mem_data_dir {

> 

>  /**

>   * struct spi_mem_op - describes a SPI memory operation

> + * @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is

> + *             sent MSB-first.

>   * @cmd.buswidth: number of IO lines used to transmit the command

>   * @cmd.opcode: operation opcode

>   * @cmd.dtr: whether the command opcode should be sent in DTR mode or not

> @@ -94,9 +97,10 @@ enum spi_mem_data_dir {

>   */

>  struct spi_mem_op {

>         struct {

> +               u8 nbytes;

>                 u8 buswidth;

>                 u8 dtr : 1;

> -               u8 opcode;

> +               u16 opcode;

>         } cmd;

> 

>         struct {

> --

> 2.27.0

>
Tudor Ambarus July 13, 2020, 6:24 a.m. UTC | #6
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> 

> Double Transfer Rate (DTR) ops are added in spi-mem. But this controller

> doesn't support DTR transactions. Since we don't use the default

> supports_op(), which rejects all DTR ops, do that explicitly in our

> supports_op().

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>


Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>


> ---

>  drivers/spi/spi-mtk-nor.c | 6 ++++++

>  1 file changed, 6 insertions(+)

> 

> diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c

> index d5f393871619..b08d8e9a8ee9 100644

> --- a/drivers/spi/spi-mtk-nor.c

> +++ b/drivers/spi/spi-mtk-nor.c

> @@ -211,6 +211,12 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,

>         if (op->cmd.buswidth != 1)

>                 return false;

> 

> +       /* DTR ops not supported. */

> +       if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)

> +               return false;

> +       if (op->cmd.nbytes != 1)

> +               return false;

> +

>         if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {

>                 if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))

>                         return true;

> --

> 2.27.0

>
Tudor Ambarus July 13, 2020, 6:34 a.m. UTC | #7
Hi, Mark,

On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> Pratyush Yadav (17):

>   spi: spi-mem: allow specifying whether an op is DTR or not

>   spi: spi-mem: allow specifying a command's extension

>   spi: atmel-quadspi: reject DTR ops

>   spi: spi-mtk-nor: reject DTR ops


These four patches are looking good, I had just few minor comments.
If you too think that they are ok, would you take them through the
SPI tree? If so, I would need an immutable tag on top of v5.8-rc1
preferably, so I can merge them back to SPI NOR and continue the
development on top of them.

Let us know if you want us to resubmit for those minor comments.

Cheers,
ta
Tudor Ambarus July 13, 2020, 9:33 a.m. UTC | #8
On 6/23/20 9:30 PM, Pratyush Yadav wrote:
> The Micron MT35XU512ABA flash does not support the quad enable bit. But

> instead of programming the Quad Enable Require field to 000b ("Device

> does not have a QE bit"), it is programmed to 111b ("Reserved").

> 

> While this is technically incorrect, it is not reason enough to abort

> BFPT parsing. Instead, continue BFPT parsing and let flashes set it in

> their fixup hooks.

> 

> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> ---

>  drivers/mtd/spi-nor/sfdp.c | 3 ++-

>  1 file changed, 2 insertions(+), 1 deletion(-)


Applied, thanks!
Mark Brown July 14, 2020, 4:40 p.m. UTC | #9
On Wed, 24 Jun 2020 00:00:13 +0530, Pratyush Yadav wrote:
> This series adds support for octal DTR flashes in the spi-nor framework,

> and then adds hooks for the Cypress Semper and Mircom Xcella flashes to

> allow running them in octal DTR mode. This series assumes that the flash

> is handed to the kernel in Legacy SPI mode.

> 

> Tested on TI J721e EVM with 1-bit ECC on the Cypress flash.

> 

> [...]


Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/4] spi: spi-mem: allow specifying whether an op is DTR or not
      commit: 4c5e2bba30e49b970a0fd07b43e0b7a3b5fd5ea7
[2/4] spi: spi-mem: allow specifying a command's extension
      commit: caf72df48be32c39f74287976ae843501ae06949
[3/4] spi: atmel-quadspi: reject DTR ops
      commit: 5c81c275582c9d9c66d2f928591a2065f2528231
[4/4] spi: spi-mtk-nor: reject DTR ops
      commit: 4728f073bfc66b8b555274ef0d7741d7f5a48947

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
Mark Brown July 14, 2020, 7:19 p.m. UTC | #10
On Mon, Jul 13, 2020 at 06:34:12AM +0000, Tudor.Ambarus@microchip.com wrote:

> These four patches are looking good, I had just few minor comments.

> If you too think that they are ok, would you take them through the

> SPI tree? If so, I would need an immutable tag on top of v5.8-rc1

> preferably, so I can merge them back to SPI NOR and continue the

> development on top of them.


The following changes since commit b3a9e3b9622ae10064826dccb4f7a52bd88c7407:

  Linux 5.8-rc1 (2020-06-14 12:45:04 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git tags/spi-mem-dtr

for you to fetch changes up to 4728f073bfc66b8b555274ef0d7741d7f5a48947:

  spi: spi-mtk-nor: reject DTR ops (2020-07-14 17:29:40 +0100)

----------------------------------------------------------------
spi: Support for DTR ops

----------------------------------------------------------------
Pratyush Yadav (4):
      spi: spi-mem: allow specifying whether an op is DTR or not
      spi: spi-mem: allow specifying a command's extension
      spi: atmel-quadspi: reject DTR ops
      spi: spi-mtk-nor: reject DTR ops

 drivers/spi/atmel-quadspi.c |  6 ++++++
 drivers/spi/spi-mem.c       | 16 ++++++++++------
 drivers/spi/spi-mtk-nor.c   | 10 ++++++++--
 drivers/spi/spi-mxic.c      |  3 ++-
 drivers/spi/spi-zynq-qspi.c | 11 ++++++-----
 include/linux/spi/spi-mem.h | 14 +++++++++++++-
 6 files changed, 45 insertions(+), 15 deletions(-)
Tudor Ambarus July 15, 2020, 3:40 a.m. UTC | #11
On 7/14/20 10:19 PM, Mark Brown wrote:
> On Mon, Jul 13, 2020 at 06:34:12AM +0000, Tudor.Ambarus@microchip.com wrote:

> 

>> These four patches are looking good, I had just few minor comments.

>> If you too think that they are ok, would you take them through the

>> SPI tree? If so, I would need an immutable tag on top of v5.8-rc1

>> preferably, so I can merge them back to SPI NOR and continue the

>> development on top of them.

> 

> The following changes since commit b3a9e3b9622ae10064826dccb4f7a52bd88c7407:

> 

>   Linux 5.8-rc1 (2020-06-14 12:45:04 -0700)

> 

> are available in the Git repository at:

> 

>   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git tags/spi-mem-dtr

> 

> for you to fetch changes up to 4728f073bfc66b8b555274ef0d7741d7f5a48947:

> 

>   spi: spi-mtk-nor: reject DTR ops (2020-07-14 17:29:40 +0100)

> 

> ----------------------------------------------------------------

> spi: Support for DTR ops

> 

> ----------------------------------------------------------------

> Pratyush Yadav (4):

>       spi: spi-mem: allow specifying whether an op is DTR or not

>       spi: spi-mem: allow specifying a command's extension

>       spi: atmel-quadspi: reject DTR ops

>       spi: spi-mtk-nor: reject DTR ops

> 

>  drivers/spi/atmel-quadspi.c |  6 ++++++

>  drivers/spi/spi-mem.c       | 16 ++++++++++------

>  drivers/spi/spi-mtk-nor.c   | 10 ++++++++--

>  drivers/spi/spi-mxic.c      |  3 ++-

>  drivers/spi/spi-zynq-qspi.c | 11 ++++++-----

>  include/linux/spi/spi-mem.h | 14 +++++++++++++-

>  6 files changed, 45 insertions(+), 15 deletions(-)

> 


Merged into spi-nor/next. Thank you!
Pratyush Yadav July 20, 2020, 4:24 p.m. UTC | #12
Hi Tudor,

On 08/07/20 04:03PM, Tudor.Ambarus@microchip.com wrote:
> On 6/23/20 9:30 PM, Pratyush Yadav wrote:

> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> > 

> > The xSPI Profile 1.0 table specifies how many dummy cycles and address

> > bytes are needed for the Read Status Register command in octal DTR mode.

> > Use that information to send the correct Read SR command.

> > 

> > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> > ---

> >  drivers/mtd/spi-nor/core.c | 25 +++++++++++++++++++++++--

> >  1 file changed, 23 insertions(+), 2 deletions(-)

> > 

> > diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c

> > index 7d24e63fcca8..f2748f1d9957 100644

> > --- a/drivers/mtd/spi-nor/core.c

> > +++ b/drivers/mtd/spi-nor/core.c

> > @@ -357,6 +357,8 @@ int spi_nor_write_disable(struct spi_nor *nor)

> >  static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

> >  {

> >         int ret;

> > +       u8 addr_bytes = nor->params->rdsr_addr_nbytes;

> > +       u8 dummy = nor->params->rdsr_dummy;

> 

> no need to introduce local variables for a single dereference


Ok.
 
> > 

> >         if (nor->spimem) {

> >                 struct spi_mem_op op =

> > @@ -365,10 +367,21 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

> >                                    SPI_MEM_OP_NO_DUMMY,

> >                                    SPI_MEM_OP_DATA_IN(1, sr, 1));

> > 

> > +               if (spi_nor_protocol_is_dtr(nor->reg_proto)) {

> > +                       op.addr.nbytes = addr_bytes;

> > +                       op.addr.val = 0;

> 

> isn't addr already initialized to 0?


Yes, it is. But I figured it won't hurt to be explicit about what we 
intend the address to be.

> > +                       op.dummy.nbytes = dummy;

> > +               }

> > +

> > +               spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);

> > +

> >                 ret = spi_mem_exec_op(nor->spimem, &op);

> >         } else {

> > -               ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,

> > -                                                   sr, 1);

> > +               if (spi_nor_protocol_is_dtr(nor->reg_proto))

> > +                       ret = -ENOTSUPP;

> > +               else

> > +                       ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,

> > +                                                           sr, 1);

> >         }

> 

> doesn't this belong to a previous patch?


It does. Will fix.
 
> > 

> >         if (ret)

> > @@ -388,6 +401,8 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)

> >  static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)

> >  {

> >         int ret;

> > +       u8 addr_bytes = nor->params->rdsr_addr_nbytes;

> > +       u8 dummy = nor->params->rdsr_dummy;

> > 

> >         if (nor->spimem) {

> >                 struct spi_mem_op op =

> > @@ -396,6 +411,12 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)

> >                                    SPI_MEM_OP_NO_DUMMY,

> >                                    SPI_MEM_OP_DATA_IN(1, fsr, 1));

> > 

> > +               if (spi_nor_protocol_is_dtr(nor->reg_proto)) {

> > +                       op.addr.nbytes = addr_bytes;

> > +                       op.addr.val = 0;

> > +                       op.dummy.nbytes = dummy;

> > +               }

> > +

> >                 spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);

> > 

> >                 ret = spi_mem_exec_op(nor->spimem, &op);


-- 
Regards,
Pratyush Yadav
Pratyush Yadav July 20, 2020, 4:38 p.m. UTC | #13
Hi Tudor,

On 08/07/20 04:01PM, Tudor.Ambarus@microchip.com wrote:
> On 6/23/20 9:30 PM, Pratyush Yadav wrote:

> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

> > 

> > This table is indication that the flash is xSPI compliant and hence

> > supports octal DTR mode. Extract information like the fast read opcode,

> > dummy cycles, the number of dummy cycles needed for a Read Status

> > Register command, and the number of address bytes needed for a Read

> > Status Register command.

> > 

> > We don't know what speed the controller is running at. Find the fast

> > read dummy cycles for the fastest frequency the flash can run at to be

> > sure we are never short of dummy cycles. If nothing is available,

> > default to 20. Flashes that use a different value should update it in

> > their fixup hooks.

> > 

> > Since we want to set read settings, expose spi_nor_set_read_settings()

> > in core.h.

> > 

> > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>

> > ---

> >  drivers/mtd/spi-nor/core.c |  2 +-

> >  drivers/mtd/spi-nor/core.h | 10 ++++

> >  drivers/mtd/spi-nor/sfdp.c | 98 ++++++++++++++++++++++++++++++++++++++

> >  3 files changed, 109 insertions(+), 1 deletion(-)

> > 

[...]
> > diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c

> > index 3f709de5ea67..d5a24e61813c 100644

> > --- a/drivers/mtd/spi-nor/sfdp.c

> > +++ b/drivers/mtd/spi-nor/sfdp.c

[...]
> > @@ -66,6 +70,16 @@ struct sfdp_bfpt_erase {

> >         u32                     shift;

> >  };

> > 

> > +/* xSPI Profile 1.0 table (from JESD216D.01). */

> > +#define PROFILE1_DWORD1_RD_FAST_CMD            GENMASK(15, 8)

> > +#define PROFILE1_DWORD1_RDSR_DUMMY             BIT(28)

> > +#define PROFILE1_DWORD1_RDSR_ADDR_BYTES                BIT(29)

> > +#define PROFILE1_DWORD4_DUMMY_200MHZ           GENMASK(11, 7)

> > +#define PROFILE1_DWORD5_DUMMY_166MHZ           GENMASK(31, 27)

> > +#define PROFILE1_DWORD5_DUMMY_133MHZ           GENMASK(21, 17)

> > +#define PROFILE1_DWORD5_DUMMY_100MHZ           GENMASK(11, 7)

> 

> we should order these macros in a consistent way. I see that previous macros

> are declared in order starting from MSB to LSB.

> 

> > +#define PROFILE1_DUMMY_DEFAULT                 20

> 

> we need to explain why the default dummy value is 20.


No reason other than the fact that it is the default for the first flash 
that uses Profile 1.0 parsing (S28HS512T). AFAIK a similar reasoning is 
followed for the default being 8 for 1-1-4 or 1-1-8 modes.

I can't think of any reasonable way of deciding on a default value since 
it varies from flash to flash.
 
> How about declaring all these macros immediately above of spi_nor_parse_profile1()?

> 

> > +

> >  #define SMPT_CMD_ADDRESS_LEN_MASK              GENMASK(23, 22)

> >  #define SMPT_CMD_ADDRESS_LEN_0                 (0x0UL << 22)

> >  #define SMPT_CMD_ADDRESS_LEN_3                 (0x1UL << 22)

> > @@ -1106,6 +1120,86 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,

> >         return ret;

> >  }

> > 

> > +/**

> > + * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table

> > + * @nor:               pointer to a 'struct spi_nor'

> > + * @param_header:      pointer to the 'struct sfdp_parameter_header' describing

> > + *                     the 4-Byte Address Instruction Table length and version.

> > + * @params:            pointer to the 'struct spi_nor_flash_parameter' to be.

> > + *

> > + * Return: 0 on success, -errno otherwise.

> > + */

> > +static int spi_nor_parse_profile1(struct spi_nor *nor,

> > +                                 const struct sfdp_parameter_header *profile1_header,

> > +                                 struct spi_nor_flash_parameter *params)

> > +{

> > +       u32 *table, opcode, addr;

> 

> s/table/dwords?

> 

> u8 opcode?

> 

> > +       size_t len;

> > +       int ret, i;

> > +       u8 dummy;

> > +

> > +       len = profile1_header->length * sizeof(*table);

> > +       table = kmalloc(len, GFP_KERNEL);

> > +       if (!table)

> > +               return -ENOMEM;

> > +

> > +       addr = SFDP_PARAM_HEADER_PTP(profile1_header);

> > +       ret = spi_nor_read_sfdp(nor, addr, len, table);

> > +       if (ret)

> > +               goto out;

> > +

> > +       /* Fix endianness of the table DWORDs. */

> > +       for (i = 0; i < profile1_header->length; i++)

> > +               table[i] = le32_to_cpu(table[i]);

> 

> le32_to_cpu_array(table, profile1_header->length);

> 

> > +

> > +       /* Get 8D-8D-8D fast read opcode and dummy cycles. */

> > +       opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]);

> > +

> > +       /*

> > +        * We don't know what speed the controller is running at. Find the

> > +        * dummy cycles for the fastest frequency the flash can run at to be

> > +        * sure we are never short of dummy cycles. A value of 0 means the

> > +        * frequency is not supported.

> > +        *

> > +        * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let

> > +        * flashes set the correct value if needed in their fixup hooks.

> > +        */

> > +       dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, table[3]);

> > +       if (!dummy)

> > +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, table[4]);

> > +       if (!dummy)

> > +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, table[4]);

> > +       if (!dummy)

> > +               dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, table[4]);

> > +       if (!dummy)

> > +               dummy = PROFILE1_DUMMY_DEFAULT;

> > +

> > +       /* Round up to an even value to avoid tripping controllers up. */

> > +       dummy = ROUND_UP_TO(dummy, 2);

> > +

[...]

-- 
Regards,
Pratyush Yadav