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>
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index d585b7a..74acdfb 100644
--- a/drivers/mtd/nand/tegra_nand.c
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -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 @@
 /* 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 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 @@
  * @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 @@
 
 	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 @@
 	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 @@
 /**
  * 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 @@
 	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 @@
 	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);
 }