diff options
| author | Cyrille Pitchen <cyrille.pitchen@microchip.com> | 2018-12-06 09:43:39 -0500 |
|---|---|---|
| committer | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-12-10 15:59:08 -0500 |
| commit | 816873eaeec63ba2e58bbd514d15a7efc6e572f7 (patch) | |
| tree | 748346eb31ddb0c1ba897c56ed2a3b7dec2ce76a | |
| parent | d05e21e3cfc7f2d4d152c7f8b0738cacdc913cb5 (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.c | 193 | ||||
| -rw-r--r-- | include/linux/mtd/spi-nor.h | 1 |
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 | |||
| 3245 | struct 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 | */ | ||
| 3265 | static 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 = ¶ms->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(¶ms_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(¶ms_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(¶ms_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 */ | ||
| 3423 | out: | ||
| 3424 | kfree(dwords); | ||
| 3425 | return ret; | ||
