mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Robert Jarzmik <robert.jarzmik@free.fr>
To: barebox@lists.infradead.org,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Subject: [PATCH] mtd: nand: fix marvell nand driver
Date: Sat, 17 Jan 2015 16:00:01 +0100	[thread overview]
Message-ID: <1421506801-1506-1-git-send-email-robert.jarzmik@free.fr> (raw)

This fixes 4 small bugs :

 - too small timings
   The calculated timings should be rounded up, ie. a minimum timing of
   3.2 nand clock cycles should be programmed as a 4 cycles timing, and
   not as 3 nand clock cycles

 - the interrupts should be masked all the time
   Writing 0 to NDCR unmasked interrupts, which is unnecessary and fools
   the linux kernel pxa3xx driver which is not yet hardened enough.

 - the command should only be launched once the controller is ready
   This fixes transient bugs where a command is not actually
   launched. The WRCMDREQ bit is asserted after setting NDCR_ND_RUN bit
   once the NFC is ready to acquire a command.

 - column calculation
   Column number was divided by 2 in 16 bits flash devices. Even if this
   is correct for NAND array addressing, it is incorrect for READID, and
   prevents an ONFI scan identification (as address is 0x10 instead of
   the 0x20 required by ONFI).

All these bugs except the second are drained from the linux kernel driver.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/mtd/nand/nand_mrvl_nfc.c | 57 ++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/drivers/mtd/nand/nand_mrvl_nfc.c b/drivers/mtd/nand/nand_mrvl_nfc.c
index 7386da0..258ff75 100644
--- a/drivers/mtd/nand/nand_mrvl_nfc.c
+++ b/drivers/mtd/nand/nand_mrvl_nfc.c
@@ -230,9 +230,6 @@ static struct nand_ecclayout ecc_layout_2KB_hwecc = {
 #define NDTR1_tWHR(c)	(min((c), 15) << 4)
 #define NDTR1_tAR(c)	(min((c), 15) << 0)
 
-/* convert nano-seconds to nand flash controller clock cycles */
-#define ns2cycle(ns, clk)	(int)((ns) * (clk / 1000000) / 1000)
-
 #define mtd_info_to_host(mtd) ((struct mrvl_nand_host *) \
 			       (((struct nand_chip *)((mtd)->priv))->priv))
 
@@ -243,6 +240,14 @@ static struct of_device_id mrvl_nand_dt_ids[] = {
 	{}
 };
 
+/* convert nano-seconds to nand flash controller clock cycles */
+static int ns2cycle(int ns, unsigned long clk_rate)
+{
+	int clk_mhz = clk_rate / 1000000;
+
+	return roundup(ns * clk_mhz, 1000) / 1000;
+}
+
 static volatile u32 _nand_readl(const char *func, const int line,
 		       struct mrvl_nand_host *host, int off)
 {
@@ -385,19 +390,26 @@ static void mrvl_nand_start(struct mrvl_nand_host *host)
 	else
 		ndcr &= ~NDCR_SPARE_EN;
 
-	ndcr |= NDCR_ND_RUN;
+	ndcr &= ~NDCR_ND_RUN;
+	ndcr |= NDCR_INT_MASK;
 
 	/* clear status bits and run */
-	nand_writel(host, NDCR, 0);
-	nand_writel(host, NDSR, NDSR_MASK);
 	nand_writel(host, NDCR, ndcr);
+	nand_writel(host, NDSR, NDSR_MASK);
+	nand_writel(host, NDCR, ndcr | NDCR_ND_RUN);
 
-	/*
-	 * Writing 12 bytes to NDBC0 sets NDBC0, NDBC1 and NDBC2 !
-	 */
-	nand_writel(host, NDCB0, host->ndcb0);
-	nand_writel(host, NDCB0, host->ndcb1);
-	nand_writel(host, NDCB0, host->ndcb2);
+	if (wait_on_timeout(host->chip.chip_delay * USECOND,
+			    nand_readl(host, NDSR) & NDSR_WRCMDREQ)) {
+		dev_err(host->dev, "Waiting for command request failed\n");
+	} else {
+		/*
+		 * Writing 12 bytes to NDBC0 sets NDBC0, NDBC1 and NDBC2 !
+		 */
+		nand_writel(host, NDSR, NDSR_WRCMDREQ);
+		nand_writel(host, NDCB0, host->ndcb0);
+		nand_writel(host, NDCB0, host->ndcb1);
+		nand_writel(host, NDCB0, host->ndcb2);
+	}
 }
 
 static void disable_int(struct mrvl_nand_host *host, uint32_t int_mask)
@@ -647,19 +659,23 @@ static void mrvl_data_stage(struct mrvl_nand_host *host)
 	nand_writel(host, NDSR, mask);
 }
 
-static void mrvl_nand_wait_cmd_done(struct mrvl_nand_host *host)
+static void mrvl_nand_wait_cmd_done(struct mrvl_nand_host *host,
+				    unsigned command)
 {
 	unsigned int mask;
+	static unsigned int nb_done;
 
 	if (host->cs == 0)
-		mask = NDSR_CS0_CMDD | NDSR_WRCMDREQ;
+		mask = NDSR_CS0_CMDD;
 	else
-		mask = NDSR_CS1_CMDD | NDSR_WRCMDREQ;
+		mask = NDSR_CS1_CMDD;
 	wait_on_timeout(host->chip.chip_delay * USECOND,
 			(nand_readl(host, NDSR) & mask) == mask);
-	if ((nand_readl(host, NDSR) & mask) != mask)
-		dev_err(host->dev, "Waiting end of command timeout, ndsr=0x%08x\n",
-			nand_readl(host, NDSR) & mask);
+	if ((nand_readl(host, NDSR) & mask) != mask) {
+		dev_err(host->dev, "Waiting end of command %dth %d timeout, ndsr=0x%08x ndcr=0x%08x\n",
+			nb_done++, command, nand_readl(host, NDSR),
+			nand_readl(host, NDCR));
+	}
 }
 
 static void mrvl_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
@@ -674,14 +690,14 @@ static void mrvl_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 	 */
 	dev_dbg(host->dev, "%s(cmd=%d, col=%d, page=%d)\n", __func__,
 		command, column, page_addr);
-	if (host->reg_ndcr & NDCR_DWIDTH_M)
+	if ((host->reg_ndcr & NDCR_DWIDTH_M) && (command != NAND_CMD_READID))
 		column /= 2;
 
 	prepare_start_command(host, command);
 	if (prepare_set_command(host, command, 0, column, page_addr)) {
 		mrvl_nand_start(host);
 		mrvl_data_stage(host);
-		mrvl_nand_wait_cmd_done(host);
+		mrvl_nand_wait_cmd_done(host, command);
 	}
 }
 
@@ -792,6 +808,7 @@ static void mrvl_nand_config_flash(struct mrvl_nand_host *host)
 	ndcr |= ((mtd->erasesize / mtd->writesize) == 64) ? NDCR_PG_PER_BLK : 0;
 	ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0;
 
+	ndcr &= ~NDCR_RD_ID_CNT_MASK;
 	ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
 	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
 	ndcr &= ~NDCR_DMA_EN;
-- 
2.1.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

             reply	other threads:[~2015-01-17 15:00 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-17 15:00 Robert Jarzmik [this message]
2015-01-19  8:02 ` Sascha Hauer

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=1421506801-1506-1-git-send-email-robert.jarzmik@free.fr \
    --to=robert.jarzmik@free.fr \
    --cc=barebox@lists.infradead.org \
    --cc=ezequiel.garcia@free-electrons.com \
    --cc=s.hauer@pengutronix.de \
    /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