From: Marcel Ziswiler Date: Mon, 7 May 2018 21:18:41 +0000 (+0200) Subject: mtd: nand: tegra: convert to driver model and live tree X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=4b11a6296aab84b628434cdbdd15697fab8a3a93;p=u-boot.git 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 Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index d585b7a652..74acdfb308 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -17,6 +17,7 @@ #include #include #include +#include #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]; - - 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); }