From: Marek Vasut <marek.vasut@gmail.com>
To: Boris Brezillon <boris.brezillon@free-electrons.com>,
Richard Weinberger <richard@nod.at>,
linux-mtd@lists.infradead.org,
Sascha Hauer <s.hauer@pengutronix.de>,
Sergio Prado <sergio.prado@e-labworks.com>,
Marc Gonzalez <marc_gonzalez@sigmadesigns.com>,
Wenyou Yang <wenyou.yang@atmel.com>,
Josh Wu <rainyfeeling@outlook.com>
Cc: David Woodhouse <dwmw2@infradead.org>,
Brian Norris <computersforpeace@gmail.com>,
Cyrille Pitchen <cyrille.pitchen@atmel.com>,
Krzysztof Kozlowski <krzk@kernel.org>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: [RESEND PATCH 2/3] mtd: nand: atmel: Add ->setup_data_interface() hooks
Date: Mon, 20 Feb 2017 23:47:10 +0100 [thread overview]
Message-ID: <4db51424-0e59-bad7-45ff-92516424dead@gmail.com> (raw)
In-Reply-To: <1487625149-7234-3-git-send-email-boris.brezillon@free-electrons.com>
On 02/20/2017 10:12 PM, Boris Brezillon wrote:
> The NAND controller IP can adapt the NAND controller timings dynamically.
> Implement the ->setup_data_interface() hook to support this feature.
>
> Note that it's not supported on at91rm9200 because this SoC has a
> completely different SMC block, which is not supported yet.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> ---
> drivers/mtd/nand/atmel/nand-controller.c | 333 ++++++++++++++++++++++++++++++-
> 1 file changed, 328 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c
> index 4207c0d37826..ae46ef711d67 100644
> --- a/drivers/mtd/nand/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/atmel/nand-controller.c
> @@ -57,6 +57,7 @@
> #include <linux/interrupt.h>
> #include <linux/mfd/syscon.h>
> #include <linux/mfd/syscon/atmel-matrix.h>
> +#include <linux/mfd/syscon/atmel-smc.h>
> #include <linux/module.h>
> #include <linux/mtd/nand.h>
> #include <linux/of_address.h>
> @@ -147,6 +148,8 @@ struct atmel_nand_cs {
> void __iomem *virt;
> dma_addr_t dma;
> } io;
> +
> + struct atmel_smc_cs_conf smcconf;
> };
>
> struct atmel_nand {
> @@ -190,6 +193,8 @@ struct atmel_nand_controller_ops {
> void (*nand_init)(struct atmel_nand_controller *nc,
> struct atmel_nand *nand);
> int (*ecc_init)(struct atmel_nand *nand);
> + int (*setup_data_interface)(struct atmel_nand *nand, int csline,
> + const struct nand_data_interface *conf);
> };
>
> struct atmel_nand_controller_caps {
> @@ -1144,6 +1149,293 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
> return 0;
> }
>
> +static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
> + const struct nand_data_interface *conf,
> + struct atmel_smc_cs_conf *smcconf)
> +{
> + u32 ncycles, totalcycles, timeps, mckperiodps;
> + struct atmel_nand_controller *nc;
> + int ret;
> +
> + nc = to_nand_controller(nand->base.controller);
> +
> + /* DDR interface not supported. */
> + if (conf->type != NAND_SDR_IFACE)
> + return -ENOTSUPP;
> +
> + /*
> + * tRC < 30ns implies EDO mode. This controller does not support this
> + * mode.
> + */
> + if (conf->timings.sdr.tRC_min < 30)
> + return -ENOTSUPP;
> +
> + atmel_smc_cs_conf_init(smcconf);
> +
> + mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
> + mckperiodps *= 1000;
You probably want to multiply before dividing to retain precision.
> + /*
> + * Set write pulse timing. This one is easy to extract:
> + *
> + * NWE_PULSE = tWP
> + */
> + ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
> + totalcycles = ncycles;
> + ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
> + ncycles);
> + if (ret)
> + return ret;
> +
> + /*
> + * The write setup timing depends on the operation done on the NAND.
> + * All operations goes through the same data bus, but the operation
> + * type depends on the address we are writing to (ALE/CLE address
> + * lines).
> + * Since we have no way to differentiate the different operations at
> + * the SMC level, we must consider the worst case (the biggest setup
> + * time among all operation types):
> + *
> + * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
> + */
> + timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
> + conf->timings.sdr.tALS_min);
> + timeps = max(timeps, conf->timings.sdr.tDS_min);
> + ncycles = DIV_ROUND_UP(timeps, mckperiodps);
> + ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
Ew, that's totally cryptic here ...
> + totalcycles += ncycles;
> + ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
> + ncycles);
> + if (ret)
> + return ret;
[...]
> +static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
> + .ale_offs = 1 << 21,
> + .cle_offs = 1 << 22,
BIT(22) ?
> .ops = &atmel_smc_nc_ops,
> };
>
> @@ -2129,14 +2452,14 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
> static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
> .ale_offs = 1 << 21,
> .cle_offs = 1 << 22,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
> .ale_offs = 1 << 22,
> .cle_offs = 1 << 21,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> @@ -2144,7 +2467,7 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
> .has_dma = true,
> .ale_offs = 1 << 21,
> .cle_offs = 1 << 22,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> @@ -2155,7 +2478,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
> },
> {
> .compatible = "atmel,at91sam9260-nand-controller",
> - .data = &atmel_rm9200_nc_caps,
> + .data = &atmel_sam9260_nc_caps,
> },
> {
> .compatible = "atmel,at91sam9261-nand-controller",
>
--
Best regards,
Marek Vasut
WARNING: multiple messages have this Message-ID (diff)
From: marek.vasut@gmail.com (Marek Vasut)
To: linux-arm-kernel@lists.infradead.org
Subject: [RESEND PATCH 2/3] mtd: nand: atmel: Add ->setup_data_interface() hooks
Date: Mon, 20 Feb 2017 23:47:10 +0100 [thread overview]
Message-ID: <4db51424-0e59-bad7-45ff-92516424dead@gmail.com> (raw)
In-Reply-To: <1487625149-7234-3-git-send-email-boris.brezillon@free-electrons.com>
On 02/20/2017 10:12 PM, Boris Brezillon wrote:
> The NAND controller IP can adapt the NAND controller timings dynamically.
> Implement the ->setup_data_interface() hook to support this feature.
>
> Note that it's not supported on at91rm9200 because this SoC has a
> completely different SMC block, which is not supported yet.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> ---
> drivers/mtd/nand/atmel/nand-controller.c | 333 ++++++++++++++++++++++++++++++-
> 1 file changed, 328 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c
> index 4207c0d37826..ae46ef711d67 100644
> --- a/drivers/mtd/nand/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/atmel/nand-controller.c
> @@ -57,6 +57,7 @@
> #include <linux/interrupt.h>
> #include <linux/mfd/syscon.h>
> #include <linux/mfd/syscon/atmel-matrix.h>
> +#include <linux/mfd/syscon/atmel-smc.h>
> #include <linux/module.h>
> #include <linux/mtd/nand.h>
> #include <linux/of_address.h>
> @@ -147,6 +148,8 @@ struct atmel_nand_cs {
> void __iomem *virt;
> dma_addr_t dma;
> } io;
> +
> + struct atmel_smc_cs_conf smcconf;
> };
>
> struct atmel_nand {
> @@ -190,6 +193,8 @@ struct atmel_nand_controller_ops {
> void (*nand_init)(struct atmel_nand_controller *nc,
> struct atmel_nand *nand);
> int (*ecc_init)(struct atmel_nand *nand);
> + int (*setup_data_interface)(struct atmel_nand *nand, int csline,
> + const struct nand_data_interface *conf);
> };
>
> struct atmel_nand_controller_caps {
> @@ -1144,6 +1149,293 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
> return 0;
> }
>
> +static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
> + const struct nand_data_interface *conf,
> + struct atmel_smc_cs_conf *smcconf)
> +{
> + u32 ncycles, totalcycles, timeps, mckperiodps;
> + struct atmel_nand_controller *nc;
> + int ret;
> +
> + nc = to_nand_controller(nand->base.controller);
> +
> + /* DDR interface not supported. */
> + if (conf->type != NAND_SDR_IFACE)
> + return -ENOTSUPP;
> +
> + /*
> + * tRC < 30ns implies EDO mode. This controller does not support this
> + * mode.
> + */
> + if (conf->timings.sdr.tRC_min < 30)
> + return -ENOTSUPP;
> +
> + atmel_smc_cs_conf_init(smcconf);
> +
> + mckperiodps = NSEC_PER_SEC / clk_get_rate(nc->mck);
> + mckperiodps *= 1000;
You probably want to multiply before dividing to retain precision.
> + /*
> + * Set write pulse timing. This one is easy to extract:
> + *
> + * NWE_PULSE = tWP
> + */
> + ncycles = DIV_ROUND_UP(conf->timings.sdr.tWP_min, mckperiodps);
> + totalcycles = ncycles;
> + ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NWE_SHIFT,
> + ncycles);
> + if (ret)
> + return ret;
> +
> + /*
> + * The write setup timing depends on the operation done on the NAND.
> + * All operations goes through the same data bus, but the operation
> + * type depends on the address we are writing to (ALE/CLE address
> + * lines).
> + * Since we have no way to differentiate the different operations at
> + * the SMC level, we must consider the worst case (the biggest setup
> + * time among all operation types):
> + *
> + * NWE_SETUP = max(tCLS, tCS, tALS, tDS) - NWE_PULSE
> + */
> + timeps = max3(conf->timings.sdr.tCLS_min, conf->timings.sdr.tCS_min,
> + conf->timings.sdr.tALS_min);
> + timeps = max(timeps, conf->timings.sdr.tDS_min);
> + ncycles = DIV_ROUND_UP(timeps, mckperiodps);
> + ncycles = ncycles > totalcycles ? ncycles - totalcycles : 0;
Ew, that's totally cryptic here ...
> + totalcycles += ncycles;
> + ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NWE_SHIFT,
> + ncycles);
> + if (ret)
> + return ret;
[...]
> +static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
> + .ale_offs = 1 << 21,
> + .cle_offs = 1 << 22,
BIT(22) ?
> .ops = &atmel_smc_nc_ops,
> };
>
> @@ -2129,14 +2452,14 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
> static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
> .ale_offs = 1 << 21,
> .cle_offs = 1 << 22,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
> .ale_offs = 1 << 22,
> .cle_offs = 1 << 21,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> @@ -2144,7 +2467,7 @@ static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
> .has_dma = true,
> .ale_offs = 1 << 21,
> .cle_offs = 1 << 22,
> - .ops = &atmel_smc_nc_ops,
> + .ops = &at91rm9200_nc_ops,
> .legacy_of_bindings = true,
> };
>
> @@ -2155,7 +2478,7 @@ static const struct of_device_id atmel_nand_controller_of_ids[] = {
> },
> {
> .compatible = "atmel,at91sam9260-nand-controller",
> - .data = &atmel_rm9200_nc_caps,
> + .data = &atmel_sam9260_nc_caps,
> },
> {
> .compatible = "atmel,at91sam9261-nand-controller",
>
--
Best regards,
Marek Vasut
next prev parent reply other threads:[~2017-02-20 22:47 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-02-20 21:12 [RESEND PATCH 0/3] mtd: nand: atmel: Add ->setup_data_interface() + PM ops Boris Brezillon
2017-02-20 21:12 ` Boris Brezillon
2017-02-20 21:12 ` [RESEND PATCH 1/3] mtd: nand: Pass the CS line to ->setup_data_interface() Boris Brezillon
2017-02-20 21:12 ` Boris Brezillon
2017-02-21 10:57 ` Marc Gonzalez
2017-02-21 10:57 ` Marc Gonzalez
2017-02-21 11:06 ` Boris Brezillon
2017-02-21 11:06 ` Boris Brezillon
2017-02-21 12:02 ` Marc Gonzalez
2017-02-21 12:02 ` Marc Gonzalez
2017-02-21 12:47 ` Boris Brezillon
2017-02-21 12:47 ` Boris Brezillon
2017-02-20 21:12 ` [RESEND PATCH 2/3] mtd: nand: atmel: Add ->setup_data_interface() hooks Boris Brezillon
2017-02-20 21:12 ` Boris Brezillon
2017-02-20 22:47 ` Marek Vasut [this message]
2017-02-20 22:47 ` Marek Vasut
2017-02-21 8:13 ` Boris Brezillon
2017-02-21 8:13 ` Boris Brezillon
2017-02-20 21:12 ` [RESEND PATCH 3/3] mtd: nand: atmel: Add PM ops Boris Brezillon
2017-02-20 21:12 ` 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=4db51424-0e59-bad7-45ff-92516424dead@gmail.com \
--to=marek.vasut@gmail.com \
--cc=boris.brezillon@free-electrons.com \
--cc=computersforpeace@gmail.com \
--cc=cyrille.pitchen@atmel.com \
--cc=dwmw2@infradead.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=marc_gonzalez@sigmadesigns.com \
--cc=rainyfeeling@outlook.com \
--cc=richard@nod.at \
--cc=s.hauer@pengutronix.de \
--cc=sergio.prado@e-labworks.com \
--cc=wenyou.yang@atmel.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.