[U-Boot] [PATCH 1/2] mtd: nand: tegra: convert to driver model and live tree

Stefan Agner stefan at agner.ch
Fri Feb 23 16:40:15 UTC 2018


On 21.02.2018 16:16, Marcel Ziswiler wrote:
> From: Marcel Ziswiler <marcel.ziswiler at 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 at 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, &reg_val))
> +	if (set_bus_width_page_size(mtd, config, &reg_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, &reg_val))
> +	if (set_bus_width_page_size(mtd, &info->config, &reg_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,
> +				   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;
>  	}
> @@ -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);
>  }


More information about the U-Boot mailing list