All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@free-electrons.com>
To: Sergio Prado <sergio.prado@e-labworks.com>
Cc: kgene@kernel.org, krzk@kernel.org, javier@osg.samsung.com,
	linux@armlinux.org.uk, linux@simtec.co.uk, richard@nod.at,
	dwmw2@infradead.org, computersforpeace@gmail.com,
	linux-arm-kernel@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-mtd@lists.infradead.org, robh+dt@kernel.org,
	mark.rutland@arm.com, devicetree@vger.kernel.org
Subject: Re: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from OF node
Date: Mon, 24 Oct 2016 15:02:01 +0200	[thread overview]
Message-ID: <20161024150201.01952f67@bbrezillon> (raw)
In-Reply-To: <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>

On Thu, 20 Oct 2016 19:42:46 -0200
Sergio Prado <sergio.prado@e-labworks.com> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 143 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 371db0d48135..ec170be881bc 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,22 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
>  /* conversion functions */
>  
>  static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
> @@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
>  	return -ENODEV;
>  }
>  
> +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> +					     const struct nand_data_interface *conf,
> +					     bool check_only)
> +{
> +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	const struct nand_sdr_timings *timings;
> +	int tacls;
> +
> +	timings = nand_get_sdr_timings(conf);
> +	if (IS_ERR(timings))
> +		return -ENOTSUPP;
> +
> +	tacls = timings->tCLS_min - timings->tWP_min;
> +	if (tacls < 0)
> +		tacls = 0;
> +
> +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);

You seem to only apply the timings in s3c2410_nand_setrate(), which is
only called at probe time or on a cpufreq even, but the core can change
timings at runtime (this is what happens each time you reset the chip).

To support that you have 2 options:
 - apply the timings in ->select_chip()
 - apply the timings here

