developer | d82d9fc | 2022-06-23 19:03:51 +0800 | [diff] [blame] | 1 | From 6bd88d34cb5a5cb1d7c544c9f5b430105b000308 Mon Sep 17 00:00:00 2001 |
| 2 | From: "SkyLake.Huang" <skylake.huang@mediatek.com> |
| 3 | Date: Thu, 23 Jun 2022 18:39:56 +0800 |
| 4 | Subject: [PATCH] drivers: mtd: spinand: Add calibration support for spinand |
| 5 | |
| 6 | Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com> |
| 7 | --- |
| 8 | drivers/mtd/nand/spi/core.c | 58 +++++++++++++++++++++++++++++++++++++ |
| 9 | 1 file changed, 58 insertions(+) |
| 10 | |
| 11 | diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c |
| 12 | index 9f5f95ff7..b346c7a8a 100644 |
| 13 | --- a/drivers/mtd/nand/spi/core.c |
| 14 | +++ b/drivers/mtd/nand/spi/core.c |
| 15 | @@ -789,6 +789,60 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, |
| 16 | return -ENOTSUPP; |
| 17 | } |
| 18 | |
| 19 | +int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) { |
| 20 | + int ret; |
| 21 | + u8 status; |
| 22 | + struct spinand_device *spinand = (struct spinand_device *)priv; |
| 23 | + struct device *dev = &spinand->spimem->spi->dev; |
| 24 | + |
| 25 | + typedef struct nand_pos my_pos; |
| 26 | + my_pos pos; |
| 27 | + typedef struct nand_page_io_req my_req; |
| 28 | + my_req req; |
| 29 | + |
| 30 | + if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) { |
| 31 | + dev_err(dev, "Must provide correct addr(length) for spinand calibration\n"); |
| 32 | + return -EINVAL; |
| 33 | + } |
| 34 | + |
| 35 | + ret = spinand_reset_op(spinand); |
| 36 | + if (ret) |
| 37 | + return ret; |
| 38 | + |
| 39 | + /* We should store our golden data in first target because |
| 40 | + * we can't switch target at this moment. |
| 41 | + */ |
| 42 | + pos = (my_pos){ |
| 43 | + .target = 0, |
| 44 | + .lun = *addr, |
| 45 | + .plane = *(addr+1), |
| 46 | + .eraseblock = *(addr+2), |
| 47 | + .page = *(addr+3), |
| 48 | + }; |
| 49 | + |
| 50 | + req = (my_req){ |
| 51 | + .pos = pos, |
| 52 | + .dataoffs = *(addr+4), |
| 53 | + .datalen = readlen, |
| 54 | + .databuf.in = buf, |
| 55 | + .mode = MTD_OPS_AUTO_OOB, |
| 56 | + }; |
| 57 | + |
| 58 | + ret = spinand_load_page_op(spinand, &req); |
| 59 | + if (ret) |
| 60 | + return ret; |
| 61 | + |
| 62 | + ret = spinand_wait(spinand, &status); |
| 63 | + if (ret < 0) |
| 64 | + return ret; |
| 65 | + |
| 66 | + struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP( |
| 67 | + false, 0, 1, buf, readlen); |
| 68 | + ret = spi_mem_exec_op(spinand->spimem, &op); |
| 69 | + |
| 70 | + return 0; |
| 71 | +} |
| 72 | + |
| 73 | static int spinand_id_detect(struct spinand_device *spinand) |
| 74 | { |
| 75 | u8 *id = spinand->id.data; |
| 76 | @@ -1004,6 +1058,10 @@ static int spinand_init(struct spinand_device *spinand) |
| 77 | if (!spinand->scratchbuf) |
| 78 | return -ENOMEM; |
| 79 | |
| 80 | + ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand); |
| 81 | + if (ret) |
| 82 | + dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret); |
| 83 | + |
| 84 | ret = spinand_detect(spinand); |
| 85 | if (ret) |
| 86 | goto err_free_bufs; |
| 87 | -- |
| 88 | 2.18.0 |
| 89 | |