mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-09 21:22:39 -05:00
x1000: refactor NAND chip identification
Decouple chip IDs from chips, and allow the chip ID table to list which read ID method should be used. Use a safe controller setup during identification instead of using the first chip's parameters. Change-Id: Ia725959c31b2838f4a3a30e5bb7fa6652ef377ed
This commit is contained in:
parent
189dee08ea
commit
17443de221
2 changed files with 69 additions and 60 deletions
|
|
@ -25,34 +25,30 @@
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const struct nand_chip supported_nand_chips[] = {
|
static const struct nand_chip chip_ato25d1ga = {
|
||||||
#if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN)
|
.log2_ppb = 6, /* 64 pages */
|
||||||
{
|
.page_size = 2048,
|
||||||
/* ATO25D1GA */
|
.oob_size = 64,
|
||||||
.mf_id = 0x9b,
|
.nr_blocks = 1024,
|
||||||
.dev_id = 0x12,
|
.bbm_pos = 2048,
|
||||||
.log2_ppb = 6, /* 64 pages */
|
.clock_freq = 150000000,
|
||||||
.page_size = 2048,
|
.dev_conf = jz_orf(SFC_DEV_CONF,
|
||||||
.oob_size = 64,
|
CE_DL(1), HOLD_DL(1), WP_DL(1),
|
||||||
.nr_blocks = 1024,
|
CPHA(0), CPOL(0),
|
||||||
.bbm_pos = 2048,
|
TSH(7), TSETUP(0), THOLD(0),
|
||||||
.clock_freq = 150000000,
|
STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
|
||||||
.dev_conf = jz_orf(SFC_DEV_CONF,
|
SMP_DELAY(1)),
|
||||||
CE_DL(1), HOLD_DL(1), WP_DL(1),
|
.flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
|
||||||
CPHA(0), CPOL(0),
|
.cmd_page_read = NANDCMD_PAGE_READ,
|
||||||
TSH(7), TSETUP(0), THOLD(0),
|
.cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
|
||||||
STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
|
.cmd_block_erase = NANDCMD_BLOCK_ERASE,
|
||||||
SMP_DELAY(1)),
|
.cmd_read_cache = NANDCMD_READ_CACHE_x4,
|
||||||
.flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT,
|
.cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
|
||||||
.cmd_page_read = NANDCMD_PAGE_READ,
|
};
|
||||||
.cmd_program_execute = NANDCMD_PROGRAM_EXECUTE,
|
|
||||||
.cmd_block_erase = NANDCMD_BLOCK_ERASE,
|
|
||||||
.cmd_read_cache = NANDCMD_READ_CACHE_x4,
|
const struct nand_chip_id supported_nand_chips[] = {
|
||||||
.cmd_program_load = NANDCMD_PROGRAM_LOAD_x4,
|
NAND_CHIP_ID(&chip_ato25d1ga, NAND_READID_ADDR, 0x9b, 0x12),
|
||||||
},
|
|
||||||
#else
|
|
||||||
{ 0 },
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips);
|
const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips);
|
||||||
|
|
@ -94,6 +90,19 @@ static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t
|
||||||
nand_set_reg(drv, reg, x);
|
nand_set_reg(drv, reg, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct nand_chip* identify_chip_method(uint8_t method,
|
||||||
|
const uint8_t* id_buf)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < nr_supported_nand_chips; ++i) {
|
||||||
|
const struct nand_chip_id* chip_id = &supported_nand_chips[i];
|
||||||
|
if (chip_id->method == method &&
|
||||||
|
!memcmp(chip_id->id_bytes, id_buf, chip_id->num_id_bytes))
|
||||||
|
return chip_id->chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static bool identify_chip(struct nand_drv* drv)
|
static bool identify_chip(struct nand_drv* drv)
|
||||||
{
|
{
|
||||||
/* Read ID command has some variations; Linux handles these 3:
|
/* Read ID command has some variations; Linux handles these 3:
|
||||||
|
|
@ -101,25 +110,13 @@ static bool identify_chip(struct nand_drv* drv)
|
||||||
* - 1 byte address, no dummy byte
|
* - 1 byte address, no dummy byte
|
||||||
* - no address byte, 1 byte dummy
|
* - no address byte, 1 byte dummy
|
||||||
*
|
*
|
||||||
* Currently we use the 2nd method, aka. address read ID.
|
* Currently we use the 2nd method, aka. address read ID, the
|
||||||
|
* other methods can be added when needed.
|
||||||
*/
|
*/
|
||||||
sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ);
|
sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ);
|
||||||
drv->mf_id = drv->scratch_buf[0];
|
drv->chip = identify_chip_method(NAND_READID_ADDR, drv->scratch_buf);
|
||||||
drv->dev_id = drv->scratch_buf[1];
|
if (drv->chip)
|
||||||
drv->dev_id2 = drv->scratch_buf[2];
|
|
||||||
|
|
||||||
for(size_t i = 0; i < nr_supported_nand_chips; ++i) {
|
|
||||||
const struct nand_chip* chip = &supported_nand_chips[i];
|
|
||||||
if(chip->mf_id != drv->mf_id || chip->dev_id != drv->dev_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if((chip->flags & NAND_CHIPFLAG_HAS_DEVID2) &&
|
|
||||||
chip->dev_id2 != drv->dev_id2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
drv->chip = chip;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -164,8 +161,13 @@ int nand_open(struct nand_drv* drv)
|
||||||
|
|
||||||
/* Initialize the controller */
|
/* Initialize the controller */
|
||||||
sfc_open();
|
sfc_open();
|
||||||
sfc_set_dev_conf(supported_nand_chips[0].dev_conf);
|
sfc_set_dev_conf(jz_orf(SFC_DEV_CONF,
|
||||||
sfc_set_clock(supported_nand_chips[0].clock_freq);
|
CE_DL(1), HOLD_DL(1), WP_DL(1),
|
||||||
|
CPHA(0), CPOL(0),
|
||||||
|
TSH(15), TSETUP(0), THOLD(0),
|
||||||
|
STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS),
|
||||||
|
SMP_DELAY(0)));
|
||||||
|
sfc_set_clock(X1000_EXCLK_FREQ);
|
||||||
|
|
||||||
/* Send the software reset command */
|
/* Send the software reset command */
|
||||||
sfc_exec(NANDCMD_RESET, 0, NULL, 0);
|
sfc_exec(NANDCMD_RESET, 0, NULL, 0);
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,8 @@
|
||||||
#define NAND_CHIPFLAG_QUAD 0x0001
|
#define NAND_CHIPFLAG_QUAD 0x0001
|
||||||
/* Chip requires QE bit set to enable quad I/O mode */
|
/* Chip requires QE bit set to enable quad I/O mode */
|
||||||
#define NAND_CHIPFLAG_HAS_QE_BIT 0x0002
|
#define NAND_CHIPFLAG_HAS_QE_BIT 0x0002
|
||||||
/* Chip has 2nd device ID byte */
|
|
||||||
#define NAND_CHIPFLAG_HAS_DEVID2 0x0004
|
|
||||||
/* True if the chip has on-die ECC */
|
/* True if the chip has on-die ECC */
|
||||||
#define NAND_CHIPFLAG_ON_DIE_ECC 0x0008
|
#define NAND_CHIPFLAG_ON_DIE_ECC 0x0004
|
||||||
|
|
||||||
/* cmd mode a d phase format has data */
|
/* cmd mode a d phase format has data */
|
||||||
#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
|
#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0)
|
||||||
|
|
@ -103,11 +101,6 @@ typedef uint32_t nand_page_t;
|
||||||
struct nand_drv;
|
struct nand_drv;
|
||||||
|
|
||||||
struct nand_chip {
|
struct nand_chip {
|
||||||
/* Manufacturer and device ID bytes */
|
|
||||||
uint8_t mf_id;
|
|
||||||
uint8_t dev_id;
|
|
||||||
uint8_t dev_id2;
|
|
||||||
|
|
||||||
/* Base2 logarithm of the number of pages per block */
|
/* Base2 logarithm of the number of pages per block */
|
||||||
unsigned log2_ppb;
|
unsigned log2_ppb;
|
||||||
|
|
||||||
|
|
@ -141,6 +134,25 @@ struct nand_chip {
|
||||||
void(*setup_chip)(struct nand_drv* drv);
|
void(*setup_chip)(struct nand_drv* drv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum nand_readid_method {
|
||||||
|
NAND_READID_OPCODE,
|
||||||
|
NAND_READID_ADDR,
|
||||||
|
NAND_READID_DUMMY,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nand_chip_id {
|
||||||
|
uint8_t method;
|
||||||
|
uint8_t num_id_bytes;
|
||||||
|
uint8_t id_bytes[4];
|
||||||
|
const struct nand_chip* chip;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NAND_CHIP_ID(_chip, _method, ...) \
|
||||||
|
{ .method = _method, \
|
||||||
|
.num_id_bytes = ARRAYLEN(((uint8_t[]){__VA_ARGS__})), \
|
||||||
|
.id_bytes = {__VA_ARGS__}, \
|
||||||
|
.chip = _chip }
|
||||||
|
|
||||||
struct nand_drv {
|
struct nand_drv {
|
||||||
/* NAND access lock. Needs to be held during any operations. */
|
/* NAND access lock. Needs to be held during any operations. */
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
|
@ -170,14 +182,9 @@ struct nand_drv {
|
||||||
|
|
||||||
/* Full page size = chip->page_size + chip->oob_size */
|
/* Full page size = chip->page_size + chip->oob_size */
|
||||||
unsigned fpage_size;
|
unsigned fpage_size;
|
||||||
|
|
||||||
/* Probed mf_id / dev_id for debugging, in case identification fails. */
|
|
||||||
uint8_t mf_id;
|
|
||||||
uint8_t dev_id;
|
|
||||||
uint8_t dev_id2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct nand_chip supported_nand_chips[];
|
extern const struct nand_chip_id supported_nand_chips[];
|
||||||
extern const size_t nr_supported_nand_chips;
|
extern const size_t nr_supported_nand_chips;
|
||||||
|
|
||||||
/* Return the static NAND driver instance.
|
/* Return the static NAND driver instance.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue