diff options
Diffstat (limited to 'firmware/target/arm/tcc780x/ata-nand-tcc780x.c')
-rw-r--r-- | firmware/target/arm/tcc780x/ata-nand-tcc780x.c | 205 |
1 files changed, 141 insertions, 64 deletions
diff --git a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c b/firmware/target/arm/tcc780x/ata-nand-tcc780x.c index 813172f590..bd7e9bb336 100644 --- a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c +++ b/firmware/target/arm/tcc780x/ata-nand-tcc780x.c | |||
@@ -38,7 +38,6 @@ static bool initialized = false; | |||
38 | static long next_yield = 0; | 38 | static long next_yield = 0; |
39 | #define MIN_YIELD_PERIOD 2000 | 39 | #define MIN_YIELD_PERIOD 2000 |
40 | 40 | ||
41 | |||
42 | /* TCC780x NAND Flash Controller */ | 41 | /* TCC780x NAND Flash Controller */ |
43 | 42 | ||
44 | #define NFC_CMD (*(volatile unsigned long *)0xF0053000) | 43 | #define NFC_CMD (*(volatile unsigned long *)0xF0053000) |
@@ -49,30 +48,30 @@ static long next_yield = 0; | |||
49 | #define NFC_IREQ (*(volatile unsigned long *)0xF0053060) | 48 | #define NFC_IREQ (*(volatile unsigned long *)0xF0053060) |
50 | #define NFC_RST (*(volatile unsigned long *)0xF0053064) | 49 | #define NFC_RST (*(volatile unsigned long *)0xF0053064) |
51 | 50 | ||
51 | /* NFC_CTRL flags */ | ||
52 | #define NFC_16BIT (1<<26) | 52 | #define NFC_16BIT (1<<26) |
53 | #define NFC_CS0 (1<<23) | 53 | #define NFC_CS0 (1<<23) |
54 | #define NFC_CS1 (1<<22) | 54 | #define NFC_CS1 (1<<22) |
55 | #define NFC_READY (1<<20) | 55 | #define NFC_READY (1<<20) |
56 | 56 | ||
57 | /* Chip characteristics, initialised by nand_get_chip_info() */ | ||
57 | 58 | ||
58 | #if defined(COWON_D2) | 59 | static int page_size = 0; |
59 | /* | 60 | static int spare_size = 0; |
60 | ===== Temporary D2 testing code ===== | 61 | static int pages_per_block = 0; |
62 | static int total_blocks = 0; | ||
63 | static int total_pages = 0; | ||
64 | static int row_cycles = 0; | ||
65 | static int col_cycles = 0; | ||
66 | static int total_banks = 0; | ||
61 | 67 | ||
62 | (assumes SAMSUNG K9LAG08UOM (2GB) in 1, 2 or 4 banks) | 68 | /* Static page buffer */ |
63 | 69 | ||
64 | Manufacturer Id: {0xec, 0xd5, 0x55, 0x25, 0x68} | 70 | #define MAX_PAGE_SIZE 4096 |
71 | #define MAX_SPARE_SIZE 128 | ||
65 | 72 | ||
66 | */ | 73 | static int page_buf[(MAX_PAGE_SIZE+MAX_SPARE_SIZE)/4]; |
67 | #define PAGE_SIZE 2048 | ||
68 | #define SPARE_SIZE 64 | ||
69 | #define PAGES_PER_BLOCK 128 | ||
70 | #define TOTAL_BLOCKS 8192 | ||
71 | #define TOTAL_PAGES (TOTAL_BLOCKS * PAGES_PER_BLOCK) | ||
72 | #define COL_CYCLES 2 | ||
73 | #define ROW_CYCLES 3 | ||
74 | 74 | ||
75 | static int page_buf[PAGE_SIZE/4]; | ||
76 | 75 | ||
77 | static void nand_chip_select(int chip) | 76 | static void nand_chip_select(int chip) |
78 | { | 77 | { |
@@ -108,10 +107,9 @@ static void nand_chip_select(int chip) | |||
108 | } | 107 | } |
109 | } | 108 | } |
110 | 109 | ||
110 | |||
111 | static void nand_read_id(int chip, unsigned char* id_buf) | 111 | static void nand_read_id(int chip, unsigned char* id_buf) |
112 | { | 112 | { |
113 | int i; | ||
114 | |||
115 | /* Enable NFC bus clock */ | 113 | /* Enable NFC bus clock */ |
116 | BCLKCTR |= DEV_NAND; | 114 | BCLKCTR |= DEV_NAND; |
117 | 115 | ||
@@ -150,7 +148,7 @@ static void nand_read_id(int chip, unsigned char* id_buf) | |||
150 | } | 148 | } |
151 | 149 | ||
152 | 150 | ||
153 | static void nand_read_uid(int chip) | 151 | static void nand_read_uid(int chip, unsigned int* uid_buf) |
154 | { | 152 | { |
155 | int i; | 153 | int i; |
156 | 154 | ||
@@ -177,8 +175,8 @@ static void nand_read_uid(int chip) | |||
177 | NFC_CMD = 0x00; | 175 | NFC_CMD = 0x00; |
178 | 176 | ||
179 | /* Write row/column address */ | 177 | /* Write row/column address */ |
180 | for (i = 0; i < COL_CYCLES; i++) NFC_SADDR = 0; | 178 | for (i = 0; i < col_cycles; i++) NFC_SADDR = 0; |
181 | for (i = 0; i < ROW_CYCLES; i++) NFC_SADDR = 0; | 179 | for (i = 0; i < row_cycles; i++) NFC_SADDR = 0; |
182 | 180 | ||
183 | /* End of read */ | 181 | /* End of read */ |
184 | NFC_CMD = 0x30; | 182 | NFC_CMD = 0x30; |
@@ -189,7 +187,7 @@ static void nand_read_uid(int chip) | |||
189 | /* Copy data to buffer (data repeats after 8 words) */ | 187 | /* Copy data to buffer (data repeats after 8 words) */ |
190 | for (i = 0; i < 8; i++) | 188 | for (i = 0; i < 8; i++) |
191 | { | 189 | { |
192 | page_buf[i] = NFC_WDATA; | 190 | uid_buf[i] = NFC_WDATA; |
193 | } | 191 | } |
194 | 192 | ||
195 | /* Reset the chip back to normal mode */ | 193 | /* Reset the chip back to normal mode */ |
@@ -225,14 +223,14 @@ static void nand_read(int chip, int row, int column, int size) | |||
225 | NFC_CMD = 0x00; | 223 | NFC_CMD = 0x00; |
226 | 224 | ||
227 | /* Write column address */ | 225 | /* Write column address */ |
228 | for (i = 0; i < COL_CYCLES; i++) | 226 | for (i = 0; i < col_cycles; i++) |
229 | { | 227 | { |
230 | NFC_SADDR = column & 0xFF; | 228 | NFC_SADDR = column & 0xFF; |
231 | column = column >> 8; | 229 | column = column >> 8; |
232 | } | 230 | } |
233 | 231 | ||
234 | /* Write row address */ | 232 | /* Write row address */ |
235 | for (i = 0; i < ROW_CYCLES; i++) | 233 | for (i = 0; i < row_cycles; i++) |
236 | { | 234 | { |
237 | NFC_SADDR = row & 0xFF; | 235 | NFC_SADDR = row & 0xFF; |
238 | row = row >> 8; | 236 | row = row >> 8; |
@@ -258,56 +256,38 @@ static void nand_read(int chip, int row, int column, int size) | |||
258 | 256 | ||
259 | 257 | ||
260 | /* TEMP testing function */ | 258 | /* TEMP testing function */ |
261 | #include <string.h> | ||
262 | #include "lcd.h" | 259 | #include "lcd.h" |
263 | 260 | ||
264 | extern int line; | 261 | extern int line; |
265 | 262 | static unsigned char str_buf[MAX_PAGE_SIZE]; | |
263 | |||
266 | static void nand_test(void) | 264 | static void nand_test(void) |
267 | { | 265 | { |
268 | int i,j,row; | 266 | int i,j,row; |
269 | unsigned char id_buf[5]; | 267 | int pages_per_mb = 1048576/page_size; |
270 | unsigned char str_buf[PAGE_SIZE]; | ||
271 | 268 | ||
272 | /* Display ID codes & UID block for each bank */ | 269 | printf("%d banks", total_banks); |
273 | for (i = 0; i < 4; i++) | 270 | printf("* %d pages", total_pages); |
274 | { | 271 | printf("* %d bytes per page", page_size); |
275 | printf("NAND bank %d:", i); | ||
276 | |||
277 | nand_read_id(i, id_buf); | ||
278 | |||
279 | printf("ID: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", | ||
280 | id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); | ||
281 | |||
282 | nand_read_uid(i); | ||
283 | |||
284 | for (j = 0; j < 8; j += 4) | ||
285 | { | ||
286 | printf("0x%08x 0x%08x 0x%08x 0x%08x", | ||
287 | page_buf[j],page_buf[j+1],page_buf[j+2],page_buf[j+3]); | ||
288 | } | ||
289 | |||
290 | line++; | ||
291 | } | ||
292 | 272 | ||
293 | while (!button_read_device()) {}; | 273 | while (!button_read_device()) {}; |
294 | 274 | ||
295 | /* Now for fun, scan the raw pages for 'TAG' and display the contents */ | 275 | /* Now for fun, scan the raw pages for 'TAG' and display the contents */ |
296 | 276 | ||
297 | row = 0; | 277 | row = 0; |
298 | while (row < TOTAL_PAGES) | 278 | while (row < total_pages) |
299 | { | 279 | { |
300 | bool found = false; | 280 | bool found = false; |
301 | unsigned char* buf_ptr = (unsigned char*)page_buf; | 281 | unsigned char* buf_ptr = (unsigned char*)page_buf; |
302 | 282 | ||
303 | line = 0; | 283 | line = 0; |
304 | 284 | ||
285 | if (row % pages_per_mb == 0) printf("%dMb", row/pages_per_mb); | ||
286 | |||
305 | /* Read a page from chip 0 */ | 287 | /* Read a page from chip 0 */ |
306 | nand_read(0, row, 0, PAGE_SIZE); | 288 | nand_read(0, row, 0, page_size); |
307 | |||
308 | if (row % 512 == 0) printf("%dMb", row/512); | ||
309 | 289 | ||
310 | for (j = 0; j < PAGE_SIZE; j++) | 290 | for (j = 0; j < page_size; j++) |
311 | { | 291 | { |
312 | if (buf_ptr[j] == 'T' && buf_ptr[j+1] == 'A' && buf_ptr[j+2] == 'G') | 292 | if (buf_ptr[j] == 'T' && buf_ptr[j+1] == 'A' && buf_ptr[j+2] == 'G') |
313 | found = true; | 293 | found = true; |
@@ -320,7 +300,7 @@ static void nand_test(void) | |||
320 | printf("Row %d:", row); | 300 | printf("Row %d:", row); |
321 | 301 | ||
322 | /* Copy ascii-readable parts out to a string */ | 302 | /* Copy ascii-readable parts out to a string */ |
323 | for (i = 0; i < PAGE_SIZE; i++) | 303 | for (i = 0; i < page_size; i++) |
324 | { | 304 | { |
325 | str_buf[i] = ' '; | 305 | str_buf[i] = ' '; |
326 | if (buf_ptr[i] > 31 && buf_ptr[i] < 128) | 306 | if (buf_ptr[i] > 31 && buf_ptr[i] < 128) |
@@ -347,7 +327,8 @@ static void nand_test(void) | |||
347 | /* Alternate hex display code | 327 | /* Alternate hex display code |
348 | for (i = 0; i<112; i+=4) | 328 | for (i = 0; i<112; i+=4) |
349 | { | 329 | { |
350 | printf("0x%08x 0x%08x 0x%08x 0x%08x",buf[i],buf[i+1],buf[i+2],buf[i+3]); | 330 | printf("0x%08x 0x%08x 0x%08x 0x%08x", |
331 | page_buf[i],page_buf[i+1],page_buf[i+2],page_buf[i+3]); | ||
351 | } | 332 | } |
352 | */ | 333 | */ |
353 | 334 | ||
@@ -358,7 +339,101 @@ static void nand_test(void) | |||
358 | row++; | 339 | row++; |
359 | } | 340 | } |
360 | } | 341 | } |
361 | #endif | 342 | |
343 | |||
344 | static void nand_get_chip_info(void) | ||
345 | { | ||
346 | bool found = false; | ||
347 | unsigned char manuf_id; | ||
348 | unsigned char id_buf[5]; | ||
349 | |||
350 | /* Read chip id from bank 0 */ | ||
351 | nand_read_id(0, id_buf); | ||
352 | |||
353 | manuf_id = id_buf[0]; | ||
354 | |||
355 | switch (manuf_id) | ||
356 | { | ||
357 | case 0xEC: /* SAMSUNG */ | ||
358 | |||
359 | switch(id_buf[1]) /* Chip Id */ | ||
360 | { | ||
361 | case 0xD5: /* K9LAG08UOM */ | ||
362 | |||
363 | page_size = 2048; | ||
364 | spare_size = 64; | ||
365 | pages_per_block = 128; | ||
366 | total_blocks = 8192; | ||
367 | col_cycles = 2; | ||
368 | row_cycles = 3; | ||
369 | |||
370 | found = true; | ||
371 | break; | ||
372 | |||
373 | case 0xD7: /* K9LBG08UOM */ | ||
374 | |||
375 | page_size = 4096; | ||
376 | spare_size = 128; | ||
377 | pages_per_block = 128; | ||
378 | total_blocks = 8192; | ||
379 | col_cycles = 2; | ||
380 | row_cycles = 3; | ||
381 | |||
382 | found = true; | ||
383 | break; | ||
384 | } | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | if (!found) | ||
389 | { | ||
390 | panicf("Unknown NAND: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", | ||
391 | id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); | ||
392 | } | ||
393 | |||
394 | total_pages = total_blocks * pages_per_block; | ||
395 | |||
396 | /* Establish how many banks are present */ | ||
397 | |||
398 | nand_read_id(1, id_buf); | ||
399 | |||
400 | if (id_buf[0] == manuf_id) | ||
401 | { | ||
402 | /* Bank 1 is populated, now check if banks 2/3 are valid */ | ||
403 | nand_read_id(2, id_buf); | ||
404 | |||
405 | if (id_buf[0] == manuf_id) | ||
406 | { | ||
407 | /* Bank 2 returned matching id - check if 2/3 are shadowing 0/1 */ | ||
408 | unsigned int uid_buf0[8]; | ||
409 | unsigned int uid_buf2[8]; | ||
410 | |||
411 | nand_read_uid(0, uid_buf0); | ||
412 | nand_read_uid(2, uid_buf2); | ||
413 | |||
414 | if (memcmp(uid_buf0, uid_buf2, 32) == 0) | ||
415 | { | ||
416 | /* UIDs match, assume banks 2/3 are shadowing 0/1 */ | ||
417 | total_banks = 2; | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | /* UIDs differ, assume banks 2/3 are valid */ | ||
422 | total_banks = 4; | ||
423 | } | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | /* Bank 2 returned differing id - assume 2/3 are junk */ | ||
428 | total_banks = 2; | ||
429 | } | ||
430 | } | ||
431 | else | ||
432 | { | ||
433 | /* Bank 1 returned differing id - assume it is junk */ | ||
434 | total_banks = 1; | ||
435 | } | ||
436 | } | ||
362 | 437 | ||
363 | 438 | ||
364 | /* API Functions */ | 439 | /* API Functions */ |
@@ -425,22 +500,24 @@ int ata_soft_reset(void) | |||
425 | 500 | ||
426 | void ata_enable(bool on) | 501 | void ata_enable(bool on) |
427 | { | 502 | { |
428 | #warning function not implemented | 503 | /* null - flash controller is enabled/disabled as needed. */ |
429 | (void)on; | 504 | (void)on; |
430 | } | 505 | } |
431 | 506 | ||
432 | int ata_init(void) | 507 | int ata_init(void) |
433 | { | 508 | { |
434 | #warning function not implemented | 509 | if (!initialized) |
510 | { | ||
511 | /* Get chip characteristics and number of banks */ | ||
512 | nand_get_chip_info(); | ||
435 | 513 | ||
436 | /* This needs to: | 514 | /* TODO: Scan all banks for bad blocks */ |
437 | a) establish how many banks are present | ||
438 | (using nand_read_id() and nand_read_uid() above) | ||
439 | b) scan all banks for bad blocks | ||
440 | c) use this info to build a physical->logical address translation | ||
441 | (using an as yet unknown scheme) | ||
442 | */ | ||
443 | 515 | ||
516 | /* TODO: Build physical->logical address translation */ | ||
517 | |||
518 | initialized = true; | ||
519 | } | ||
520 | |||
444 | /* TEMP - print out some diagnostics */ | 521 | /* TEMP - print out some diagnostics */ |
445 | nand_test(); | 522 | nand_test(); |
446 | 523 | ||