> +
> +	return 0;
> +}
> +
>  /**
>   * s3c2410_nand_init_chip - initialise a single instance of an chip
>   * @info: The base NAND controller the chip is on.
> @@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  				   struct s3c2410_nand_mtd *nmtd,
>  				   struct s3c2410_nand_set *set)
>  {
> +	struct device_node *np = info->device->of_node;
>  	struct nand_chip *chip = &nmtd->chip;
>  	void __iomem *regs = info->regs;
>  
> +	nand_set_flash_node(chip, set->of_node);
> +
>  	chip->write_buf    = s3c2410_nand_write_buf;
>  	chip->read_buf     = s3c2410_nand_read_buf;
>  	chip->select_chip  = s3c2410_nand_select_chip;
> @@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->options	   = set->options;
>  	chip->controller   = &info->controller;
>  
> +	/*
> +	 * let's keep behavior unchanged for legacy boards booting via pdata and
> +	 * auto-detect timings only when booting with a device tree.
> +	 */
> +	if (np)
> +		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
> +
>  	switch (info->cpu_type) {
>  	case TYPE_S3C2410:
>  		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
> @@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->ecc.mode = info->platform->ecc_mode;
>  
>  	/* If you use u-boot BBT creation code, specifying this flag will
> -	 * let the kernel fish out the BBT from the NAND, and also skip the
> -	 * full NAND scan that can take 1/2s or so. Little things... */
> -	if (set->flash_bbt) {
> +	 * let the kernel fish out the BBT from the NAND */
> +	if (set->flash_bbt)
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
> -		chip->options |= NAND_SKIP_BBTSCAN;
> -	}
>  }
>  
>  /**
> @@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  		return -EINVAL;
>  	}
>  
> +	if (chip->bbt_options & NAND_BBT_USE_FLASH)
> +		chip->options |= NAND_SKIP_BBTSCAN;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id s3c24xx_nand_dt_ids[] = {
> +	{
> +		.compatible = "samsung,s3c2410-nand",
> +		.data = &s3c2410_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
> +		.data = &s3c2412_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2440-nand",
> +		.data = &s3c2440_nand_devtype_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
> +
> +static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
> +{
> +	const struct s3c24XX_nand_devtype_data *devtype_data;
> +	struct s3c2410_platform_nand *pdata;
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +	struct device_node *np = pdev->dev.of_node, *child;
> +	struct s3c2410_nand_set *sets;
> +
> +	devtype_data = of_device_get_match_data(&pdev->dev);
> +	if (!devtype_data)
> +		return -ENODEV;
> +
> +	info->cpu_type = devtype_data->type;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	pdev->dev.platform_data = pdata;
> +
> +	pdata->nr_sets = of_get_child_count(np);
> +	if (!pdata->nr_sets)
> +		return 0;
> +
> +	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
> +	if (!sets)
> +		return -ENOMEM;
> +
> +	pdata->sets = sets;
> +
> +	for_each_available_child_of_node(np, child) {
> +
> +		sets->name = (char *)child->name;
> +		sets->of_node = child;
> +		sets->nr_chips = 1;
> +
> +		of_node_get(child);
> +
> +		sets++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
> +{
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +
> +	info->cpu_type = platform_get_device_id(pdev)->driver_data;
> +
>  	return 0;
>  }
>  
> @@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  */
>  static int s3c24xx_nand_probe(struct platform_device *pdev)
>  {
> -	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
> -	enum s3c_cpu_type cpu_type;
> +	struct s3c2410_platform_nand *plat;
>  	struct s3c2410_nand_info *info;
>  	struct s3c2410_nand_mtd *nmtd;
>  	struct s3c2410_nand_set *sets;
> @@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  	int nr_sets;
>  	int setno;
>  
> -	cpu_type = platform_get_device_id(pdev)->driver_data;
> -
>  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>  	if (info == NULL) {
>  		err = -ENOMEM;
> @@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
>  
> +	if (pdev->dev.of_node)
> +		err = s3c24xx_nand_probe_dt(pdev);
> +	else
> +		err = s3c24xx_nand_probe_pdata(pdev);
> +
> +	if (err)
> +		goto exit_error;
> +
> +	plat = to_nand_plat(pdev);
> +
>  	/* allocate and map the resource */
>  
>  	/* currently we assume we have the one resource */
> @@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	info->device	= &pdev->dev;
>  	info->platform	= plat;
> -	info->cpu_type	= cpu_type;
>  
>  	info->regs = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(info->regs)) {
> @@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
>  
> -	/* initialise the hardware */
> -
> -	err = s3c2410_nand_inithw(info);
> -	if (err != 0)
> -		goto exit_error;
> -
>  	sets = (plat != NULL) ? plat->sets : NULL;
>  	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
>  
> @@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  			sets++;
>  	}
>  
> +	/* initialise the hardware */
> +	err = s3c2410_nand_inithw(info);
> +	if (err != 0)
> +		goto exit_error;
> +
>  	err = s3c2410_nand_cpufreq_register(info);
>  	if (err < 0) {
>  		dev_err(&pdev->dev, "failed to init cpufreq support\n");
> @@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
>  	.id_table	= s3c24xx_driver_ids,
>  	.driver		= {
>  		.name	= "s3c24xx-nand",
> +		.of_match_table = s3c24xx_nand_dt_ids,
>  	},
>  };
>  
> diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
> index 729af13d1773..f01659026b26 100644
> --- a/include/linux/platform_data/mtd-nand-s3c2410.h
> +++ b/include/linux/platform_data/mtd-nand-s3c2410.h
> @@ -40,6 +40,7 @@ struct s3c2410_nand_set {
>  	char			*name;
>  	int			*nr_map;
>  	struct mtd_partition	*partitions;
> +	struct device_node	*of_node;
>  };
>  
>  struct s3c2410_platform_nand {

WARNING: multiple messages have this Message-ID (diff)
From: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To: Sergio Prado <sergio.prado-1e4yhPs3/ABSwrhanM7KvQ@public.gmane.org>
Cc: kgene-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	krzk-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	javier-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org,
	linux-Y5A6D6n0/KfQXOPxS62xeg@public.gmane.org,
	richard-/L3Ra7n9ekc@public.gmane.org,
	dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from OF node
Date: Mon, 24 Oct 2016 15:02:01 +0200	[thread overview]
Message-ID: <20161024150201.01952f67@bbrezillon> (raw)
In-Reply-To: <1476999766-32526-4-git-send-email-sergio.prado-1e4yhPs3/ABSwrhanM7KvQ@public.gmane.org>

On Thu, 20 Oct 2016 19:42:46 -0200
Sergio Prado <sergio.prado-1e4yhPs3/ABSwrhanM7KvQ@public.gmane.org> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado-1e4yhPs3/ABSwrhanM7KvQ@public.gmane.org>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 143 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 371db0d48135..ec170be881bc 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,22 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
>  /* conversion functions */
>  
>  static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
> @@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
>  	return -ENODEV;
>  }
>  
> +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> +					     const struct nand_data_interface *conf,
> +					     bool check_only)
> +{
> +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	const struct nand_sdr_timings *timings;
> +	int tacls;
> +
> +	timings = nand_get_sdr_timings(conf);
> +	if (IS_ERR(timings))
> +		return -ENOTSUPP;
> +
> +	tacls = timings->tCLS_min - timings->tWP_min;
> +	if (tacls < 0)
> +		tacls = 0;
> +
> +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);

