diff options
Diffstat (limited to 'drivers/mtd/nand/gpmi-nand/gpmi-nand.c')
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index f638cd8077ca..959cb9b70310 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -285,9 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) geo->ecc_strength = get_ecc_strength(this); if (!gpmi_check_ecc(this)) { dev_err(this->dev, - "We can not support this nand chip." - " Its required ecc strength(%d) is beyond our" - " capability(%d).\n", geo->ecc_strength, + "required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n", + geo->ecc_strength, this->devdata->bch_max_ecc_strength); return -EINVAL; } @@ -1082,6 +1081,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int first, last, marker_pos; int ecc_parity_size; int col = 0; + int old_swap_block_mark = this->swap_block_mark; /* The size of ECC parity */ ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; @@ -1090,17 +1090,21 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, first = offs / size; last = (offs + len - 1) / size; - /* - * Find the chunk which contains the Block Marker. If this chunk is - * in the range of [first, last], we have to read out the whole page. - * Why? since we had swapped the data at the position of Block Marker - * to the metadata which is bound with the chunk 0. - */ - marker_pos = geo->block_mark_byte_offset / size; - if (last >= marker_pos && first <= marker_pos) { - dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n", + if (this->swap_block_mark) { + /* + * Find the chunk which contains the Block Marker. + * If this chunk is in the range of [first, last], + * we have to read out the whole page. + * Why? since we had swapped the data at the position of Block + * Marker to the metadata which is bound with the chunk 0. + */ + marker_pos = geo->block_mark_byte_offset / size; + if (last >= marker_pos && first <= marker_pos) { + dev_dbg(this->dev, + "page:%d, first:%d, last:%d, marker at:%d\n", page, first, last, marker_pos); - return gpmi_ecc_read_page(mtd, chip, buf, 0, page); + return gpmi_ecc_read_page(mtd, chip, buf, 0, page); + } } meta = geo->metadata_size; @@ -1146,7 +1150,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1); this->bch_geometry = old_geo; - this->swap_block_mark = true; + this->swap_block_mark = old_swap_block_mark; return max_bitflips; } @@ -1180,7 +1184,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* Handle block mark swapping. */ block_mark_swapping(this, - (void *) payload_virt, (void *) auxiliary_virt); + (void *)payload_virt, (void *)auxiliary_virt); } else { /* * If control arrives here, we're not doing block mark swapping, @@ -1310,10 +1314,10 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, /* * Now, we want to make sure the block mark is correct. In the - * Swapping/Raw case, we already have it. Otherwise, we need to - * explicitly read it. + * non-transcribing case (!GPMI_IS_MX23()), we already have it. + * Otherwise, we need to explicitly read it. */ - if (!this->swap_block_mark) { + if (GPMI_IS_MX23(this)) { /* Read the block mark into the first byte of the OOB buffer. */ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); chip->oob_poi[0] = chip->read_byte(mtd); @@ -1354,7 +1358,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) chipnr = (int)(ofs >> chip->chip_shift); chip->select_chip(mtd, chipnr); - column = this->swap_block_mark ? mtd->writesize : 0; + column = !GPMI_IS_MX23(this) ? mtd->writesize : 0; /* Write the block mark. */ block_mark = this->data_buffer_dma; @@ -1597,8 +1601,9 @@ static int mx23_boot_init(struct gpmi_nand_data *this) dev_dbg(dev, "Transcribing mark in block %u\n", block); ret = chip->block_markbad(mtd, byte); if (ret) - dev_err(dev, "Failed to mark block bad with " - "ret %d\n", ret); + dev_err(dev, + "Failed to mark block bad with ret %d\n", + ret); } } @@ -1649,9 +1654,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this) struct bch_geometry *bch_geo = &this->bch_geometry; int ret; - /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ - this->swap_block_mark = !GPMI_IS_MX23(this); - /* Set up the medium geometry */ ret = gpmi_set_geometry(this); if (ret) @@ -1715,9 +1717,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) chip->badblock_pattern = &gpmi_bbt_descr; chip->block_markbad = gpmi_block_markbad; chip->options |= NAND_NO_SUBPAGE_WRITE; - if (of_get_nand_on_flash_bbt(this->dev->of_node)) + + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + this->swap_block_mark = !GPMI_IS_MX23(this); + + if (of_get_nand_on_flash_bbt(this->dev->of_node)) { chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + if (of_property_read_bool(this->dev->of_node, + "fsl,no-blockmark-swap")) + this->swap_block_mark = false; + } + dev_dbg(this->dev, "Blockmark swapping %sabled\n", + this->swap_block_mark ? "en" : "dis"); + /* * Allocate a temporary DMA buffer for reading ID in the * nand_scan_ident(). @@ -1760,16 +1773,16 @@ err_out: static const struct of_device_id gpmi_nand_id_table[] = { { .compatible = "fsl,imx23-gpmi-nand", - .data = (void *)&gpmi_devdata_imx23, + .data = &gpmi_devdata_imx23, }, { .compatible = "fsl,imx28-gpmi-nand", - .data = (void *)&gpmi_devdata_imx28, + .data = &gpmi_devdata_imx28, }, { .compatible = "fsl,imx6q-gpmi-nand", - .data = (void *)&gpmi_devdata_imx6q, + .data = &gpmi_devdata_imx6q, }, { .compatible = "fsl,imx6sx-gpmi-nand", - .data = (void *)&gpmi_devdata_imx6sx, + .data = &gpmi_devdata_imx6sx, }, {} }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); |