linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Matthieu CASTET <matthieu.castet@parrot.com>
To: linux-mtd@lists.infradead.org, linux-omap@vger.kernel.org
Cc: dedekind1@gmail.com, Matthieu CASTET <matthieu.castet@parrot.com>
Subject: [PATCH 2/3] mtd nand : get timings from onfi
Date: Tue,  6 Nov 2012 17:44:36 +0100	[thread overview]
Message-ID: <1352220277-4251-2-git-send-email-matthieu.castet@parrot.com> (raw)
In-Reply-To: <1352220277-4251-1-git-send-email-matthieu.castet@parrot.com>

We get from onfi param the max speed supported by the chip.
A precomputed table for ONFI timings is generated.

Signed-off-by: Matthieu CASTET <matthieu.castet@parrot.com>
---
 drivers/mtd/nand/Makefile      |    2 +-
 drivers/mtd/nand/nand_base.c   |    1 +
 drivers/mtd/nand/nand_timing.c |  170 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h       |   56 +++++++++++++
 4 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/nand_timing.c

diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 2cbd091..2fc1a99 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -54,4 +54,4 @@ obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/
 obj-$(CONFIG_MTD_NAND_XWAY)		+= xway_nand.o
 
-nand-objs := nand_base.o nand_bbt.o
+nand-objs := nand_base.o nand_bbt.o nand_timing.o
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8916bc6..0d6bd88 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3238,6 +3238,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 ident_done:
+	nand_select_speed(chip, *maf_id, *dev_id);
 
 	/* Try to identify manufacturer */
 	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
