mtd: nand: fsmc: support SDR timing configuration
Subsystems (2)
v2 cover mtd: nand: fsmc: support SDR timing configuration
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(-)
Signature · 1 line
2.7.4
PATCH v2 1/3 mtd: nand: fsmc: reduce number of arguments of fsmc_nand_setup()
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.
--- drivers/mtd/nand/fsmc_nand.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/mtd/nand/fsmc_nand.c +8 -10
@@ -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 ; }
Signature · 1 line
2.7.4
PATCH v2 2/3 mtd: nand: fsmc: add support for SDR timings
In reply to Thomas PetazzoniUntil 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.
--- drivers/mtd/nand/fsmc_nand.c | 94 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-)
drivers/mtd/nand/fsmc_nand.c +89 -5
@@ -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 ; }
Signature · 1 line
2.7.4
PATCH v2 3/3 mtd: nand: fsmc: remove default timings
In reply to Thomas PetazzoniWhen 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.
--- drivers/mtd/nand/fsmc_nand.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-)
drivers/mtd/nand/fsmc_nand.c +1 -15
@@ -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 ;
Signature · 1 line
2.7.4
Boris Brezillon
Appliedv2 cover mtd: nand: fsmc: support SDR timing configuration
In reply to Thomas PetazzoniQuoted 10 lines · On Sat, 29 Apr 2017 10:52:33 +0200 Thomas Petazzoni…
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.
Quoted 6 lines
- 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
Quoted 13 lines
Best regards,
Thomas
Thomas Petazzoni (3):
mtd: nand: fsmc: reduce number of arguments offsmc_nand_setup()
mtd: nand: fsmc: add support for SDR timings
mtd: nand: fsmc: remove default timingsdrivers/mtd/nand/fsmc_nand.c | 120 +++++++++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 26 deletions(-)