aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/raw/cadence-nand-controller.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/raw/cadence-nand-controller.c')
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index f6c7102a1e32..efddc5c68afb 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -30,7 +30,6 @@
* Generic mode is used for executing rest of commands.
*/
-#define MAX_OOB_SIZE_PER_SECTOR 32
#define MAX_ADDRESS_CYC 6
#define MAX_ERASE_ADDRESS_CYC 3
#define MAX_DATA_SIZE 0xFFFC
@@ -190,6 +189,7 @@
/* BCH Engine identification register 3. */
#define BCH_CFG_3 0x844
+#define BCH_CFG_3_METADATA_SIZE GENMASK(23, 16)
/* Ready/Busy# line status. */
#define RBN_SETINGS 0x1004
@@ -499,6 +499,7 @@ struct cdns_nand_ctrl {
unsigned long assigned_cs;
struct list_head chips;
+ u8 bch_metadata_size;
};
struct cdns_nand_chip {
@@ -997,6 +998,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl,
return status;
cadence_nand_reset_irq(cdns_ctrl);
+ reinit_completion(&cdns_ctrl->complete);
writel_relaxed((u32)cdns_ctrl->dma_cdma_desc,
cdns_ctrl->reg + CMD_REG2);
@@ -1077,6 +1079,14 @@ static int cadence_nand_read_bch_caps(struct cdns_nand_ctrl *cdns_ctrl)
int max_step_size = 0, nstrengths, i;
u32 reg;
+ reg = readl_relaxed(cdns_ctrl->reg + BCH_CFG_3);
+ cdns_ctrl->bch_metadata_size = FIELD_GET(BCH_CFG_3_METADATA_SIZE, reg);
+ if (cdns_ctrl->bch_metadata_size < 4) {
+ dev_err(cdns_ctrl->dev,
+ "Driver needs at least 4 bytes of BCH meta data\n");
+ return -EIO;
+ }
+
reg = readl_relaxed(cdns_ctrl->reg + BCH_CFG_0);
cdns_ctrl->ecc_strengths[0] = FIELD_GET(BCH_CFG_0_CORR_CAP_0, reg);
cdns_ctrl->ecc_strengths[1] = FIELD_GET(BCH_CFG_0_CORR_CAP_1, reg);
@@ -1170,7 +1180,8 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl)
writel_relaxed(0xFFFFFFFF, cdns_ctrl->reg + INTR_STATUS);
cadence_nand_get_caps(cdns_ctrl);
- cadence_nand_read_bch_caps(cdns_ctrl);
+ if (cadence_nand_read_bch_caps(cdns_ctrl))
+ return -EIO;
/*
* Set IO width access to 8.
@@ -2585,9 +2596,8 @@ int cadence_nand_attach_chip(struct nand_chip *chip)
{
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip);
- u32 ecc_size = cdns_chip->sector_count * chip->ecc.bytes;
+ u32 ecc_size;
struct mtd_info *mtd = nand_to_mtd(chip);
- u32 max_oob_data_size;
int ret;
if (chip->options & NAND_BUSWIDTH_16) {
@@ -2603,12 +2613,9 @@ int cadence_nand_attach_chip(struct nand_chip *chip)
chip->options |= NAND_NO_SUBPAGE_WRITE;
cdns_chip->bbm_offs = chip->badblockpos;
- if (chip->options & NAND_BUSWIDTH_16) {
- cdns_chip->bbm_offs &= ~0x01;
- cdns_chip->bbm_len = 2;
- } else {
- cdns_chip->bbm_len = 1;
- }
+ cdns_chip->bbm_offs &= ~0x01;
+ /* this value should be even number */
+ cdns_chip->bbm_len = 2;
ret = nand_ecc_choose_conf(chip,
&cdns_ctrl->ecc_caps,
@@ -2625,13 +2632,12 @@ int cadence_nand_attach_chip(struct nand_chip *chip)
/* Error correction configuration. */
cdns_chip->sector_size = chip->ecc.size;
cdns_chip->sector_count = mtd->writesize / cdns_chip->sector_size;
+ ecc_size = cdns_chip->sector_count * chip->ecc.bytes;
cdns_chip->avail_oob_size = mtd->oobsize - ecc_size;
- max_oob_data_size = MAX_OOB_SIZE_PER_SECTOR;
-
- if (cdns_chip->avail_oob_size > max_oob_data_size)
- cdns_chip->avail_oob_size = max_oob_data_size;
+ if (cdns_chip->avail_oob_size > cdns_ctrl->bch_metadata_size)
+ cdns_chip->avail_oob_size = cdns_ctrl->bch_metadata_size;
if ((cdns_chip->avail_oob_size + cdns_chip->bbm_len + ecc_size)
> mtd->oobsize)