Skip to content

Commit 5a90d41

Browse files
mike-dunndedekind
authored andcommitted
mtd: nand/docg4: add support for writing in reliable mode
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> Acked-by: Robert Jarzmik <robert.jarzmik@free.fr> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
1 parent 740bb0c commit 5a90d41

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

drivers/mtd/nand/docg4.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@
4545
#include <linux/bch.h>
4646
#include <linux/bitrev.h>
4747

48+
/*
49+
* In "reliable mode" consecutive 2k pages are used in parallel (in some
50+
* fashion) to store the same data. The data can be read back from the
51+
* even-numbered pages in the normal manner; odd-numbered pages will appear to
52+
* contain junk. Systems that boot from the docg4 typically write the secondary
53+
* program loader (SPL) code in this mode. The SPL is loaded by the initial
54+
* program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
55+
* to the reset vector address). This module parameter enables you to use this
56+
* driver to write the SPL. When in this mode, no more than 2k of data can be
57+
* written at a time, because the addresses do not increment in the normal
58+
* manner, and the starting offset must be within an even-numbered 2k region;
59+
* i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
60+
* 0x1a00, ... Reliable mode is a special case and should not be used unless
61+
* you know what you're doing.
62+
*/
63+
static bool reliable_mode;
64+
module_param(reliable_mode, bool, 0);
65+
MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
66+
4867
/*
4968
* You'll want to ignore badblocks if you're reading a partition that contains
5069
* data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
@@ -113,6 +132,7 @@ struct docg4_priv {
113132
#define DOCG4_SEQ_PAGEWRITE 0x16
114133
#define DOCG4_SEQ_PAGEPROG 0x1e
115134
#define DOCG4_SEQ_BLOCKERASE 0x24
135+
#define DOCG4_SEQ_SETMODE 0x45
116136

117137
/* DOC_FLASHCOMMAND register commands */
118138
#define DOCG4_CMD_PAGE_READ 0x00
@@ -122,6 +142,8 @@ struct docg4_priv {
122142
#define DOC_CMD_PROG_BLOCK_ADDR 0x60
123143
#define DOCG4_CMD_PAGEWRITE 0x80
124144
#define DOC_CMD_PROG_CYCLE2 0x10
145+
#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */
146+
#define DOC_CMD_RELIABLE_MODE 0x22
125147
#define DOC_CMD_RESET 0xff
126148

127149
/* DOC_POWERMODE register bits */
@@ -611,6 +633,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
611633
dev_dbg(doc->dev,
612634
"docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
613635
sequence_reset(mtd);
636+
637+
if (unlikely(reliable_mode)) {
638+
writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
639+
writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
640+
writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
641+
write_nop(docptr);
642+
}
643+
614644
writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
615645
writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
616646
write_nop(docptr);
@@ -691,6 +721,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
691721
break;
692722

693723
case NAND_CMD_SEQIN:
724+
if (unlikely(reliable_mode)) {
725+
uint16_t g4_page = g4_addr >> 16;
726+
727+
/* writes to odd-numbered 2k pages are invalid */
728+
if (g4_page & 0x01)
729+
dev_warn(doc->dev,
730+
"invalid reliable mode address\n");
731+
}
732+
694733
write_page_prologue(mtd, g4_addr);
695734

696735
/* hack for deferred write of oob bytes */

0 commit comments

Comments
 (0)