1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 #include "flashif.h" 10 11 typedef struct Nandtab Nandtab; 12 13 struct Nandtab { 14 short manufacturer; 15 uchar id; 16 uchar l2bytesperpage; 17 ushort pagesperblock; 18 ushort blocks; 19 uchar tPROGms; 20 ushort tBERASEms; 21 uchar tRus; 22 }; 23 24 static Nandtab nandtab[] = { 25 { 0xec, 0xe6, 9, 16, 1024, 1, 4, 7 }, /* Samsung KM29U64000T */ 26 27 { 0x98, 0xe6, 9, 16, 1024, 1, 4, 25 }, /* Toshiba TC58V64AFT */ 28 { 0x98, 0x73, 9, 32, 1024, 1, 10, 25}, /* Toshiba TC56V128AFT */ 29 /* Generic entries which take timings from Toshiba SMIL example code */ 30 { -1, 0xea, 8, 16, 512, 20, 400, 100 }, 31 { -1, 0xe3, 9, 16, 512, 20, 400, 100 }, 32 { -1, 0xe5, 9, 16, 512, 20, 400, 100 }, 33 { -1, 0x73, 9, 32, 1024, 20, 400, 100 }, 34 { -1, 0x75, 9, 32, 2048, 20, 400, 100 }, 35 { -1, 0x76, 9, 32, 4096, 20, 400, 100 }, 36 }; 37 38 enum { 39 ReadMode1 = 0x00, 40 ReadMode2 = 0x01, 41 Program = 0x10, 42 ReadMode3 = 0x50, 43 Erase1 = 0x60, 44 ReadStatus = 0x70, 45 Write = 0x80, 46 Identify = 0x90, 47 Erase2 = 0xd0, 48 49 StatusReady = 0x40, 50 StatusFail = 0x01, 51 }; 52 53 /* 54 * NAND flash driver 55 */ 56 57 #define DPRINT if(0)print 58 #define EPRINT if(1)print 59 60 static int idchip(Flash *f); 61 62 static void 63 nand_writebyte(Flash *f, uchar b) 64 { 65 archnand_write(f, &b, 1); 66 } 67 68 static uchar 69 nand_readbyte(Flash *f) 70 { 71 uchar b; 72 archnand_read(f, &b, 1); 73 return b; 74 } 75 76 static int 77 idchip(Flash *f) 78 { 79 int x; 80 uchar maker, device; 81 82 f->id = 0; 83 f->devid = 0; 84 f->width = 1; 85 archnand_claim(f, 1); 86 archnand_setCLEandALE(f, 1, 0); 87 nand_writebyte(f, Identify); 88 archnand_setCLEandALE(f, 0, 1); 89 nand_writebyte(f, 0); 90 archnand_setCLEandALE(f, 0, 0); 91 maker = nand_readbyte(f); 92 device = nand_readbyte(f); 93 archnand_claim(f, 0); 94 iprint("man=%#ux device=%#ux\n", maker, device); 95 for(x = 0; x < sizeof(nandtab) / sizeof(nandtab[0]); x++){ 96 if(nandtab[x].id == (device & 0xff) 97 && (nandtab[x].manufacturer == maker || nandtab[x].manufacturer == -1)){ 98 ulong bpp; 99 f->id = maker; 100 f->devid = device; 101 f->nr = 1; 102 bpp = 1 << nandtab[x].l2bytesperpage; 103 bpp |= bpp >> 5; 104 f->regions[0].erasesize = bpp * nandtab[x].pagesperblock; 105 f->size = f->regions[0].erasesize * nandtab[x].blocks; 106 f->regions[0].n = nandtab[x].blocks; 107 f->regions[0].start = 0; 108 f->regions[0].end = f->size; 109 f->regions[0].pagesize = bpp; 110 f->data = &nandtab[x]; 111 return 0; 112 } 113 } 114 print("nand: device %#.2ux/%#.2ux not recognised\n", maker, device); 115 return -1; 116 } 117 118 static int 119 erasezone(Flash *f, Flashregion *r, ulong byteaddr) 120 { 121 Nandtab *nt = f->data; 122 int paddress; 123 uchar val; 124 int rv; 125 uchar addr[2]; 126 127 if(byteaddr%r->erasesize || byteaddr >= f->size) 128 return -1; /* bad zone */ 129 paddress = byteaddr/r->erasesize * nt->pagesperblock; /* can simplify ... */ 130 //print("erasezone(%.8lux) page %d %.8lux\n", byteaddr, paddress, r->erasesize); 131 archnand_claim(f, 1); 132 archnand_setCLEandALE(f, 1, 0); // command mode 133 nand_writebyte(f, Erase1); 134 archnand_setCLEandALE(f, 0, 1); // address mode 135 addr[0] = paddress; 136 addr[1] = paddress >> 8; 137 archnand_write(f, addr, 2); 138 archnand_setCLEandALE(f, 1, 0); // command mode 139 nand_writebyte(f, Erase2); 140 nand_writebyte(f, ReadStatus); 141 archnand_setCLEandALE(f, 0, 0); // data mode 142 143 do { 144 val = nand_readbyte(f); 145 } while((val & StatusReady) != StatusReady); 146 147 if((val & StatusFail) != 0){ 148 print("erasezone failed: %.2ux\n", val); 149 rv = -1; 150 } 151 else 152 rv = 0; 153 archnand_claim(f, 0); // turn off chip 154 return rv; 155 } 156 157 static int 158 writepage(Flash *f, ulong page, ushort addr, void *buf, long n) 159 { 160 uchar cmd; 161 uchar val; 162 int rv; 163 uchar cmdbuf[3]; 164 165 //print("writepage(%ld, %d, %ld)\n", page, addr, n); 166 // Fake a read to set the pointer 167 if(addr < 256) 168 cmd = ReadMode1; 169 else if(addr < 512){ 170 cmd = ReadMode2; 171 addr -= 256; 172 }else{ 173 cmd = ReadMode3; 174 addr -= 512; 175 } 176 archnand_claim(f, 1); 177 archnand_setCLEandALE(f, 1, 0); // command mode 178 nand_writebyte(f, cmd); 179 nand_writebyte(f, Write); 180 archnand_setCLEandALE(f, 0, 1); // address mode 181 cmdbuf[0] = addr; 182 cmdbuf[1] = page; 183 cmdbuf[2] = page >> 8; 184 archnand_write(f, cmdbuf, 3); 185 archnand_setCLEandALE(f, 0, 0); // data mode 186 archnand_write(f, buf, n); 187 archnand_setCLEandALE(f, 1, 0); // command mode 188 nand_writebyte(f, Program); 189 nand_writebyte(f, ReadStatus); 190 archnand_setCLEandALE(f, 0, 0); // data mode 191 192 do { 193 val = nand_readbyte(f); 194 }while((val & StatusReady) != StatusReady); 195 196 if((val & StatusFail) != 0){ 197 print("writepage failed: %.2ux\n", val); 198 rv = -1; 199 }else 200 rv = 0; 201 202 archnand_claim(f, 0); 203 return rv; 204 } 205 206 static int 207 write(Flash *f, ulong offset, void *buf, long n) 208 { 209 Nandtab *nt = f->data; 210 ulong page; 211 ulong addr; 212 ulong xbpp; 213 214 //print("write(%ld, %ld)\n", offset, n); 215 216 xbpp = (1 << nt->l2bytesperpage); 217 xbpp |= (xbpp >> 5); 218 page = offset / xbpp; 219 addr = offset % xbpp; 220 221 while(n > 0){ 222 int count; 223 count = xbpp - addr; 224 if(count > n) 225 count = n; 226 if(writepage(f, page, addr, buf, count) < 0) 227 return -1; 228 offset += count; 229 n -= count; 230 buf = (uchar *)buf + count; 231 addr = 0; 232 } 233 //print("write done\n"); 234 return 0; 235 } 236 237 static int 238 read(Flash *f, ulong offset, void *buf, long n) 239 { 240 Nandtab *nt = f->data; 241 uchar cmd; 242 ulong page; 243 ulong addr; 244 ushort bytesperpage, xbytesperpage, skip, partialaddr; 245 uchar cmdbuf[3]; 246 int toread; 247 248 //print("read(%ld, %.8lux, %ld)\n", offset, buf, n); 249 250 bytesperpage = (1 << nt->l2bytesperpage); 251 xbytesperpage = bytesperpage; 252 xbytesperpage += bytesperpage >> 5; // 512 => 16, 256 => 8 253 page = offset / xbytesperpage; 254 partialaddr = offset % xbytesperpage; 255 skip = 0; 256 if(partialaddr >= bytesperpage && xbytesperpage - partialaddr < n){ 257 // cannot start read in extended area, and then chain into main area, 258 // so start on last byte of main area, and skip the extra bytes 259 // stupid chip design this one 260 skip = partialaddr - bytesperpage + 1; 261 n += skip; 262 partialaddr = bytesperpage - 1; 263 } 264 addr = partialaddr; 265 if(addr >= bytesperpage){ 266 cmd = ReadMode3; 267 addr -= bytesperpage; 268 }else if(addr >= 256){ 269 cmd = ReadMode2; 270 addr -= 256; 271 }else 272 cmd = ReadMode1; 273 274 //print("cmd %.2x page %.4lux addr %.8lux partialaddr %d skip %d\n", cmd, page, addr, partialaddr, skip); 275 // Read first page 276 archnand_claim(f, 1); 277 archnand_setCLEandALE(f, 1, 0); 278 nand_writebyte(f, cmd); 279 archnand_setCLEandALE(f, 0, 1); 280 cmdbuf[0] = addr; 281 cmdbuf[1] = page; 282 cmdbuf[2] = page >> 8; 283 archnand_write(f, cmdbuf, 3); 284 archnand_setCLEandALE(f, 0, 0); 285 if(partialaddr){ 286 // partial first page 287 microdelay(nt->tRus); 288 toread = partialaddr < xbytesperpage ? xbytesperpage - partialaddr : 0; 289 if(toread > n) 290 toread = n; 291 if(skip){ 292 archnand_read(f, 0, skip); 293 toread -= skip; 294 n -= skip; 295 // partialaddr += skip; 296 } 297 archnand_read(f, buf, toread); 298 n -= toread; 299 // partialaddr += toread; 300 buf = (uchar *)buf + toread; 301 } 302 while(n){ 303 microdelay(nt->tRus); 304 toread = xbytesperpage; 305 if(n < toread) 306 toread = n; 307 archnand_read(f, buf, toread); 308 n -= toread; 309 buf = (uchar *)buf + toread; 310 } 311 archnand_claim(f, 0); 312 //print("readn done\n"); 313 return 0; 314 } 315 316 static int 317 reset(Flash *f) 318 { 319 //iprint("nandreset\n"); 320 if(f->data != nil) 321 return 1; 322 f->write = write; 323 f->read = read; 324 f->eraseall = nil; 325 f->erasezone = erasezone; 326 f->suspend = nil; 327 f->resume = nil; 328 f->sort = "nand"; 329 archnand_init(f); 330 return idchip(f); 331 } 332 333 void 334 flashnandlink(void) 335 { 336 addflashcard("nand", reset); 337 } 338