summaryrefslogtreecommitdiff
path: root/firmware/target/arm/tcc780x/ata-nand-tcc780x.c
diff options
context:
space:
mode:
authorRob Purchase <shotofadds@rockbox.org>2008-07-12 23:01:49 +0000
committerRob Purchase <shotofadds@rockbox.org>2008-07-12 23:01:49 +0000
commitee72b3bbc6885628466bab093b181778bdfde974 (patch)
tree48021443c9e6f0ff22438fdfa3746c6c08ee3b77 /firmware/target/arm/tcc780x/ata-nand-tcc780x.c
parent6e4aab0fe97bb58f36d113ccc9e7b5ac7fddf923 (diff)
downloadrockbox-ee72b3bbc6885628466bab093b181778bdfde974.tar.gz
rockbox-ee72b3bbc6885628466bab093b181778bdfde974.zip
Make the TCC780x NAND driver also build for 77x targets. This is work-in-progress stuff and does not yet work fully on 77x, but it's a step in the right direction. Also replace some magic numbers with #defines.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18019 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/tcc780x/ata-nand-tcc780x.c')
-rw-r--r--firmware/target/arm/tcc780x/ata-nand-tcc780x.c867
1 files changed, 0 insertions, 867 deletions
diff --git a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c b/firmware/target/arm/tcc780x/ata-nand-tcc780x.c
deleted file mode 100644
index 80245c91bd..0000000000
--- a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c
+++ /dev/null
@@ -1,867 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Rob Purchase
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "ata.h"
22#include "ata-target.h"
23#include "system.h"
24#include <string.h>
25#include "led.h"
26#include "panic.h"
27
28/* The NAND driver is currently work-in-progress and as such contains
29 some dead code and debug stuff, such as the next few lines. */
30#include "lcd.h"
31#include "font.h"
32#include "button.h"
33#include <sprintf.h>
34
35/* #define USE_TCC_LPT */
36/* #define USE_ECC_CORRECTION */
37
38/* for compatibility */
39int ata_spinup_time = 0;
40
41long last_disk_activity = -1;
42
43/** static, private data **/
44static bool initialized = false;
45
46static struct mutex ata_mtx SHAREDBSS_ATTR;
47
48#define SECTOR_SIZE 512
49
50/* TCC780x NAND Flash Controller */
51
52#define NFC_CMD (*(volatile unsigned long *)0xF0053000)
53#define NFC_SADDR (*(volatile unsigned long *)0xF005300C)
54#define NFC_SDATA (*(volatile unsigned long *)0xF0053040)
55#define NFC_WDATA (*(volatile unsigned long *)0xF0053010)
56#define NFC_CTRL (*(volatile unsigned long *)0xF0053050)
57 #define NFC_16BIT (1<<26)
58 #define NFC_CS0 (1<<23)
59 #define NFC_CS1 (1<<22)
60 #define NFC_READY (1<<20)
61#define NFC_IREQ (*(volatile unsigned long *)0xF0053060)
62#define NFC_RST (*(volatile unsigned long *)0xF0053064)
63
64/* TCC780x ECC Controller */
65
66#define ECC_CTRL (*(volatile unsigned long *)0xF005B000)
67 #define ECC_M4EN (1<<6)
68 #define ECC_ENC (1<<27)
69 #define ECC_READY (1<<26)
70#define ECC_BASE (*(volatile unsigned long *)0xF005B004)
71#define ECC_CLR (*(volatile unsigned long *)0xF005B00C)
72#define ECC_MLC0W (*(volatile unsigned long *)0xF005B030)
73#define ECC_MLC1W (*(volatile unsigned long *)0xF005B034)
74#define ECC_MLC2W (*(volatile unsigned long *)0xF005B038)
75#define ECC_ERRADDR (*(volatile unsigned long *)0xF005B050)
76#define ECC_ERRDATA (*(volatile unsigned long *)0xF005B060)
77#define ECC_ERR (*(volatile unsigned long *)0xF005B070)
78
79/* GPIOs */
80
81#define NAND_GPIO_SET(n) GPIOB_SET = n
82#define NAND_GPIO_CLEAR(n) GPIOB_CLEAR = n
83#define NAND_GPIO_OUT_EN(n) GPIOB_DIR |= n
84
85#define WE_GPIO_BIT (1<<19) /* Write Enable */
86#define CS_GPIO_BIT (1<<21) /* Chip Select (4 banks when used with NFC_CSx) */
87
88/* Chip characteristics, initialised by nand_get_chip_info() */
89
90static int page_size = 0;
91static int spare_size = 0;
92static int pages_per_block = 0;
93static int blocks_per_bank = 0;
94static int pages_per_bank = 0;
95static int row_cycles = 0;
96static int col_cycles = 0;
97static int total_banks = 0;
98static int sectors_per_page = 0;
99static int bytes_per_segment = 0;
100static int sectors_per_segment = 0;
101static int segments_per_bank = 0;
102
103/* Maximum values for static buffers */
104
105#define MAX_PAGE_SIZE 4096
106#define MAX_SPARE_SIZE 128
107#define MAX_BLOCKS_PER_BANK 8192
108#define MAX_PAGES_PER_BLOCK 128
109#define BLOCKS_PER_SEGMENT 4
110#define MAX_BANKS 4
111
112#define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / BLOCKS_PER_SEGMENT)
113
114/* Logical/Physical translation table */
115
116struct lpt_entry
117{
118 short bank;
119 short phys_segment;
120};
121static struct lpt_entry lpt_lookup[MAX_SEGMENTS];
122
123/* Write Caches */
124
125#define MAX_WRITE_CACHES 8
126
127struct write_cache
128{
129 short bank;
130 short phys_segment;
131 short log_segment;
132 short page_map[MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT];
133};
134static struct write_cache write_caches[MAX_WRITE_CACHES];
135
136static int write_caches_in_use = 0;
137
138#ifdef USE_TCC_LPT
139/* Read buffer (used for reading LPT blocks only) */
140static unsigned char page_buf[MAX_PAGE_SIZE + MAX_SPARE_SIZE]
141 __attribute__ ((aligned (4)));
142#endif
143
144#ifdef USE_ECC_CORRECTION
145static unsigned int ecc_sectors_corrected = 0;
146static unsigned int ecc_bits_corrected = 0;
147static unsigned int ecc_fail_count = 0;
148#endif
149
150
151/* Conversion functions */
152
153static inline int phys_segment_to_page_addr(int phys_segment, int page_in_seg)
154{
155 int page_addr = phys_segment * pages_per_block * 2;
156
157 if (page_in_seg & 1)
158 {
159 /* Data is located in block+1 */
160 page_addr += pages_per_block;
161 }
162
163 if (page_in_seg & 2)
164 {
165 /* Data is located in second plane */
166 page_addr += (blocks_per_bank/2) * pages_per_block;
167 }
168
169 page_addr += page_in_seg/4;
170
171 return page_addr;
172}
173
174
175/* NAND physical access functions */
176
177static void nand_chip_select(int bank)
178{
179 if (bank == -1)
180 {
181 /* Disable both chip selects */
182 NAND_GPIO_CLEAR(CS_GPIO_BIT);
183 NFC_CTRL |= NFC_CS0 | NFC_CS1;
184 }
185 else
186 {
187 /* NFC chip select */
188#ifdef USE_TCC_LPT
189 if (!(bank & 1))
190#else
191 if (bank & 1)
192#endif
193 {
194 NFC_CTRL &= ~NFC_CS0;
195 NFC_CTRL |= NFC_CS1;
196 }
197 else
198 {
199 NFC_CTRL |= NFC_CS0;
200 NFC_CTRL &= ~NFC_CS1;
201 }
202
203 /* Secondary chip select */
204 if (bank & 2)
205 NAND_GPIO_SET(CS_GPIO_BIT);
206 else
207 NAND_GPIO_CLEAR(CS_GPIO_BIT);
208 }
209}
210
211
212static void nand_read_id(int bank, unsigned char* id_buf)
213{
214 int i;
215
216 /* Enable NFC bus clock */
217 BCLKCTR |= DEV_NAND;
218
219 /* Reset NAND controller */
220 NFC_RST = 0;
221
222 /* Set slow cycle timings since the chip is as yet unidentified */
223 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x353;
224
225 nand_chip_select(bank);
226
227 /* Set write protect */
228 NAND_GPIO_CLEAR(WE_GPIO_BIT);
229
230 /* Reset command */
231 NFC_CMD = 0xFF;
232
233 /* Set 8-bit data width */
234 NFC_CTRL &= ~NFC_16BIT;
235
236 /* Read ID command, single address cycle */
237 NFC_CMD = 0x90;
238 NFC_SADDR = 0x00;
239
240 /* Read the 5 chip ID bytes */
241 for (i = 0; i < 5; i++)
242 {
243 id_buf[i] = NFC_SDATA & 0xFF;
244 }
245
246 nand_chip_select(-1);
247
248 /* Disable NFC bus clock */
249 BCLKCTR &= ~DEV_NAND;
250}
251
252
253static void nand_read_uid(int bank, unsigned int* uid_buf)
254{
255 int i;
256
257 /* Enable NFC bus clock */
258 BCLKCTR |= DEV_NAND;
259
260 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
261 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
262
263 nand_chip_select(bank);
264
265 /* Set write protect */
266 NAND_GPIO_CLEAR(WE_GPIO_BIT);
267
268 /* Set 8-bit data width */
269 NFC_CTRL &= ~NFC_16BIT;
270
271 /* Undocumented (SAMSUNG specific?) commands set the chip into a
272 special mode allowing a normally-hidden UID block to be read. */
273 NFC_CMD = 0x30;
274 NFC_CMD = 0x65;
275
276 /* Read command */
277 NFC_CMD = 0x00;
278
279 /* Write row/column address */
280 for (i = 0; i < col_cycles; i++) NFC_SADDR = 0;
281 for (i = 0; i < row_cycles; i++) NFC_SADDR = 0;
282
283 /* End of read */
284 NFC_CMD = 0x30;
285
286 /* Wait until complete */
287 while (!(NFC_CTRL & NFC_READY)) {};
288
289 /* Copy data to buffer (data repeats after 8 words) */
290 for (i = 0; i < 8; i++)
291 {
292 uid_buf[i] = NFC_WDATA;
293 }
294
295 /* Reset the chip back to normal mode */
296 NFC_CMD = 0xFF;
297
298 nand_chip_select(-1);
299
300 /* Disable NFC bus clock */
301 BCLKCTR &= ~DEV_NAND;
302}
303
304
305static void nand_read_raw(int bank, int row, int column, int size, void* buf)
306{
307 int i;
308
309 /* Enable NFC bus clock */
310 BCLKCTR |= DEV_NAND;
311
312 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
313 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
314
315 nand_chip_select(bank);
316
317 /* Set write protect */
318 NAND_GPIO_CLEAR(WE_GPIO_BIT);
319
320 /* Set 8-bit data width */
321 NFC_CTRL &= ~NFC_16BIT;
322
323 /* Read command */
324 NFC_CMD = 0x00;
325
326 /* Write column address */
327 for (i = 0; i < col_cycles; i++)
328 {
329 NFC_SADDR = column & 0xFF;
330 column = column >> 8;
331 }
332
333 /* Write row address */
334 for (i = 0; i < row_cycles; i++)
335 {
336 NFC_SADDR = row & 0xFF;
337 row = row >> 8;
338 }
339
340 /* End of read command */
341 NFC_CMD = 0x30;
342
343 /* Wait until complete */
344 while (!(NFC_CTRL & NFC_READY)) {};
345
346 /* Read data into page buffer */
347 if (((unsigned int)buf & 3) || (size & 3))
348 {
349 /* Use byte copy since either the buffer or size are not word-aligned */
350 /* TODO: Byte copy only where necessary (use words for mid-section) */
351 for (i = 0; i < size; i++)
352 {
353 ((unsigned char*)buf)[i] = NFC_SDATA;
354 }
355 }
356 else
357 {
358 /* Use 4-byte copy as buffer and size are both word-aligned */
359 for (i = 0; i < (size/4); i++)
360 {
361 ((unsigned int*)buf)[i] = NFC_WDATA;
362 }
363 }
364
365 nand_chip_select(-1);
366
367 /* Disable NFC bus clock */
368 BCLKCTR &= ~DEV_NAND;
369}
370
371
372static void nand_get_chip_info(void)
373{
374 bool found = false;
375 unsigned char manuf_id;
376 unsigned char id_buf[8];
377
378 /* Read chip id from bank 0 */
379 nand_read_id(0, id_buf);
380
381 manuf_id = id_buf[0];
382
383 switch (manuf_id)
384 {
385 case 0xEC: /* SAMSUNG */
386
387 switch(id_buf[1]) /* Chip Id */
388 {
389 case 0xD5: /* K9LAG08UOM */
390
391 page_size = 2048;
392 spare_size = 64;
393 pages_per_block = 128;
394 blocks_per_bank = 8192;
395 col_cycles = 2;
396 row_cycles = 3;
397
398 found = true;
399 break;
400
401 case 0xD7: /* K9LBG08UOM */
402
403 page_size = 4096;
404 spare_size = 128;
405 pages_per_block = 128;
406 blocks_per_bank = 8192;
407 col_cycles = 2;
408 row_cycles = 3;
409
410 found = true;
411 break;
412 }
413 break;
414 }
415
416 if (!found)
417 {
418 panicf("Unknown NAND: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
419 id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
420 }
421
422 pages_per_bank = blocks_per_bank * pages_per_block;
423 segments_per_bank = blocks_per_bank / BLOCKS_PER_SEGMENT;
424 bytes_per_segment = page_size * pages_per_block * BLOCKS_PER_SEGMENT;
425 sectors_per_page = page_size / SECTOR_SIZE;
426 sectors_per_segment = bytes_per_segment / SECTOR_SIZE;
427
428 /* Establish how many banks are present */
429 nand_read_id(1, id_buf);
430
431 if (id_buf[0] == manuf_id)
432 {
433 /* Bank 1 is populated, now check if banks 2/3 are valid */
434 nand_read_id(2, id_buf);
435
436 if (id_buf[0] == manuf_id)
437 {
438 /* Bank 2 returned matching id - check if 2/3 are shadowing 0/1 */
439 unsigned int uid_buf0[8];
440 unsigned int uid_buf2[8];
441
442 nand_read_uid(0, uid_buf0);
443 nand_read_uid(2, uid_buf2);
444
445 if (memcmp(uid_buf0, uid_buf2, 32) == 0)
446 {
447 /* UIDs match, assume banks 2/3 are shadowing 0/1 */
448 total_banks = 2;
449 }
450 else
451 {
452 /* UIDs differ, assume banks 2/3 are valid */
453 total_banks = 4;
454 }
455 }
456 else
457 {
458 /* Bank 2 returned differing id - assume 2/3 are junk */
459 total_banks = 2;
460 }
461 }
462 else
463 {
464 /* Bank 1 returned differing id - assume it is junk */
465 total_banks = 1;
466 }
467
468 /*
469 Sanity checks:
470 1. "BMP" tag at block 0, page 0, offset <page_size> [always present]
471 2. On most D2s, <page_size>+3 is 'M' and <page_size>+4 is no. of banks.
472 This is not present on some older players (formatted with early FW?)
473 */
474
475 nand_read_raw(0, /* bank */
476 0, /* page */
477 page_size, /* offset */
478 8, id_buf);
479
480 if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present");
481
482 if (id_buf[3] == 'M')
483 {
484 if (id_buf[4] != total_banks) panicf("BMPM total_banks mismatch");
485 }
486}
487
488
489static bool nand_read_sector_of_phys_page(int bank, int page,
490 int sector, void* buf)
491{
492#ifndef USE_ECC_CORRECTION
493 nand_read_raw(bank, page,
494 sector * (SECTOR_SIZE+16),
495 SECTOR_SIZE, buf);
496 return true;
497#else
498 /* Not yet implemented */
499 return false;
500#endif
501}
502
503
504static bool nand_read_sector_of_phys_segment(int bank, int phys_segment,
505 int page_in_seg, int sector,
506 void* buf)
507{
508 int page_addr = phys_segment_to_page_addr(phys_segment,
509 page_in_seg);
510
511 return nand_read_sector_of_phys_page(bank, page_addr, sector, buf);
512}
513
514
515static bool nand_read_sector_of_logical_segment(int log_segment, int sector,
516 void* buf)
517{
518 int page_in_segment = sector / sectors_per_page;
519 int sector_in_page = sector % sectors_per_page;
520
521 int bank = lpt_lookup[log_segment].bank;
522 int phys_segment = lpt_lookup[log_segment].phys_segment;
523
524 /* Check if any of the write caches refer to this segment/page.
525 If present we need to read the cached page instead. */
526
527 int cache_num = 0;
528 bool found = false;
529
530 while (!found && cache_num < write_caches_in_use)
531 {
532 if (write_caches[cache_num].log_segment == log_segment
533 && write_caches[cache_num].page_map[page_in_segment] != -1)
534 {
535 found = true;
536 bank = write_caches[cache_num].bank;
537 phys_segment = write_caches[cache_num].phys_segment;
538 page_in_segment = write_caches[cache_num].page_map[page_in_segment];
539 }
540 else
541 {
542 cache_num++;
543 }
544 }
545
546 return nand_read_sector_of_phys_segment(bank, phys_segment,
547 page_in_segment,
548 sector_in_page, buf);
549}
550
551
552#ifdef USE_TCC_LPT
553
554/* Reading the LPT from NAND is not yet fully understood. This code is therefore
555 not enabled by default, as it gives much worse results than the bank-scanning
556 approach currently used. */
557
558static void read_lpt_block(int bank, int phys_segment)
559{
560 int page = 1; /* table starts at page 1 of segment */
561 bool cont = true;
562
563 struct lpt_entry* lpt_ptr = NULL;
564
565 while (cont && page < pages_per_block)
566 {
567 int i = 0;
568 unsigned int* int_buf = (int*)page_buf;
569
570 nand_read_sector_of_phys_segment(bank, phys_segment,
571 page, 0, /* only sector 0 is used */
572 page_buf);
573
574 /* Find out which chunk of the LPT table this section contains.
575 Do this by reading the logical segment number of entry 0 */
576 if (lpt_ptr == NULL)
577 {
578 int first_bank = int_buf[0] / segments_per_bank;
579 int first_phys_segment = int_buf[0] % segments_per_bank;
580
581 unsigned char spare_buf[16];
582
583 nand_read_raw(first_bank,
584 phys_segment_to_page_addr(first_phys_segment, 0),
585 SECTOR_SIZE, /* offset */
586 16, spare_buf);
587
588 int first_log_segment = (spare_buf[6] << 8) | spare_buf[7];
589
590 lpt_ptr = &lpt_lookup[first_log_segment];
591
592#if defined(BOOTLOADER) && 1
593 printf("lpt @ %lx:%lx (ls:%lx)",
594 first_bank, first_phys_segment, first_log_segment);
595#endif
596 }
597
598 while (cont && (i < SECTOR_SIZE/4))
599 {
600 if (int_buf[i] != 0xFFFFFFFF)
601 {
602 lpt_ptr->bank = int_buf[i] / segments_per_bank;
603 lpt_ptr->phys_segment = int_buf[i] % segments_per_bank;
604
605 lpt_ptr++;
606 i++;
607 }
608 else cont = false;
609 }
610 page++;
611 }
612}
613
614#endif /* USE_TCC_LPT */
615
616
617static void read_write_cache_segment(int bank, int phys_segment)
618{
619 int page;
620 unsigned char spare_buf[16];
621
622 if (write_caches_in_use == MAX_WRITE_CACHES)
623 panicf("Max NAND write caches reached");
624
625 write_caches[write_caches_in_use].bank = bank;
626 write_caches[write_caches_in_use].phys_segment = phys_segment;
627
628 /* Loop over each page in the phys segment (from page 1 onwards).
629 Read spare for 1st sector, store location of page in array. */
630 for (page = 1; page < pages_per_block * BLOCKS_PER_SEGMENT; page++)
631 {
632 unsigned short cached_page;
633 unsigned short log_segment;
634
635 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
636 SECTOR_SIZE, /* offset to first sector's spare */
637 16, spare_buf);
638
639 cached_page = (spare_buf[3] << 8) | spare_buf[2]; /* why does endian */
640 log_segment = (spare_buf[6] << 8) | spare_buf[7]; /* -ness differ? */
641
642 if (cached_page != 0xFFFF)
643 {
644 write_caches[write_caches_in_use].log_segment = log_segment;
645 write_caches[write_caches_in_use].page_map[cached_page] = page;
646 }
647 }
648 write_caches_in_use++;
649}
650
651
652int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
653 void* inbuf)
654{
655#ifdef HAVE_MULTIVOLUME
656 (void)drive; /* unused for now */
657#endif
658 mutex_lock(&ata_mtx);
659
660 while (incount > 0)
661 {
662 int done = 0;
663 int segment = start / sectors_per_segment;
664 int secmod = start % sectors_per_segment;
665
666 while (incount > 0 && secmod < sectors_per_segment)
667 {
668 if (!nand_read_sector_of_logical_segment(segment, secmod, inbuf))
669 {
670 mutex_unlock(&ata_mtx);
671 return -1;
672 }
673
674 inbuf += SECTOR_SIZE;
675 incount--;
676 secmod++;
677 done++;
678 }
679
680 if (done < 0)
681 {
682 mutex_unlock(&ata_mtx);
683 return -1;
684 }
685 start += done;
686 }
687
688 mutex_unlock(&ata_mtx);
689 return 0;
690}
691
692int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count,
693 const void* outbuf)
694{
695#ifdef HAVE_MULTIVOLUME
696 (void)drive; /* unused for now */
697#endif
698
699 /* TODO: Learn more about TNFTL and implement this one day... */
700 (void)start;
701 (void)count;
702 (void)outbuf;
703 return -1;
704}
705
706void ata_spindown(int seconds)
707{
708 /* null */
709 (void)seconds;
710}
711
712bool ata_disk_is_active(void)
713{
714 /* null */
715 return 0;
716}
717
718void ata_sleep(void)
719{
720 /* null */
721}
722
723void ata_spin(void)
724{
725 /* null */
726}
727
728/* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */
729int ata_hard_reset(void)
730{
731 /* null */
732 return 0;
733}
734
735int ata_soft_reset(void)
736{
737 /* null */
738 return 0;
739}
740
741void ata_enable(bool on)
742{
743 /* null - flash controller is enabled/disabled as needed. */
744 (void)on;
745}
746
747int ata_init(void)
748{
749 int i, bank, phys_segment;
750 unsigned char spare_buf[16];
751
752 if (initialized) return 0;
753
754 /* Set GPIO direction for chip select & write protect */
755 NAND_GPIO_OUT_EN(CS_GPIO_BIT | WE_GPIO_BIT);
756
757 /* Get chip characteristics and number of banks */
758 nand_get_chip_info();
759
760 for (i = 0; i < MAX_SEGMENTS; i++)
761 {
762 lpt_lookup[i].bank = -1;
763 lpt_lookup[i].phys_segment = -1;
764 }
765
766 write_caches_in_use = 0;
767
768 for (i = 0; i < MAX_WRITE_CACHES; i++)
769 {
770 int page;
771
772 write_caches[i].log_segment = -1;
773 write_caches[i].bank = -1;
774 write_caches[i].phys_segment = -1;
775
776 for (page = 0; page < MAX_PAGES_PER_BLOCK * 4; page++)
777 {
778 write_caches[i].page_map[page] = -1;
779 }
780 }
781
782 /* Scan banks to build up block translation table */
783 for (bank = 0; bank < total_banks; bank++)
784 {
785 for (phys_segment = 0; phys_segment < segments_per_bank; phys_segment++)
786 {
787 /* Read spare bytes from first sector of each segment */
788 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0),
789 SECTOR_SIZE, /* offset */
790 16, spare_buf);
791
792 switch (spare_buf[4]) /* block type */
793 {
794#ifdef USE_TCC_LPT
795 case 0x12:
796 {
797 /* Log->Phys Translation table (for Main data area) */
798 read_lpt_block(bank, phys_segment);
799 break;
800 }
801#else
802 case 0x17:
803 {
804 /* Main data area segment */
805 unsigned short segment = (spare_buf[6] << 8) | spare_buf[7];
806
807 if (segment < MAX_SEGMENTS)
808 {
809 lpt_lookup[segment].bank = bank;
810 lpt_lookup[segment].phys_segment = phys_segment;
811 }
812 break;
813 }
814#endif
815
816 case 0x15:
817 {
818 /* Recently-written page data (for Main data area) */
819 read_write_cache_segment(bank, phys_segment);
820 break;
821 }
822 }
823 }
824 }
825
826#ifndef USE_TCC_LPT
827 /* Scan banks a second time as 0x13 segments appear to override 0x17 */
828 for (bank = 0; bank < total_banks; bank++)
829 {
830 for (phys_segment = 0; phys_segment < segments_per_bank; phys_segment++)
831 {
832 /* Read spare bytes from first sector of each segment */
833 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0),
834 SECTOR_SIZE, /* offset */
835 16, spare_buf);
836
837 switch (spare_buf[4]) /* block type */
838 {
839 case 0x13:
840 {
841 /* Main data area segment */
842 unsigned short segment = (spare_buf[6] << 8) | spare_buf[7];
843
844 if (segment < MAX_SEGMENTS)
845 {
846 /* 0x17 seems to override 0x13, so store in our LPT */
847 lpt_lookup[segment].bank = bank;
848 lpt_lookup[segment].phys_segment = phys_segment;
849 }
850 break;
851 }
852 }
853 }
854 }
855#endif
856
857 initialized = true;
858
859 return 0;
860}
861
862
863/* TEMP: This will return junk, it's here for compilation only */
864unsigned short* ata_get_identify(void)
865{
866 return (unsigned short*)0x21000000; /* Unused DRAM */
867}