forked from len0rd/rockbox
TCC NAND: The BLOCKS_PER_SEGMENT define was actually the number of planes mentioned in the Samsung NAND datasheet. Add this to the nand_id struct, so that it can be runtime detected (required for some D2s to boot). Use the struct directly instead of making a local copy, and format the nand_info table to 80 columns.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20186 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
3fe6152a1a
commit
9f6e117e82
3 changed files with 90 additions and 71 deletions
|
|
@ -31,16 +31,24 @@ struct nand_manufacturer
|
||||||
|
|
||||||
static const struct nand_info samsung[] =
|
static const struct nand_info samsung[] =
|
||||||
{
|
{
|
||||||
/* { id1, id2, pages_per_block, blocks_per_bank, page_size, spare_size, col_cycles, row_cycles } */
|
/*
|
||||||
|
id1, id2
|
||||||
|
pages/block, blocks, page_size, spare_size, col_cycles, row_cycles, planes
|
||||||
|
*/
|
||||||
|
{0xDC, 0x10, /* K9F4G08UOM */
|
||||||
|
64, 4096, 2048, 64, 2, 3, 1 },
|
||||||
|
|
||||||
/* K9F4G08UOM */
|
{0xD3, 0x51, /* K9K8G08UOM */
|
||||||
{0xDC, 0x10, 64, 4096, 2048, 64, 2, 3 },
|
64, 8192, 2048, 64, 2, 3, 1 },
|
||||||
/* K9K8G08UOM */
|
|
||||||
{0xD3, 0x51, 64, 8192, 2048, 64, 2, 3 },
|
{0xD5, 0x14, /* K9GAG08UOM */
|
||||||
/* K9LAG08UOM */
|
128, 4096, 4096, 128, 2, 3, 2 },
|
||||||
{0xD5, 0x55, 128, 8192, 2048, 64, 2, 3 },
|
|
||||||
/* K9LBG08UOM, K9HBG08U1M, K9MCG08U5M */
|
{0xD5, 0x55, /* K9LAG08UOM, K9HBG08U1M, K9MCG08U5M */
|
||||||
{0xD7, 0x55, 128, 8192, 4096, 128, 2, 3 },
|
128, 8192, 2048, 64, 2, 3, 4 },
|
||||||
|
|
||||||
|
{0xD7, 0x55, /* K9LBG08UOM */
|
||||||
|
128, 8192, 4096, 128, 2, 3, 4 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NI(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))}
|
#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[] =
|
||||||
NI(0xEC, samsung),
|
NI(0xEC, samsung),
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct nand_info* nand_identify(unsigned char data[5])
|
struct nand_info* nand_identify(unsigned char data[5])
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,9 @@ struct nand_info
|
||||||
unsigned short blocks_per_bank;
|
unsigned short blocks_per_bank;
|
||||||
unsigned short page_size;
|
unsigned short page_size;
|
||||||
unsigned short spare_size;
|
unsigned short spare_size;
|
||||||
unsigned short col_cycles;
|
unsigned char col_cycles;
|
||||||
unsigned short row_cycles;
|
unsigned char row_cycles;
|
||||||
|
unsigned char planes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nand_info* nand_identify(unsigned char data[5]);
|
struct nand_info* nand_identify(unsigned char data[5]);
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,9 @@ static struct mutex ata_mtx SHAREDBSS_ATTR;
|
||||||
|
|
||||||
#if defined(COWON_D2) || defined(IAUDIO_7)
|
#if defined(COWON_D2) || defined(IAUDIO_7)
|
||||||
#define FTL_V2
|
#define FTL_V2
|
||||||
#define BLOCKS_PER_SEGMENT 4
|
|
||||||
#define MAX_WRITE_CACHES 8
|
#define MAX_WRITE_CACHES 8
|
||||||
#else
|
#else
|
||||||
#define FTL_V1
|
#define FTL_V1
|
||||||
#define BLOCKS_PER_SEGMENT 1
|
|
||||||
#define MAX_WRITE_CACHES 4
|
#define MAX_WRITE_CACHES 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -87,28 +85,26 @@ static struct mutex ata_mtx SHAREDBSS_ATTR;
|
||||||
|
|
||||||
/* Chip characteristics, initialised by nand_get_chip_info() */
|
/* Chip characteristics, initialised by nand_get_chip_info() */
|
||||||
|
|
||||||
static int page_size = 0;
|
static struct nand_info* nand_data = NULL;
|
||||||
static int spare_size = 0;
|
|
||||||
static int pages_per_block = 0;
|
static int total_banks = 0;
|
||||||
static int blocks_per_bank = 0;
|
static int pages_per_bank = 0;
|
||||||
static int pages_per_bank = 0;
|
|
||||||
static int row_cycles = 0;
|
|
||||||
static int col_cycles = 0;
|
|
||||||
static int total_banks = 0;
|
|
||||||
static int sectors_per_page = 0;
|
static int sectors_per_page = 0;
|
||||||
static int bytes_per_segment = 0;
|
static int bytes_per_segment = 0;
|
||||||
static int sectors_per_segment = 0;
|
static int sectors_per_segment = 0;
|
||||||
static int segments_per_bank = 0;
|
static int segments_per_bank = 0;
|
||||||
|
static int pages_per_segment = 0;
|
||||||
|
|
||||||
/* Maximum values for static buffers */
|
/* Maximum values for static buffers */
|
||||||
|
|
||||||
#define MAX_PAGE_SIZE 4096
|
#define MAX_PAGE_SIZE 4096
|
||||||
#define MAX_SPARE_SIZE 128
|
#define MAX_SPARE_SIZE 128
|
||||||
#define MAX_BLOCKS_PER_BANK 8192
|
#define MAX_BLOCKS_PER_BANK 8192
|
||||||
#define MAX_PAGES_PER_BLOCK 128
|
#define MAX_PAGES_PER_BLOCK 128
|
||||||
#define MAX_BANKS 4
|
#define MAX_BANKS 4
|
||||||
|
#define MAX_BLOCKS_PER_SEGMENT 4
|
||||||
|
|
||||||
#define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / BLOCKS_PER_SEGMENT)
|
#define MAX_SEGMENTS (MAX_BLOCKS_PER_BANK * MAX_BANKS / MAX_BLOCKS_PER_SEGMENT)
|
||||||
|
|
||||||
/* Logical/Physical translation table */
|
/* Logical/Physical translation table */
|
||||||
|
|
||||||
|
|
@ -134,7 +130,7 @@ struct write_cache
|
||||||
short inplace_pages_used;
|
short inplace_pages_used;
|
||||||
short random_bank;
|
short random_bank;
|
||||||
short random_phys_segment;
|
short random_phys_segment;
|
||||||
short page_map[MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT];
|
short page_map[MAX_PAGES_PER_BLOCK * MAX_BLOCKS_PER_SEGMENT];
|
||||||
};
|
};
|
||||||
static struct write_cache write_caches[MAX_WRITE_CACHES];
|
static struct write_cache write_caches[MAX_WRITE_CACHES];
|
||||||
|
|
||||||
|
|
@ -149,27 +145,41 @@ static unsigned int ecc_fail_count = 0;
|
||||||
|
|
||||||
/* Conversion functions */
|
/* Conversion functions */
|
||||||
|
|
||||||
static inline int phys_segment_to_page_addr(int phys_segment, int page_in_seg)
|
static int phys_segment_to_page_addr(int phys_segment, int page_in_seg)
|
||||||
{
|
{
|
||||||
#if BLOCKS_PER_SEGMENT == 4 /* D2 */
|
int page_addr = 0;
|
||||||
int page_addr = phys_segment * pages_per_block * 2;
|
|
||||||
|
|
||||||
if (page_in_seg & 1)
|
switch (nand_data->planes)
|
||||||
{
|
{
|
||||||
/* Data is located in block+1 */
|
case 1:
|
||||||
page_addr += pages_per_block;
|
{
|
||||||
|
page_addr = (phys_segment * nand_data->pages_per_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
page_addr = phys_segment * nand_data->pages_per_block * 2;
|
||||||
|
|
||||||
|
if (page_in_seg & 1)
|
||||||
|
{
|
||||||
|
/* Data is located in block+1 */
|
||||||
|
page_addr += nand_data->pages_per_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand_data->planes == 4 && page_in_seg & 2)
|
||||||
|
{
|
||||||
|
/* Data is located in 2nd half of bank */
|
||||||
|
page_addr +=
|
||||||
|
(nand_data->blocks_per_bank/2) * nand_data->pages_per_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page_in_seg & 2)
|
page_addr += (page_in_seg / nand_data->planes);
|
||||||
{
|
|
||||||
/* Data is located in second plane */
|
|
||||||
page_addr += (blocks_per_bank/2) * pages_per_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_addr += page_in_seg/4;
|
|
||||||
#elif BLOCKS_PER_SEGMENT == 1 /* M200 */
|
|
||||||
int page_addr = (phys_segment * pages_per_block) + page_in_seg;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return page_addr;
|
return page_addr;
|
||||||
}
|
}
|
||||||
|
|
@ -276,8 +286,8 @@ static void nand_read_uid(int bank, unsigned int* uid_buf)
|
||||||
NFC_CMD = 0x00;
|
NFC_CMD = 0x00;
|
||||||
|
|
||||||
/* Write row/column address */
|
/* Write row/column address */
|
||||||
for (i = 0; i < col_cycles; i++) NFC_SADDR = 0;
|
for (i = 0; i < nand_data->col_cycles; i++) NFC_SADDR = 0;
|
||||||
for (i = 0; i < row_cycles; i++) NFC_SADDR = 0;
|
for (i = 0; i < nand_data->row_cycles; i++) NFC_SADDR = 0;
|
||||||
|
|
||||||
/* End of read */
|
/* End of read */
|
||||||
NFC_CMD = 0x30;
|
NFC_CMD = 0x30;
|
||||||
|
|
@ -323,14 +333,14 @@ static void nand_read_raw(int bank, int row, int column, int size, void* buf)
|
||||||
NFC_CMD = 0x00;
|
NFC_CMD = 0x00;
|
||||||
|
|
||||||
/* Write column address */
|
/* Write column address */
|
||||||
for (i = 0; i < col_cycles; i++)
|
for (i = 0; i < nand_data->col_cycles; i++)
|
||||||
{
|
{
|
||||||
NFC_SADDR = column & 0xFF;
|
NFC_SADDR = column & 0xFF;
|
||||||
column = column >> 8;
|
column = column >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write row address */
|
/* Write row address */
|
||||||
for (i = 0; i < row_cycles; i++)
|
for (i = 0; i < nand_data->row_cycles; i++)
|
||||||
{
|
{
|
||||||
NFC_SADDR = row & 0xFF;
|
NFC_SADDR = row & 0xFF;
|
||||||
row = row >> 8;
|
row = row >> 8;
|
||||||
|
|
@ -379,7 +389,7 @@ static void nand_get_chip_info(void)
|
||||||
manuf_id = id_buf[0];
|
manuf_id = id_buf[0];
|
||||||
|
|
||||||
/* Identify the chip geometry */
|
/* Identify the chip geometry */
|
||||||
struct nand_info* nand_data = nand_identify(id_buf);
|
nand_data = nand_identify(id_buf);
|
||||||
|
|
||||||
if (nand_data == NULL)
|
if (nand_data == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -387,19 +397,19 @@ static void nand_get_chip_info(void)
|
||||||
id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
|
id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
page_size = nand_data->page_size;
|
pages_per_bank = nand_data->blocks_per_bank * nand_data->pages_per_block;
|
||||||
spare_size = nand_data->spare_size;
|
|
||||||
pages_per_block = nand_data->pages_per_block;
|
segments_per_bank = nand_data->blocks_per_bank / nand_data->planes;
|
||||||
blocks_per_bank = nand_data->blocks_per_bank;
|
|
||||||
col_cycles = nand_data->col_cycles;
|
bytes_per_segment = nand_data->page_size * nand_data->pages_per_block
|
||||||
row_cycles = nand_data->row_cycles;
|
* nand_data->planes;
|
||||||
|
|
||||||
|
sectors_per_page = nand_data->page_size / SECTOR_SIZE;
|
||||||
|
|
||||||
pages_per_bank = blocks_per_bank * pages_per_block;
|
|
||||||
segments_per_bank = blocks_per_bank / BLOCKS_PER_SEGMENT;
|
|
||||||
bytes_per_segment = page_size * pages_per_block * BLOCKS_PER_SEGMENT;
|
|
||||||
sectors_per_page = page_size / SECTOR_SIZE;
|
|
||||||
sectors_per_segment = bytes_per_segment / SECTOR_SIZE;
|
sectors_per_segment = bytes_per_segment / SECTOR_SIZE;
|
||||||
|
|
||||||
|
pages_per_segment = sectors_per_segment / sectors_per_page;
|
||||||
|
|
||||||
/* Establish how many banks are present */
|
/* Establish how many banks are present */
|
||||||
nand_read_id(1, id_buf);
|
nand_read_id(1, id_buf);
|
||||||
|
|
||||||
|
|
@ -447,10 +457,9 @@ static void nand_get_chip_info(void)
|
||||||
This is not present on some older players (formatted with early FW?)
|
This is not present on some older players (formatted with early FW?)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nand_read_raw(0, /* bank */
|
nand_read_raw(0, 0, /* bank, page */
|
||||||
0, /* page */
|
nand_data->page_size, /* offset */
|
||||||
page_size, /* offset */
|
8, id_buf); /* length, dest */
|
||||||
8, id_buf);
|
|
||||||
|
|
||||||
if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present");
|
if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present");
|
||||||
|
|
||||||
|
|
@ -611,7 +620,9 @@ static void read_random_writes_cache(int bank, int phys_segment)
|
||||||
#ifndef FTL_V1
|
#ifndef FTL_V1
|
||||||
/* Loop over each page in the phys segment (from page 1 onwards).
|
/* Loop over each page in the phys segment (from page 1 onwards).
|
||||||
Read spare for 1st sector, store location of page in array. */
|
Read spare for 1st sector, store location of page in array. */
|
||||||
for (page = 1; page < pages_per_block * BLOCKS_PER_SEGMENT; page++)
|
for (page = 1;
|
||||||
|
page < (nand_data->pages_per_block * nand_data->planes);
|
||||||
|
page++)
|
||||||
{
|
{
|
||||||
unsigned short cached_page;
|
unsigned short cached_page;
|
||||||
|
|
||||||
|
|
@ -663,7 +674,7 @@ static void read_inplace_writes_cache(int bank, int phys_segment)
|
||||||
|
|
||||||
/* Find how many pages have been written to the new segment */
|
/* Find how many pages have been written to the new segment */
|
||||||
while (log_segment != -1 &&
|
while (log_segment != -1 &&
|
||||||
page < (pages_per_block * BLOCKS_PER_SEGMENT) - 1)
|
page < (nand_data->pages_per_block * nand_data->planes) - 1)
|
||||||
{
|
{
|
||||||
page++;
|
page++;
|
||||||
nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
|
nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page),
|
||||||
|
|
@ -802,10 +813,9 @@ int nand_init(void)
|
||||||
if (type == SECTYPE_MAIN_INPLACE_CACHE)
|
if (type == SECTYPE_MAIN_INPLACE_CACHE)
|
||||||
{
|
{
|
||||||
/* Check last sector of sequential write cache block */
|
/* Check last sector of sequential write cache block */
|
||||||
nand_read_raw(bank,
|
nand_read_raw(bank, phys_segment_to_page_addr
|
||||||
phys_segment_to_page_addr(phys_segment,
|
(phys_segment, pages_per_segment - 1),
|
||||||
(pages_per_block * BLOCKS_PER_SEGMENT) - 1),
|
nand_data->page_size + nand_data->spare_size - 16,
|
||||||
page_size + spare_size - 16,
|
|
||||||
16, spare_buf);
|
16, spare_buf);
|
||||||
|
|
||||||
/* If last sector has been written, treat block as main data */
|
/* If last sector has been written, treat block as main data */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue