diff mbox

[1/3] mtd: nand/docg4: add support for writing in reliable mode

Message ID 1354910843-5598-2-git-send-email-mikedunn@newsguy.com
State Accepted
Commit 5a90d41b693bda1318807a49d38ef1444f61dfdd
Headers show

Commit Message

Mike Dunn Dec. 7, 2012, 8:07 p.m. UTC
The controller on the docg4 has a "reliable" mode, where consecutive 2k pages
are used in parallel.  The initial program loader (IPL) on my Treo 680 expects
the secondary program loader (SPL) to be written in this mode.  This patch adds
support for writing data in reliable mode, by way of a module parameter.
Support for reading in this mode (as the IPL does) is not supported yet, but
alternate (even-numbered) 2k pages written in reliable mode can be read normally
(odd-numbered pages will contain junk and generate ecc errors).

Signed-off-by: Mike Dunn <mikedunn@newsguy.com>
---

u-boot now runs on my Treo at power-up.  Yay!

 drivers/mtd/nand/docg4.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

Comments

Robert Jarzmik Dec. 9, 2012, 10:25 a.m. UTC | #1
Mike Dunn <mikedunn@newsguy.com> writes:

> The controller on the docg4 has a "reliable" mode, where consecutive 2k pages
> are used in parallel.  The initial program loader (IPL) on my Treo 680 expects
> the secondary program loader (SPL) to be written in this mode.  This patch adds
> support for writing data in reliable mode, by way of a module parameter.
> Support for reading in this mode (as the IPL does) is not supported yet, but
> alternate (even-numbered) 2k pages written in reliable mode can be read normally
> (odd-numbered pages will contain junk and generate ecc errors).

Hi Mike,

I was considering adding this to the docg3 driver, but I didn't because I was
afraid what would happen if you change this mode *after* mounting a partition.
Imagine you have your rootfs mounted on /dev/mtd2, and u-boot is in /dev/mtd1 :
wouldn't changing the reliable mode to write "mtd1" corrupt all writes to mtd2 ?

The patch I chose to make barebox (instead of u-boot) work was to write the
barebox part with a special tool which "duplicates" pages, which ends up in the
same flash writes.

My feeling here is this mode should be "mtd partition bound", not driver bound
if you want to have it in your driver.

Cheers.

--
Robert
Robert Jarzmik Dec. 9, 2012, 10:38 a.m. UTC | #2
Robert Jarzmik <robert.jarzmik@free.fr> writes:

> I was considering adding this to the docg3 driver, but I didn't because I was
> afraid what would happen if you change this mode *after* mounting a partition.
> Imagine you have your rootfs mounted on /dev/mtd2, and u-boot is in /dev/mtd1 :
> wouldn't changing the reliable mode to write "mtd1" corrupt all writes to mtd2
> ?

I will rephrase that : I didn't "succeed" in having that parameter mtd partition
bound. If you find a way, I'll steal it for docg3 driver :)

If you don't, your patch is fine :
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
Mike Dunn Dec. 10, 2012, 7:32 p.m. UTC | #3
Hi Robert.  Nice to hear from you.

On 12/09/2012 02:25 AM, Robert Jarzmik wrote:
> Mike Dunn <mikedunn@newsguy.com> writes:
> 
>> The controller on the docg4 has a "reliable" mode, where consecutive 2k pages
>> are used in parallel.  The initial program loader (IPL) on my Treo 680 expects
>> the secondary program loader (SPL) to be written in this mode.  This patch adds
>> support for writing data in reliable mode, by way of a module parameter.
>> Support for reading in this mode (as the IPL does) is not supported yet, but
>> alternate (even-numbered) 2k pages written in reliable mode can be read normally
>> (odd-numbered pages will contain junk and generate ecc errors).
> 
> Hi Mike,
> 
> I was considering adding this to the docg3 driver, but I didn't because I was
> afraid what would happen if you change this mode *after* mounting a partition.


Well, it's a module parameter, so the mode can't change unless the module is
reloaded, which means everything must be umounted first, right?


