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