You seem to only apply the timings in s3c2410_nand_setrate(), which is
only called at probe time or on a cpufreq even, but the core can change
timings at runtime (this is what happens each time you reset the chip).

To support that you have 2 options:
 - apply the timings in ->select_chip()
 - apply the timings here

> +
> +	return 0;
> +}
> +
>  /**
>   * s3c2410_nand_init_chip - initialise a single instance of an chip
>   * @info: The base NAND controller the chip is on.
> @@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  				   struct s3c2410_nand_mtd *nmtd,
>  				   struct s3c2410_nand_set *set)
>  {
> +	struct device_node *np = info->device->of_node;
>  	struct nand_chip *chip = &nmtd->chip;
>  	void __iomem *regs = info->regs;
>  
> +	nand_set_flash_node(chip, set->of_node);
> +
>  	chip->write_buf    = s3c2410_nand_write_buf;
>  	chip->read_buf     = s3c2410_nand_read_buf;
>  	chip->select_chip  = s3c2410_nand_select_chip;
> @@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->options	   = set->options;
>  	chip->controller   = &info->controller;
>  
> +	/*
> +	 * let's keep behavior unchanged for legacy boards booting via pdata and
> +	 * auto-detect timings only when booting with a device tree.
> +	 */
> +	if (np)
> +		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
> +
>  	switch (info->cpu_type) {
>  	case TYPE_S3C2410:
>  		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
> @@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->ecc.mode = info->platform->ecc_mode;
>  
>  	/* If you use u-boot BBT creation code, specifying this flag will
> -	 * let the kernel fish out the BBT from the NAND, and also skip the
> -	 * full NAND scan that can take 1/2s or so. Little things... */
> -	if (set->flash_bbt) {
> +	 * let the kernel fish out the BBT from the NAND */
> +	if (set->flash_bbt)
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
> -		chip->options |= NAND_SKIP_BBTSCAN;
> -	}
>  }
>  
>  /**
> @@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  		return -EINVAL;
>  	}
>  
> +	if (chip->bbt_options & NAND_BBT_USE_FLASH)
> +		chip->options |= NAND_SKIP_BBTSCAN;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id s3c24xx_nand_dt_ids[] = {
> +	{
> +		.compatible = "samsung,s3c2410-nand",
> +		.data = &s3c2410_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
> +		.data = &s3c2412_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2440-nand",
> +		.data = &s3c2440_nand_devtype_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
> +
> +static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
> +{
> +	const struct s3c24XX_nand_devtype_data *devtype_data;
> +	struct s3c2410_platform_nand *pdata;
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +	struct device_node *np = pdev->dev.of_node, *child;
> +	struct s3c2410_nand_set *sets;
> +
> +	devtype_data = of_device_get_match_data(&pdev->dev);
> +	if (!devtype_data)
> +		return -ENODEV;
> +
> +	info->cpu_type = devtype_data->type;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	pdev->dev.platform_data = pdata;
> +
> +	pdata->nr_sets = of_get_child_count(np);
> +	if (!pdata->nr_sets)
> +		return 0;
> +
> +	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
> +	if (!sets)
> +		return -ENOMEM;
> +
> +	pdata->sets = sets;
> +
> +	for_each_available_child_of_node(np, child) {
> +
> +		sets->name = (char *)child->name;
> +		sets->of_node = child;
> +		sets->nr_chips = 1;
> +
> +		of_node_get(child);
> +
> +		sets++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
> +{
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +
> +	info->cpu_type = platform_get_device_id(pdev)->driver_data;
> +
>  	return 0;
>  }
>  
> @@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  */
>  static int s3c24xx_nand_probe(struct platform_device *pdev)
>  {
> -	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
> -	enum s3c_cpu_type cpu_type;
> +	struct s3c2410_platform_nand *plat;
>  	struct s3c2410_nand_info *info;
>  	struct s3c2410_nand_mtd *nmtd;
>  	struct s3c2410_nand_set *sets;
> @@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  	int nr_sets;
>  	int setno;
>  
> -	cpu_type = platform_get_device_id(pdev)->driver_data;
> -
>  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>  	if (info == NULL) {
>  		err = -ENOMEM;
> @@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
>  
> +	if (pdev->dev.of_node)
> +		err = s3c24xx_nand_probe_dt(pdev);
> +	else
> +		err = s3c24xx_nand_probe_pdata(pdev);
> +
> +	if (err)
> +		goto exit_error;
> +
> +	plat = to_nand_plat(pdev);
> +
>  	/* allocate and map the resource */
>  
>  	/* currently we assume we have the one resource */
> @@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	info->device	= &pdev->dev;
>  	info->platform	= plat;
> -	info->cpu_type	= cpu_type;
>  
>  	info->regs = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(info->regs)) {
> @@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
>  
> -	/* initialise the hardware */
> -
> -	err = s3c2410_nand_inithw(info);
> -	if (err != 0)
> -		goto exit_error;
> -
>  	sets = (plat != NULL) ? plat->sets : NULL;
>  	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
>  
> @@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  			sets++;
>  	}
>  
> +	/* initialise the hardware */
> +	err = s3c2410_nand_inithw(info);
> +	if (err != 0)
> +		goto exit_error;
> +
>  	err = s3c2410_nand_cpufreq_register(info);
>  	if (err < 0) {
>  		dev_err(&pdev->dev, "failed to init cpufreq support\n");
> @@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
>  	.id_table	= s3c24xx_driver_ids,
>  	.driver		= {
>  		.name	= "s3c24xx-nand",
> +		.of_match_table = s3c24xx_nand_dt_ids,
>  	},
>  };
>  
> diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
> index 729af13d1773..f01659026b26 100644
> --- a/include/linux/platform_data/mtd-nand-s3c2410.h
> +++ b/include/linux/platform_data/mtd-nand-s3c2410.h
> @@ -40,6 +40,7 @@ struct s3c2410_nand_set {
>  	char			*name;
>  	int			*nr_map;
>  	struct mtd_partition	*partitions;
> +	struct device_node	*of_node;
>  };
>  
>  struct s3c2410_platform_nand {

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: boris.brezillon@free-electrons.com (Boris Brezillon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from OF node
Date: Mon, 24 Oct 2016 15:02:01 +0200	[thread overview]
Message-ID: <20161024150201.01952f67@bbrezillon> (raw)
In-Reply-To: <1476999766-32526-4-git-send-email-sergio.prado@e-labworks.com>

On Thu, 20 Oct 2016 19:42:46 -0200
Sergio Prado <sergio.prado@e-labworks.com> wrote:

> Allows configuring Samsung's s3c2410 memory controller using a
> devicetree.
> 
> Signed-off-by: Sergio Prado <sergio.prado@e-labworks.com>
> ---
>  drivers/mtd/nand/s3c2410.c                     | 158 ++++++++++++++++++++++---
>  include/linux/platform_data/mtd-nand-s3c2410.h |   1 +
>  2 files changed, 143 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
> index 371db0d48135..ec170be881bc 100644
> --- a/drivers/mtd/nand/s3c2410.c
> +++ b/drivers/mtd/nand/s3c2410.c
> @@ -39,6 +39,8 @@
>  #include <linux/slab.h>
>  #include <linux/clk.h>
>  #include <linux/cpufreq.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include <linux/mtd/mtd.h>
>  #include <linux/mtd/nand.h>
> @@ -185,6 +187,22 @@ struct s3c2410_nand_info {
>  #endif
>  };
>  
> +struct s3c24XX_nand_devtype_data {
> +	enum s3c_cpu_type type;
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
> +	.type = TYPE_S3C2410,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
> +	.type = TYPE_S3C2412,
> +};
> +
> +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
> +	.type = TYPE_S3C2440,
> +};
> +
>  /* conversion functions */
>  
>  static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
> @@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
>  	return -ENODEV;
>  }
>  
> +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
> +					     const struct nand_data_interface *conf,
> +					     bool check_only)
> +{
> +	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
> +	struct s3c2410_platform_nand *pdata = info->platform;
> +	const struct nand_sdr_timings *timings;
> +	int tacls;
> +
> +	timings = nand_get_sdr_timings(conf);
> +	if (IS_ERR(timings))
> +		return -ENOTSUPP;
> +
> +	tacls = timings->tCLS_min - timings->tWP_min;
> +	if (tacls < 0)
> +		tacls = 0;
> +
> +	pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
> +	pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
> +	pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);

