summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/onenand/onenand_base.c72
-rw-r--r--include/linux/mtd/onenand.h1
2 files changed, 72 insertions, 1 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index dcc969f..d482437 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -36,6 +36,35 @@ static inline void *memcpy_16(void *dst, const void *src, unsigned int len)
return ret;
}
+/**
+ * onenand_oob_64 - oob info for large (2KB) page
+ */
+static struct nand_ecclayout onenand_oob_64 = {
+ .eccbytes = 20,
+ .eccpos = {
+ 8, 9, 10, 11, 12,
+ 24, 25, 26, 27, 28,
+ 40, 41, 42, 43, 44,
+ 56, 57, 58, 59, 60,
+ },
+ .oobfree = {
+ {2, 3}, {14, 2}, {18, 3}, {30, 2},
+ {34, 3}, {46, 2}, {50, 3}, {62, 2}
+ }
+};
+
+/**
+ * onenand_oob_32 - oob info for middle (1KB) page
+ */
+static struct nand_ecclayout onenand_oob_32 = {
+ .eccbytes = 10,
+ .eccpos = {
+ 8, 9, 10, 11, 12,
+ 24, 25, 26, 27, 28,
+ },
+ .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
+};
+
static const unsigned char ffchars[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
@@ -1079,7 +1108,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
#define onenand_verify_oob(...) (0)
#endif
-#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
+#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
/**
* onenand_fill_auto_oob - [Internal] oob auto-placement transfer
@@ -2058,6 +2087,7 @@ static int onenand_probe(struct mtd_info *mtd)
*/
int onenand_scan(struct mtd_info *mtd, int maxchips)
{
+ int i;
struct onenand_chip *this = mtd->priv;
if (!this->read_word)
@@ -2115,6 +2145,46 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
this->options |= ONENAND_OOBBUF_ALLOC;
}
+ this->state = FL_READY;
+
+ /*
+ * Allow subpage writes up to oobsize.
+ */
+ switch (mtd->oobsize) {
+ case 64:
+ this->ecclayout = &onenand_oob_64;
+ mtd->subpage_sft = 2;
+ break;
+
+ case 32:
+ this->ecclayout = &onenand_oob_32;
+ mtd->subpage_sft = 1;
+ break;
+
+ default:
+ printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
+ mtd->oobsize);
+ mtd->subpage_sft = 0;
+ /* To prevent kernel oops */
+ this->ecclayout = &onenand_oob_32;
+ break;
+ }
+
+ this->subpagesize = mtd->writesize >> mtd->subpage_sft;
+
+ /*
+ * The number of bytes available for a client to place data into
+ * the out of band area
+ */
+ this->ecclayout->oobavail = 0;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
+ this->ecclayout->oobfree[i].length; i++)
+ this->ecclayout->oobavail +=
+ this->ecclayout->oobfree[i].length;
+ mtd->oobavail = this->ecclayout->oobavail;
+
+ mtd->ecclayout = this->ecclayout;
+
/* Unlock whole block */
onenand_unlock_all(mtd);
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 7547e96..2597e34 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -107,6 +107,7 @@ struct onenand_chip {
unsigned char *oob_buf;
struct nand_oobinfo *autooob;
+ int subpagesize;
struct nand_ecclayout *ecclayout;
void *bbm;