aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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];