From 7670ec4a14891a1a182b98a9c403ffbf6b49e4b1 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:39:56 +0800 Subject: [PATCH 5/6] drivers: mtd: spinand: Add calibration support for spinand Signed-off-by: SkyLake.Huang --- drivers/mtd/nand/spi/core.c | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -979,6 +979,56 @@ static int spinand_manufacturer_match(st return -ENOTSUPP; } +int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) { + struct spinand_device *spinand = (struct spinand_device *)priv; + struct device *dev = &spinand->spimem->spi->dev; + struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, buf, readlen); + struct nand_pos pos; + struct nand_page_io_req req; + u8 status; + int ret; + + if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) { + dev_err(dev, "Must provide correct addr(length) for spinand calibration\n"); + return -EINVAL; + } + + ret = spinand_reset_op(spinand); + if (ret) + return ret; + + /* We should store our golden data in first target because + * we can't switch target at this moment. + */ + pos = (struct nand_pos){ + .target = 0, + .lun = *addr, + .plane = *(addr+1), + .eraseblock = *(addr+2), + .page = *(addr+3), + }; + + req = (struct nand_page_io_req){ + .pos = pos, + .dataoffs = *(addr+4), + .datalen = readlen, + .databuf.in = buf, + .mode = MTD_OPS_AUTO_OOB, + }; + + ret = spinand_load_page_op(spinand, &req); + if (ret) + return ret; + + ret = spinand_wait(spinand, &status); + if (ret < 0) + return ret; + + ret = spi_mem_exec_op(spinand->spimem, &op); + + return 0; +} + static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; @@ -1229,6 +1279,10 @@ static int spinand_init(struct spinand_d if (!spinand->scratchbuf) return -ENOMEM; + ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand); + if (ret) + dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret); + ret = spinand_detect(spinand); if (ret) goto err_free_bufs;