enigma2 20150309 -> 20150316
[opendreambox.git] / meta-bsp / dm800sev2 / recipes / linux / linux-dreambox-3.2 / 0001-add-support-for-toshiba-nand-flash-add-workaround-fo.patch
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
6
7 ---
8  drivers/mtd/brcmnand/brcmnand_base.c |   84 +++++++++++++++++++++++++++++++---
9  1 file changed, 78 insertions(+), 6 deletions(-)
10
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);
16                         }
17  
18  #ifndef DEBUG_HW_ECC
19 -                       if (oobarea || (valid == BRCMNAND_CORRECTABLE_ECC_ERROR)) 
20 +                       if (oobarea || (valid == BRCMNAND_CORRECTABLE_ECC_ERROR && chip->ecclevel == BRCMNAND_ECC_HAMMING)) 
21  #endif
22                         {
23                                 PLATFORM_IOFLUSH_WAR();
24 @@ -6165,7 +6165,29 @@ brcmnand_write_page(struct mtd_info *mtd,
25         int oobWritten = 0;
26         int ret = 0;
27         uint64_t offset = page << chip->page_shift;
28 +       uint8_t eccbuf[chip->eccsteps * chip->eccOobSize];
29  
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)
33 +               {
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));
36 +
37 +                       memset(eccbuf, 0xff, sizeof(eccbuf));
38 +
39 +                       ret = brcmnand_posted_read_oob(mtd, eccbuf, offset, 0);
40 +
41 +                       if (!ret) {
42 +                               if (!memcmp(eccbuf+1, "\x85\x19\x03\x20\x08\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff", 15))
43 +                                       inp_oob = eccbuf;
44 +                       }
45 +                       else
46 +                               printk("BCH-4 jffs2 hack read oob failed %08llx\n", offset);
47 +
48 +                       brcmnand_ctrl_write(bchp_nand_acc_control(0), acc);
49 +               }
50 +       }
51  
52  if (gdebug > 3 ) {
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;
57  
58 -       
59         switch(ops->mode) {
60  
61         case MTD_OPS_PLACE_OOB:
62 -       case MTD_OPS_RAW:
63 -               memcpy(chip->oob_poi + ops->ooboffs, oob, len);
64 +       case MTD_OPS_RAW: {
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;
68 +                       int cnt=0;
69 +                       int rp=oobfree_in->offset, wp=oobfree_out->offset;
70 +
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 */
75 +
76 +                       BUG_ON(writtenLen || ops->ooboffs);  // this code only works for single page writes...
77 +
78 +                       memset(chip->oob_poi, 0xff, chip->eccOobSize);
79 +
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;
86 +                       }
87 +               }
88 +               else
89 +                       memcpy(chip->oob_poi + ops->ooboffs, oob, len);
90                 return oob + len;
91 +       }
92  
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;
97  
98         while(1) {
99 +               uint32_t acc = 0;
100 +
101                 /* Submit one page at a time */
102 -                
103                 numPages = 1;
104 -               
105 +
106                 if (likely(oob)) {
107 +                       if (chip->ecclayout == &brcmnand_oob_bch4_2k) {
108 +                               uint32_t block_size = (1 << chip->erase_shift);
109 +
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));
113 +                               }
114 +                       }
115 +
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);}
120  
121                 status |= chip->write_page_oob(mtd, chip->oob_poi, page);
122  
123 +               if (acc)
124 +                       brcmnand_ctrl_write(bchp_nand_acc_control(0), acc);
125 +
126                 if (status)
127                         break;
128                 
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
131          */
132  
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);
136 +
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);
139 +
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);
142 +
143 +               chip->ctrl_write(bchp_nand_config(chip->ctrl->CS[chip->csi]), nand_config);
144 +       }
145 +
146         /* 
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
149 -- 
150 1.7.10.4
151