mtd: denali: use CONFIG_SYS_NAND_SELF_INIT

Some variants of the Denali NAND controller need some registers
set up based on the device information that has been detected during
nand_scan_ident().

CONFIG_SYS_NAND_SELF_INIT has to be defined to insert code between
nand_scan_ident() and nand_scan_tail().  It is also helpful to reduce
the difference between this driver and its Linux counterpart because
this driver was ported from Linux.  Moreover, doc/README.nand recommends
to use CONFIG_SYS_NAND_SELF_INIT.

Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Cc: Scott Wood <scottwood@freescale.com>
Cc: Chin Liang See <clsee@altera.com>
master
Masahiro Yamada 10 years ago committed by Scott Wood
parent 35c204d8a9
commit 65e4145a20
  1. 7
      drivers/mtd/nand/Kconfig
  2. 121
      drivers/mtd/nand/denali.c
  3. 5
      drivers/mtd/nand/denali.h

@ -1,9 +1,16 @@
menu "NAND Device Support"
config SYS_NAND_SELF_INIT
bool
help
This option, if enabled, provides more flexible and linux-like
NAND initialization process.
if !SPL_BUILD
config NAND_DENALI
bool "Support Denali NAND controller"
select SYS_NAND_SELF_INIT
help
Enable support for the Denali NAND controller.

@ -44,7 +44,7 @@ static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
* this macro allows us to convert from an MTD structure to our own
* device context (denali) structure.
*/
#define mtd_to_denali(m) (((struct nand_chip *)mtd->priv)->priv)
#define mtd_to_denali(m) container_of(m->priv, struct denali_nand_info, nand)
/* These constants are defined by the driver to enable common driver
* configuration options. */
@ -1144,70 +1144,117 @@ static void denali_hw_init(struct denali_nand_info *denali)
static struct nand_ecclayout nand_oob;
static int denali_nand_init(struct nand_chip *nand)
static int denali_init(struct denali_nand_info *denali)
{
struct denali_nand_info *denali;
int ret;
denali = malloc(sizeof(*denali));
if (!denali)
return -ENOMEM;
denali_hw_init(denali);
nand->priv = denali;
denali->mtd->name = "denali-nand";
denali->mtd->owner = THIS_MODULE;
denali->mtd->priv = &denali->nand;
denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
/* register the driver with the NAND core subsystem */
denali->nand.select_chip = denali_select_chip;
denali->nand.cmdfunc = denali_cmdfunc;
denali->nand.read_byte = denali_read_byte;
denali->nand.read_buf = denali_read_buf;
denali->nand.waitfunc = denali_waitfunc;
/*
* scan for NAND devices attached to the controller
* this is the first stage in a two step process to register
* with the nand subsystem
*/
if (nand_scan_ident(denali->mtd, denali->max_banks, NULL)) {
ret = -ENXIO;
goto fail;
}
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
/* check whether flash got BBT table (located at end of flash). As we
* use NAND_BBT_NO_OOB, the BBT page will start with
* bbt_pattern. We will have mirror pattern too */
nand->bbt_options |= NAND_BBT_USE_FLASH;
denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
/*
* We are using main + spare with ECC support. As BBT need ECC support,
* we need to ensure BBT code don't write to OOB for the BBT pattern.
* All BBT info will be stored into data area with ECC support.
*/
nand->bbt_options |= NAND_BBT_NO_OOB;
denali->nand.bbt_options |= NAND_BBT_NO_OOB;
#endif
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
nand->ecc.read_oob = denali_read_oob;
nand->ecc.write_oob = denali_write_oob;
nand->ecc.read_page = denali_read_page;
nand->ecc.read_page_raw = denali_read_page_raw;
nand->ecc.write_page = denali_write_page;
nand->ecc.write_page_raw = denali_write_page_raw;
denali->nand.ecc.mode = NAND_ECC_HW;
denali->nand.ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
/*
* Tell driver the ecc strength. This register may be already set
* correctly. So we read this value out.
*/
nand->ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
switch (nand->ecc.size) {
denali->nand.ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
switch (denali->nand.ecc.size) {
case 512:
nand->ecc.bytes = (nand->ecc.strength * 13 + 15) / 16 * 2;
denali->nand.ecc.bytes =
(denali->nand.ecc.strength * 13 + 15) / 16 * 2;
break;
case 1024:
nand->ecc.bytes = (nand->ecc.strength * 14 + 15) / 16 * 2;
denali->nand.ecc.bytes =
(denali->nand.ecc.strength * 14 + 15) / 16 * 2;
break;
default:
pr_err("Unsupported ECC size\n");
return -EINVAL;
ret = -EINVAL;
goto fail;
}
nand_oob.eccbytes = nand->ecc.bytes;
nand->ecc.layout = &nand_oob;
/* Set address of hardware control function */
nand->cmdfunc = denali_cmdfunc;
nand->read_byte = denali_read_byte;
nand->read_buf = denali_read_buf;
nand->select_chip = denali_select_chip;
nand->waitfunc = denali_waitfunc;
denali_hw_init(denali);
return 0;
nand_oob.eccbytes = denali->nand.ecc.bytes;
denali->nand.ecc.layout = &nand_oob;
/* override the default operations */
denali->nand.ecc.read_page = denali_read_page;
denali->nand.ecc.read_page_raw = denali_read_page_raw;
denali->nand.ecc.write_page = denali_write_page;
denali->nand.ecc.write_page_raw = denali_write_page_raw;
denali->nand.ecc.read_oob = denali_read_oob;
denali->nand.ecc.write_oob = denali_write_oob;
if (nand_scan_tail(denali->mtd)) {
ret = -ENXIO;
goto fail;
}
ret = nand_register(0);
fail:
return ret;
}
static int __board_nand_init(void)
{
struct denali_nand_info *denali;
denali = kzalloc(sizeof(*denali), GFP_KERNEL);
if (!denali)
return -ENOMEM;
/*
* If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible
* for instantiating struct nand_chip, while drivers/mtd/nand/nand.c
* still provides a "struct mtd_info nand_info" instance.
*/
denali->mtd = &nand_info[0];
/*
* In the future, these base addresses should be taken from
* Device Tree or platform data.
*/
denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
return denali_init(denali);
}
int board_nand_init(struct nand_chip *chip)
void board_nand_init(void)
{
return denali_nand_init(chip);
if (__board_nand_init() < 0)
pr_warn("Failed to initialize Denali NAND controller.\n");
}

@ -434,9 +434,8 @@ struct nand_buf {
#define DT 3
struct denali_nand_info {
struct mtd_info mtd;
struct nand_chip *nand;
struct mtd_info *mtd;
struct nand_chip nand;
int flash_bank; /* currently selected chip */
int status;
int platform;

Loading…
Cancel
Save