
On 21.02.2018 16:16, Marcel Ziswiler wrote:
From: Marcel Ziswiler marcel.ziswiler@toradex.com
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_MISC. Once UCLASS_NAND is supported, it would be possible to migrate to it.
Signed-off-by: Marcel Ziswiler marcel.ziswiler@toradex.com
drivers/mtd/nand/tegra_nand.c | 98 ++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 43 deletions(-)
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index c03c9cb178..405018018c 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -18,6 +18,7 @@ #include <asm/gpio.h> #include <fdtdec.h> #include <bouncebuf.h> +#include <dm.h> #include "tegra_nand.h"
DECLARE_GLOBAL_DATA_PTR; @@ -29,6 +30,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:
@@ -91,9 +99,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
@@ -453,8 +463,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; @@ -514,7 +524,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 */
@@ -722,7 +732,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);
@@ -883,51 +893,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,
if (err) return err;GPIOD_IS_OUT);
- 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,
if (err < 0) return err;FDT_NAND_TIMING_COUNT);
- /* 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; }
@@ -950,7 +948,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;
@@ -975,17 +973,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_MISC,
There is also UCLASS_MTD, which I was going to use in a upcoming patchset for mxs_nand.c.
I see that drivers/mtd/nand/denali_dt.c is currently using UCLASS_MISC, Masahiro, any reason for that?
Commit d85879938d ("dm: implement a MTD uclass") seems to suggest that it should be fine for NAND flash drivers too...
-- Stefan
- .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];
- if (tegra_nand_init(nand, 0))
puts("Tegra NAND init failed\n");
- struct udevice *dev;
- int ret;
- ret = uclass_get_device_by_driver(UCLASS_MISC,
DM_GET_DRIVER(tegra_nand), &dev);
- if (ret && ret != -ENODEV)
pr_err("Failed to initialize %s. (error %d)\n", dev->name,
ret);
}