aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorVipin Kumar <vipin.kumar@st.com>2012-03-14 02:17:14 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-03-26 19:59:34 -0400
commite2f6bce8d94d2c82d4f7ae9d94743963a3b10136 (patch)
treeed6cdc5023282b4322d5490fd579105f7483ab0b /drivers/mtd
parentf63acb75c5d8a9eb7cc5548e3e778d2a00bf3bae (diff)
mtd: nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform
FSMC controllers provide registers to program the required timing values for attached NAND device. The timing values used until now are relaxed and should work for all devices. Although, for read/write performance improvements, the fsmc nand driver should accept nand timings as a platform data and program the timing parameters into fsmc registers accordingly. This patch implements this modification. Additionally, it programs the default timing parameters if these are not passed via platform data. Signed-off-by: Vipin Kumar <vipin.kumar@st.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/fsmc_nand.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index a5099607d203..e7ae63ab59c6 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -303,6 +303,8 @@ struct fsmc_nand_data {
303 struct resource *resaddr; 303 struct resource *resaddr;
304 struct resource *resdata; 304 struct resource *resdata;
305 305
306 struct fsmc_nand_timings *dev_timings;
307
306 void __iomem *data_va; 308 void __iomem *data_va;
307 void __iomem *cmd_va; 309 void __iomem *cmd_va;
308 void __iomem *addr_va; 310 void __iomem *addr_va;
@@ -383,21 +385,41 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
383 * FSMC registers 385 * FSMC registers
384 */ 386 */
385static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, 387static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank,
386 uint32_t busw) 388 uint32_t busw, struct fsmc_nand_timings *timings)
387{ 389{
388 uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; 390 uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
391 uint32_t tclr, tar, thiz, thold, twait, tset;
392 struct fsmc_nand_timings *tims;
393 struct fsmc_nand_timings default_timings = {
394 .tclr = FSMC_TCLR_1,
395 .tar = FSMC_TAR_1,
396 .thiz = FSMC_THIZ_1,
397 .thold = FSMC_THOLD_4,
398 .twait = FSMC_TWAIT_6,
399 .tset = FSMC_TSET_0,
400 };
401
402 if (timings)
403 tims = timings;
404 else
405 tims = &default_timings;
406
407 tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
408 tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
409 thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT;
410 thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT;
411 twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT;
412 tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
389 413
390 if (busw) 414 if (busw)
391 writel(value | FSMC_DEVWID_16, &regs->bank_regs[bank].pc); 415 writel(value | FSMC_DEVWID_16, &regs->bank_regs[bank].pc);
392 else 416 else
393 writel(value | FSMC_DEVWID_8, &regs->bank_regs[bank].pc); 417 writel(value | FSMC_DEVWID_8, &regs->bank_regs[bank].pc);
394 418
395 writel(readl(&regs->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1, 419 writel(readl(&regs->bank_regs[bank].pc) | tclr | tar,
396 &regs->bank_regs[bank].pc); 420 &regs->bank_regs[bank].pc);
397 writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, 421 writel(thiz | thold | twait | tset, &regs->bank_regs[bank].comm);
398 &regs->bank_regs[bank].comm); 422 writel(thiz | thold | twait | tset, &regs->bank_regs[bank].attrib);
399 writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
400 &regs->bank_regs[bank].attrib);
401} 423}
402 424
403/* 425/*
@@ -783,6 +805,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
783 host->select_chip = pdata->select_bank; 805 host->select_chip = pdata->select_bank;
784 host->partitions = pdata->partitions; 806 host->partitions = pdata->partitions;
785 host->nr_partitions = pdata->nr_partitions; 807 host->nr_partitions = pdata->nr_partitions;
808 host->dev_timings = pdata->nand_timings;
786 regs = host->regs_va; 809 regs = host->regs_va;
787 810
788 /* Link all private pointers */ 811 /* Link all private pointers */
@@ -807,7 +830,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
807 if (pdata->width == FSMC_NAND_BW16) 830 if (pdata->width == FSMC_NAND_BW16)
808 nand->options |= NAND_BUSWIDTH_16; 831 nand->options |= NAND_BUSWIDTH_16;
809 832
810 fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); 833 fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16,
834 host->dev_timings);
811 835
812 if (AMBA_REV_BITS(host->pid) >= 8) { 836 if (AMBA_REV_BITS(host->pid) >= 8) {
813 nand->ecc.read_page = fsmc_read_page_hwecc; 837 nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -979,7 +1003,8 @@ static int fsmc_nand_resume(struct device *dev)
979 if (host) { 1003 if (host) {
980 clk_enable(host->clk); 1004 clk_enable(host->clk);
981 fsmc_nand_setup(host->regs_va, host->bank, 1005 fsmc_nand_setup(host->regs_va, host->bank,
982 host->nand.options & NAND_BUSWIDTH_16); 1006 host->nand.options & NAND_BUSWIDTH_16,
1007 host->dev_timings);
983 } 1008 }
984 return 0; 1009 return 0;
985} 1010}