mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 15:37:23 +00:00
mtd: nand: tegra: convert to driver model and live tree
The Tegra NAND driver recently got broken by ongoing driver model resp. live tree migration work: NAND: Could not decode nand-flash in device tree Tegra NAND init failed 0 MiB A patch for NAND uclass support was proposed about a year ago: https://patchwork.ozlabs.org/patch/722282/ It was not merged and I do not see on-going work for this. This commit just provides a driver model probe hook to retrieve further configuration from the live device tree. As there is no NAND ulass as of yet (ab)using UCLASS_MTD. Once UCLASS_NAND is supported, it would be possible to migrate to it. Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
parent
da342f06b3
commit
4b11a6296a
1 changed files with 54 additions and 42 deletions
|
@ -17,6 +17,7 @@
|
|||
#include <asm/gpio.h>
|
||||
#include <fdtdec.h>
|
||||
#include <bouncebuf.h>
|
||||
#include <dm.h>
|
||||
#include "tegra_nand.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
@ -28,6 +29,13 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
/* ECC bytes to be generated for tag data */
|
||||
#define TAG_ECC_BYTES 4
|
||||
|
||||
static const struct udevice_id tegra_nand_dt_ids[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra20-nand",
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
/* 64 byte oob block info for large page (== 2KB) device
|
||||
*
|
||||
* OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC:
|
||||
|
@ -90,9 +98,11 @@ struct nand_drv {
|
|||
struct fdt_nand config;
|
||||
};
|
||||
|
||||
static struct nand_drv nand_ctrl;
|
||||
static struct mtd_info *our_mtd;
|
||||
static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
|
||||
struct tegra_nand_info {
|
||||
struct udevice *dev;
|
||||
struct nand_drv nand_ctrl;
|
||||
struct nand_chip nand_chip;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for command completion
|
||||
|
@ -452,8 +462,8 @@ static void stop_command(struct nand_ctlr *reg)
|
|||
* @param *reg_val address of reg_val
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
static int set_bus_width_page_size(struct fdt_nand *config,
|
||||
u32 *reg_val)
|
||||
static int set_bus_width_page_size(struct mtd_info *our_mtd,
|
||||
struct fdt_nand *config, u32 *reg_val)
|
||||
{
|
||||
if (config->width == 8)
|
||||
*reg_val = CFG_BUS_WIDTH_8BIT;
|
||||
|
@ -513,7 +523,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
config = &info->config;
|
||||
if (set_bus_width_page_size(config, ®_val))
|
||||
if (set_bus_width_page_size(mtd, config, ®_val))
|
||||
return -EINVAL;
|
||||
|
||||
/* Need to be 4-byte aligned */
|
||||
|
@ -721,7 +731,7 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
if (((int)chip->oob_poi) & 0x03)
|
||||
return -EINVAL;
|
||||
info = (struct nand_drv *)nand_get_controller_data(chip);
|
||||
if (set_bus_width_page_size(&info->config, ®_val))
|
||||
if (set_bus_width_page_size(mtd, &info->config, ®_val))
|
||||
return -EINVAL;
|
||||
|
||||
stop_command(info->reg);
|
||||
|
@ -882,51 +892,39 @@ static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT],
|
|||
/**
|
||||
* Decode NAND parameters from the device tree
|
||||
*
|
||||
* @param blob Device tree blob
|
||||
* @param node Node containing "nand-flash" compatible node
|
||||
* @param dev Driver model device
|
||||
* @param config Device tree NAND configuration
|
||||
* @return 0 if ok, -ve on error (FDT_ERR_...)
|
||||
*/
|
||||
static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config)
|
||||
static int fdt_decode_nand(struct udevice *dev, struct fdt_nand *config)
|
||||
{
|
||||
int err;
|
||||
|
||||
config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg");
|
||||
config->enabled = fdtdec_get_is_enabled(blob, node);
|
||||
config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8);
|
||||
err = gpio_request_by_name_nodev(offset_to_ofnode(node),
|
||||
"nvidia,wp-gpios", 0, &config->wp_gpio, GPIOD_IS_OUT);
|
||||
config->reg = (struct nand_ctlr *)dev_read_addr(dev);
|
||||
config->enabled = dev_read_enabled(dev);
|
||||
config->width = dev_read_u32_default(dev, "nvidia,nand-width", 8);
|
||||
err = gpio_request_by_name(dev, "nvidia,wp-gpios", 0, &config->wp_gpio,
|
||||
GPIOD_IS_OUT);
|
||||
if (err)
|
||||
return err;
|
||||
err = fdtdec_get_int_array(blob, node, "nvidia,timing",
|
||||
config->timing, FDT_NAND_TIMING_COUNT);
|
||||
err = dev_read_u32_array(dev, "nvidia,timing", config->timing,
|
||||
FDT_NAND_TIMING_COUNT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Now look up the controller and decode that */
|
||||
node = fdt_next_node(blob, node, NULL);
|
||||
if (node < 0)
|
||||
return node;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Board-specific NAND initialization
|
||||
*
|
||||
* @param nand nand chip info structure
|
||||
* @return 0, after initialized, -1 on error
|
||||
*/
|
||||
int tegra_nand_init(struct nand_chip *nand, int devnum)
|
||||
static int tegra_probe(struct udevice *dev)
|
||||
{
|
||||
struct nand_drv *info = &nand_ctrl;
|
||||
struct tegra_nand_info *tegra = dev_get_priv(dev);
|
||||
struct nand_chip *nand = &tegra->nand_chip;
|
||||
struct nand_drv *info = &tegra->nand_ctrl;
|
||||
struct fdt_nand *config = &info->config;
|
||||
int node, ret;
|
||||
struct mtd_info *our_mtd;
|
||||
int ret;
|
||||
|
||||
node = fdtdec_next_compatible(gd->fdt_blob, 0,
|
||||
COMPAT_NVIDIA_TEGRA20_NAND);
|
||||
if (node < 0)
|
||||
return -1;
|
||||
if (fdt_decode_nand(gd->fdt_blob, node, config)) {
|
||||
if (fdt_decode_nand(dev, config)) {
|
||||
printf("Could not decode nand-flash in device tree\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -949,7 +947,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
|||
nand->ecc.strength = 1;
|
||||
nand->select_chip = nand_select_chip;
|
||||
nand->dev_ready = nand_dev_ready;
|
||||
nand_set_controller_data(nand, &nand_ctrl);
|
||||
nand_set_controller_data(nand, &tegra->nand_ctrl);
|
||||
|
||||
/* Disable subpage writes as we do not provide ecc->hwctl */
|
||||
nand->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
|
@ -974,17 +972,31 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_register(devnum, our_mtd);
|
||||
if (ret)
|
||||
ret = nand_register(0, our_mtd);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register MTD: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(tegra_nand) = {
|
||||
.name = "tegra-nand",
|
||||
.id = UCLASS_MTD,
|
||||
.of_match = tegra_nand_dt_ids,
|
||||
.probe = tegra_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct tegra_nand_info),
|
||||
};
|
||||
|
||||
void board_nand_init(void)
|
||||
{
|
||||
struct nand_chip *nand = &nand_chip[0];
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
if (tegra_nand_init(nand, 0))
|
||||
puts("Tegra NAND init failed\n");
|
||||
ret = uclass_get_device_by_driver(UCLASS_MTD,
|
||||
DM_GET_DRIVER(tegra_nand), &dev);
|
||||
if (ret && ret != -ENODEV)
|
||||
pr_err("Failed to initialize %s. (error %d)\n", dev->name,
|
||||
ret);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue