summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2016-04-15 09:10:30 -0400
committerBoris Brezillon <boris.brezillon@free-electrons.com>2016-06-06 07:48:32 -0400
commit614049a8d9048756bde4531cd1065b491c1af275 (patch)
tree917ed5002d798623ca61def45066a252163df57b /drivers/mtd
parentdecba6d47869f3b5f057df5add52ece92d8e3d22 (diff)
mtd: nand: sunxi: add support for DMA assisted operations
The sunxi NAND controller is able to pipeline ECC operations only when operated in DMA mode, which improves a lot NAND throughput while keeping CPU usage low. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/sunxi_nand.c330
1 files changed, 323 insertions, 7 deletions
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index a83a690688b4..ef7f6dfde80b 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -153,6 +153,7 @@
153 153
154/* define bit use in NFC_ECC_ST */ 154/* define bit use in NFC_ECC_ST */
155#define NFC_ECC_ERR(x) BIT(x) 155#define NFC_ECC_ERR(x) BIT(x)
156#define NFC_ECC_ERR_MSK GENMASK(15, 0)
156#define NFC_ECC_PAT_FOUND(x) BIT(x + 16) 157#define NFC_ECC_PAT_FOUND(x) BIT(x + 16)
157#define NFC_ECC_ERR_CNT(b, x) (((x) >> (((b) % 4) * 8)) & 0xff) 158#define NFC_ECC_ERR_CNT(b, x) (((x) >> (((b) % 4) * 8)) & 0xff)
158 159
@@ -273,6 +274,7 @@ struct sunxi_nfc {
273 unsigned long clk_rate; 274 unsigned long clk_rate;
274 struct list_head chips; 275 struct list_head chips;
275 struct completion complete; 276 struct completion complete;
277 struct dma_chan *dmac;
276}; 278};
277 279
278static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) 280static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
@@ -365,6 +367,67 @@ static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
365 return ret; 367 return ret;
366} 368}
367 369
370static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
371 int chunksize, int nchunks,
372 enum dma_data_direction ddir,
373 struct scatterlist *sg)
374{
375 struct nand_chip *nand = mtd_to_nand(mtd);
376 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
377 struct dma_async_tx_descriptor *dmad;
378 enum dma_transfer_direction tdir;
379 dma_cookie_t dmat;
380 int ret;
381
382 if (ddir == DMA_FROM_DEVICE)
383 tdir = DMA_DEV_TO_MEM;
384 else
385 tdir = DMA_MEM_TO_DEV;
386
387 sg_init_one(sg, buf, nchunks * chunksize);
388 ret = dma_map_sg(nfc->dev, sg, 1, ddir);
389 if (!ret)
390 return -ENOMEM;
391
392 dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
393 if (IS_ERR(dmad)) {
394 ret = PTR_ERR(dmad);
395 goto err_unmap_buf;
396 }
397
398 writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
399 nfc->regs + NFC_REG_CTL);
400 writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
401 writel(chunksize, nfc->regs + NFC_REG_CNT);
402 dmat = dmaengine_submit(dmad);
403
404 ret = dma_submit_error(dmat);
405 if (ret)
406 goto err_clr_dma_flag;
407
408 return 0;
409
410err_clr_dma_flag:
411 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
412 nfc->regs + NFC_REG_CTL);
413
414err_unmap_buf:
415 dma_unmap_sg(nfc->dev, sg, 1, ddir);
416 return ret;
417}
418
419static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
420 enum dma_data_direction ddir,
421 struct scatterlist *sg)
422{
423 struct nand_chip *nand = mtd_to_nand(mtd);
424 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
425
426 dma_unmap_sg(nfc->dev, sg, 1, ddir);
427 writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
428 nfc->regs + NFC_REG_CTL);
429}
430
368static int sunxi_nfc_dev_ready(struct mtd_info *mtd) 431static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
369{ 432{
370 struct nand_chip *nand = mtd_to_nand(mtd); 433 struct nand_chip *nand = mtd_to_nand(mtd);
@@ -822,17 +885,15 @@ static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
822} 885}
823 886
824static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob, 887static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
825 int step, bool *erased) 888 int step, u32 status, bool *erased)
826{ 889{
827 struct nand_chip *nand = mtd_to_nand(mtd); 890 struct nand_chip *nand = mtd_to_nand(mtd);
828 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); 891 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
829 struct nand_ecc_ctrl *ecc = &nand->ecc; 892 struct nand_ecc_ctrl *ecc = &nand->ecc;
830 u32 status, tmp; 893 u32 tmp;
831 894
832 *erased = false; 895 *erased = false;
833 896
834 status = readl(nfc->regs + NFC_REG_ECC_ST);
835
836 if (status & NFC_ECC_ERR(step)) 897 if (status & NFC_ECC_ERR(step))
837 return -EBADMSG; 898 return -EBADMSG;
838 899
@@ -898,6 +959,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
898 *cur_off = oob_off + ecc->bytes + 4; 959 *cur_off = oob_off + ecc->bytes + 4;
899 960
900 ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0, 961 ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
962 readl(nfc->regs + NFC_REG_ECC_ST),
901 &erased); 963 &erased);
902 if (erased) 964 if (erased)
903 return 1; 965 return 1;
@@ -967,6 +1029,128 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
967 *cur_off = mtd->oobsize + mtd->writesize; 1029 *cur_off = mtd->oobsize + mtd->writesize;
968} 1030}
969 1031
1032static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
1033 int oob_required, int page,
1034 int nchunks)
1035{
1036 struct nand_chip *nand = mtd_to_nand(mtd);
1037 bool randomized = nand->options & NAND_NEED_SCRAMBLING;
1038 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1039 struct nand_ecc_ctrl *ecc = &nand->ecc;
1040 unsigned int max_bitflips = 0;
1041 int ret, i, raw_mode = 0;
1042 struct scatterlist sg;
1043 u32 status;
1044
1045 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1046 if (ret)
1047 return ret;
1048
1049 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
1050 DMA_FROM_DEVICE, &sg);
1051 if (ret)
1052 return ret;
1053
1054 sunxi_nfc_hw_ecc_enable(mtd);
1055 sunxi_nfc_randomizer_config(mtd, page, false);
1056 sunxi_nfc_randomizer_enable(mtd);
1057
1058 writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
1059 NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
1060
1061 dma_async_issue_pending(nfc->dmac);
1062
1063 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
1064 nfc->regs + NFC_REG_CMD);
1065
1066 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
1067 if (ret)
1068 dmaengine_terminate_all(nfc->dmac);
1069
1070 sunxi_nfc_randomizer_disable(mtd);
1071 sunxi_nfc_hw_ecc_disable(mtd);
1072
1073 sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
1074
1075 if (ret)
1076 return ret;
1077
1078 status = readl(nfc->regs + NFC_REG_ECC_ST);
1079
1080 for (i = 0; i < nchunks; i++) {
1081 int data_off = i * ecc->size;
1082 int oob_off = i * (ecc->bytes + 4);
1083 u8 *data = buf + data_off;
1084 u8 *oob = nand->oob_poi + oob_off;
1085 bool erased;
1086
1087 ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
1088 oob_required ? oob : NULL,
1089 i, status, &erased);
1090
1091 /* ECC errors are handled in the second loop. */
1092 if (ret < 0)
1093 continue;
1094
1095 if (oob_required && !erased) {
1096 /* TODO: use DMA to retrieve OOB */
1097 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
1098 nand->read_buf(mtd, oob, ecc->bytes + 4);
1099
1100 sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
1101 !i, page);
1102 }
1103
1104 if (erased)
1105 raw_mode = 1;
1106
1107 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1108 }
1109
1110 if (status & NFC_ECC_ERR_MSK) {
1111 for (i = 0; i < nchunks; i++) {
1112 int data_off = i * ecc->size;
1113 int oob_off = i * (ecc->bytes + 4);
1114 u8 *data = buf + data_off;
1115 u8 *oob = nand->oob_poi + oob_off;
1116
1117 if (!(status & NFC_ECC_ERR(i)))
1118 continue;
1119
1120 /*
1121 * Re-read the data with the randomizer disabled to
1122 * identify bitflips in erased pages.
1123 */
1124 if (randomized) {
1125 /* TODO: use DMA to read page in raw mode */
1126 nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
1127 data_off, -1);
1128 nand->read_buf(mtd, data, ecc->size);
1129 }
1130
1131 /* TODO: use DMA to retrieve OOB */
1132 nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
1133 nand->read_buf(mtd, oob, ecc->bytes + 4);
1134
1135 ret = nand_check_erased_ecc_chunk(data, ecc->size,
1136 oob, ecc->bytes + 4,
1137 NULL, 0,
1138 ecc->strength);
1139 if (ret >= 0)
1140 raw_mode = 1;
1141
1142 sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
1143 }
1144 }
1145
1146 if (oob_required)
1147 sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
1148 NULL, !raw_mode,
1149 page);
1150
1151 return max_bitflips;
1152}
1153
970static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, 1154static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
971 const u8 *data, int data_off, 1155 const u8 *data, int data_off,
972 const u8 *oob, int oob_off, 1156 const u8 *oob, int oob_off,
@@ -1065,6 +1249,23 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
1065 return max_bitflips; 1249 return max_bitflips;
1066} 1250}
1067 1251
1252static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
1253 struct nand_chip *chip, u8 *buf,
1254 int oob_required, int page)
1255{
1256 int ret;
1257
1258 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
1259 chip->ecc.steps);
1260 if (ret >= 0)
1261 return ret;
1262
1263 /* Fallback to PIO mode */
1264 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
1265
1266 return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
1267}
1268
1068static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, 1269static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
1069 struct nand_chip *chip, 1270 struct nand_chip *chip,
1070 u32 data_offs, u32 readlen, 1271 u32 data_offs, u32 readlen,
@@ -1098,6 +1299,25 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
1098 return max_bitflips; 1299 return max_bitflips;
1099} 1300}
1100 1301
1302static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
1303 struct nand_chip *chip,
1304 u32 data_offs, u32 readlen,
1305 u8 *buf, int page)
1306{
1307 int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
1308 int ret;
1309
1310 ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
1311 if (ret >= 0)
1312 return ret;
1313
1314 /* Fallback to PIO mode */
1315 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
1316
1317 return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
1318 buf, page);
1319}
1320
1101static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, 1321static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
1102 struct nand_chip *chip, 1322 struct nand_chip *chip,
1103 const uint8_t *buf, int oob_required, 1323 const uint8_t *buf, int oob_required,
@@ -1130,6 +1350,69 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
1130 return 0; 1350 return 0;
1131} 1351}
1132 1352
1353static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
1354 struct nand_chip *chip,
1355 const u8 *buf,
1356 int oob_required,
1357 int page)
1358{
1359 struct nand_chip *nand = mtd_to_nand(mtd);
1360 struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
1361 struct nand_ecc_ctrl *ecc = &nand->ecc;
1362 struct scatterlist sg;
1363 int ret, i;
1364
1365 ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
1366 if (ret)
1367 return ret;
1368
1369 ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
1370 DMA_TO_DEVICE, &sg);
1371 if (ret)
1372 goto pio_fallback;
1373
1374 for (i = 0; i < ecc->steps; i++) {
1375 const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
1376
1377 sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
1378 }
1379
1380 sunxi_nfc_hw_ecc_enable(mtd);
1381 sunxi_nfc_randomizer_config(mtd, page, false);
1382 sunxi_nfc_randomizer_enable(mtd);
1383
1384 writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
1385 nfc->regs + NFC_REG_RCMD_SET);
1386
1387 dma_async_issue_pending(nfc->dmac);
1388
1389 writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
1390 NFC_DATA_TRANS | NFC_ACCESS_DIR,
1391 nfc->regs + NFC_REG_CMD);
1392
1393 ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
1394 if (ret)
1395 dmaengine_terminate_all(nfc->dmac);
1396
1397 sunxi_nfc_randomizer_disable(mtd);
1398 sunxi_nfc_hw_ecc_disable(mtd);
1399
1400 sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
1401
1402 if (ret)
1403 return ret;
1404
1405 if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
1406 /* TODO: use DMA to transfer extra OOB bytes ? */
1407 sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
1408 NULL, page);
1409
1410 return 0;
1411
1412pio_fallback:
1413 return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
1414}
1415
1133static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, 1416static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
1134 struct nand_chip *chip, 1417 struct nand_chip *chip,
1135 uint8_t *buf, int oob_required, 1418 uint8_t *buf, int oob_required,
@@ -1550,14 +1833,27 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
1550 struct nand_ecc_ctrl *ecc, 1833 struct nand_ecc_ctrl *ecc,
1551 struct device_node *np) 1834 struct device_node *np)
1552{ 1835{
1836 struct nand_chip *nand = mtd_to_nand(mtd);
1837 struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
1838 struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
1553 int ret; 1839 int ret;
1554 1840
1555 ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); 1841 ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
1556 if (ret) 1842 if (ret)
1557 return ret; 1843 return ret;
1558 1844
1559 ecc->read_page = sunxi_nfc_hw_ecc_read_page; 1845 if (nfc->dmac) {
1560 ecc->write_page = sunxi_nfc_hw_ecc_write_page; 1846 ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
1847 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
1848 ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
1849 nand->options |= NAND_USE_BOUNCE_BUFFER;
1850 } else {
1851 ecc->read_page = sunxi_nfc_hw_ecc_read_page;
1852 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
1853 ecc->write_page = sunxi_nfc_hw_ecc_write_page;
1854 }
1855
1856 /* TODO: support DMA for raw accesses */
1561 ecc->read_oob_raw = nand_read_oob_std; 1857 ecc->read_oob_raw = nand_read_oob_std;
1562 ecc->write_oob_raw = nand_write_oob_std; 1858 ecc->write_oob_raw = nand_write_oob_std;
1563 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; 1859 ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
@@ -1881,16 +2177,34 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
1881 if (ret) 2177 if (ret)
1882 goto out_mod_clk_unprepare; 2178 goto out_mod_clk_unprepare;
1883 2179
2180 nfc->dmac = dma_request_slave_channel(dev, "rxtx");
2181 if (nfc->dmac) {
2182 struct dma_slave_config dmac_cfg = { };
2183
2184 dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
2185 dmac_cfg.dst_addr = dmac_cfg.src_addr;
2186 dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
2187 dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
2188 dmac_cfg.src_maxburst = 4;
2189 dmac_cfg.dst_maxburst = 4;
2190 dmaengine_slave_config(nfc->dmac, &dmac_cfg);
2191 } else {
2192 dev_warn(dev, "failed to request rxtx DMA channel\n");
2193 }
2194
1884 platform_set_drvdata(pdev, nfc); 2195 platform_set_drvdata(pdev, nfc);
1885 2196
1886 ret = sunxi_nand_chips_init(dev, nfc); 2197 ret = sunxi_nand_chips_init(dev, nfc);
1887 if (ret) { 2198 if (ret) {
1888 dev_err(dev, "failed to init nand chips\n"); 2199 dev_err(dev, "failed to init nand chips\n");
1889 goto out_mod_clk_unprepare; 2200 goto out_release_dmac;
1890 } 2201 }
1891 2202
1892 return 0; 2203 return 0;
1893 2204
2205out_release_dmac:
2206 if (nfc->dmac)
2207 dma_release_channel(nfc->dmac);
1894out_mod_clk_unprepare: 2208out_mod_clk_unprepare:
1895 clk_disable_unprepare(nfc->mod_clk); 2209 clk_disable_unprepare(nfc->mod_clk);
1896out_ahb_clk_unprepare: 2210out_ahb_clk_unprepare:
@@ -1904,6 +2218,8 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
1904 struct sunxi_nfc *nfc = platform_get_drvdata(pdev); 2218 struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
1905 2219
1906 sunxi_nand_chips_cleanup(nfc); 2220 sunxi_nand_chips_cleanup(nfc);
2221 if (nfc->dmac)
2222 dma_release_channel(nfc->dmac);
1907 clk_disable_unprepare(nfc->mod_clk); 2223 clk_disable_unprepare(nfc->mod_clk);
1908 clk_disable_unprepare(nfc->ahb_clk); 2224 clk_disable_unprepare(nfc->ahb_clk);
1909 2225