aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris BREZILLON <boris.brezillon@free-electrons.com>2014-11-30 13:10:29 -0500
committerBrian Norris <computersforpeace@gmail.com>2014-12-01 03:41:50 -0500
commitda3bc42c1becfde026656df50ad155239d4e1a6b (patch)
tree3c316a22370984f58c5a603ee2644809104ee8f3
parent66de54a761831f2e9f31941fa49c94bfcde5f586 (diff)
mtd: nand: gpmi: add proper raw access support
Several MTD users (either in user or kernel space) expect a valid raw access support to NAND chip devices. This is particularly true for testing tools which are often touching the data stored in a NAND chip in raw mode to artificially generate errors. The GPMI drivers do not implemenent raw access functions, and thus rely on default HW_ECC scheme implementation. The default implementation consider the data and OOB area as properly separated in their respective NAND section, which is not true for the GPMI controller. In this driver/controller some OOB data are stored at the beginning of the NAND data area (these data are called metadata in the driver), then ECC bytes are interleaved with data chunk (which is similar to the HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as OOB data. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Tested-by: Huang Shijie <shijie8@gmail.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c183
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h2
2 files changed, 185 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 959cb9b70310..987de1e3821c 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
791 this->page_buffer_phys); 791 this->page_buffer_phys);
792 kfree(this->cmd_buffer); 792 kfree(this->cmd_buffer);
793 kfree(this->data_buffer_dma); 793 kfree(this->data_buffer_dma);
794 kfree(this->raw_buffer);
794 795
795 this->cmd_buffer = NULL; 796 this->cmd_buffer = NULL;
796 this->data_buffer_dma = NULL; 797 this->data_buffer_dma = NULL;
@@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
837 if (!this->page_buffer_virt) 838 if (!this->page_buffer_virt)
838 goto error_alloc; 839 goto error_alloc;
839 840
841 this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
842 if (!this->raw_buffer)
843 goto error_alloc;
840 844
841 /* Slice up the page buffer. */ 845 /* Slice up the page buffer. */
842 this->payload_virt = this->page_buffer_virt; 846 this->payload_virt = this->page_buffer_virt;
@@ -1347,6 +1351,183 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
1347 return status & NAND_STATUS_FAIL ? -EIO : 0; 1351 return status & NAND_STATUS_FAIL ? -EIO : 0;
1348} 1352}
1349 1353
1354/*
1355 * This function reads a NAND page without involving the ECC engine (no HW
1356 * ECC correction).
1357 * The tricky part in the GPMI/BCH controller is that it stores ECC bits
1358 * inline (interleaved with payload DATA), and do not align data chunk on
1359 * byte boundaries.
1360 * We thus need to take care moving the payload data and ECC bits stored in the
1361 * page into the provided buffers, which is why we're using gpmi_copy_bits.
1362 *
1363 * See set_geometry_by_ecc_info inline comments to have a full description
1364 * of the layout used by the GPMI controller.
1365 */
1366static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
1367 struct nand_chip *chip, uint8_t *buf,
1368 int oob_required, int page)
1369{
1370 struct gpmi_nand_data *this = chip->priv;
1371 struct bch_geometry *nfc_geo = &this->bch_geometry;
1372 int eccsize = nfc_geo->ecc_chunk_size;
1373 int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
1374 u8 *tmp_buf = this->raw_buffer;
1375 size_t src_bit_off;
1376 size_t oob_bit_off;
1377 size_t oob_byte_off;
1378 uint8_t *oob = chip->oob_poi;
1379 int step;
1380
1381 chip->read_buf(mtd, tmp_buf,
1382 mtd->writesize + mtd->oobsize);
1383
1384 /*
1385 * If required, swap the bad block marker and the data stored in the
1386 * metadata section, so that we don't wrongly consider a block as bad.
1387 *
1388 * See the layout description for a detailed explanation on why this
1389 * is needed.
1390 */
1391 if (this->swap_block_mark) {
1392 u8 swap = tmp_buf[0];
1393
1394 tmp_buf[0] = tmp_buf[mtd->writesize];
1395 tmp_buf[mtd->writesize] = swap;
1396 }
1397
1398 /*
1399 * Copy the metadata section into the oob buffer (this section is
1400 * guaranteed to be aligned on a byte boundary).
1401 */
1402 if (oob_required)
1403 memcpy(oob, tmp_buf, nfc_geo->metadata_size);
1404
1405 oob_bit_off = nfc_geo->metadata_size * 8;
1406 src_bit_off = oob_bit_off;
1407
1408 /* Extract interleaved payload data and ECC bits */
1409 for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
1410 if (buf)
1411 gpmi_copy_bits(buf, step * eccsize * 8,
1412 tmp_buf, src_bit_off,
1413 eccsize * 8);
1414 src_bit_off += eccsize * 8;
1415
1416 /* Align last ECC block to align a byte boundary */
1417 if (step == nfc_geo->ecc_chunk_count - 1 &&
1418 (oob_bit_off + eccbits) % 8)
1419 eccbits += 8 - ((oob_bit_off + eccbits) % 8);
1420
1421 if (oob_required)
1422 gpmi_copy_bits(oob, oob_bit_off,
1423 tmp_buf, src_bit_off,
1424 eccbits);
1425
1426 src_bit_off += eccbits;
1427 oob_bit_off += eccbits;
1428 }
1429
1430 if (oob_required) {
1431 oob_byte_off = oob_bit_off / 8;
1432
1433 if (oob_byte_off < mtd->oobsize)
1434 memcpy(oob + oob_byte_off,
1435 tmp_buf + mtd->writesize + oob_byte_off,
1436 mtd->oobsize - oob_byte_off);
1437 }
1438
1439 return 0;
1440}
1441
1442/*
1443 * This function writes a NAND page without involving the ECC engine (no HW
1444 * ECC generation).
1445 * The tricky part in the GPMI/BCH controller is that it stores ECC bits
1446 * inline (interleaved with payload DATA), and do not align data chunk on
1447 * byte boundaries.
1448 * We thus need to take care moving the OOB area at the right place in the
1449 * final page, which is why we're using gpmi_copy_bits.
1450 *
1451 * See set_geometry_by_ecc_info inline comments to have a full description
1452 * of the layout used by the GPMI controller.
1453 */
1454static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
1455 struct nand_chip *chip,
1456 const uint8_t *buf,
1457 int oob_required)
1458{
1459 struct gpmi_nand_data *this = chip->priv;
1460 struct bch_geometry *nfc_geo = &this->bch_geometry;
1461 int eccsize = nfc_geo->ecc_chunk_size;
1462 int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
1463 u8 *tmp_buf = this->raw_buffer;
1464 uint8_t *oob = chip->oob_poi;
1465 size_t dst_bit_off;
1466 size_t oob_bit_off;
1467 size_t oob_byte_off;
1468 int step;
1469
1470 /*
1471 * Initialize all bits to 1 in case we don't have a buffer for the
1472 * payload or oob data in order to leave unspecified bits of data
1473 * to their initial state.
1474 */
1475 if (!buf || !oob_required)
1476 memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
1477
1478 /*
1479 * First copy the metadata section (stored in oob buffer) at the
1480 * beginning of the page, as imposed by the GPMI layout.
1481 */
1482 memcpy(tmp_buf, oob, nfc_geo->metadata_size);
1483 oob_bit_off = nfc_geo->metadata_size * 8;
1484 dst_bit_off = oob_bit_off;
1485
1486 /* Interleave payload data and ECC bits */
1487 for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
1488 if (buf)
1489 gpmi_copy_bits(tmp_buf, dst_bit_off,
1490 buf, step * eccsize * 8, eccsize * 8);
1491 dst_bit_off += eccsize * 8;
1492
1493 /* Align last ECC block to align a byte boundary */
1494 if (step == nfc_geo->ecc_chunk_count - 1 &&
1495 (oob_bit_off + eccbits) % 8)
1496 eccbits += 8 - ((oob_bit_off + eccbits) % 8);
1497
1498 if (oob_required)
1499 gpmi_copy_bits(tmp_buf, dst_bit_off,
1500 oob, oob_bit_off, eccbits);
1501
1502 dst_bit_off += eccbits;
1503 oob_bit_off += eccbits;
1504 }
1505
1506 oob_byte_off = oob_bit_off / 8;
1507
1508 if (oob_required && oob_byte_off < mtd->oobsize)
1509 memcpy(tmp_buf + mtd->writesize + oob_byte_off,
1510 oob + oob_byte_off, mtd->oobsize - oob_byte_off);
1511
1512 /*
1513 * If required, swap the bad block marker and the first byte of the
1514 * metadata section, so that we don't modify the bad block marker.
1515 *
1516 * See the layout description for a detailed explanation on why this
1517 * is needed.
1518 */
1519 if (this->swap_block_mark) {
1520 u8 swap = tmp_buf[0];
1521
1522 tmp_buf[0] = tmp_buf[mtd->writesize];
1523 tmp_buf[mtd->writesize] = swap;
1524 }
1525
1526 chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize);
1527
1528 return 0;
1529}
1530
1350static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) 1531static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
1351{ 1532{
1352 struct nand_chip *chip = mtd->priv; 1533 struct nand_chip *chip = mtd->priv;
@@ -1664,6 +1845,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
1664 ecc->write_page = gpmi_ecc_write_page; 1845 ecc->write_page = gpmi_ecc_write_page;
1665 ecc->read_oob = gpmi_ecc_read_oob; 1846 ecc->read_oob = gpmi_ecc_read_oob;
1666 ecc->write_oob = gpmi_ecc_write_oob; 1847 ecc->write_oob = gpmi_ecc_write_oob;
1848 ecc->read_page_raw = gpmi_ecc_read_page_raw;
1849 ecc->write_page_raw = gpmi_ecc_write_page_raw;
1667 ecc->mode = NAND_ECC_HW; 1850 ecc->mode = NAND_ECC_HW;
1668 ecc->size = bch_geo->ecc_chunk_size; 1851 ecc->size = bch_geo->ecc_chunk_size;
1669 ecc->strength = bch_geo->ecc_strength; 1852 ecc->strength = bch_geo->ecc_strength;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 20da1f139853..544062f65020 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -189,6 +189,8 @@ struct gpmi_nand_data {
189 void *auxiliary_virt; 189 void *auxiliary_virt;
190 dma_addr_t auxiliary_phys; 190 dma_addr_t auxiliary_phys;
191 191
192 void *raw_buffer;
193
192 /* DMA channels */ 194 /* DMA channels */
193#define DMA_CHANS 8 195#define DMA_CHANS 8
194 struct dma_chan *dma_chans[DMA_CHANS]; 196 struct dma_chan *dma_chans[DMA_CHANS];