mtd: spi-nor: Add a post BFPT parsing fixup hook

Experience has proven that SFDP tables are sometimes wrong, and parsing
of these broken tables can lead to erroneous flash config.

This leaves us 2 options:

1/ set the SPI_NOR_SKIP_SFDP flag and completely ignore SFDP parsing
2/ fix things at runtime

While #1 should always work, it might imply extra work if most of the
SFDP is correct. #2 has the benefit of keeping the generic SFDP parsing
logic almost untouched while allowing SPI NOR manufacturer drivers to
fix the broken bits.

Add a spi_nor_fixups struct where we'll put all our fixup hooks, each
of them being called at a different point in the scan process.

We start a hook called just after the BFPT parsing to allow fixing up
info extracted from the BFPT section. More hooks will be added if other
sections need to be fixed.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
This commit is contained in:
Boris Brezillon 2018-12-06 11:37:35 +01:00
parent 548ed6847f
commit 2aaa5f7e0c
1 changed files with 209 additions and 178 deletions

View File

@ -42,6 +42,196 @@
#define SPI_NOR_MAX_ID_LEN 6
#define SPI_NOR_MAX_ADDR_WIDTH 4
struct spi_nor_read_command {
u8 num_mode_clocks;
u8 num_wait_states;
u8 opcode;
enum spi_nor_protocol proto;
};
struct spi_nor_pp_command {
u8 opcode;
enum spi_nor_protocol proto;
};
enum spi_nor_read_command_index {
SNOR_CMD_READ,
SNOR_CMD_READ_FAST,
SNOR_CMD_READ_1_1_1_DTR,
/* Dual SPI */
SNOR_CMD_READ_1_1_2,
SNOR_CMD_READ_1_2_2,
SNOR_CMD_READ_2_2_2,
SNOR_CMD_READ_1_2_2_DTR,
/* Quad SPI */
SNOR_CMD_READ_1_1_4,
SNOR_CMD_READ_1_4_4,
SNOR_CMD_READ_4_4_4,
SNOR_CMD_READ_1_4_4_DTR,
/* Octo SPI */
SNOR_CMD_READ_1_1_8,
SNOR_CMD_READ_1_8_8,
SNOR_CMD_READ_8_8_8,
SNOR_CMD_READ_1_8_8_DTR,
SNOR_CMD_READ_MAX
};
enum spi_nor_pp_command_index {
SNOR_CMD_PP,
/* Quad SPI */
SNOR_CMD_PP_1_1_4,
SNOR_CMD_PP_1_4_4,
SNOR_CMD_PP_4_4_4,
/* Octo SPI */
SNOR_CMD_PP_1_1_8,
SNOR_CMD_PP_1_8_8,
SNOR_CMD_PP_8_8_8,
SNOR_CMD_PP_MAX
};
struct spi_nor_flash_parameter {
u64 size;
u32 page_size;
struct spi_nor_hwcaps hwcaps;
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX];
int (*quad_enable)(struct spi_nor *nor);
};
struct sfdp_parameter_header {
u8 id_lsb;
u8 minor;
u8 major;
u8 length; /* in double words */
u8 parameter_table_pointer[3]; /* byte address */
u8 id_msb;
};
#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb)
#define SFDP_PARAM_HEADER_PTP(p) \
(((p)->parameter_table_pointer[2] << 16) | \
((p)->parameter_table_pointer[1] << 8) | \
((p)->parameter_table_pointer[0] << 0))
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
#define SFDP_SIGNATURE 0x50444653U
#define SFDP_JESD216_MAJOR 1
#define SFDP_JESD216_MINOR 0
#define SFDP_JESD216A_MINOR 5
#define SFDP_JESD216B_MINOR 6
struct sfdp_header {
u32 signature; /* Ox50444653U <=> "SFDP" */
u8 minor;
u8 major;
u8 nph; /* 0-base number of parameter headers */
u8 unused;
/* Basic Flash Parameter Table. */
struct sfdp_parameter_header bfpt_header;
};
/* Basic Flash Parameter Table */
/*
* JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
* They are indexed from 1 but C arrays are indexed from 0.
*/
#define BFPT_DWORD(i) ((i) - 1)
#define BFPT_DWORD_MAX 16
/* The first version of JESB216 defined only 9 DWORDs. */
#define BFPT_DWORD_MAX_JESD216 9
/* 1st DWORD. */
#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16)
#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17)
#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17)
#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17)
#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17)
#define BFPT_DWORD1_DTR BIT(19)
#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20)
#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21)
#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22)
/* 5th DWORD. */
#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0)
#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4)
/* 11th DWORD. */
#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4
#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4)
/* 15th DWORD. */
/*
* (from JESD216 rev B)
* Quad Enable Requirements (QER):
* - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
* reads based on instruction. DQ3/HOLD# functions are hold during
* instruction phase.
* - 001b: QE is bit 1 of status register 2. It is set via Write Status with
* two data bytes where bit 1 of the second byte is one.
* [...]
* Writing only one byte to the status register has the side-effect of
* clearing status register 2, including the QE bit. The 100b code is
* used if writing one byte to the status register does not modify
* status register 2.
* - 010b: QE is bit 6 of status register 1. It is set via Write Status with
* one data byte where bit 6 is one.
* [...]
* - 011b: QE is bit 7 of status register 2. It is set via Write status
* register 2 instruction 3Eh with one data byte where bit 7 is one.
* [...]
* The status register 2 is read using instruction 3Fh.
* - 100b: QE is bit 1 of status register 2. It is set via Write Status with
* two data bytes where bit 1 of the second byte is one.
* [...]
* In contrast to the 001b code, writing one byte to the status
* register does not modify status register 2.
* - 101b: QE is bit 1 of status register 2. Status register 1 is read using
* Read Status instruction 05h. Status register2 is read using
* instruction 35h. QE is set via Writ Status instruction 01h with
* two data bytes where bit 1 of the second byte is one.
* [...]
*/
#define BFPT_DWORD15_QER_MASK GENMASK(22, 20)
#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */
#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20)
#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */
#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
struct sfdp_bfpt {
u32 dwords[BFPT_DWORD_MAX];
};
/**
* struct spi_nor_fixups - SPI NOR fixup hooks
* @post_bfpt: called after the BFPT table has been parsed
*
* Those hooks can be used to tweak the SPI NOR configuration when the SFDP
* table is broken or not available.
*/
struct spi_nor_fixups {
int (*post_bfpt)(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt,
struct spi_nor_flash_parameter *params);
};
struct flash_info {
char *name;
@ -91,6 +281,9 @@ struct flash_info {
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
int (*quad_enable)(struct spi_nor *nor);
};
@ -2076,71 +2269,6 @@ static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
return 0;
}
struct spi_nor_read_command {
u8 num_mode_clocks;
u8 num_wait_states;
u8 opcode;
enum spi_nor_protocol proto;
};
struct spi_nor_pp_command {
u8 opcode;
enum spi_nor_protocol proto;
};
enum spi_nor_read_command_index {
SNOR_CMD_READ,
SNOR_CMD_READ_FAST,
SNOR_CMD_READ_1_1_1_DTR,
/* Dual SPI */
SNOR_CMD_READ_1_1_2,
SNOR_CMD_READ_1_2_2,
SNOR_CMD_READ_2_2_2,
SNOR_CMD_READ_1_2_2_DTR,
/* Quad SPI */
SNOR_CMD_READ_1_1_4,
SNOR_CMD_READ_1_4_4,
SNOR_CMD_READ_4_4_4,
SNOR_CMD_READ_1_4_4_DTR,
/* Octo SPI */
SNOR_CMD_READ_1_1_8,
SNOR_CMD_READ_1_8_8,
SNOR_CMD_READ_8_8_8,
SNOR_CMD_READ_1_8_8_DTR,
SNOR_CMD_READ_MAX
};
enum spi_nor_pp_command_index {
SNOR_CMD_PP,
/* Quad SPI */
SNOR_CMD_PP_1_1_4,
SNOR_CMD_PP_1_4_4,
SNOR_CMD_PP_4_4_4,
/* Octo SPI */
SNOR_CMD_PP_1_1_8,
SNOR_CMD_PP_1_8_8,
SNOR_CMD_PP_8_8_8,
SNOR_CMD_PP_MAX
};
struct spi_nor_flash_parameter {
u64 size;
u32 page_size;
struct spi_nor_hwcaps hwcaps;
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX];
int (*quad_enable)(struct spi_nor *nor);
};
static void
spi_nor_set_read_settings(struct spi_nor_read_command *read,
u8 num_mode_clocks,
@ -2263,117 +2391,6 @@ static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr,
return ret;
}
struct sfdp_parameter_header {
u8 id_lsb;
u8 minor;
u8 major;
u8 length; /* in double words */
u8 parameter_table_pointer[3]; /* byte address */
u8 id_msb;
};
#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb)
#define SFDP_PARAM_HEADER_PTP(p) \
(((p)->parameter_table_pointer[2] << 16) | \
((p)->parameter_table_pointer[1] << 8) | \
((p)->parameter_table_pointer[0] << 0))
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
#define SFDP_SIGNATURE 0x50444653U
#define SFDP_JESD216_MAJOR 1
#define SFDP_JESD216_MINOR 0
#define SFDP_JESD216A_MINOR 5
#define SFDP_JESD216B_MINOR 6
struct sfdp_header {
u32 signature; /* Ox50444653U <=> "SFDP" */
u8 minor;
u8 major;
u8 nph; /* 0-base number of parameter headers */
u8 unused;
/* Basic Flash Parameter Table. */
struct sfdp_parameter_header bfpt_header;
};
/* Basic Flash Parameter Table */
/*
* JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
* They are indexed from 1 but C arrays are indexed from 0.
*/
#define BFPT_DWORD(i) ((i) - 1)
#define BFPT_DWORD_MAX 16
/* The first version of JESB216 defined only 9 DWORDs. */
#define BFPT_DWORD_MAX_JESD216 9
/* 1st DWORD. */
#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16)
#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17)
#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17)
#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17)
#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17)
#define BFPT_DWORD1_DTR BIT(19)
#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20)
#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21)
#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22)
/* 5th DWORD. */
#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0)
#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4)
/* 11th DWORD. */
#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4
#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4)
/* 15th DWORD. */
/*
* (from JESD216 rev B)
* Quad Enable Requirements (QER):
* - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
* reads based on instruction. DQ3/HOLD# functions are hold during
* instruction phase.
* - 001b: QE is bit 1 of status register 2. It is set via Write Status with
* two data bytes where bit 1 of the second byte is one.
* [...]
* Writing only one byte to the status register has the side-effect of
* clearing status register 2, including the QE bit. The 100b code is
* used if writing one byte to the status register does not modify
* status register 2.
* - 010b: QE is bit 6 of status register 1. It is set via Write Status with
* one data byte where bit 6 is one.
* [...]
* - 011b: QE is bit 7 of status register 2. It is set via Write status
* register 2 instruction 3Eh with one data byte where bit 7 is one.
* [...]
* The status register 2 is read using instruction 3Fh.
* - 100b: QE is bit 1 of status register 2. It is set via Write Status with
* two data bytes where bit 1 of the second byte is one.
* [...]
* In contrast to the 001b code, writing one byte to the status
* register does not modify status register 2.
* - 101b: QE is bit 1 of status register 2. Status register 1 is read using
* Read Status instruction 05h. Status register2 is read using
* instruction 35h. QE is set via Writ Status instruction 01h with
* two data bytes where bit 1 of the second byte is one.
* [...]
*/
#define BFPT_DWORD15_QER_MASK GENMASK(22, 20)
#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */
#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20)
#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */
#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
struct sfdp_bfpt {
u32 dwords[BFPT_DWORD_MAX];
};
/* Fast Read settings. */
static inline void
@ -2617,6 +2634,19 @@ static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
map->uniform_erase_type = erase_mask;
}
static int
spi_nor_post_bfpt_fixups(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt,
struct spi_nor_flash_parameter *params)
{
if (nor->info->fixups && nor->info->fixups->post_bfpt)
return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt,
params);
return 0;
}
/**
* spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
* @nor: pointer to a 'struct spi_nor'
@ -2769,7 +2799,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
/* Stop here if not JESD216 rev A or later. */
if (bfpt_header->length < BFPT_DWORD_MAX)
return 0;
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
params);
/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
params->page_size = bfpt.dwords[BFPT_DWORD(11)];
@ -2804,7 +2835,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return -EINVAL;
}
return 0;
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
}
#define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)