> Imagine you have your rootfs mounted on /dev/mtd2, and u-boot is in /dev/mtd1 :
> wouldn't changing the reliable mode to write "mtd1" corrupt all writes to mtd2 ?


I think this may only apply to docg3 (and docp3).  If I'm interpreting your
point correctly and IIRC from working with the docp3... the docg4 doesn't have
"planes".  Reliable mode uses *consecutive* 2k pages on the docg4, so the
side-effects of writing in reliable mode are restricted to the adjacent page,
not some far-away offset.  The lack of "planes" on the docg4 greatly simplifies
things.

Does this make sense?


> 
> The patch I chose to make barebox (instead of u-boot) work was to write the
> barebox part with a special tool which "duplicates" pages, which ends up in the
> same flash writes.
> 
> My feeling here is this mode should be "mtd partition bound", not driver bound
> if you want to have it in your driver.


My thinking is that it's a special case, probably limited to writing the SPL, so
making it a module parameter where the user has to explicitly specify it would
make it available to users without too much risk.  I also put a scary warning
about it in a comment in the driver source.

BTW, I think that my factory babdblock tables are written in reliable mode, so
it would be useful to add support to the driver for reading in this mode as well
(this patch only writes in reliable mode).  Data written in reliable mode can
still be read normally from the even-numbered 2k pages (I don't recall if this
is the case for the docg3), so I can read the factory bbt now, just not as reliably.

Thanks,
Mike
Mike Dunn Dec. 10, 2012, 7:34 p.m. UTC | #4
On 12/09/2012 02:38 AM, Robert Jarzmik wrote:
> Robert Jarzmik <robert.jarzmik@free.fr> writes:
> 
>> I was considering adding this to the docg3 driver, but I didn't because I was
>> afraid what would happen if you change this mode *after* mounting a partition.
>> Imagine you have your rootfs mounted on /dev/mtd2, and u-boot is in /dev/mtd1 :
>> wouldn't changing the reliable mode to write "mtd1" corrupt all writes to mtd2
>> ?
> 
> I will rephrase that : I didn't "succeed" in having that parameter mtd partition
> bound. If you find a way, I'll steal it for docg3 driver :)


Yeah, I seemed to recall that reliable mode is supported in the docg3 driver.


> 
> If you don't, your patch is fine :
> Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
> 

Thanks Robert.

Mike
Robert Jarzmik Dec. 15, 2012, 10:37 a.m. UTC | #5
Mike Dunn <mikedunn@newsguy.com> writes:

Hi Mike,

Sorry for the late reply, I was taken over by work.

> Well, it's a module parameter, so the mode can't change unless the module is
> reloaded, which means everything must be umounted first, right?
Right.

>> Imagine you have your rootfs mounted on /dev/mtd2, and u-boot is in /dev/mtd1 :
>> wouldn't changing the reliable mode to write "mtd1" corrupt all writes to mtd2 ?
> I think this may only apply to docg3 (and docp3).  If I'm interpreting your
> point correctly and IIRC from working with the docp3... the docg4 doesn't have
> "planes".  Reliable mode uses *consecutive* 2k pages on the docg4, so the
> side-effects of writing in reliable mode are restricted to the adjacent page,
> not some far-away offset.  The lack of "planes" on the docg4 greatly simplifies
> things.
>
> Does this make sense?
Yes. As a side note, the reliable mode of docg3 write on consecutive 512b pages
(see log in commit c3de8a8a5a28603f8d318245992dbcda2e88a007).

>> The patch I chose to make barebox (instead of u-boot) work was to write the
>> barebox part with a special tool which "duplicates" pages, which ends up in the
>> same flash writes.
>> 
>> My feeling here is this mode should be "mtd partition bound", not driver bound
>> if you want to have it in your driver.
> My thinking is that it's a special case, probably limited to writing the SPL, so
> making it a module parameter where the user has to explicitly specify it would
> make it available to users without too much risk.  I also put a scary warning
> about it in a comment in the driver source.
OK, your choice.

