Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mtd: spinand: List vendor specific operations and make sure they are supported

It is probably safe to expect that all SPI controller drivers will ever
support all the most basic SPI NAND operations, such as write enable,
register reads, page program, block erases, etc. However, what about
vendor specific operations? So far nobody complained about it, but as we
are about to introduce octal DTR support, and as none of the SPI NAND
instruction set is defined in any standard, we must remain careful about
these extra operations.

One way to make sure we do not blindly get ourselves in strange
situations with vendor commands failing silently is to make the check
once for all, while probing the chip. However at this stage we have no
such list, so let's add the necessary infrastructure to allow:
- registering vendor operations,
- checking they are actually supported when appropriate.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

+31
+26
drivers/mtd/nand/spi/core.c
··· 1424 1424 spinand->op_templates = &spinand->ssdr_op_templates; 1425 1425 } 1426 1426 1427 + static int spinand_support_vendor_ops(struct spinand_device *spinand, 1428 + const struct spinand_info *info) 1429 + { 1430 + int i; 1431 + 1432 + /* 1433 + * The vendor ops array is only used in order to verify this chip and all its memory 1434 + * operations are supported. If we see patterns emerging, we could ideally name these 1435 + * operations and define them at the SPI NAND core level instead. 1436 + * For now, this only serves as a sanity check. 1437 + */ 1438 + for (i = 0; i < info->vendor_ops->nops; i++) { 1439 + const struct spi_mem_op *op = &info->vendor_ops->ops[i]; 1440 + 1441 + if (!spi_mem_supports_op(spinand->spimem, op)) 1442 + return -EOPNOTSUPP; 1443 + } 1444 + 1445 + return 0; 1446 + } 1447 + 1427 1448 static const struct spi_mem_op * 1428 1449 spinand_select_op_variant(struct spinand_device *spinand, 1429 1450 const struct spinand_op_variants *variants) ··· 1511 1490 u8 *id = spinand->id.data; 1512 1491 struct nand_device *nand = spinand_to_nand(spinand); 1513 1492 unsigned int i; 1493 + int ret; 1514 1494 1515 1495 for (i = 0; i < table_size; i++) { 1516 1496 const struct spinand_info *info = &table[i]; ··· 1556 1534 return -EOPNOTSUPP; 1557 1535 1558 1536 spinand->ssdr_op_templates.update_cache = op; 1537 + 1538 + ret = spinand_support_vendor_ops(spinand, info); 1539 + if (ret) 1540 + return ret; 1559 1541 1560 1542 return 0; 1561 1543 }
+5
include/linux/mtd/spinand.h
··· 494 494 * @op_variants.read_cache: variants of the read-cache operation 495 495 * @op_variants.write_cache: variants of the write-cache operation 496 496 * @op_variants.update_cache: variants of the update-cache operation 497 + * @vendor_ops: vendor specific operations 497 498 * @select_target: function used to select a target/die. Required only for 498 499 * multi-die chips 499 500 * @configure_chip: Align the chip configuration with the core settings ··· 519 518 const struct spinand_op_variants *write_cache; 520 519 const struct spinand_op_variants *update_cache; 521 520 } op_variants; 521 + const struct spinand_op_variants *vendor_ops; 522 522 int (*select_target)(struct spinand_device *spinand, 523 523 unsigned int target); 524 524 int (*configure_chip)(struct spinand_device *spinand); ··· 545 543 .write_cache = __write, \ 546 544 .update_cache = __update, \ 547 545 } 546 + 547 + #define SPINAND_INFO_VENDOR_OPS(__ops) \ 548 + .vendor_ops = __ops 548 549 549 550 #define SPINAND_ECCINFO(__ooblayout, __get_status) \ 550 551 .eccinfo = { \