[RESEND PATCH v2 3/3] mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
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
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,