diff --git a/drivers/mtd/nand/nand_timing.c b/drivers/mtd/nand/nand_timing.c
new file mode 100644
index 0000000..7211c9c
--- /dev/null
+++ b/drivers/mtd/nand/nand_timing.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+/*
+ * this table is precomputed from onfi timings with the following program
+ */
+#if 0
+int print_timing(const struct onfi_timings *timings, int edo_off)
+{
+	struct reduced_onfi t;
+	int tmp;
+	int edo = timings->tRC < 30 && !edo_off;
+
+	/* nWE low */
+	t.twp = max(timings->tWP, timings->tDS);
+
+	/* nCS low to nWE low */
+	tmp = max(timings->tCLS, timings->tCS);
+	tmp = max(tmp, timings->tALS);
+	t.twsetup = tmp - t.twp;
+	assert(t.twsetup >= 0);
+
+	/* nWE high */
+	tmp = max(timings->tWH, timings->tDH); /* nWE high & data hold */
+	tmp = max(tmp, timings->tCH); /* cs hold */
+	tmp = max(tmp, timings->tCLH); /* cmd hold */
+	t.twh = max(tmp, timings->tALH); /* addr hold */
+
+	assert(t.twp + t.twh <= timings->tWC);
+	t.twc = timings->tWC;
+
+	t.edo = edo;
+	if (edo == 0) {
+
+		/* nRE low */
+		t.trp = max(timings->tRP, timings->tREA);
+
+		/* nRE high */
+		t.treh = timings->tREH;
+		t.trc = max(timings->tRC, t.trp + t.treh);
+	}
+	else {
+		/* nRE low */
+		t.trp = timings->tRP;
+
+		/* nRE high */
+		t.treh = timings->tREH;
+
+		t.trc = max(timings->tRC, timings->tREA);
+	}
+
+	/* nCS low to nRE low */
+	t.trsetup = max(timings->tCEA - timings->tREA, timings->tCLR);
+
+	/* Min time from rdn rising edge to output hi-Z */
+	t.bta = timings->tRHZ;
+
+	/* Min time from busy rising edge and rdn falling edge (read).*/
+	t.tbusy = timings->tRR;
+
+	/* Min time from wrn rising edge to rdn falling edge. */
+	t.twhr = timings->tWHR;
+	assert(t.twhr >= 0);
+
+	t.tceh = 0;
+
+	printf("{\n");
+	printf("/* %s edo=%d */\n", timings->name, t.edo);
+	printf(".twp = %3d,  .twh = %3d, .twc = %3d, .twsetup = %d,\n",
+			t.twp, t.twh, t.twc, t.twsetup);
+	printf(".trp = %3d,  .treh = %3d, .trc = %3d, .trsetup = %d,\n",
+			t.trp, t.treh, t.trc, t.trsetup);
+	printf(".twhr = %d, .tceh = %d,  .bta = %d, .tbusy = %d, .edo = %d,\n",
+			t.twhr, t.tceh, t.bta, t.tbusy, t.edo);
+	printf("},\n");
+#endif
+
+static struct reduced_onfi nand_timing[] =
+{
+	{
+		/* onfi mode 0 edo=0 */
+		.twp =  50,  .twh =  30, .twc = 100, .twsetup = 20,
+		.trp =  50,  .treh =  30, .trc = 100, .trsetup = 60,
+		.twhr = 120, .tceh = 0,  .bta = 200, .tbusy = 39, .edo = 0,
+	},
+	{
+		/* onfi mode 1 edo=0 */
+		.twp =  25,  .twh =  15, .twc =  45, .twsetup = 10,
+		.trp =  30,  .treh =  15, .trc =  50, .trsetup = 15,
+		.twhr = 80, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 0,
+	},
+	{
+		/* onfi mode 2 edo=0 */
+		.twp =  17,  .twh =  15, .twc =  35, .twsetup = 8,
+		.trp =  25,  .treh =  15, .trc =  40, .trsetup = 10,
+		.twhr = 80, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 0,
+	},
+	{
+		/* onfi mode 3 edo=0 */
+		.twp =  15,  .twh =  10, .twc =  30, .twsetup = 10,
+		.trp =  20,  .treh =  10, .trc =  30, .trsetup = 10,
+		.twhr = 60, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 0,
+	},
+	{
+		/* onfi mode 4 edo=1 */
+		.twp =  12,  .twh =  10, .twc =  25, .twsetup = 8,
+		.trp =  12,  .treh =  10, .trc =  25, .trsetup = 10,
+		.twhr = 60, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 1,
+	},
+	{
+		/* onfi mode 5 edo=1 */
+		.twp =  10,  .twh =   7, .twc =  20, .twsetup = 5,
+		.trp =  10,  .treh =   7, .trc =  20, .trsetup = 10,
+		.twhr = 60, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 1,
+	},
+	{
+		/* onfi mode 4 edo=0 */
+		.twp =  12,  .twh =  10, .twc =  25, .twsetup = 8,
+		.trp =  20,  .treh =  10, .trc =  30, .trsetup = 10,
+		.twhr = 60, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 0,
+	},
+	{
+		/* onfi mode 5 edo=0 */
+		.twp =  10,  .twh =   7, .twc =  20, .twsetup = 5,
+		.trp =  16,  .treh =   7, .trc =  23, .trsetup = 10,
+		.twhr = 60, .tceh = 0,  .bta = 100, .tbusy = 20, .edo = 0,
+	},
+};
+
+void nand_select_speed(struct nand_chip *chip, int maf_id, int dev_id)
+{
+	int i;
+	chip->onfi_speed = -1;
+	if (chip->onfi_version) {
+		int mode = le16_to_cpu(chip->onfi_params.async_timing_mode);
+		int max_mode = 0;
+		for (i = 0; i <= 5; i++) {
+			if (mode & (1 << i))
+				max_mode = i;
+		}
+		chip->onfi_speed = max_mode;
+	}
+	/*
+	 * For flash that are not ONFI we could use maf_id and dev_id to select a
+	 * speed. But we need to make sure to select a speed compatible with all
+	 * flash generation that share the same ids.
+	 */
+}
+
+const struct reduced_onfi *nand_get_timing(int mode, int edo)
+{
+	if (mode < 0)
+		mode = 0;
+	if (!edo && mode >= 4)
+		mode += 2;
+	if (mode >  ARRAY_SIZE(nand_timing))
+		mode = 0;
+	return &(nand_timing[mode]);
+}
+EXPORT_SYMBOL_GPL(nand_get_timing);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c8518d4..95f2871 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -474,6 +474,7 @@ struct nand_buffers {
  * @pagebuf_bitflips:	[INTERN] holds the bitflip count for the page which is
  *			currently in data_buf.
  * @subpagesize:	[INTERN] holds the subpagesize
+ * @onfi_speed:		[INTERN] holds the ONFI speed, -1 if not supported.
  * @onfi_version:	[INTERN] holds the chip ONFI version (BCD encoded),
  *			non 0 if ONFI supported.
  * @onfi_params:	[INTERN] holds the ONFI page parameter when ONFI is
@@ -545,6 +546,7 @@ struct nand_chip {
 	int badblockpos;
 	int badblockbits;
 
+	int	onfi_speed;
 	int onfi_version;
 	struct nand_onfi_params	onfi_params;
 
@@ -691,6 +693,60 @@ struct platform_nand_data {
 	struct platform_nand_ctrl ctrl;
 };
 
+/**
+ * timing in ns,
+ *  there are computed from onfi table :
+ *  twsetup = max(tCLS, tCS, tALS) - twp
+ *  twp = max(tWP, tDS)
+ *  twh = max(tCLH, tCH, tALH, tDH, tWH)
+ *  twc = tWC
+ *  trsetup = max(tCEA-tREA, tCLR)
+ *  treh = tREH
+ *  if (edo == 0) {
+ *    trp = max(tRP, tREA)
+ *    trc = max(tRC, trp + treh)
+ *  }
+ *  else {
+ *    trp = tRP
+ *    trc = max(tRC, tREA)
+ *  }
+ *
+ *  bta = max(tRHZ, tCHZ)
+ *  busy = tRR
+ *  twhr = tWHR
+ *
+ *  Note that twp + twh can be smaller than twc, so you should do :
+ *  twp_clk = ns_to_ticks(twp)
+ *  twh_clk = ns_to_ticks(max(twh, twc - ticks_to_ns(twp_clk)))
+ *  or
+ *  twh_clk = ps_to_ticks(max(ns_to_ps(twh), ns_to_ps(twc) - ticks_to_ps(twp_clk)))
+ *  using picosecond can help for rounding. For example a 156Mhz, mode=4 edo=1
+ *  with ps we got twp_clk=twh_clk=2 (12820 ps)
+ *  without ps we got twp_clk = 2 (12 ns) and twh_clk=3 (18 ns)
+ *  This is because 12820 + 12820 > 15000 but 12 + 12 < 15.
+ */
+struct reduced_onfi {
+	u8 twsetup; /* nCS low to nWE low */
+	u8 twp; /* nWE low */
+	u8 twh; /* nWE high */
+	u8 twc; /* write cyle */
+
+	u8 trsetup; /* nCS low to nRE low */
+	u8 trp; /* nRE low */
+	u8 treh; /* nRE high */
+	u8 trc; /* read cycle */
+
+	u8 bta; /* Min time from nRE rising edge to output hi-Z */
+	u8 tbusy; /* Min time from busy rising edge and nRE falling edge */
+	u8 twhr; /* Min time from nWE rising edge to nRE falling edge. */
+	u8 tceh; /* Min time for nCE high */
+
+	u8 edo; /* edo mode */
+};
+
+void nand_select_speed(struct nand_chip *chip, int maf_id, int dev_id);
+const struct reduced_onfi *nand_get_timing(int mode, int edo);
+
 /* Some helpers to access the data structures */
 static inline
 struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
-- 
1.7.10.4


  reply	other threads:[~2012-11-06 16:44 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-06 16:44 [PATCH 1/3] omap gpmc : add support of setting CYCLE2CYCLEDELAY and BUSTURNAROUND Matthieu CASTET
2012-11-06 16:44 ` Matthieu CASTET [this message]
2012-11-06 16:44 ` [PATCH 3/3] omap nand : use onfi mode to compute optimized timings Matthieu CASTET
2012-11-06 17:23 ` [PATCH 1/3] omap gpmc : add support of setting CYCLE2CYCLEDELAY and BUSTURNAROUND Jon Hunter
2012-11-06 18:00   ` Matthieu CASTET
2012-11-06 20:34     ` Jon Hunter
2012-11-07  8:58       ` Mohammed, Afzal
2012-11-07 21:40         ` Tony Lindgren
2012-11-08 12:54           ` Mohammed, Afzal

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=1352220277-4251-2-git-send-email-matthieu.castet@parrot.com \
    --to=matthieu.castet@parrot.com \
    --cc=dedekind1@gmail.com \
    --cc=linux-mtd@lists.infradead.org \
    --cc=linux-omap@vger.kernel.org \
    /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 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).