[U-Boot] [PATCH v2 1/2] mtd: denali: use CONFIG_SYS_NAND_SELF_INIT
Masahiro Yamada
yamada.m at jp.panasonic.com
Thu Nov 13 12:31:50 CET 2014
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 at jp.panasonic.com>
Cc: Scott Wood <scottwood at freescale.com>
Cc: Chin Liang See <clsee at altera.com>
---
Changes in v2:
- Use &nand_info[0] instead of nand_info
- Print a warning message if initialization fails
drivers/mtd/nand/Kconfig | 7 +++
drivers/mtd/nand/denali.c | 121 ++++++++++++++++++++++++++++++++--------------
drivers/mtd/nand/denali.h | 5 +-
3 files changed, 93 insertions(+), 40 deletions(-)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 75c2c06..c242214 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -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.
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 308b784..24bc0ab 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -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");
}
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 3277da7..a258df0 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -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;
--
1.9.1
More information about the U-Boot
mailing list