summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_denali.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-10-30 12:30:31 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2020-11-10 08:42:26 +0100
commitb6bcd96de5a75bdc5d06a06f2efffc2d89e346ec (patch)
tree3d6f1260487b7c2fd9cfef201203b9dbc933a31c /drivers/mtd/nand/nand_denali.c
parent18a8bfd6a7ea8e93b88fba49b73348b943713076 (diff)
downloadbarebox-b6bcd96de5a75bdc5d06a06f2efffc2d89e346ec.tar.gz
barebox-b6bcd96de5a75bdc5d06a06f2efffc2d89e346ec.tar.xz
mtd: nand: Update to Linux-5.9
This updates the barebox NAND layer and parts of the mtd layer to Linux-5.9. This patch is huge, but the barebox NAND layer is so far away from the Linux NAND layer that a step by step update would have taken ages. Unlike Linux barebox has functions to mark a block as good. This feature has been preserved. Also barebox used to make NAND write support optional, this feature is lost during the update for the sake of better compatibility to the Linux NAND layer. This patch has been tested: - GPMI aka nand_mxs on i.MX6 - nand_imx on i.MX25 - nand_omap_gpmc on AM335x - atmel_nand on Atmel sama5d3 - nand_denali on SoCFPGA Currently untested: - nand_orion - nand_mrvl_nfc - nand_s3c24xx The nand_denali driver is tested with the update of that driver to Linux-5.9 following in the next patch. I could only test the drivers with the NAND chips found on my boards, so there's still enough room for regressions, especially given that the NAND drivers themselves are mostly not updated. With the NAND layer being up-to-date with Linux it should hopefully be easy to update drivers to their Linux counterpart as well if necessary. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mtd/nand/nand_denali.c')
-rw-r--r--drivers/mtd/nand/nand_denali.c67
1 files changed, 29 insertions, 38 deletions
diff --git a/drivers/mtd/nand/nand_denali.c b/drivers/mtd/nand/nand_denali.c
index bffcbd8a7f..49028bf082 100644
--- a/drivers/mtd/nand/nand_denali.c
+++ b/drivers/mtd/nand/nand_denali.c
@@ -23,6 +23,7 @@
#include <malloc.h>
#include <init.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand.h>
#include <io.h>
#include <clock.h>
@@ -888,6 +889,8 @@ static bool is_erased(uint8_t *buf, int len)
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
uint32_t irq_status, unsigned int *max_bitflips)
{
+ struct nand_chip *chip = &denali->nand;
+ struct mtd_info *mtd = nand_to_mtd(chip);
bool check_erased_page = false;
unsigned int bitflips = 0;
@@ -933,7 +936,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
- denali->nand.mtd.ecc_stats.corrected++;
+ mtd->ecc_stats.corrected++;
bitflips++;
}
} else {
@@ -995,7 +998,8 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
* writes a page. user specifies type, and this function handles the
* configuration details.
*/
-static int write_page(struct nand_chip *chip, const uint8_t *buf, bool raw_xfer)
+static int write_page(struct nand_chip *chip, const uint8_t *buf, bool raw_xfer,
+ int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = nand_to_denali(chip);
@@ -1012,6 +1016,8 @@ static int write_page(struct nand_chip *chip, const uint8_t *buf, bool raw_xfer)
*/
setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer);
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
/* copy buffer into DMA buffer */
memcpy(denali->buf.buf, buf, mtd->writesize);
@@ -1041,7 +1047,7 @@ static int write_page(struct nand_chip *chip, const uint8_t *buf, bool raw_xfer)
denali_enable_dma(denali, false);
dma_sync_single_for_cpu(addr, size, DMA_TO_DEVICE);
- return 0;
+ return nand_prog_page_end_op(chip);
}
/* NAND core entry points */
@@ -1052,13 +1058,13 @@ static int write_page(struct nand_chip *chip, const uint8_t *buf, bool raw_xfer)
* by write_page above.
*/
static int denali_write_page(struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
+ const uint8_t *buf, int oob_required, int page)
{
/*
* for regular page writes, we let HW handle all the ECC
* data written to the device.
*/
- return write_page(chip, buf, false);
+ return write_page(chip, buf, false, page);
}
/*
@@ -1067,13 +1073,13 @@ static int denali_write_page(struct nand_chip *chip,
* write_page() function above.
*/
static int denali_write_page_raw(struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
+ const uint8_t *buf, int oob_required, int page)
{
/*
* for raw page writes, we want to disable ECC and simply write
* whatever data is in the buffer.
*/
- return write_page(chip, buf, true);
+ return write_page(chip, buf, true, page);
}
static int denali_write_oob(struct nand_chip *chip, int page)
@@ -1104,15 +1110,10 @@ static int denali_read_page(struct nand_chip *chip,
(INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR);
bool check_erased_page = false;
- if (page != denali->page) {
- dev_err(denali->dev,
- "IN %s: page %d is not equal to denali->page %d",
- __func__, page, denali->page);
- BUG();
- }
-
setup_ecc_for_xfer(denali, true, false);
+ nand_read_page_op(chip, page, 0, NULL, 0);
+
denali_enable_dma(denali, true);
dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE);
@@ -1161,6 +1162,8 @@ static int denali_read_page_raw(struct nand_chip *chip,
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
+ nand_read_page_op(chip, page, 0, NULL, 0);
+
if (page != denali->page) {
dev_err(denali->dev,
"IN %s: page %d is not equal to denali->page %d",
@@ -1227,11 +1230,8 @@ static int denali_waitfunc(struct nand_chip *chip)
static void denali_cmdfunc(struct nand_chip *chip, unsigned int cmd, int col,
int page)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = nand_to_denali(chip);
uint32_t addr, id;
- uint32_t pages_per_block;
- uint32_t block;
int i;
switch (cmd) {
@@ -1296,18 +1296,6 @@ static void denali_cmdfunc(struct nand_chip *chip, unsigned int cmd, int col,
case NAND_CMD_READOOB:
/* TODO: Read OOB data */
break;
- case NAND_CMD_UNLOCK1:
- pages_per_block = mtd->erasesize / mtd->writesize;
- block = page / pages_per_block;
- addr = (uint32_t)MODE_10 | (block * pages_per_block);
- index_addr(denali, addr, 0x10);
- break;
- case NAND_CMD_UNLOCK2:
- pages_per_block = mtd->erasesize / mtd->writesize;
- block = (page+pages_per_block-1) / pages_per_block;
- addr = (uint32_t)MODE_10 | (block * pages_per_block);
- index_addr(denali, addr, 0x11);
- break;
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
addr = MODE_10 | BANK(denali->flash_bank) | page;
@@ -1376,9 +1364,10 @@ static void denali_drv_init(struct denali_nand_info *denali)
int denali_init(struct denali_nand_info *denali)
{
struct nand_chip *nand = &denali->nand;
- struct mtd_info *mtd = &nand->mtd;
+ struct mtd_info *mtd = nand_to_mtd(nand);
int ret = 0;
uint32_t val;
+ struct nand_ecclayout *ecclayout;
if (denali->platform == INTEL_CE4100) {
/*
@@ -1477,7 +1466,7 @@ int denali_init(struct denali_nand_info *denali)
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
nand->ecc.strength = 15;
- nand->ecc.layout = &nand_15bit_oob;
+ ecclayout = &nand_15bit_oob;
nand->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (mtd->oobsize < (denali->bbtskipbytes +
@@ -1487,24 +1476,26 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
} else {
nand->ecc.strength = 8;
- nand->ecc.layout = &nand_8bit_oob;
+ ecclayout = &nand_8bit_oob;
nand->ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}
- nand->ecc.layout->oobfree[0].offset =
- denali->bbtskipbytes + nand->ecc.layout->eccbytes;
- nand->ecc.layout->oobfree[0].length =
- mtd->oobsize - nand->ecc.layout->eccbytes -
+ ecclayout->oobfree[0].offset =
+ denali->bbtskipbytes + ecclayout->eccbytes;
+ ecclayout->oobfree[0].length =
+ mtd->oobsize - ecclayout->eccbytes -
denali->bbtskipbytes;
+ mtd_set_ecclayout(mtd, ecclayout);
+
/*
* Let driver know the total blocks number and how many blocks
* contained by each nand chip. blksperchip will help driver to
* know how many blocks is taken by FW.
*/
denali->totalblks = mtd->size >> nand->phys_erase_shift;
- denali->blksperchip = denali->totalblks / nand->numchips;
+ denali->blksperchip = denali->totalblks;
/* override the default read operations */
nand->ecc.size = ECC_SECTOR_SIZE;
@@ -1534,7 +1525,7 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
- return add_mtd_nand_device(nand, "nand");
+ return add_mtd_nand_device(mtd, "nand");
failed_req_irq:
denali_irq_cleanup(denali->irq, denali);