Instantiate onfi_helper object for SPI NAND. Enable SPI NAND core to detect SPI NANDs with parameter page. Signed-off-by: Shivamurthy Shastri <sshivamurthy@xxxxxxxxxx> --- drivers/mtd/nand/spi/core.c | 103 ++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4c15bb58c623..b031c4a2cdf9 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -400,6 +400,100 @@ static int spinand_lock_block(struct spinand_device *spinand, u8 lock) return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock); } +/** + * spinand_read_param_page_op - Read parameter page operation + * @base: the nand device + * @page: page number where parameter page tables can be found + * @buf: buffer used to store the parameter page + * @len: length of the buffer + * + * Read parameter page + * + * Returns 0 on success, a negative error code otherwise. + */ +static int spinand_parameter_page_read(struct nand_device *base, + u8 page, void *buf, unsigned int len) +{ + struct spinand_device *spinand = nand_to_spinand(base); + struct spi_mem_op pread_op = SPINAND_PAGE_READ_OP(page); + struct spi_mem_op pread_cache_op = + SPINAND_PAGE_READ_FROM_CACHE_OP(false, + 0, + 1, + buf, + len); + u8 feature; + u8 status; + int ret; + + if (len && !buf) + return -EINVAL; + + ret = spinand_read_reg_op(spinand, REG_CFG, + &feature); + if (ret) + return ret; + + /* CFG_OTP_ENABLE is used to enable parameter page access */ + feature |= CFG_OTP_ENABLE; + + spinand_write_reg_op(spinand, REG_CFG, feature); + + ret = spi_mem_exec_op(spinand->spimem, &pread_op); + if (ret) + return ret; + + ret = spinand_wait(spinand, &status); + if (ret < 0) + return ret; + + ret = spi_mem_exec_op(spinand->spimem, &pread_cache_op); + if (ret) + return ret; + + ret = spinand_read_reg_op(spinand, REG_CFG, + &feature); + if (ret) + return ret; + + feature &= ~CFG_OTP_ENABLE; + + spinand_write_reg_op(spinand, REG_CFG, feature); + + return 0; +} + +static int check_version(struct nand_device *base, + struct nand_onfi_params *p, int *onfi_version) +{ + /* + * SPI NANDs do not necessarily support ONFI standard, + * but, parameter page looks the same as an ONFI table. + */ + if (!le16_to_cpu(p->revision)) + *onfi_version = 0; + + return 0; +} + +static int spinand_intf_data(struct nand_device *base, + struct nand_onfi_params *p) +{ + return 0; +} + +static int spinand_param_page_detect(struct spinand_device *spinand) +{ + struct nand_device *base = spinand_to_nand(spinand); + + base->helper.page = 0x01; + base->helper.check_revision = check_version; + base->helper.parameter_page_read = spinand_parameter_page_read; + base->helper.init_intf_data = spinand_intf_data; + + return nand_onfi_detect(base); +} + static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status) { struct nand_device *nand = spinand_to_nand(spinand); @@ -910,6 +1004,15 @@ static int spinand_detect(struct spinand_device *spinand) return ret; } + if (!spinand->base.memorg.pagesize) { + ret = spinand_param_page_detect(spinand); + if (ret <= 0) { + dev_err(dev, "no parameter page for %*phN\n", + SPINAND_MAX_ID_LEN, spinand->id.data); + return -ENODEV; + } + } + if (nand->memorg.ntargets > 1 && !spinand->select_target) { dev_err(dev, "SPI NANDs with more than one die must implement ->select_target()\n"); -- 2.17.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/