diff options
author | Lothar Waßmann <LW@KARO-electronics.de> | 2014-03-28 06:35:06 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-07-28 01:06:31 -0400 |
commit | 2a500afe1e0e84c7a126df693dbd01353756dcfa (patch) | |
tree | 278caaa0a91938c570c217f0b64d954724b1747d /drivers/mtd | |
parent | d8c0372baadb29e60668c2bddfcf39294f3d4581 (diff) |
mtd: gpmi: make blockmark swapping optional
With a flash-based BBT there is no reason to move the Factory Bad
Block Marker from the data area buffer (to where it is mapped by the
GPMI NAND controller) to the OOB buffer. Thus, make this feature
configurable via DT. This is required for the Ka-Ro electronics
platforms.
In the original code 'this->swap_block_mark' was synonymous with
'!GPMI_IS_MX23()', so use the latter at the relevant places.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Acked-by: Huang Shijie <b32955@freescale.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 16a533a78edd..959cb9b70310 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
@@ -1081,6 +1081,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
1081 | int first, last, marker_pos; | 1081 | int first, last, marker_pos; |
1082 | int ecc_parity_size; | 1082 | int ecc_parity_size; |
1083 | int col = 0; | 1083 | int col = 0; |
1084 | int old_swap_block_mark = this->swap_block_mark; | ||
1084 | 1085 | ||
1085 | /* The size of ECC parity */ | 1086 | /* The size of ECC parity */ |
1086 | ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; | 1087 | ecc_parity_size = geo->gf_len * geo->ecc_strength / 8; |
@@ -1089,17 +1090,21 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
1089 | first = offs / size; | 1090 | first = offs / size; |
1090 | last = (offs + len - 1) / size; | 1091 | last = (offs + len - 1) / size; |
1091 | 1092 | ||
1092 | /* | 1093 | if (this->swap_block_mark) { |
1093 | * Find the chunk which contains the Block Marker. If this chunk is | 1094 | /* |
1094 | * in the range of [first, last], we have to read out the whole page. | 1095 | * Find the chunk which contains the Block Marker. |
1095 | * Why? since we had swapped the data at the position of Block Marker | 1096 | * If this chunk is in the range of [first, last], |
1096 | * to the metadata which is bound with the chunk 0. | 1097 | * we have to read out the whole page. |
1097 | */ | 1098 | * Why? since we had swapped the data at the position of Block |
1098 | marker_pos = geo->block_mark_byte_offset / size; | 1099 | * Marker to the metadata which is bound with the chunk 0. |
1099 | if (last >= marker_pos && first <= marker_pos) { | 1100 | */ |
1100 | dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n", | 1101 | marker_pos = geo->block_mark_byte_offset / size; |
1102 | if (last >= marker_pos && first <= marker_pos) { | ||
1103 | dev_dbg(this->dev, | ||
1104 | "page:%d, first:%d, last:%d, marker at:%d\n", | ||
1101 | page, first, last, marker_pos); | 1105 | page, first, last, marker_pos); |
1102 | return gpmi_ecc_read_page(mtd, chip, buf, 0, page); | 1106 | return gpmi_ecc_read_page(mtd, chip, buf, 0, page); |
1107 | } | ||
1103 | } | 1108 | } |
1104 | 1109 | ||
1105 | meta = geo->metadata_size; | 1110 | meta = geo->metadata_size; |
@@ -1145,7 +1150,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | |||
1145 | writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); | 1150 | writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); |
1146 | writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1); | 1151 | writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1); |
1147 | this->bch_geometry = old_geo; | 1152 | this->bch_geometry = old_geo; |
1148 | this->swap_block_mark = true; | 1153 | this->swap_block_mark = old_swap_block_mark; |
1149 | 1154 | ||
1150 | return max_bitflips; | 1155 | return max_bitflips; |
1151 | } | 1156 | } |
@@ -1309,10 +1314,10 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | |||
1309 | 1314 | ||
1310 | /* | 1315 | /* |
1311 | * Now, we want to make sure the block mark is correct. In the | 1316 | * Now, we want to make sure the block mark is correct. In the |
1312 | * Swapping/Raw case, we already have it. Otherwise, we need to | 1317 | * non-transcribing case (!GPMI_IS_MX23()), we already have it. |
1313 | * explicitly read it. | 1318 | * Otherwise, we need to explicitly read it. |
1314 | */ | 1319 | */ |
1315 | if (!this->swap_block_mark) { | 1320 | if (GPMI_IS_MX23(this)) { |
1316 | /* Read the block mark into the first byte of the OOB buffer. */ | 1321 | /* Read the block mark into the first byte of the OOB buffer. */ |
1317 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | 1322 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); |
1318 | chip->oob_poi[0] = chip->read_byte(mtd); | 1323 | chip->oob_poi[0] = chip->read_byte(mtd); |
@@ -1353,7 +1358,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1353 | chipnr = (int)(ofs >> chip->chip_shift); | 1358 | chipnr = (int)(ofs >> chip->chip_shift); |
1354 | chip->select_chip(mtd, chipnr); | 1359 | chip->select_chip(mtd, chipnr); |
1355 | 1360 | ||
1356 | column = this->swap_block_mark ? mtd->writesize : 0; | 1361 | column = !GPMI_IS_MX23(this) ? mtd->writesize : 0; |
1357 | 1362 | ||
1358 | /* Write the block mark. */ | 1363 | /* Write the block mark. */ |
1359 | block_mark = this->data_buffer_dma; | 1364 | block_mark = this->data_buffer_dma; |
@@ -1649,9 +1654,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this) | |||
1649 | struct bch_geometry *bch_geo = &this->bch_geometry; | 1654 | struct bch_geometry *bch_geo = &this->bch_geometry; |
1650 | int ret; | 1655 | int ret; |
1651 | 1656 | ||
1652 | /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ | ||
1653 | this->swap_block_mark = !GPMI_IS_MX23(this); | ||
1654 | |||
1655 | /* Set up the medium geometry */ | 1657 | /* Set up the medium geometry */ |
1656 | ret = gpmi_set_geometry(this); | 1658 | ret = gpmi_set_geometry(this); |
1657 | if (ret) | 1659 | if (ret) |
@@ -1715,9 +1717,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) | |||
1715 | chip->badblock_pattern = &gpmi_bbt_descr; | 1717 | chip->badblock_pattern = &gpmi_bbt_descr; |
1716 | chip->block_markbad = gpmi_block_markbad; | 1718 | chip->block_markbad = gpmi_block_markbad; |
1717 | chip->options |= NAND_NO_SUBPAGE_WRITE; | 1719 | chip->options |= NAND_NO_SUBPAGE_WRITE; |
1718 | if (of_get_nand_on_flash_bbt(this->dev->of_node)) | 1720 | |
1721 | /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ | ||
1722 | this->swap_block_mark = !GPMI_IS_MX23(this); | ||
1723 | |||
1724 | if (of_get_nand_on_flash_bbt(this->dev->of_node)) { | ||
1719 | chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; | 1725 | chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; |
1720 | 1726 | ||
1727 | if (of_property_read_bool(this->dev->of_node, | ||
1728 | "fsl,no-blockmark-swap")) | ||
1729 | this->swap_block_mark = false; | ||
1730 | } | ||
1731 | dev_dbg(this->dev, "Blockmark swapping %sabled\n", | ||
1732 | this->swap_block_mark ? "en" : "dis"); | ||
1733 | |||
1721 | /* | 1734 | /* |
1722 | * Allocate a temporary DMA buffer for reading ID in the | 1735 | * Allocate a temporary DMA buffer for reading ID in the |
1723 | * nand_scan_ident(). | 1736 | * nand_scan_ident(). |