summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/nand_id.c30
-rw-r--r--firmware/export/nand_id.h5
-rw-r--r--firmware/target/arm/ata-nand-telechips.c128
3 files changed, 91 insertions, 72 deletions
diff --git a/firmware/drivers/nand_id.c b/firmware/drivers/nand_id.c
index dfb96c8820..f2b9861c7c 100644
--- a/firmware/drivers/nand_id.c
+++ b/firmware/drivers/nand_id.c
@@ -31,16 +31,24 @@ struct nand_manufacturer
31 31
32static const struct nand_info samsung[] = 32static const struct nand_info samsung[] =
33{ 33{
34/* { id1, id2, pages_per_block, blocks_per_bank, page_size, spare_size, col_cycles, row_cycles } */ 34/*
35 35 id1, id2
36 /* K9F4G08UOM */ 36 pages/block, blocks, page_size, spare_size, col_cycles, row_cycles, planes
37 {0xDC, 0x10, 64, 4096, 2048, 64, 2, 3 }, 37*/
38 /* K9K8G08UOM */ 38 {0xDC, 0x10, /* K9F4G08UOM */
39 {0xD3, 0x51, 64, 8192, 2048, 64, 2, 3 }, 39 64, 4096, 2048, 64, 2, 3, 1 },
40 /* K9LAG08UOM */ 40
41 {0xD5, 0x55, 128, 8192, 2048, 64, 2, 3 }, 41 {0xD3, 0x51, /* K9K8G08UOM */
42 /* K9LBG08UOM, K9HBG08U1M, K9MCG08U5M */ 42 64, 8192, 2048, 64, 2, 3, 1 },
43 {0xD7, 0x55, 128, 8192, 4096, 128, 2, 3 }, 43
44 {0xD5, 0x14, /* K9GAG08UOM */
45 128, 4096, 4096, 128, 2, 3, 2 },
46
47 {0xD5, 0x55, /* K9LAG08UOM, K9HBG08U1M, K9MCG08U5M */
48 128, 8192, 2048, 64, 2, 3, 4 },
49
50 {0xD7, 0x55, /* K9LBG08UOM */
51 128, 8192, 4096, 128, 2, 3, 4 },
44}; 52};
45 53
46#define NI(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))} 54#define NI(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))}
@@ -49,7 +57,7 @@ static const struct nand_manufacturer all[] =
49 NI(0xEC, samsung), 57 NI(0xEC, samsung),
50}; 58};
51 59
52// -------------------------------------------------------------------------------------------------- 60// -----------------------------------------------------------------------------
53 61
54struct nand_info* nand_identify(unsigned char data[5]) 62struct nand_info* nand_identify(unsigned char data[5])
55 { 63 {
diff --git a/firmware/export/nand_id.h b/firmware/export/nand_id.h
index 188b6c161a..fb7ea18b8d 100644
--- a/firmware/export/nand_id.h
+++ b/firmware/export/nand_id.h
@@ -29,8 +29,9 @@ struct nand_info
29 unsigned short blocks_per_bank; 29 unsigned short blocks_per_bank;
30 unsigned short page_size; 30 unsigned short page_size;
31 unsigned short spare_size; 31 unsigned short spare_size;
32 unsigned short col_cycles; 32 unsigned char col_cycles;
33 unsigned short row_cycles; 33 unsigned char row_cycles;
34 unsigned char planes;
34}; 35};
35 36
36struct nand_info* nand_identify(unsigned char data[5]); 37struct nand_info* nand_identify(unsigned char data[5]);
diff --git a/firmware/target/arm/ata-nand-telechips.c b/firmware/target/arm/ata-nand-telechips.c
index 60d2211977..6d1d536194 100644
--- a/firmware/target/arm/ata-nand-telechips.c
+++ b/firmware/target/arm/ata-nand-telechips.c
@@ -44,11 +44,9 @@ static struct mutex ata_mtx SHAREDBSS_ATTR;
44 44
45#if defined(COWON_D2) || defined(IAUDIO_7) 45#if defined(COWON_D2) || defined(IAUDIO_7)
46#define FTL_V2 46#define FTL_V2
47#define BLOCKS_PER_SEGMENT 4
48#define MAX_WRITE_CACHES 8 47#define MAX_WRITE_CACHES 8
49#else 48#else
50#define FTL_V1 49#define FTL_V1
51#define BLOCKS_PER_SEGMENT 1
52#define MAX_WRITE_CACHES 4 50#define MAX_WRITE_CACHES 4
53#endif 51#endif
54 52
@@ -87,28 +85,26 @@ static struct mutex ata_mtx SHAREDBSS_ATTR;
87 85
88/* Chip characteristics, initialised by nand_get_chip_info() */ 86/* Chip characteristics, initialised by nand_get_chip_info() */
89 87
90static int page_size = 0; 88static struct nand_info* nand_data = NULL;
91static int spare_size = 0; 89
92static int pages_per_block = 0; 90static int total_banks = 0;
93static int blocks_per_bank = 0; 91static int pages_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; 92static int sectors_per_page = 0;
99static int bytes_per_segment = 0; 93static int bytes_per_segment = 0;
100static int sectors_per_segment = 0; 94static int sectors_per_segment = 0;
101static int segments_per_bank = 0; 95static int segments_per_bank = 0;
96static int pages_per_segment = 0;
102 97
103/* Maximum values for static buffers */ 98/* Maximum values for static buffers */
104 99
105#define MAX_PAGE_SIZE 4096 100#define MAX_PAGE_SIZE 4096
106#define MAX_SPARE_SIZE 128 101#define MAX_SPARE_SIZE 128
107#define MAX_BLOCKS_PER_BANK 8192 102#define MAX_BLOCKS_PER_BANK 8192
108#define MAX_PAGES_PER_BLOCK 128 103#define MAX_PAGES_PER_BLOCK 128
109#define MAX_BANKS 4 104#define MAX_BANKS 4
105#define MAX_BLOCKS_PER_SEGMENT 4
110 106
111#define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / BLOCKS_PER_SEGMENT) 107#define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / MAX_BLOCKS_PER_SEGMENT)
112 108
113/* Logical/Physical translation table */ 109/* Logical/Physical translation table */
114 110
@@ -134,7 +130,7 @@ struct write_cache
134 short inplace_pages_used; 130 short inplace_pages_used;
135 short random_bank; 131 short random_bank;
136 short random_phys_segment; 132 short random_phys_segment;
137 short page_map[MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT]; 133 short page_map[MAX_PAGES_PER_BLOCK * MAX_BLOCKS_PER_SEGMENT];
138}; 134};
139static struct write_cache write_caches[MAX_WRITE_CACHES]; 135static struct write_cache write_caches[MAX_WRITE_CACHES];
140 136
@@ -149,27 +145,41 @@ static unsigned int ecc_fail_count = 0;
149 145
150/* Conversion functions */ 146/* Conversion functions */
151 147
152static inline int phys_segment_to_page_addr(int phys_segment, int page_in_seg) 148static int phys_segment_to_page_addr(int phys_segment, int page_in_seg)
153{ 149{
154#if BLOCKS_PER_SEGMENT == 4 /* D2 */ 150 int page_addr = 0;
155 int page_addr = phys_segment * pages_per_block * 2;
156 151
157 if (page_in_seg & 1) 152 switch (nand_data->planes)
158 { 153 {
159 /* Data is located in block+1 */ 154 case 1:
160 page_addr += pages_per_block; 155 {
161 } 156 page_addr = (phys_segment * nand_data->pages_per_block);
157 break;
158 }
162 159
163 if (page_in_seg & 2) 160 case 2:
164 { 161 case 4:
165 /* Data is located in second plane */ 162 {
166 page_addr += (blocks_per_bank/2) * pages_per_block; 163 page_addr = phys_segment * nand_data->pages_per_block * 2;
167 }
168 164
169 page_addr += page_in_seg/4; 165 if (page_in_seg & 1)
170#elif BLOCKS_PER_SEGMENT == 1 /* M200 */ 166 {
171 int page_addr = (phys_segment * pages_per_block) + page_in_seg; 167 /* Data is located in block+1 */
172#endif 168 page_addr += nand_data->pages_per_block;
169 }
170
171 if (nand_data->planes == 4 && page_in_seg & 2)
172 {
173 /* Data is located in 2nd half of bank */
174 page_addr +=
175 (nand_data->blocks_per_bank/2) * nand_data->pages_per_block;
176 }
177
178 break;
179 }
180 }
181
182 page_addr += (page_in_seg / nand_data->planes);
173 183
174 return page_addr; 184 return page_addr;
175} 185}
@@ -276,8 +286,8 @@ static void nand_read_uid(int bank, unsigned int* uid_buf)
276 NFC_CMD = 0x00; 286 NFC_CMD = 0x00;
277 287
278 /* Write row/column address */ 288 /* Write row/column address */
279 for (i = 0; i < col_cycles; i++) NFC_SADDR = 0; 289 for (i = 0; i < nand_data->col_cycles; i++) NFC_SADDR = 0;
280 for (i = 0; i < row_cycles; i++) NFC_SADDR = 0; 290 for (i = 0; i < nand_data->row_cycles; i++) NFC_SADDR = 0;
281 291
282 /* End of read */ 292 /* End of read */
283 NFC_CMD = 0x30; 293 NFC_CMD = 0x30;
@@ -323,14 +333,14 @@ static void nand_read_raw(int bank, int row, int column, int size, void* buf)
323 NFC_CMD = 0x00; 333 NFC_CMD = 0x00;
324 334
325 /* Write column address */ 335 /* Write column address */
326 for (i = 0; i < col_cycles; i++) 336 for (i = 0; i < nand_data->col_cycles; i++)
327 { 337 {
328 NFC_SADDR = column & 0xFF; 338 NFC_SADDR = column & 0xFF;
329 column = column >> 8; 339 column = column >> 8;
330 } 340 }
331 341
332 /* Write row address */ 342 /* Write row address */
333 for (i = 0; i < row_cycles; i++) 343 for (i = 0; i < nand_data->row_cycles; i++)
334 { 344 {
335 NFC_SADDR = row & 0xFF; 345 NFC_SADDR = row & 0xFF;
336 row = row >> 8; 346 row = row >> 8;
@@ -379,7 +389,7 @@ static void nand_get_chip_info(void)
379 manuf_id = id_buf[0]; 389 manuf_id = id_buf[0];
380 390
381 /* Identify the chip geometry */ 391 /* Identify the chip geometry */
382 struct nand_info* nand_data = nand_identify(id_buf); 392 nand_data = nand_identify(id_buf);
383 393
384 if (nand_data == NULL) 394 if (nand_data == NULL)
385 { 395 {
@@ -387,18 +397,18 @@ static void nand_get_chip_info(void)
387 id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); 397 id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
388 } 398 }
389 399
390 page_size = nand_data->page_size; 400 pages_per_bank = nand_data->blocks_per_bank * nand_data->pages_per_block;
391 spare_size = nand_data->spare_size; 401
392 pages_per_block = nand_data->pages_per_block; 402 segments_per_bank = nand_data->blocks_per_bank / nand_data->planes;
393 blocks_per_bank = nand_data->blocks_per_bank; 403
394 col_cycles = nand_data->col_cycles; 404 bytes_per_segment = nand_data->page_size * nand_data->pages_per_block
395 row_cycles = nand_data->row_cycles; 405 * nand_data->planes;
396 406
397 pages_per_bank = blocks_per_bank * pages_per_block; 407 sectors_per_page = nand_data->page_size / SECTOR_SIZE;
398 segments_per_bank = blocks_per_bank / BLOCKS_PER_SEGMENT; 408
399 bytes_per_segment = page_size * pages_per_block * BLOCKS_PER_SEGMENT;
400 sectors_per_page = page_size / SECTOR_SIZE;
401 sectors_per_segment = bytes_per_segment / SECTOR_SIZE; 409 sectors_per_segment = bytes_per_segment / SECTOR_SIZE;
410
411 pages_per_segment = sectors_per_segment / sectors_per_page;
402 412
403 /* Establish how many banks are present */ 413 /* Establish how many banks are present */
404 nand_read_id(1, id_buf); 414 nand_read_id(1, id_buf);
@@ -447,10 +457,9 @@ static void nand_get_chip_info(void)
447 This is not present on some older players (formatted with early FW?) 457 This is not present on some older players (formatted with early FW?)
448 */ 458 */
449 459
450 nand_read_raw(0, /* bank */ 460 nand_read_raw(0, 0, /* bank, page */
451 0, /* page */ 461 nand_data->page_size, /* offset */
452 page_size, /* offset */ 462 8, id_buf); /* length, dest */
453 8, id_buf);
454 463
455 if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present"); 464 if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present");
456 465
@@ -611,7 +620,9 @@ static void read_random_writes_cache(int bank, int phys_segment)
611#ifndef FTL_V1 620#ifndef FTL_V1
612 /* Loop over each page in the phys segment (from page 1 onwards). 621 /* Loop over each page in the phys segment (from page 1 onwards).
613 Read spare for 1st sector, store location of page in array. */ 622 Read spare for 1st sector, store location of page in array. */
614 for (page = 1; page < pages_per_block * BLOCKS_PER_SEGMENT; page++) 623 for (page = 1;
624 page < (nand_data->pages_per_block * nand_data->planes);
625 page++)
615 { 626 {
616 unsigned short cached_page; 627 unsigned short cached_page;
617 628
@@ -663,7 +674,7 @@ static void read_inplace_writes_cache(int bank, int phys_segment)
663 674
664 /* Find how many pages have been written to the new segment */ 675 /* Find how many pages have been written to the new segment */
665 while (log_segment != -1 && 676 while (log_segment != -1 &&
666 page < (pages_per_block * BLOCKS_PER_SEGMENT) - 1) 677 page < (nand_data->pages_per_block * nand_data->planes) - 1)
667 { 678 {
668 page++; 679 page++;
669 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), 680 nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
@@ -802,10 +813,9 @@ int nand_init(void)
802 if (type == SECTYPE_MAIN_INPLACE_CACHE) 813 if (type == SECTYPE_MAIN_INPLACE_CACHE)
803 { 814 {
804 /* Check last sector of sequential write cache block */ 815 /* Check last sector of sequential write cache block */
805 nand_read_raw(bank, 816 nand_read_raw(bank, phys_segment_to_page_addr
806 phys_segment_to_page_addr(phys_segment, 817 (phys_segment, pages_per_segment - 1),
807 (pages_per_block * BLOCKS_PER_SEGMENT) - 1), 818 nand_data->page_size + nand_data->spare_size - 16,
808 page_size + spare_size - 16,
809 16, spare_buf); 819 16, spare_buf);
810 820
811 /* If last sector has been written, treat block as main data */ 821 /* If last sector has been written, treat block as main data */