diff options
-rw-r--r-- | drivers/mtd/nand/docg4.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 799da5d1c857..54b1e5e359b8 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c | |||
@@ -46,6 +46,25 @@ | |||
46 | #include <linux/bitrev.h> | 46 | #include <linux/bitrev.h> |
47 | 47 | ||
48 | /* | 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 | |||
67 | /* | ||
49 | * You'll want to ignore badblocks if you're reading a partition that contains | 68 | * You'll want to ignore badblocks if you're reading a partition that contains |
50 | * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since | 69 | * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since |
51 | * it does not use mtd nand's method for marking bad blocks (using oob area). | 70 | * it does not use mtd nand's method for marking bad blocks (using oob area). |
@@ -113,6 +132,7 @@ struct docg4_priv { | |||
113 | #define DOCG4_SEQ_PAGEWRITE 0x16 | 132 | #define DOCG4_SEQ_PAGEWRITE 0x16 |
114 | #define DOCG4_SEQ_PAGEPROG 0x1e | 133 | #define DOCG4_SEQ_PAGEPROG 0x1e |
115 | #define DOCG4_SEQ_BLOCKERASE 0x24 | 134 | #define DOCG4_SEQ_BLOCKERASE 0x24 |
135 | #define DOCG4_SEQ_SETMODE 0x45 | ||
116 | 136 | ||
117 | /* DOC_FLASHCOMMAND register commands */ | 137 | /* DOC_FLASHCOMMAND register commands */ |
118 | #define DOCG4_CMD_PAGE_READ 0x00 | 138 | #define DOCG4_CMD_PAGE_READ 0x00 |
@@ -122,6 +142,8 @@ struct docg4_priv { | |||
122 | #define DOC_CMD_PROG_BLOCK_ADDR 0x60 | 142 | #define DOC_CMD_PROG_BLOCK_ADDR 0x60 |
123 | #define DOCG4_CMD_PAGEWRITE 0x80 | 143 | #define DOCG4_CMD_PAGEWRITE 0x80 |
124 | #define DOC_CMD_PROG_CYCLE2 0x10 | 144 | #define DOC_CMD_PROG_CYCLE2 0x10 |
145 | #define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */ | ||
146 | #define DOC_CMD_RELIABLE_MODE 0x22 | ||
125 | #define DOC_CMD_RESET 0xff | 147 | #define DOC_CMD_RESET 0xff |
126 | 148 | ||
127 | /* DOC_POWERMODE register bits */ | 149 | /* DOC_POWERMODE register bits */ |
@@ -611,6 +633,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr) | |||
611 | dev_dbg(doc->dev, | 633 | dev_dbg(doc->dev, |
612 | "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); | 634 | "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); |
613 | sequence_reset(mtd); | 635 | 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 | |||
614 | writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); | 644 | writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); |
615 | writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); | 645 | writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); |
616 | write_nop(docptr); | 646 | write_nop(docptr); |
@@ -691,6 +721,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column, | |||
691 | break; | 721 | break; |
692 | 722 | ||
693 | case NAND_CMD_SEQIN: | 723 | 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 | |||
694 | write_page_prologue(mtd, g4_addr); | 733 | write_page_prologue(mtd, g4_addr); |
695 | 734 | ||
696 | /* hack for deferred write of oob bytes */ | 735 | /* hack for deferred write of oob bytes */ |