Skip to content

Commit 8a136fc

Browse files
CyrillePitchenambarus
authored andcommitted
mtd: spi-nor: parse SFDP 4-byte Address Instruction Table
This patch adds supports 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> [tudor.ambarus@microchip.com: solved conflicts] Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
1 parent 721c908 commit 8a136fc

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
@@ -2022,6 +2022,7 @@ struct sfdp_parameter_header {
20222022

20232023
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
20242024
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
2025+
#define SFDP_4BAIT_ID 0xff84u /* 4-byte Address Instruction Table */
20252026

20262027
#define SFDP_SIGNATURE 0x50444653U
20272028
#define SFDP_JESD216_MAJOR 1
@@ -2428,6 +2429,149 @@ spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
24282429
map->uniform_region.size = flash_size;
24292430
}
24302431

2432+
struct sfdp_4bait {
2433+
/* The hardware capability. */
2434+
u32 hwcaps;
2435+
2436+
/*
2437+
* The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
2438+
* the associated 4-byte address op code is supported.
2439+
*/
2440+
u32 supported_bit;
2441+
};
2442+
2443+
static int spi_nor_parse_4bait(struct spi_nor *nor,
2444+
const struct sfdp_parameter_header *param_header,
2445+
struct spi_nor_flash_parameter *params)
2446+
{
2447+
static const struct sfdp_4bait reads[] = {
2448+
{ SNOR_HWCAPS_READ, BIT(0) },
2449+
{ SNOR_HWCAPS_READ_FAST, BIT(1) },
2450+
{ SNOR_HWCAPS_READ_1_1_2, BIT(2) },
2451+
{ SNOR_HWCAPS_READ_1_2_2, BIT(3) },
2452+
{ SNOR_HWCAPS_READ_1_1_4, BIT(4) },
2453+
{ SNOR_HWCAPS_READ_1_4_4, BIT(5) },
2454+
{ SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
2455+
{ SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
2456+
{ SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
2457+
};
2458+
static const struct sfdp_4bait programs[] = {
2459+
{ SNOR_HWCAPS_PP, BIT(6) },
2460+
{ SNOR_HWCAPS_PP_1_1_4, BIT(7) },
2461+
{ SNOR_HWCAPS_PP_1_4_4, BIT(8) },
2462+
};
2463+
static const struct sfdp_4bait erases[SNOR_CMD_ERASE_MAX] = {
2464+
{ 0u /* not used */, BIT(9) },
2465+
{ 0u /* not used */, BIT(10) },
2466+
{ 0u /* not used */, BIT(11) },
2467+
{ 0u /* not used */, BIT(12) },
2468+
};
2469+
u32 dwords[2], addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
2470+
struct spi_nor_erase_map *map = &nor->erase_map;
2471+
int i, err;
2472+
2473+
if (param_header->major != SFDP_JESD216_MAJOR ||
2474+
param_header->length < ARRAY_SIZE(dwords))
2475+
return -EINVAL;
2476+
2477+
/* Read the 4-byte Address Instruction Table. */
2478+
addr = SFDP_PARAM_HEADER_PTP(param_header);
2479+
err = spi_nor_read_sfdp(nor, addr, sizeof(dwords), dwords);
2480+
if (err)
2481+
return err;
2482+
2483+
/* Fix endianness of the 4BAIT DWORDs. */
2484+
for (i = 0; i < ARRAY_SIZE(dwords); i++)
2485+
dwords[i] = le32_to_cpu(dwords[i]);
2486+
2487+
/*
2488+
* Compute the subset of (Fast) Read commands for which the 4-byte
2489+
* version is supported.
2490+
*/
2491+
discard_hwcaps = 0;
2492+
read_hwcaps = 0;
2493+
for (i = 0; i < ARRAY_SIZE(reads); i++) {
2494+
const struct sfdp_4bait *read = &reads[i];
2495+
2496+
discard_hwcaps |= read->hwcaps;
2497+
if ((params->hwcaps.mask & read->hwcaps) &&
2498+
(dwords[0] & read->supported_bit))
2499+
read_hwcaps |= read->hwcaps;
2500+
}
2501+
2502+
/*
2503+
* Compute the subset of Page Program commands for which the 4-byte
2504+
* version is supported.
2505+
*/
2506+
pp_hwcaps = 0;
2507+
for (i = 0; i < ARRAY_SIZE(programs); i++) {
2508+
const struct sfdp_4bait *program = &programs[i];
2509+
2510+
discard_hwcaps |= program->hwcaps;
2511+
if ((params->hwcaps.mask & program->hwcaps) &&
2512+
(dwords[0] & program->supported_bit))
2513+
pp_hwcaps |= program->hwcaps;
2514+
}
2515+
2516+
/*
2517+
* Compute the subet of Sector Erase commands for which the 4-byte
2518+
* version is supported.
2519+
*/
2520+
erase_mask = 0;
2521+
for (i = 0; i < SNOR_CMD_ERASE_MAX; i++) {
2522+
const struct sfdp_4bait *erase = &erases[i];
2523+
2524+
if ((map->commands[i].size > 0) &&
2525+
(dwords[0] & erase->supported_bit))
2526+
erase_mask |= BIT(i);
2527+
}
2528+
2529+
/*
2530+
* We need at least one 4-byte op code per read, program and erase
2531+
* operation; the .read(), .write() and .erase() hooks share the
2532+
* nor->addr_width value.
2533+
*/
2534+
if (!read_hwcaps || !pp_hwcaps || !erase_mask)
2535+
return 0;
2536+
2537+
/*
2538+
* Discard all operations from the 4-byte instruction set which are
2539+
* not supported by this memory.
2540+
*/
2541+
params->hwcaps.mask &= ~discard_hwcaps;
2542+
params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
2543+
2544+
/* Use the 4-byte address instruction set. */
2545+
for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
2546+
struct spi_nor_read_command *read_cmd = &params->reads[i];
2547+
2548+
read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
2549+
}
2550+
for (i = 0; i < SNOR_CMD_PP_MAX; i++) {
2551+
struct spi_nor_pp_command *pp_cmd = &params->page_programs[i];
2552+
2553+
pp_cmd->opcode = spi_nor_convert_3to4_program(pp_cmd->opcode);
2554+
}
2555+
for (i = 0; i < SNOR_CMD_ERASE_MAX; i++) {
2556+
struct spi_nor_erase_command *erase_cmd = &map->commands[i];
2557+
2558+
if (erase_mask & BIT(i))
2559+
erase_cmd->opcode = (dwords[1] >> (i * 8)) & 0xFF;
2560+
else
2561+
spi_nor_set_erase_command(erase_cmd, 0u, 0xFF);
2562+
}
2563+
2564+
/*
2565+
* We set nor->addr_width here to skip spi_nor_set_4byte_opcodes()
2566+
* later because this latest function implements a legacy quirk for
2567+
* the erase size of Spansion memory. However this quirk is no longer
2568+
* needed with new SFDP compliant memories.
2569+
*/
2570+
nor->addr_width = 4;
2571+
nor->flags |= SPI_NOR_4B_OPCODES;
2572+
return 0;
2573+
}
2574+
24312575
/**
24322576
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
24332577
* @nor: pointer to a 'struct spi_nor'
@@ -2526,6 +2670,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
25262670
dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
25272671
break;
25282672

2673+
case SFDP_4BAIT_ID:
2674+
err = spi_nor_parse_4bait(nor, param_header, params);
2675+
break;
2676+
25292677
default:
25302678
break;
25312679
}

0 commit comments

Comments
 (0)