mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
nand: Introduce CONFIG_SYS_NAND_SELF_INIT
This allows a driver to run code between nand_scan_ident() and nand_scan_tail(), among other things. See the additions to doc/README.nand for details. To allow a gradual transition, Boards that don't set CONFIG_SYS_NAND_SELF_INIT will still be initialized the old way, but new drivers should not require this, and existing drivers should be converted when convenient. Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
parent
25efd99dbb
commit
578931b34d
3 changed files with 126 additions and 37 deletions
|
@ -120,6 +120,68 @@ Configuration Options:
|
||||||
CONFIG_SYS_NAND_MAX_CHIPS
|
CONFIG_SYS_NAND_MAX_CHIPS
|
||||||
The maximum number of NAND chips per device to be supported.
|
The maximum number of NAND chips per device to be supported.
|
||||||
|
|
||||||
|
CONFIG_SYS_NAND_SELF_INIT
|
||||||
|
Traditionally, glue code in drivers/mtd/nand/nand.c has driven
|
||||||
|
the initialization process -- it provides the mtd and nand
|
||||||
|
structs, calls a board init function for a specific device,
|
||||||
|
calls nand_scan(), and registers with mtd.
|
||||||
|
|
||||||
|
This arrangement does not provide drivers with the flexibility to
|
||||||
|
run code between nand_scan_ident() and nand_scan_tail(), or other
|
||||||
|
deviations from the "normal" flow.
|
||||||
|
|
||||||
|
If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/nand.c
|
||||||
|
will make one call to board_nand_init(), with no arguments. That
|
||||||
|
function is responsible for calling a driver init function for
|
||||||
|
each NAND device on the board, that performs all initialization
|
||||||
|
tasks except setting mtd->name, and registering with the rest of
|
||||||
|
U-Boot. Those last tasks are accomplished by calling nand_register()
|
||||||
|
on the new mtd device.
|
||||||
|
|
||||||
|
Example of new init to be added to the end of an existing driver
|
||||||
|
init:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* devnum is the device number to be used in nand commands
|
||||||
|
* and in mtd->name. Must be less than
|
||||||
|
* CONFIG_SYS_NAND_MAX_DEVICE.
|
||||||
|
*/
|
||||||
|
mtd = &nand_info[devnum];
|
||||||
|
|
||||||
|
/* chip is struct nand_chip, and is now provided by the driver. */
|
||||||
|
mtd->priv = &chip;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in appropriate values if this driver uses these fields,
|
||||||
|
* or uses the standard read_byte/write_buf/etc. functions from
|
||||||
|
* nand_base.c that use these fields.
|
||||||
|
*/
|
||||||
|
chip.IO_ADDR_R = ...;
|
||||||
|
chip.IO_ADDR_W = ...;
|
||||||
|
|
||||||
|
if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL))
|
||||||
|
error out
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert here any code you wish to run after the chip has been
|
||||||
|
* identified, but before any other I/O is done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nand_scan_tail(mtd))
|
||||||
|
error out
|
||||||
|
|
||||||
|
if (nand_register(devnum))
|
||||||
|
error out
|
||||||
|
|
||||||
|
In addition to providing more flexibility to the driver, it reduces
|
||||||
|
the difference between a U-Boot driver and its Linux counterpart.
|
||||||
|
nand_init() is now reduced to calling board_nand_init() once, and
|
||||||
|
printing a size summary. This should also make it easier to
|
||||||
|
transition to delayed NAND initialization.
|
||||||
|
|
||||||
|
Please convert your driver even if you don't need the extra
|
||||||
|
flexibility, so that one day we can eliminate the old mechanism.
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <nand.h>
|
#include <nand.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifndef CONFIG_SYS_NAND_BASE_LIST
|
#ifndef CONFIG_SYS_NAND_BASE_LIST
|
||||||
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
|
#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
|
||||||
|
@ -31,63 +32,84 @@
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
int nand_curr_device = -1;
|
int nand_curr_device = -1;
|
||||||
|
|
||||||
|
|
||||||
nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
|
nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||||
|
|
||||||
|
#ifndef CONFIG_SYS_NAND_SELF_INIT
|
||||||
static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
|
static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||||
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
|
static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char default_nand_name[] = "nand";
|
static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
|
||||||
static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
|
|
||||||
|
|
||||||
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
|
static unsigned long total_nand_size; /* in kiB */
|
||||||
ulong base_addr)
|
|
||||||
|
/* Register an initialized NAND mtd device with the U-Boot NAND command. */
|
||||||
|
int nand_register(int devnum)
|
||||||
{
|
{
|
||||||
|
struct mtd_info *mtd;
|
||||||
|
|
||||||
|
if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mtd = &nand_info[devnum];
|
||||||
|
|
||||||
|
sprintf(dev_name[devnum], "nand%d", devnum);
|
||||||
|
mtd->name = dev_name[devnum];
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_DEVICE
|
||||||
|
/*
|
||||||
|
* Add MTD device so that we can reference it later
|
||||||
|
* via the mtdcore infrastructure (e.g. ubi).
|
||||||
|
*/
|
||||||
|
add_mtd_device(mtd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
total_nand_size += mtd->size / 1024;
|
||||||
|
|
||||||
|
if (nand_curr_device == -1)
|
||||||
|
nand_curr_device = devnum;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SYS_NAND_SELF_INIT
|
||||||
|
static void nand_init_chip(int i)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = &nand_info[i];
|
||||||
|
struct nand_chip *nand = &nand_chip[i];
|
||||||
|
ulong base_addr = base_address[i];
|
||||||
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
|
int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
|
||||||
static int __attribute__((unused)) i = 0;
|
|
||||||
|
|
||||||
if (maxchips < 1)
|
if (maxchips < 1)
|
||||||
maxchips = 1;
|
maxchips = 1;
|
||||||
|
|
||||||
mtd->priv = nand;
|
mtd->priv = nand;
|
||||||
|
|
||||||
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
|
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
|
||||||
if (board_nand_init(nand) == 0) {
|
|
||||||
if (nand_scan(mtd, maxchips) == 0) {
|
|
||||||
if (!mtd->name)
|
|
||||||
mtd->name = (char *)default_nand_name;
|
|
||||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
|
||||||
else
|
|
||||||
mtd->name += gd->reloc_off;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_DEVICE
|
if (board_nand_init(nand))
|
||||||
/*
|
return;
|
||||||
* Add MTD device so that we can reference it later
|
|
||||||
* via the mtdcore infrastructure (e.g. ubi).
|
|
||||||
*/
|
|
||||||
sprintf(dev_name[i], "nand%d", i);
|
|
||||||
mtd->name = dev_name[i++];
|
|
||||||
add_mtd_device(mtd);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
mtd->name = NULL;
|
|
||||||
} else {
|
|
||||||
mtd->name = NULL;
|
|
||||||
mtd->size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (nand_scan(mtd, maxchips))
|
||||||
|
return;
|
||||||
|
|
||||||
|
nand_register(i);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void nand_init(void)
|
void nand_init(void)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SYS_NAND_SELF_INIT
|
||||||
|
board_nand_init();
|
||||||
|
#else
|
||||||
int i;
|
int i;
|
||||||
unsigned int size = 0;
|
|
||||||
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
|
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
|
||||||
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
|
nand_init_chip(i);
|
||||||
size += nand_info[i].size / 1024;
|
#endif
|
||||||
if (nand_curr_device == -1)
|
|
||||||
nand_curr_device = i;
|
printf("%lu MiB\n", total_nand_size / 1024);
|
||||||
}
|
|
||||||
printf("%u MiB\n", size / 1024);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
|
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -30,7 +30,12 @@ extern void nand_init(void);
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_SYS_NAND_SELF_INIT
|
||||||
|
void board_nand_init(void);
|
||||||
|
int nand_register(int devnum);
|
||||||
|
#else
|
||||||
extern int board_nand_init(struct nand_chip *nand);
|
extern int board_nand_init(struct nand_chip *nand);
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct mtd_info nand_info_t;
|
typedef struct mtd_info nand_info_t;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue