diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c3cc66039925..7b87e2e70484 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4991,6 +4991,24 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc) return manufacturer_desc ? manufacturer_desc->name : "Unknown"; } +static void rawnand_check_data_only_read_support(struct nand_chip *chip) +{ + /* Use an arbitrary size for the check */ + if (!nand_read_data_op(chip, NULL, SZ_512, true, true)) + chip->controller->supported_op.data_only_read = 1; +} + +static void rawnand_early_check_supported_ops(struct nand_chip *chip) +{ + /* The supported_op fields should not be set by individual drivers */ + WARN_ON_ONCE(chip->controller->supported_op.data_only_read); + + if (!nand_has_exec_op(chip)) + return; + + rawnand_check_data_only_read_support(chip); +} + /* * Get the flash and manufacturer id and lookup if the type is supported. */ @@ -5023,6 +5041,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) /* Select the device */ nand_select_target(chip, 0); + rawnand_early_check_supported_ops(chip); + /* Send the command for reading device ID */ ret = nand_readid_op(chip, 0, id_data, 2); if (ret) diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 85b6d9372d80..836757717660 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip) if (!p) return -ENOMEM; - if (!nand_has_exec_op(chip) || - !nand_read_data_op(chip, p, sizeof(*p), true, true)) + if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) use_datain = true; for (i = 0; i < JEDEC_PARAM_PAGES; i++) { diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 7586befce7f9..f15ef90aec8c 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip) if (!pbuf) return -ENOMEM; - if (!nand_has_exec_op(chip) || - !nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true)) + if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) use_datain = true; for (i = 0; i < ONFI_PARAM_PAGES; i++) { diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index dcf90144d70b..28c5dce782dd 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1094,10 +1094,18 @@ struct nand_controller_ops { * * @lock: lock used to serialize accesses to the NAND controller * @ops: NAND controller operations. + * @supported_op: NAND controller known-to-be-supported operations, + * only writable by the core after initial checking. + * @supported_op.data_only_read: The controller supports reading more data from + * the bus without restarting an entire read operation nor + * changing the column. */ struct nand_controller { struct mutex lock; const struct nand_controller_ops *ops; + struct { + unsigned int data_only_read: 1; + } supported_op; }; static inline void nand_controller_init(struct nand_controller *nfc)