1 From b552f755de420b959937afcda30c488d97183cd0 Mon Sep 17 00:00:00 2001
2 From: Andreas Monzner <andreas.monzner@dream-property.net>
3 Date: Mon, 9 Mar 2015 13:19:38 +0100
4 Subject: [PATCH] add support for toshiba nand flash, add workaround for jffs2
5 with bch-4 error correction
8 drivers/mtd/brcmnand/brcmnand_base.c | 84 +++++++++++++++++++++++++++++++---
9 1 file changed, 78 insertions(+), 6 deletions(-)
11 diff --git a/drivers/mtd/brcmnand/brcmnand_base.c b/drivers/mtd/brcmnand/brcmnand_base.c
12 index f7a06a0..e49149d 100644
13 --- a/drivers/mtd/brcmnand/brcmnand_base.c
14 +++ b/drivers/mtd/brcmnand/brcmnand_base.c
15 @@ -2950,7 +2950,7 @@ printk("%s: before intr_status=%08x\n", __FUNCTION__, intr_status);
19 - if (oobarea || (valid == BRCMNAND_CORRECTABLE_ECC_ERROR))
20 + if (oobarea || (valid == BRCMNAND_CORRECTABLE_ECC_ERROR && chip->ecclevel == BRCMNAND_ECC_HAMMING))
23 PLATFORM_IOFLUSH_WAR();
24 @@ -6165,7 +6165,29 @@ brcmnand_write_page(struct mtd_info *mtd,
27 uint64_t offset = page << chip->page_shift;
28 + uint8_t eccbuf[chip->eccsteps * chip->eccOobSize];
30 + if (chip->ecclayout == &brcmnand_oob_bch4_2k && !inp_oob) {
31 + uint32_t block_size = (1 << chip->erase_shift);
32 + if (!(((uint32_t)offset) % block_size) && inp_buf[0] == 0x85 && inp_buf[1] == 0x19 && inp_buf[3] == 0xe0)
34 + uint32_t acc = brcmnand_ctrl_read(bchp_nand_acc_control(0));
35 + brcmnand_ctrl_write(bchp_nand_acc_control(0), acc & (~BCHP_NAND_ACC_CONTROL_RD_ECC_EN_MASK));
37 + memset(eccbuf, 0xff, sizeof(eccbuf));
39 + ret = brcmnand_posted_read_oob(mtd, eccbuf, offset, 0);
42 + if (!memcmp(eccbuf+1, "\x85\x19\x03\x20\x08\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff", 15))
46 + printk("BCH-4 jffs2 hack read oob failed %08llx\n", offset);
48 + brcmnand_ctrl_write(bchp_nand_acc_control(0), acc);
53 printk("-->%s, offset=%0llx\n", __FUNCTION__, offset);}
54 @@ -6411,13 +6433,37 @@ brcmnand_fill_oob(struct brcmnand_chip *chip, uint8_t *oob, struct mtd_oob_ops *
55 size_t writtenLen = oob - ops->oobbuf;
56 size_t len = ops->ooblen - writtenLen;
61 case MTD_OPS_PLACE_OOB:
63 - memcpy(chip->oob_poi + ops->ooboffs, oob, len);
65 + if (chip->ecclayout == &brcmnand_oob_bch4_2k && !memcmp(oob+2, "\x85\x19\x03\x20", 4) && !memcmp(oob+9, "\x08\x00\x00\x00", 4)) {
66 + struct nand_oobfree *oobfree_in = brcmnand_oob_64.oobfree;
67 + struct nand_oobfree *oobfree_out = brcmnand_oob_bch4_2k.oobfree;
69 + int rp=oobfree_in->offset, wp=oobfree_out->offset;
71 + /* translate oob content prepared for hamming ecc to bch-4 ecc
72 + take care .. with bch-4 only 35 bytes are free usable per sector in oob area...
73 + with hamming it was 50 bytes... so the last 15 bytes are lost!!
74 + but who cares ubi doesn't use the oob area.. and jffs2 just need 8 bytes for the block marker */
76 + BUG_ON(writtenLen || ops->ooboffs); // this code only works for single page writes...
78 + memset(chip->oob_poi, 0xff, chip->eccOobSize);
80 + while (oobfree_in->length && oobfree_out->length && cnt++ < len) {
81 + chip->oob_poi[wp++] = oob[rp++];
82 + if (rp == oobfree_in->offset + oobfree_in->length)
83 + rp = (++oobfree_in)->offset;
84 + if (wp == oobfree_out->offset + oobfree_out->length)
85 + wp = (++oobfree_out)->offset;
89 + memcpy(chip->oob_poi + ops->ooboffs, oob, len);
93 case MTD_OPS_AUTO_OOB: {
94 struct nand_oobfree *free = chip->ecclayout->oobfree;
95 @@ -6722,11 +6768,21 @@ printk("-->%s, to=%08x, len=%d\n", __FUNCTION__, (uint32_t) to, (int)ops->len);}
96 page = to >> chip->page_shift;
101 /* Submit one page at a time */
107 + if (chip->ecclayout == &brcmnand_oob_bch4_2k) {
108 + uint32_t block_size = (1 << chip->erase_shift);
110 + if (!(((uint32_t)to) % block_size) && !memcmp(oob, "\x85\x19\x03\x20\x08\x00\x00\x00", 8)) {
111 + acc = brcmnand_ctrl_read(bchp_nand_acc_control(0));
112 + brcmnand_ctrl_write(bchp_nand_acc_control(0), acc & (~BCHP_NAND_ACC_CONTROL_WR_ECC_EN_MASK));
116 chip->oob_poi = BRCMNAND_OOBBUF(chip->ctrl->buffers);
117 memset(chip->oob_poi, 0xff, mtd->oobsize);
118 oob = brcmnand_fill_oob(chip, oob, ops);
119 @@ -6737,6 +6793,9 @@ printk("-->%s, to=%08x, len=%d\n", __FUNCTION__, (uint32_t) to, (int)ops->len);}
121 status |= chip->write_page_oob(mtd, chip->oob_poi, page);
124 + brcmnand_ctrl_write(bchp_nand_acc_control(0), acc);
129 @@ -9485,6 +9544,19 @@ printk("%s: Ecc level set to %d, sectorSize=%d from ID table\n", __FUNCTION__, c
130 * else ID not in database, but CONFIG reg was passed at command line, already handled
133 + if (foundInIdTable && brcmnand_dev_id == TOSHIBA_TC58NVG3S0ETA00 && brcmnand_maf_id == FLASHTYPE_TOSHIBA && (nand_config >> 24) == 0x48) {
134 + nand_config &= ~(BCHP_NAND_CONFIG_BLOCK_SIZE_MASK);
135 + nand_config |= (BCHP_NAND_CONFIG_BLOCK_SIZE_BK_SIZE_128KB << BCHP_NAND_CONFIG_BLOCK_SIZE_SHIFT);
137 + nand_config &= ~(BCHP_NAND_CONFIG_PAGE_SIZE_MASK);
138 + nand_config |= (BCHP_NAND_CONFIG_PAGE_SIZE_PG_SIZE_2KB << BCHP_NAND_CONFIG_PAGE_SIZE_SHIFT);
140 + nand_config &= ~(BCHP_NAND_CONFIG_DEVICE_SIZE_MASK);
141 + nand_config |= (BCHP_NAND_CONFIG_DEVICE_SIZE_DVC_SIZE_512MB << BCHP_NAND_CONFIG_DEVICE_SIZE_SHIFT);
143 + chip->ctrl_write(bchp_nand_config(chip->ctrl->CS[chip->csi]), nand_config);
147 * For some ID case, the ID decode does not yield all informations,
148 * so we read it back, making sure that NAND CONFIG register and chip-> struct