aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 5aaa7f541ea1..bb77f750e75a 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -27,6 +27,7 @@
27#include <linux/of_device.h> 27#include <linux/of_device.h>
28#include <linux/of_mtd.h> 28#include <linux/of_mtd.h>
29#include "gpmi-nand.h" 29#include "gpmi-nand.h"
30#include "bch-regs.h"
30 31
31/* Resource names for the GPMI NAND driver. */ 32/* Resource names for the GPMI NAND driver. */
32#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" 33#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
@@ -1049,6 +1050,90 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
1049 return max_bitflips; 1050 return max_bitflips;
1050} 1051}
1051 1052
1053/* Fake a virtual small page for the subpage read */
1054static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
1055 uint32_t offs, uint32_t len, uint8_t *buf, int page)
1056{
1057 struct gpmi_nand_data *this = chip->priv;
1058 void __iomem *bch_regs = this->resources.bch_regs;
1059 struct bch_geometry old_geo = this->bch_geometry;
1060 struct bch_geometry *geo = &this->bch_geometry;
1061 int size = chip->ecc.size; /* ECC chunk size */
1062 int meta, n, page_size;
1063 u32 r1_old, r2_old, r1_new, r2_new;
1064 unsigned int max_bitflips;
1065 int first, last, marker_pos;
1066 int ecc_parity_size;
1067 int col = 0;
1068
1069 /* The size of ECC parity */
1070 ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
1071
1072 /* Align it with the chunk size */
1073 first = offs / size;
1074 last = (offs + len - 1) / size;
1075
1076 /*
1077 * Find the chunk which contains the Block Marker. If this chunk is
1078 * in the range of [first, last], we have to read out the whole page.
1079 * Why? since we had swapped the data at the position of Block Marker
1080 * to the metadata which is bound with the chunk 0.
1081 */
1082 marker_pos = geo->block_mark_byte_offset / size;
1083 if (last >= marker_pos && first <= marker_pos) {
1084 dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n",
1085 page, first, last, marker_pos);
1086 return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
1087 }
1088
1089 meta = geo->metadata_size;
1090 if (first) {
1091 col = meta + (size + ecc_parity_size) * first;
1092 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
1093
1094 meta = 0;
1095 buf = buf + first * size;
1096 }
1097
1098 /* Save the old environment */
1099 r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
1100 r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
1101
1102 /* change the BCH registers and bch_geometry{} */
1103 n = last - first + 1;
1104 page_size = meta + (size + ecc_parity_size) * n;
1105
1106 r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
1107 BM_BCH_FLASH0LAYOUT0_META_SIZE);
1108 r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
1109 | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
1110 writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
1111
1112 r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
1113 r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
1114 writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
1115
1116 geo->ecc_chunk_count = n;
1117 geo->payload_size = n * size;
1118 geo->page_size = page_size;
1119 geo->auxiliary_status_offset = ALIGN(meta, 4);
1120
1121 dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
1122 page, offs, len, col, first, n, page_size);
1123
1124 /* Read the subpage now */
1125 this->swap_block_mark = false;
1126 max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page);
1127
1128 /* Restore */
1129 writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
1130 writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
1131 this->bch_geometry = old_geo;
1132 this->swap_block_mark = true;
1133
1134 return max_bitflips;
1135}
1136
1052static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, 1137static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
1053 const uint8_t *buf, int oob_required) 1138 const uint8_t *buf, int oob_required)
1054{ 1139{
@@ -1566,6 +1651,17 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
1566 ecc->layout = &gpmi_hw_ecclayout; 1651 ecc->layout = &gpmi_hw_ecclayout;
1567 1652
1568 /* 1653 /*
1654 * We only enable the subpage read when:
1655 * (1) the chip is imx6, and
1656 * (2) the size of the ECC parity is byte aligned.
1657 */
1658 if (GPMI_IS_MX6Q(this) &&
1659 ((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
1660 ecc->read_subpage = gpmi_ecc_read_subpage;
1661 chip->options |= NAND_SUBPAGE_READ;
1662 }
1663
1664 /*
1569 * Can we enable the extra features? such as EDO or Sync mode. 1665 * Can we enable the extra features? such as EDO or Sync mode.
1570 * 1666 *
1571 * We do not check the return value now. That's means if we fail in 1667 * We do not check the return value now. That's means if we fail in