* [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration
@ 2017-04-29 8:52 Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 1/3] mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup() Thomas Petazzoni
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2017-04-29 8:52 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This patch series add support for configuring the FSMC NAND controller
timings according to the SDR timings exposed by the NAND chip.
Changes since v1:
- Dropped all patches from the series that have already been merged
in nand/next.
- Rework the implementation as suggested by Boris Brezillon, i.e by
implementing ->setup_data_interface() only when we are going to use
the NAND SDR timings. If there is a "timings" DT property, we keep
using the old strategy without ->setup_data_interface().
The patch series is based on the nand/next branch.
Best regards,
Thomas
Thomas Petazzoni (3):
mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup()
mtd: nand: fsmc: add support for SDR timings
mtd: nand: fsmc: remove default timings
drivers/mtd/nand/fsmc_nand.c | 120 +++++++++++++++++++++++++++++++++----------
1 file changed, 94 insertions(+), 26 deletions(-)
--
2.7.4
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/3] mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup()
2017-04-29 8:52 [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Thomas Petazzoni
@ 2017-04-29 8:52 ` Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 2/3] mtd: nand: fsmc: add support for SDR timings Thomas Petazzoni
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2017-04-29 8:52 UTC (permalink / raw)
To: linux-arm-kernel
In preparation for the introduction of support for using SDR timings
exposed by the NAND flash instead of hard-coded timings, this commit
reworks the fsmc_nand_setup() function to take a "struct fsmc_nand_data"
as argument, which already contains the I/O registers base address, bank
and bus width information.
The timings is also currently contained in the "struct fsmc_nand_data",
but we still pass it as a separate argument because the support for
using SDR timings will pass a different value.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/mtd/nand/fsmc_nand.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index cea50d2..43108dd 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -302,11 +302,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
* This routine initializes timing parameters related to NAND memory access in
* FSMC registers
*/
-static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
- uint32_t busw, struct fsmc_nand_timings *timings)
+static void fsmc_nand_setup(struct fsmc_nand_data *host,
+ struct fsmc_nand_timings *timings)
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset;
+ unsigned int bank = host->bank;
+ void __iomem *regs = host->regs_va;
struct fsmc_nand_timings *tims;
struct fsmc_nand_timings default_timings = {
.tclr = FSMC_TCLR_1,
@@ -318,7 +320,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
};
if (timings)
- tims = timings;
+ tims = host->dev_timings;
else
tims = &default_timings;
@@ -329,7 +331,7 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
- if (busw)
+ if (host->nand.options & NAND_BUSWIDTH_16)
writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC));
else
@@ -933,9 +935,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break;
}
- fsmc_nand_setup(host->regs_va, host->bank,
- nand->options & NAND_BUSWIDTH_16,
- host->dev_timings);
+ fsmc_nand_setup(host, host->dev_timings);
if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -1073,9 +1073,7 @@ static int fsmc_nand_resume(struct device *dev)
struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host) {
clk_prepare_enable(host->clk);
- fsmc_nand_setup(host->regs_va, host->bank,
- host->nand.options & NAND_BUSWIDTH_16,
- host->dev_timings);
+ fsmc_nand_setup(host, host->dev_timings);
}
return 0;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/3] mtd: nand: fsmc: add support for SDR timings
2017-04-29 8:52 [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 1/3] mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup() Thomas Petazzoni
@ 2017-04-29 8:52 ` Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 3/3] mtd: nand: fsmc: remove default timings Thomas Petazzoni
2017-05-15 19:36 ` [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Boris Brezillon
3 siblings, 0 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2017-04-29 8:52 UTC (permalink / raw)
To: linux-arm-kernel
Until now, the fsmc_nand driver was either using controller timings
specified in the Device Tree (through FSMC specific DT properties) or
alternatively default/fallback timings.
This commit implements support to use the timings advertised by the NAND
chip itself, by implementing the ->setup_data_interface() hook. To
preserve backward compatibility, if timings are specified in the Device
Tree, we use the timings from the Device Tree (and don't implement
->setup_data_interface).
Many thanks to Boris Brezillon for coming up with the logic to convert
the NAND chip timings into the timings expected by the FSMC controller.
Also, since the timings are now not only coming from the DT, the message
warning that default timings will be used is removed.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/mtd/nand/fsmc_nand.c | 94 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 89 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 43108dd..442e4df 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -346,6 +346,88 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
FSMC_NAND_REG(regs, bank, ATTRIB));
}
+static int fsmc_calc_timings(struct fsmc_nand_data *host,
+ const struct nand_sdr_timings *sdrt,
+ struct fsmc_nand_timings *tims)
+{
+ unsigned long hclk = clk_get_rate(host->clk);
+ unsigned long hclkn = NSEC_PER_SEC / hclk;
+ uint32_t thiz, thold, twait, tset;
+
+ if (sdrt->tRC_min < 30000)
+ return -EOPNOTSUPP;
+
+ tims->tar = DIV_ROUND_UP(sdrt->tAR_min / 1000, hclkn) - 1;
+ if (tims->tar > FSMC_TAR_MASK)
+ tims->tar = FSMC_TAR_MASK;
+ tims->tclr = DIV_ROUND_UP(sdrt->tCLR_min / 1000, hclkn) - 1;
+ if (tims->tclr > FSMC_TCLR_MASK)
+ tims->tclr = FSMC_TCLR_MASK;
+
+ thiz = sdrt->tCS_min - sdrt->tWP_min;
+ tims->thiz = DIV_ROUND_UP(thiz / 1000, hclkn);
+
+ thold = sdrt->tDH_min;
+ if (thold < sdrt->tCH_min)
+ thold = sdrt->tCH_min;
+ if (thold < sdrt->tCLH_min)
+ thold = sdrt->tCLH_min;
+ if (thold < sdrt->tWH_min)
+ thold = sdrt->tWH_min;
+ if (thold < sdrt->tALH_min)
+ thold = sdrt->tALH_min;
+ if (thold < sdrt->tREH_min)
+ thold = sdrt->tREH_min;
+ tims->thold = DIV_ROUND_UP(thold / 1000, hclkn);
+ if (tims->thold == 0)
+ tims->thold = 1;
+ else if (tims->thold > FSMC_THOLD_MASK)
+ tims->thold = FSMC_THOLD_MASK;
+
+ twait = max(sdrt->tRP_min, sdrt->tWP_min);
+ tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+ if (tims->twait == 0)
+ tims->twait = 1;
+ else if (tims->twait > FSMC_TWAIT_MASK)
+ tims->twait = FSMC_TWAIT_MASK;
+
+ tset = max(sdrt->tCS_min - sdrt->tWP_min,
+ sdrt->tCEA_max - sdrt->tREA_max);
+ tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
+ if (tims->tset == 0)
+ tims->tset = 1;
+ else if (tims->tset > FSMC_TSET_MASK)
+ tims->tset = FSMC_TSET_MASK;
+
+ return 0;
+}
+
+static int fsmc_setup_data_interface(struct mtd_info *mtd,
+ const struct nand_data_interface *conf,
+ bool check_only)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct fsmc_nand_data *host = nand_get_controller_data(nand);
+ struct fsmc_nand_timings tims;
+ const struct nand_sdr_timings *sdrt;
+ int ret;
+
+ sdrt = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdrt))
+ return PTR_ERR(sdrt);
+
+ ret = fsmc_calc_timings(host, sdrt, &tims);
+ if (ret)
+ return ret;
+
+ if (check_only)
+ return 0;
+
+ fsmc_nand_setup(host, &tims);
+
+ return 0;
+}
+
/*
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/
@@ -798,10 +880,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return -ENOMEM;
ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
sizeof(*host->dev_timings));
- if (ret) {
- dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
+ if (ret)
host->dev_timings = NULL;
- }
/* Set default NAND bank to 0 */
host->bank = 0;
@@ -935,7 +1015,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
break;
}
- fsmc_nand_setup(host, host->dev_timings);
+ if (host->dev_timings)
+ fsmc_nand_setup(host, host->dev_timings);
+ else
+ nand->setup_data_interface = fsmc_setup_data_interface;
if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -1073,7 +1156,8 @@ static int fsmc_nand_resume(struct device *dev)
struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host) {
clk_prepare_enable(host->clk);
- fsmc_nand_setup(host, host->dev_timings);
+ if (host->dev_timings)
+ fsmc_nand_setup(host, host->dev_timings);
}
return 0;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 3/3] mtd: nand: fsmc: remove default timings
2017-04-29 8:52 [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 1/3] mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup() Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 2/3] mtd: nand: fsmc: add support for SDR timings Thomas Petazzoni
@ 2017-04-29 8:52 ` Thomas Petazzoni
2017-05-15 19:36 ` [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Boris Brezillon
3 siblings, 0 replies; 5+ messages in thread
From: Thomas Petazzoni @ 2017-04-29 8:52 UTC (permalink / raw)
To: linux-arm-kernel
When timings are no longer provided by the Device Tree, we now use the
SDR timings specified by the NAND flash, and such SDR timings are always
provided. Therefore, it is no longer necessary to keep "default" timings
in the fmsc driver.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/mtd/nand/fsmc_nand.c | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 442e4df..f58c912 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -303,26 +303,12 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
* FSMC registers
*/
static void fsmc_nand_setup(struct fsmc_nand_data *host,
- struct fsmc_nand_timings *timings)
+ struct fsmc_nand_timings *tims)
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset;
unsigned int bank = host->bank;
void __iomem *regs = host->regs_va;
- struct fsmc_nand_timings *tims;
- struct fsmc_nand_timings default_timings = {
- .tclr = FSMC_TCLR_1,
- .tar = FSMC_TAR_1,
- .thiz = FSMC_THIZ_1,
- .thold = FSMC_THOLD_4,
- .twait = FSMC_TWAIT_6,
- .tset = FSMC_TSET_0,
- };
-
- if (timings)
- tims = host->dev_timings;
- else
- tims = &default_timings;
tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration
2017-04-29 8:52 [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Thomas Petazzoni
` (2 preceding siblings ...)
2017-04-29 8:52 ` [PATCH v2 3/3] mtd: nand: fsmc: remove default timings Thomas Petazzoni
@ 2017-05-15 19:36 ` Boris Brezillon
3 siblings, 0 replies; 5+ messages in thread
From: Boris Brezillon @ 2017-05-15 19:36 UTC (permalink / raw)
To: linux-arm-kernel
On Sat, 29 Apr 2017 10:52:33 +0200
Thomas Petazzoni <thomas.petazzoni@free-electrons.com> wrote:
> Hello,
>
> This patch series add support for configuring the FSMC NAND controller
> timings according to the SDR timings exposed by the NAND chip.
>
> Changes since v1:
>
> - Dropped all patches from the series that have already been merged
> in nand/next.
>
> - Rework the implementation as suggested by Boris Brezillon, i.e by
> implementing ->setup_data_interface() only when we are going to use
> the NAND SDR timings. If there is a "timings" DT property, we keep
> using the old strategy without ->setup_data_interface().
>
> The patch series is based on the nand/next branch.
Applied to nand/next.
Thanks,
Boris
>
> Best regards,
>
> Thomas
>
> Thomas Petazzoni (3):
> mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup()
> mtd: nand: fsmc: add support for SDR timings
> mtd: nand: fsmc: remove default timings
>
> drivers/mtd/nand/fsmc_nand.c | 120 +++++++++++++++++++++++++++++++++----------
> 1 file changed, 94 insertions(+), 26 deletions(-)
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-05-15 19:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-29 8:52 [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 1/3] mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup() Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 2/3] mtd: nand: fsmc: add support for SDR timings Thomas Petazzoni
2017-04-29 8:52 ` [PATCH v2 3/3] mtd: nand: fsmc: remove default timings Thomas Petazzoni
2017-05-15 19:36 ` [PATCH v2 0/3] mtd: nand: fsmc: support SDR timing configuration Boris Brezillon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).