You seem to only apply the timings in s3c2410_nand_setrate(), which is
only called at probe time or on a cpufreq even, but the core can change
timings at runtime (this is what happens each time you reset the chip).

To support that you have 2 options:
 - apply the timings in ->select_chip()
 - apply the timings here

> +
> +	return 0;
> +}
> +
>  /**
>   * s3c2410_nand_init_chip - initialise a single instance of an chip
>   * @info: The base NAND controller the chip is on.
> @@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  				   struct s3c2410_nand_mtd *nmtd,
>  				   struct s3c2410_nand_set *set)
>  {
> +	struct device_node *np = info->device->of_node;
>  	struct nand_chip *chip = &nmtd->chip;
>  	void __iomem *regs = info->regs;
>  
> +	nand_set_flash_node(chip, set->of_node);
> +
>  	chip->write_buf    = s3c2410_nand_write_buf;
>  	chip->read_buf     = s3c2410_nand_read_buf;
>  	chip->select_chip  = s3c2410_nand_select_chip;
> @@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->options	   = set->options;
>  	chip->controller   = &info->controller;
>  
> +	/*
> +	 * let's keep behavior unchanged for legacy boards booting via pdata and
> +	 * auto-detect timings only when booting with a device tree.
> +	 */
> +	if (np)
> +		chip->setup_data_interface = s3c2410_nand_setup_data_interface;
> +
>  	switch (info->cpu_type) {
>  	case TYPE_S3C2410:
>  		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
> @@ -859,12 +911,9 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
>  	chip->ecc.mode = info->platform->ecc_mode;
>  
>  	/* If you use u-boot BBT creation code, specifying this flag will
> -	 * let the kernel fish out the BBT from the NAND, and also skip the
> -	 * full NAND scan that can take 1/2s or so. Little things... */
> -	if (set->flash_bbt) {
> +	 * let the kernel fish out the BBT from the NAND */
> +	if (set->flash_bbt)
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
> -		chip->options |= NAND_SKIP_BBTSCAN;
> -	}
>  }
>  
>  /**
> @@ -943,6 +992,77 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  		return -EINVAL;
>  	}
>  
> +	if (chip->bbt_options & NAND_BBT_USE_FLASH)
> +		chip->options |= NAND_SKIP_BBTSCAN;
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id s3c24xx_nand_dt_ids[] = {
> +	{
> +		.compatible = "samsung,s3c2410-nand",
> +		.data = &s3c2410_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2412-nand", /* also compatible with s3c6400 */
> +		.data = &s3c2412_nand_devtype_data,
> +	}, {
> +		.compatible = "samsung,s3c2440-nand",
> +		.data = &s3c2440_nand_devtype_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
> +
> +static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
> +{
> +	const struct s3c24XX_nand_devtype_data *devtype_data;
> +	struct s3c2410_platform_nand *pdata;
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +	struct device_node *np = pdev->dev.of_node, *child;
> +	struct s3c2410_nand_set *sets;
> +
> +	devtype_data = of_device_get_match_data(&pdev->dev);
> +	if (!devtype_data)
> +		return -ENODEV;
> +
> +	info->cpu_type = devtype_data->type;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	pdev->dev.platform_data = pdata;
> +
> +	pdata->nr_sets = of_get_child_count(np);
> +	if (!pdata->nr_sets)
> +		return 0;
> +
> +	sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, GFP_KERNEL);
> +	if (!sets)
> +		return -ENOMEM;
> +
> +	pdata->sets = sets;
> +
> +	for_each_available_child_of_node(np, child) {
> +
> +		sets->name = (char *)child->name;
> +		sets->of_node = child;
> +		sets->nr_chips = 1;
> +
> +		of_node_get(child);
> +
> +		sets++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
> +{
> +	struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
> +
> +	info->cpu_type = platform_get_device_id(pdev)->driver_data;
> +
>  	return 0;
>  }
>  
> @@ -955,8 +1075,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
>  */
>  static int s3c24xx_nand_probe(struct platform_device *pdev)
>  {
> -	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
> -	enum s3c_cpu_type cpu_type;
> +	struct s3c2410_platform_nand *plat;
>  	struct s3c2410_nand_info *info;
>  	struct s3c2410_nand_mtd *nmtd;
>  	struct s3c2410_nand_set *sets;
> @@ -966,8 +1085,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  	int nr_sets;
>  	int setno;
>  
> -	cpu_type = platform_get_device_id(pdev)->driver_data;
> -
>  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>  	if (info == NULL) {
>  		err = -ENOMEM;
> @@ -989,6 +1106,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
>  
> +	if (pdev->dev.of_node)
> +		err = s3c24xx_nand_probe_dt(pdev);
> +	else
> +		err = s3c24xx_nand_probe_pdata(pdev);
> +
> +	if (err)
> +		goto exit_error;
> +
> +	plat = to_nand_plat(pdev);
> +
>  	/* allocate and map the resource */
>  
>  	/* currently we assume we have the one resource */
> @@ -997,7 +1124,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	info->device	= &pdev->dev;
>  	info->platform	= plat;
> -	info->cpu_type	= cpu_type;
>  
>  	info->regs = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(info->regs)) {
> @@ -1007,12 +1133,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  
>  	dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
>  
> -	/* initialise the hardware */
> -
> -	err = s3c2410_nand_inithw(info);
> -	if (err != 0)
> -		goto exit_error;
> -
>  	sets = (plat != NULL) ? plat->sets : NULL;
>  	nr_sets = (plat != NULL) ? plat->nr_sets : 1;
>  
> @@ -1056,6 +1176,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
>  			sets++;
>  	}
>  
> +	/* initialise the hardware */
> +	err = s3c2410_nand_inithw(info);
> +	if (err != 0)
> +		goto exit_error;
> +
>  	err = s3c2410_nand_cpufreq_register(info);
>  	if (err < 0) {
>  		dev_err(&pdev->dev, "failed to init cpufreq support\n");
> @@ -1156,6 +1281,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
>  	.id_table	= s3c24xx_driver_ids,
>  	.driver		= {
>  		.name	= "s3c24xx-nand",
> +		.of_match_table = s3c24xx_nand_dt_ids,
>  	},
>  };
>  
> diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h
> index 729af13d1773..f01659026b26 100644
> --- a/include/linux/platform_data/mtd-nand-s3c2410.h
> +++ b/include/linux/platform_data/mtd-nand-s3c2410.h
> @@ -40,6 +40,7 @@ struct s3c2410_nand_set {
>  	char			*name;
>  	int			*nr_map;
>  	struct mtd_partition	*partitions;
> +	struct device_node	*of_node;
>  };
>  
>  struct s3c2410_platform_nand {

  reply	other threads:[~2016-10-24 13:02 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-20 21:42 [PATCH v3 0/3] mtd: s3c2410: add device tree support Sergio Prado
2016-10-20 21:42 ` Sergio Prado
2016-10-20 21:42 ` [PATCH v3 1/3] mtd: s3c2410: make ecc mode configurable via platform data Sergio Prado
2016-10-20 21:42   ` Sergio Prado
2016-10-21 18:27   ` Krzysztof Kozlowski
2016-10-21 18:27     ` Krzysztof Kozlowski
2016-10-21 18:51     ` Marek Vasut
2016-10-21 18:51       ` Marek Vasut
2016-10-21 18:51       ` Marek Vasut
2016-10-21 20:06       ` Krzysztof Kozlowski
2016-10-21 20:06         ` Krzysztof Kozlowski
2016-10-21 20:06         ` Krzysztof Kozlowski
2016-10-21 19:05     ` Sergio Prado
2016-10-21 19:05       ` Sergio Prado
2016-10-22 12:29     ` Boris Brezillon
2016-10-22 12:29       ` Boris Brezillon
2016-10-22 15:32       ` Krzysztof Kozlowski
2016-10-22 15:32         ` Krzysztof Kozlowski
2016-10-20 21:42 ` [PATCH v3 2/3] dt-bindings: mtd: add DT binding for s3c2410 flash controller Sergio Prado
2016-10-20 21:42   ` Sergio Prado
2016-10-26 23:19   ` Rob Herring
2016-10-26 23:19     ` Rob Herring
2016-10-20 21:42 ` [PATCH v3 3/3] mtd: s3c2410: parse the device configuration from OF node Sergio Prado
2016-10-20 21:42   ` Sergio Prado
2016-10-24 13:02   ` Boris Brezillon [this message]
2016-10-24 13:02     ` Boris Brezillon
2016-10-24 13:02     ` Boris Brezillon
2016-10-24 18:47     ` Sergio Prado
2016-10-24 18:47       ` Sergio Prado
2016-10-24 18:50       ` Boris Brezillon
2016-10-24 18:50         ` Boris Brezillon
2016-10-24 18:50         ` Boris Brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161024150201.01952f67@bbrezillon \
    --to=boris.brezillon@free-electrons.com \
    --cc=computersforpeace@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dwmw2@infradead.org \
    --cc=javier@osg.samsung.com \
    --cc=kgene@kernel.org \
    --cc=krzk@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=linux@simtec.co.uk \
    --cc=mark.rutland@arm.com \
    --cc=richard@nod.at \
    --cc=robh+dt@kernel.org \
    --cc=sergio.prado@e-labworks.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.