aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@microchip.com>2018-12-06 09:43:39 -0500
committerBoris Brezillon <boris.brezillon@bootlin.com>2018-12-10 15:59:08 -0500
commit816873eaeec63ba2e58bbd514d15a7efc6e572f7 (patch)
tree748346eb31ddb0c1ba897c56ed2a3b7dec2ce76a
parentd05e21e3cfc7f2d4d152c7f8b0738cacdc913cb5 (diff)
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). Flashes that have the 4BAIT table declared can now support SPINOR_OP_PP_1_1_4_4B and SPINOR_OP_PP_1_4_4_4B opcodes. Tested on MX25L25673G. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@microchip.com> [tudor.ambarus@microchip.com: - rework erase and page program logic, - pass DMA-able buffer to spi_nor_read_sfdp(), - introduce SPI_NOR_HAS_4BAIT - various minor updates.] Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c193
-rw-r--r--include/linux/mtd/spi-nor.h1
2 files changed, 193 insertions, 1 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4896b9aaa6fa..69ed5f2b2c8c 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -121,6 +121,7 @@ struct sfdp_parameter_header {
121 121
122#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ 122#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
123#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ 123#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
124#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */
124 125
125#define SFDP_SIGNATURE 0x50444653U 126#define SFDP_SIGNATURE 0x50444653U
126#define SFDP_JESD216_MAJOR 1 127#define SFDP_JESD216_MAJOR 1
@@ -3239,6 +3240,191 @@ out:
3239 return ret; 3240 return ret;
3240} 3241}
3241 3242
3243#define SFDP_4BAIT_DWORD_MAX 2
3244
3245struct sfdp_4bait {
3246 /* The hardware capability. */
3247 u32 hwcaps;
3248
3249 /*
3250 * The <supported_bit> bit in DWORD1 of the 4BAIT tells us whether
3251 * the associated 4-byte address op code is supported.
3252 */
3253 u32 supported_bit;
3254};
3255
3256/**
3257 * spi_nor_parse_4bait() - parse the 4-Byte Address Instruction Table
3258 * @nor: pointer to a 'struct spi_nor'.
3259 * @param_header: pointer to the 'struct sfdp_parameter_header' describing
3260 * the 4-Byte Address Instruction Table length and version.
3261 * @params: pointer to the 'struct spi_nor_flash_parameter' to be.
3262 *
3263 * Return: 0 on success, -errno otherwise.
3264 */
3265static int spi_nor_parse_4bait(struct spi_nor *nor,
3266 const struct sfdp_parameter_header *param_header,
3267 struct spi_nor_flash_parameter *params)
3268{
3269 static const struct sfdp_4bait reads[] = {
3270 { SNOR_HWCAPS_READ, BIT(0) },
3271 { SNOR_HWCAPS_READ_FAST, BIT(1) },
3272 { SNOR_HWCAPS_READ_1_1_2, BIT(2) },
3273 { SNOR_HWCAPS_READ_1_2_2, BIT(3) },
3274 { SNOR_HWCAPS_READ_1_1_4, BIT(4) },
3275 { SNOR_HWCAPS_READ_1_4_4, BIT(5) },
3276 { SNOR_HWCAPS_READ_1_1_1_DTR, BIT(13) },
3277 { SNOR_HWCAPS_READ_1_2_2_DTR, BIT(14) },
3278 { SNOR_HWCAPS_READ_1_4_4_DTR, BIT(15) },
3279 };
3280 static const struct sfdp_4bait programs[] = {
3281 { SNOR_HWCAPS_PP, BIT(6) },
3282 { SNOR_HWCAPS_PP_1_1_4, BIT(7) },
3283 { SNOR_HWCAPS_PP_1_4_4, BIT(8) },
3284 };
3285 static const struct sfdp_4bait erases[SNOR_ERASE_TYPE_MAX] = {
3286 { 0u /* not used */, BIT(9) },
3287 { 0u /* not used */, BIT(10) },
3288 { 0u /* not used */, BIT(11) },
3289 { 0u /* not used */, BIT(12) },
3290 };
3291 struct spi_nor_pp_command *params_pp = params->page_programs;
3292 struct spi_nor_erase_map *map = &nor->erase_map;
3293 struct spi_nor_erase_type *erase_type = map->erase_type;
3294 u32 *dwords;
3295 size_t len;
3296 u32 addr, discard_hwcaps, read_hwcaps, pp_hwcaps, erase_mask;
3297 int i, ret;
3298
3299 if (param_header->major != SFDP_JESD216_MAJOR ||
3300 param_header->length < SFDP_4BAIT_DWORD_MAX)
3301 return -EINVAL;
3302
3303 /* Read the 4-byte Address Instruction Table. */
3304 len = sizeof(*dwords) * SFDP_4BAIT_DWORD_MAX;
3305
3306 /* Use a kmalloc'ed bounce buffer to guarantee it is DMA-able. */
3307 dwords = kmalloc(len, GFP_KERNEL);
3308 if (!dwords)
3309 return -ENOMEM;
3310
3311 addr = SFDP_PARAM_HEADER_PTP(param_header);
3312 ret = spi_nor_read_sfdp(nor, addr, len, dwords);
3313 if (ret)
3314 return ret;
3315
3316 /* Fix endianness of the 4BAIT DWORDs. */
3317 for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++)
3318 dwords[i] = le32_to_cpu(dwords[i]);
3319
3320 /*
3321 * Compute the subset of (Fast) Read commands for which the 4-byte
3322 * version is supported.
3323 */
3324 discard_hwcaps = 0;
3325 read_hwcaps = 0;
3326 for (i = 0; i < ARRAY_SIZE(reads); i++) {
3327 const struct sfdp_4bait *read = &reads[i];
3328
3329 discard_hwcaps |= read->hwcaps;
3330 if ((params->hwcaps.mask & read->hwcaps) &&
3331 (dwords[0] & read->supported_bit))
3332 read_hwcaps |= read->hwcaps;
3333 }
3334
3335 /*
3336 * Compute the subset of Page Program commands for which the 4-byte
3337 * version is supported.
3338 */
3339 pp_hwcaps = 0;
3340 for (i = 0; i < ARRAY_SIZE(programs); i++) {
3341 const struct sfdp_4bait *program = &programs[i];
3342
3343 /*
3344 * The 4 Byte Address Instruction (Optional) Table is the only
3345 * SFDP table that indicates support for Page Program Commands.
3346 * Bypass the params->hwcaps.mask and consider 4BAIT the biggest
3347 * authority for specifying Page Program support.
3348 */
3349 discard_hwcaps |= program->hwcaps;
3350 if (dwords[0] & program->supported_bit)
3351 pp_hwcaps |= program->hwcaps;
3352 }
3353
3354 /*
3355 * Compute the subset of Sector Erase commands for which the 4-byte
3356 * version is supported.
3357 */
3358 erase_mask = 0;
3359 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3360 const struct sfdp_4bait *erase = &erases[i];
3361
3362 if (dwords[0] & erase->supported_bit)
3363 erase_mask |= BIT(i);
3364 }
3365
3366 /* Replicate the sort done for the map's erase types in BFPT. */
3367 erase_mask = spi_nor_sort_erase_mask(map, erase_mask);
3368
3369 /*
3370 * We need at least one 4-byte op code per read, program and erase
3371 * operation; the .read(), .write() and .erase() hooks share the
3372 * nor->addr_width value.
3373 */
3374 if (!read_hwcaps || !pp_hwcaps || !erase_mask)
3375 goto out;
3376
3377 /*
3378 * Discard all operations from the 4-byte instruction set which are
3379 * not supported by this memory.
3380 */
3381 params->hwcaps.mask &= ~discard_hwcaps;
3382 params->hwcaps.mask |= (read_hwcaps | pp_hwcaps);
3383
3384 /* Use the 4-byte address instruction set. */
3385 for (i = 0; i < SNOR_CMD_READ_MAX; i++) {
3386 struct spi_nor_read_command *read_cmd = &params->reads[i];
3387
3388 read_cmd->opcode = spi_nor_convert_3to4_read(read_cmd->opcode);
3389 }
3390
3391 /* 4BAIT is the only SFDP table that indicates page program support. */
3392 if (pp_hwcaps & SNOR_HWCAPS_PP)
3393 spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP],
3394 SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
3395 if (pp_hwcaps & SNOR_HWCAPS_PP_1_1_4)
3396 spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_1_1_4],
3397 SPINOR_OP_PP_1_1_4_4B,
3398 SNOR_PROTO_1_1_4);
3399 if (pp_hwcaps & SNOR_HWCAPS_PP_1_4_4)
3400 spi_nor_set_pp_settings(&params_pp[SNOR_CMD_PP_1_4_4],
3401 SPINOR_OP_PP_1_4_4_4B,
3402 SNOR_PROTO_1_4_4);
3403
3404 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
3405 if (erase_mask & BIT(i))
3406 erase_type[i].opcode = (dwords[1] >>
3407 erase_type[i].idx * 8) & 0xFF;
3408 else
3409 spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
3410 }
3411
3412 /*
3413 * We set SNOR_F_HAS_4BAIT in order to skip spi_nor_set_4byte_opcodes()
3414 * later because we already did the conversion to 4byte opcodes. Also,
3415 * this latest function implements a legacy quirk for the erase size of
3416 * Spansion memory. However this quirk is no longer needed with new
3417 * SFDP compliant memories.
3418 */
3419 nor->addr_width = 4;
3420 nor->flags |= SNOR_F_4B_OPCODES | SNOR_F_HAS_4BAIT;
3421
3422 /* fall through */
3423out:
3424 kfree(dwords);
3425 return ret;