Skip to content

Commit 1f70f3b

Browse files
CyrillePitchenambarus
authored andcommitted
mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
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 <cyrille.pitchen@microchip.com> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
1 parent d2de66f commit 1f70f3b

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

drivers/mtd/spi-nor/spi-nor.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,7 @@ struct sfdp_parameter_header {
21122112

21132113
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
21142114
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
2115+
#define SFDP_4BAIT_ID 0xff84u /* 4-byte Address Instruction Table */
21152116

21162117
#define SFDP_SIGNATURE 0x50444653U
21172118
#define SFDP_JESD216_MAJOR 1
@@ -2799,6 +2800,149 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
27992800
return ret;
28002801
}
28012802

2803+
struct sfdp_4bait {
2804+
/* The hardware capability. */
2805+
u32 hwcaps;
2806+
2807+
/*
2808+
* The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
2809+
* the associated 4-byte address op code is supported.
2810+
*/
2811+
u32 supported_bit;
2812+
};
2813+
2814+
static int spi_nor_parse_4bait(struct spi_nor *nor,
2815+
const struct sfdp_parameter_header *param_header,
2816+
struct spi_nor_flash_parameter *params)
2817+
{
2818+
static const struct sfdp_4bait reads[] = {
2819+
{ SNOR_HWCAPS_READ, BIT(0) },
2820+
{ SNOR_HWCAPS_READ_FAST, BIT(1) },
2821+
{ SNOR_HWCAPS_READ_1_1_2, BIT(2) },
2822+
{ SNOR_HWCAPS_READ_1_2_2, BIT(3) },
2823+
{ SNOR_HWCAPS_READ_1_1_4, BIT(4) },
2824+
{ SNOR_HWCAPS_READ_1_4_4, BIT(5) },
2825+
{ SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
2826+
{ SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
2827+
{ SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
2828+
};
2829+
static const struct sfdp_4bait programs[] = {
2830+
{ SNOR_HWCAPS_PP, BIT(6) },
2831+
{ SNOR_HWCAPS_PP_1_1_4, BIT(7) },
2832+
{ SNOR_HWCAPS_PP_1_4_4, BIT(8) },
2833+
};
2834+
static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
2835+
{ 0u /* not used */, BIT(9) },
2836+
{ 0u /* not used */, BIT(10) },
2837+
{ 0u /* not used */, BIT(11) },
2838+
{ 0u /* not used */, BIT(12) },
2839+
};
2840+
u32 dwords[2], addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
2841+
struct spi_nor_erase_map *map = &nor->erase_map;
2842+
int i, err;
2843+
2844+
if (param_header->major != SFDP_JESD216_MAJOR ||
2845+
param_header->length < ARRAY_SIZE(dwords))
2846+
return -EINVAL;
2847+
2848+
/* Read the 4-byte Address Instruction Table. */
2849+
addr = SFDP_PARAM_HEADER_PTP(param_header);
2850+
err = spi_nor_read_sfdp(nor, addr, sizeof(dwords), dwords);
2851+
if (err)
2852+
return err;
2853+
2854+
/* Fix endianness of the 4BAIT DWORDs. */
2855+
for (i = 0; i < ARRAY_SIZE(dwords); i++)
2856+
dwords[i] = le32_to_cpu(dwords[i]);
2857+
2858+
/*
2859+
* Compute the subset of (Fast) Read commands for which the 4-byte
2860+
* version is supported.
2861+
*/
2862+
discard_hwcaps = 0;
2863+
read_hwcaps = 0;
2864+
for (i = 0; i < ARRAY_SIZE(reads); i++) {
2865+
const struct sfdp_4bait *read = &reads[i];
2866+
2867+
discard_hwcaps |= read->hwcaps;
2868+
if ((params->hwcaps.mask & read->hwcaps) &&
2869+
(dwords[0] & read->supported_bit))
2870+
read_hwcaps |= read->hwcaps;
2871+
}
2872+
2873+
/*
2874+
* Compute the subset of Page Program commands for which the 4-byte
2875+
* version is supported.
2876+
*/
2877+
pp_hwcaps = 0;
2878+
for (i = 0; i < ARRAY_SIZE(programs); i++) {
2879+
const struct sfdp_4bait *program = &programs[i];
2880+
2881+
discard_hwcaps |= program->hwcaps;
2882+
if ((params->hwcaps.mask & program->hwcaps) &&
2883+
(dwords[0] & program->supported_bit))
2884+
pp_hwcaps |= program->hwcaps;
2885+
}
2886+
2887+
/*
2888+
* Compute the subet of Sector Erase commands for which the 4-byte
2889+
* version is supported.
2890+
*/
2891+
erase_mask = 0;
2892+
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
2893+
const struct sfdp_4bait *erase = &erases[i];
2894+
2895+
if (map->erase_type[i].size > 0 &&
2896+
(dwords[0] & erase->supported_bit))
2897+
erase_mask |= BIT(i);
2898+
}
2899+
2900+
/*
2901+
* We need at least one 4-byte op code per read, program and erase
2902+
* operation; the .read(), .write() and .erase() hooks share the
2903+
* nor->addr_width value.
2904+
*/
2905+
if (!read_hwcaps || !pp_hwcaps || !erase_mask)
2906+
return 0;
2907+
2908+
/*
2909+
* Discard all operations from the 4-byte instruction set which are
2910+
* not supported by this memory.
2911+
*/
2912+
params->hwcaps.mask &= ~discard_hwcaps;
2913+
params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
2914+
2915+
/* Use the 4-byte address instruction set. */
2916+
for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
2917+
struct spi_nor_read_command *read_cmd = &params->reads[i];
2918+
2919+
read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
2920+
}
2921+
for (i = 0; i < SNOR_CMD_PP_MAX; i++) {
2922+
struct spi_nor_pp_command *pp_cmd = &params->page_programs[i];
2923+
2924+
pp_cmd->opcode = spi_nor_convert_3to4_program(pp_cmd->opcode);
2925+
}
2926+
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
2927+
struct spi_nor_erase_type *erase = &map->erase_type[i];
2928+
2929+
if (erase_mask & BIT(erase->idx))
2930+
erase->opcode = (dwords[1] >> (erase->idx * 8)) & 0xFF;
2931+
else
2932+
spi_nor_set_erase_type(erase, 0u, 0xFF);
2933+
}
2934+
2935+
/*
2936+
* We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
2937+
* later because this latest function implements a legacy quirk for
2938+
* the erase size of Spansion memory. However this quirk is no longer
2939+
* needed with new SFDP compliant memories.
2940+
*/
2941+
nor->addr_width = 4;
2942+
nor->flags |= SPI_NOR_4B_OPCODES;
2943+
return 0;
2944+
}
2945+
28022946
/**
28032947
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
28042948
* @nor: pointer to a 'struct spi_nor'
@@ -2897,6 +3041,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
28973041
err = spi_nor_parse_smpt(nor, param_header);
28983042
break;
28993043

3044+
case SFDP_4BAIT_ID:
3045+
err = spi_nor_parse_4bait(nor, param_header, params);
3046+
break;
3047+
29003048
default:
29013049
break;
29023050
}

0 commit comments

Comments
 (0)