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:
Marcel Ziswiler 2018-05-07 23:18:41 +02:00 committed by Tom Warren
parent da342f06b3
commit 4b11a6296a

View file

@ -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, &reg_val))
if (set_bus_width_page_size(mtd, config, &reg_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, &reg_val))
if (set_bus_width_page_size(mtd, &info->config, &reg_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);
}