[RESEND PATCH v2 3/3] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table

2018-08-27 Thread Tudor Ambarus
From: Cyrille Pitchen 

Add support for SFDP (JESD216B) 4-byte Address Instruction Table. This
table is optional but when available, we parse it to get the 4-byte
address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).

Signed-off-by: Cyrille Pitchen 
Signed-off-by: Tudor Ambarus 
---
 drivers/mtd/spi-nor/spi-nor.c | 148 ++
 1 file changed, 148 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 522d5aa..4e69d47 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2196,6 +2196,7 @@ struct sfdp_parameter_header {
 
 #define SFDP_BFPT_ID   0xff00  /* Basic Flash Parameter Table */
 #define SFDP_SECTOR_MAP_ID 0xff81  /* Sector Map Table */
+#define SFDP_4BAIT_ID  0xff84u /* 4-byte Address Instruction Table */
 
 #define SFDP_SIGNATURE 0x50444653U
 #define SFDP_JESD216_MAJOR 1
@@ -2883,6 +2884,149 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
return ret;
 }
 
+struct sfdp_4bait {
+   /* The hardware capability. */
+   u32 hwcaps;
+
+   /*
+* The  bit in DWORD1 of the 4BAIT tells us whether
+* the associated 4-byte address op code is supported.
+*/
+   u32 supported_bit;
+};
+
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+  const struct sfdp_parameter_header *param_header,
+  struct spi_nor_flash_parameter *params)
+{
+   static const struct sfdp_4bait reads[] = {
+   { SNOR_HWCAPS_READ, BIT(0) },
+   { SNOR_HWCAPS_READ_FAST,BIT(1) },
+   { SNOR_HWCAPS_READ_1_1_2,   BIT(2) },
+   { SNOR_HWCAPS_READ_1_2_2,   BIT(3) },
+   { SNOR_HWCAPS_READ_1_1_4,   BIT(4) },
+   { SNOR_HWCAPS_READ_1_4_4,   BIT(5) },
+   { SNOR_HWCAPS_READ_1_1_1_DTR,   BIT(13) },
+   { SNOR_HWCAPS_READ_1_2_2_DTR,   BIT(14) },
+   { SNOR_HWCAPS_READ_1_4_4_DTR,   BIT(15) },
+   };
+   static const struct sfdp_4bait programs[] = {
+   { SNOR_HWCAPS_PP,   BIT(6) },
+   { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
+   { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
+   };
+   static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
+   { 0u /* not used */,BIT(9) },
+   { 0u /* not used */,BIT(10) },
+   { 0u /* not used */,BIT(11) },
+   { 0u /* not used */,BIT(12) },
+   };
+   u32 dwords[2], addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
+   struct spi_nor_erase_map *map = &nor->erase_map;
+   int i, err;
+
+   if (param_header->major != SFDP_JESD216_MAJOR ||
+   param_header->length < ARRAY_SIZE(dwords))
+   return -EINVAL;
+
+   /* Read the 4-byte Address Instruction Table. */
+   addr = SFDP_PARAM_HEADER_PTP(param_header);
+   err = spi_nor_read_sfdp(nor, addr, sizeof(dwords), dwords);
+   if (err)
+   return err;
+
+   /* Fix endianness of the 4BAIT DWORDs. */
+   for (i = 0; i < ARRAY_SIZE(dwords); i++)
+   dwords[i] = le32_to_cpu(dwords[i]);
+
+   /*
+* Compute the subset of (Fast) Read commands for which the 4-byte
+* version is supported.
+*/
+   discard_hwcaps = 0;
+   read_hwcaps = 0;
+   for (i = 0; i < ARRAY_SIZE(reads); i++) {
+   const struct sfdp_4bait *read = &reads[i];
+
+   discard_hwcaps |= read->hwcaps;
+   if ((params->hwcaps.mask & read->hwcaps) &&
+   (dwords[0] & read->supported_bit))
+   read_hwcaps |= read->hwcaps;
+   }
+
+   /*
+* Compute the subset of Page Program commands for which the 4-byte
+* version is supported.
+*/
+   pp_hwcaps = 0;
+   for (i = 0; i < ARRAY_SIZE(programs); i++) {
+   const struct sfdp_4bait *program = &programs[i];
+
+   discard_hwcaps |= program->hwcaps;
+   if ((params->hwcaps.mask & program->hwcaps) &&
+   (dwords[0] & program->supported_bit))
+   pp_hwcaps |= program->hwcaps;
+   }
+
+   /*
+* Compute the subet of Sector Erase commands for which the 4-byte
+* version is supported.
+*/
+   erase_mask = 0;
+   for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+   const struct sfdp_4bait *erase = &erases[i];
+
+   if (map->erase_type[i].size > 0 &&
+   (dwords[0] & erase->supported_bit))
+   erase_mask |= BIT(i);
+   }
+
+   /*
+* We need at least one 4-byte op code per read, 

[PATCH v2 3/3] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table

2018-07-12 Thread Tudor Ambarus
From: Cyrille Pitchen 

Add support for SFDP (JESD216B) 4-byte Address Instruction Table. This
table is optional but when available, we parse it to get the 4-byte
address op codes supported by the memory.
Using these op codes is stateless as opposed to entering the 4-byte
address mode or setting the Base Address Register (BAR).

Signed-off-by: Cyrille Pitchen 
Signed-off-by: Tudor Ambarus 
---
 drivers/mtd/spi-nor/spi-nor.c | 148 ++
 1 file changed, 148 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 7c6291c..74f9b46 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2196,6 +2196,7 @@ struct sfdp_parameter_header {
 
 #define SFDP_BFPT_ID   0xff00  /* Basic Flash Parameter Table */
 #define SFDP_SECTOR_MAP_ID 0xff81  /* Sector Map Table */
+#define SFDP_4BAIT_ID  0xff84u /* 4-byte Address Instruction Table */
 
 #define SFDP_SIGNATURE 0x50444653U
 #define SFDP_JESD216_MAJOR 1
@@ -2883,6 +2884,149 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
return ret;
 }
 
+struct sfdp_4bait {
+   /* The hardware capability. */
+   u32 hwcaps;
+
+   /*
+* The  bit in DWORD1 of the 4BAIT tells us whether
+* the associated 4-byte address op code is supported.
+*/
+   u32 supported_bit;
+};
+
+static int spi_nor_parse_4bait(struct spi_nor *nor,
+  const struct sfdp_parameter_header *param_header,
+  struct spi_nor_flash_parameter *params)
+{
+   static const struct sfdp_4bait reads[] = {
+   { SNOR_HWCAPS_READ, BIT(0) },
+   { SNOR_HWCAPS_READ_FAST,BIT(1) },
+   { SNOR_HWCAPS_READ_1_1_2,   BIT(2) },
+   { SNOR_HWCAPS_READ_1_2_2,   BIT(3) },
+   { SNOR_HWCAPS_READ_1_1_4,   BIT(4) },
+   { SNOR_HWCAPS_READ_1_4_4,   BIT(5) },
+   { SNOR_HWCAPS_READ_1_1_1_DTR,   BIT(13) },
+   { SNOR_HWCAPS_READ_1_2_2_DTR,   BIT(14) },
+   { SNOR_HWCAPS_READ_1_4_4_DTR,   BIT(15) },
+   };
+   static const struct sfdp_4bait programs[] = {
+   { SNOR_HWCAPS_PP,   BIT(6) },
+   { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
+   { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
+   };
+   static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
+   { 0u /* not used */,BIT(9) },
+   { 0u /* not used */,BIT(10) },
+   { 0u /* not used */,BIT(11) },
+   { 0u /* not used */,BIT(12) },
+   };
+   u32 dwords[2], addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
+   struct spi_nor_erase_map *map = &nor->erase_map;
+   int i, err;
+
+   if (param_header->major != SFDP_JESD216_MAJOR ||
+   param_header->length < ARRAY_SIZE(dwords))
+   return -EINVAL;
+
+   /* Read the 4-byte Address Instruction Table. */
+   addr = SFDP_PARAM_HEADER_PTP(param_header);
+   err = spi_nor_read_sfdp(nor, addr, sizeof(dwords), dwords);
+   if (err)
+   return err;
+
+   /* Fix endianness of the 4BAIT DWORDs. */
+   for (i = 0; i < ARRAY_SIZE(dwords); i++)
+   dwords[i] = le32_to_cpu(dwords[i]);
+
+   /*
+* Compute the subset of (Fast) Read commands for which the 4-byte
+* version is supported.
+*/
+   discard_hwcaps = 0;
+   read_hwcaps = 0;
+   for (i = 0; i < ARRAY_SIZE(reads); i++) {
+   const struct sfdp_4bait *read = &reads[i];
+
+   discard_hwcaps |= read->hwcaps;
+   if ((params->hwcaps.mask & read->hwcaps) &&
+   (dwords[0] & read->supported_bit))
+   read_hwcaps |= read->hwcaps;
+   }
+
+   /*
+* Compute the subset of Page Program commands for which the 4-byte
+* version is supported.
+*/
+   pp_hwcaps = 0;
+   for (i = 0; i < ARRAY_SIZE(programs); i++) {
+   const struct sfdp_4bait *program = &programs[i];
+
+   discard_hwcaps |= program->hwcaps;
+   if ((params->hwcaps.mask & program->hwcaps) &&
+   (dwords[0] & program->supported_bit))
+   pp_hwcaps |= program->hwcaps;
+   }
+
+   /*
+* Compute the subet of Sector Erase commands for which the 4-byte
+* version is supported.
+*/
+   erase_mask = 0;
+   for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+   const struct sfdp_4bait *erase = &erases[i];
+
+   if (map->erase_type[i].size > 0 &&
+   (dwords[0] & erase->supported_bit))
+   erase_mask |= BIT(i);
+   }
+
+   /*
+* We need at least one 4-byte op code per read,