Re: [PATCH v5 3/3] mtd: spi-nor: Rework hwcaps selection for the spi-mem case

2019-08-06 Thread Tudor.Ambarus


On 08/06/2019 08:10 AM, Vignesh Raghavendra wrote:
> +static int spi_nor_spimem_check_op(struct spi_nor *nor,
> +struct spi_mem_op *op)
> +{
> + /*
> +  * First test with 4 address bytes. The opcode itself might
> +  * be a 3B addressing opcode but we don't care, because
> +  * SPI controller implementation should not check the opcode,
> +  * but just the sequence.
> +  */
> + op->addr.nbytes = 4;
> + if (!spi_mem_supports_op(nor->spimem, op)) {
> + /* If flash size <16MB, 3 address bytes are sufficient */
> + if (nor->mtd.size <= SZ_16M) {
> + op->addr.nbytes = 3;
> + if (!spi_mem_supports_op(nor->spimem, op))
> + return -ENOTSUPP;
> + return 0;
> + }
> + return -ENOTSUPP;
> + }
> +
> + return 0;
> +}

We can get rid of a level of indentation by writing it as:

static int spi_nor_spimem_check_op(struct spi_nor *nor,
   struct spi_mem_op *op)
{
op->addr.nbytes = 4;
if (!spi_mem_supports_op(nor->spimem, op)) {
if (nor->mtd.size > SZ_16M)
return -ENOTSUPP;

/* If flash size <16MB, 3 address bytes are sufficient */
op->addr.nbytes = 3;
if (!spi_mem_supports_op(nor->spimem, op))
return -ENOTSUPP;
}

return 0;
}

I'll do this by myself when applying, no need to resubmit.

Thanks, Vignesh!
ta


[PATCH v5 3/3] mtd: spi-nor: Rework hwcaps selection for the spi-mem case

2019-08-05 Thread Vignesh Raghavendra
From: Boris Brezillon 

The spi-mem layer provides a spi_mem_supports_op() function to check
whether a specific operation is supported by the controller or not.
This is much more accurate than the hwcaps selection logic based on
SPI_{RX,TX}_ flags.

Rework the hwcaps selection logic to use spi_mem_supports_op() when
nor->spimem != NULL.

Signed-off-by: Boris Brezillon 
Signed-off-by: Vignesh Raghavendra 
---
v5:
Fix a bug in spi_nor_spimem_check_op()

 drivers/mtd/spi-nor/spi-nor.c | 184 +++---
 include/linux/mtd/spi-nor.h   |  14 +++
 2 files changed, 162 insertions(+), 36 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index de906ab907c7..eb258ce5a6dd 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2951,6 +2951,130 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 
addr,
return ret;
 }
 
+/**
+ * spi_nor_spimem_check_op - check if the operation is supported
+ *   by controller
+ *@nor:pointer to a 'struct spi_nor'
+ *@op: pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_spimem_check_op(struct spi_nor *nor,
+  struct spi_mem_op *op)
+{
+   /*
+* First test with 4 address bytes. The opcode itself might
+* be a 3B addressing opcode but we don't care, because
+* SPI controller implementation should not check the opcode,
+* but just the sequence.
+*/
+   op->addr.nbytes = 4;
+   if (!spi_mem_supports_op(nor->spimem, op)) {
+   /* If flash size <16MB, 3 address bytes are sufficient */
+   if (nor->mtd.size <= SZ_16M) {
+   op->addr.nbytes = 3;
+   if (!spi_mem_supports_op(nor->spimem, op))
+   return -ENOTSUPP;
+   return 0;
+   }
+   return -ENOTSUPP;
+   }
+
+   return 0;
+}
+
+/**
+ * spi_nor_spimem_check_readop - check if the read op is supported
+ *   by controller
+ *@nor: pointer to a 'struct spi_nor'
+ *@read:pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_spimem_check_readop(struct spi_nor *nor,
+  const struct spi_nor_read_command *read)
+{
+   struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
+ SPI_MEM_OP_ADDR(3, 0, 1),
+ SPI_MEM_OP_DUMMY(0, 1),
+ SPI_MEM_OP_DATA_IN(0, NULL, 1));
+
+   op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
+   op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
+   op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
+   op.dummy.buswidth = op.addr.buswidth;
+   op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
+ op.dummy.buswidth / 8;
+
+   return spi_nor_spimem_check_op(nor, );
+}
+
+/**
+ * spi_nor_spimem_check_pp - check if the page program op is supported
+ *   by controller
+ *@nor: pointer to a 'struct spi_nor'
+ *@pp:  pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_spimem_check_pp(struct spi_nor *nor,
+  const struct spi_nor_pp_command *pp)
+{
+   struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
+ SPI_MEM_OP_ADDR(3, 0, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+
+   op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
+   op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
+   op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
+
+   return spi_nor_spimem_check_op(nor, );
+}
+
+/**
+ * spi_nor_spimem_adjust_hwcaps - Find optimal Read/Write protocol
+ *based on SPI controller capabilities
+ * @nor:pointer to a 'struct spi_nor'
+ * @params: pointer to the 'struct spi_nor_flash_parameter'
+ *  representing SPI NOR flash capabilities
+ * @hwcaps: pointer to resulting capabilities after adjusting
+ *  according to controller and flash's capability
+ */
+static void
+spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor,
+const struct spi_nor_flash_parameter *params,
+u32 *hwcaps)
+{
+   unsigned int cap;
+
+   /* DTR modes are not supported yet, mask them all. */
+   *hwcaps &= ~SNOR_HWCAPS_DTR;
+
+   /* X-X-X modes are