As I have now the rootfs (ubifs on /dev/mtd2) on /, I cannot use docg3 as a
module and remove it anymore. Hence my hope somebody comes out with a solution
so that I have :
 - /dev/mtd1 in reliable mode (for the SPL)
 - /dev/mtd2 in normal mode (for root filesystem)

By now, I chose to use the SPL to rewrite itself (ie. barebox overwrites
/dev/mtd2 content). That's a bit sub-optimal as a fully booted kernel would be
able to make more checks (reread written blocks, check OOB signatures, ...).

> BTW, I think that my factory babdblock tables are written in reliable mode, so
> it would be useful to add support to the driver for reading in this mode as well
> (this patch only writes in reliable mode).  Data written in reliable mode can
> still be read normally from the even-numbered 2k pages (I don't recall if this
> is the case for the docg3), so I can read the factory bbt now, just not as
> reliably.
Ah good point, I will check on the docg3 how it worked, to see if they used also
the reliable mode for BBT table.

Cheers.
diff mbox

Patch

diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 799da5d..54b1e5e 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -46,6 +46,25 @@ 
 #include <linux/bitrev.h>
 
 /*
+ * In "reliable mode" consecutive 2k pages are used in parallel (in some
+ * fashion) to store the same data.  The data can be read back from the
+ * even-numbered pages in the normal manner; odd-numbered pages will appear to
+ * contain junk.  Systems that boot from the docg4 typically write the secondary
+ * program loader (SPL) code in this mode.  The SPL is loaded by the initial
+ * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
+ * to the reset vector address).  This module parameter enables you to use this
+ * driver to write the SPL.  When in this mode, no more than 2k of data can be
+ * written at a time, because the addresses do not increment in the normal
+ * manner, and the starting offset must be within an even-numbered 2k region;
+ * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
+ * 0x1a00, ...  Reliable mode is a special case and should not be used unless
+ * you know what you're doing.
+ */
+static bool reliable_mode;
+module_param(reliable_mode, bool, 0);
+MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
+
+/*
  * You'll want to ignore badblocks if you're reading a partition that contains
  * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
  * it does not use mtd nand's method for marking bad blocks (using oob area).
@@ -113,6 +132,7 @@  struct docg4_priv {
 #define DOCG4_SEQ_PAGEWRITE		0x16
 #define DOCG4_SEQ_PAGEPROG		0x1e
 #define DOCG4_SEQ_BLOCKERASE		0x24
+#define DOCG4_SEQ_SETMODE		0x45
 
 /* DOC_FLASHCOMMAND register commands */
 #define DOCG4_CMD_PAGE_READ             0x00
@@ -122,6 +142,8 @@  struct docg4_priv {
 #define DOC_CMD_PROG_BLOCK_ADDR		0x60
 #define DOCG4_CMD_PAGEWRITE		0x80
 #define DOC_CMD_PROG_CYCLE2		0x10
+#define DOCG4_CMD_FAST_MODE		0xa3 /* functionality guessed */
+#define DOC_CMD_RELIABLE_MODE		0x22
 #define DOC_CMD_RESET			0xff
 
 /* DOC_POWERMODE register bits */
@@ -611,6 +633,14 @@  static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
 	dev_dbg(doc->dev,
 	      "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
 	sequence_reset(mtd);
+
+	if (unlikely(reliable_mode)) {
+		writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
+		writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
+		writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
+		write_nop(docptr);
+	}
+
 	writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
 	writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
 	write_nop(docptr);
@@ -691,6 +721,15 @@  static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
 		break;
 
 	case NAND_CMD_SEQIN:
+		if (unlikely(reliable_mode)) {
+			uint16_t g4_page = g4_addr >> 16;
+
+			/* writes to odd-numbered 2k pages are invalid */
+			if (g4_page & 0x01)
+				dev_warn(doc->dev,
+					 "invalid reliable mode address\n");
+		}
+
 		write_page_prologue(mtd, g4_addr);
 
 		/* hack for deferred write of oob bytes */