mtd: nand: tegra: convert to driver model and live tree
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>
Mon, 7 May 2018 21:18:41 +0000 (23:18 +0200)
committerTom Warren <twarren@nvidia.com>
Thu, 10 May 2018 23:34:10 +0000 (16:34 -0700)
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>
drivers/mtd/nand/tegra_nand.c

index d585b7a..74acdfb 100644 (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];
-
-       if (tegra_nand_init(nand, 0))
-               puts("Tegra NAND init failed\n");
+       struct udevice *dev;
+       int ret;
+
+       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);
 }