aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2006-12-22 02:21:54 -0500
committerArtem Bityutskiy <dedekind@infradead.org>2007-01-10 07:35:00 -0500
commit60d84f9739a47d0ed8e19805d9056e39fba31c79 (patch)
tree8a93ba3f6de707446e191328f7190f7669d3619c
parentf62724873652ddb19edf7f92843e9456fe3be3ea (diff)
[MTD] OneNAND: add subpage write support
OneNAND supports up to 4 writes at one NAND page. Add support of this feature. Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/mtd/onenand/onenand_base.c56
-rw-r--r--include/linux/mtd/onenand.h2
2 files changed, 44 insertions, 14 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 3fab4d1b68bd..51fb84055ba3 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -192,8 +192,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
192 struct onenand_chip *this = mtd->priv; 192 struct onenand_chip *this = mtd->priv;
193 int value, readcmd = 0, block_cmd = 0; 193 int value, readcmd = 0, block_cmd = 0;
194 int block, page; 194 int block, page;
195 /* Now we use page size operation */
196 int sectors = 4, count = 4;
197 195
198 /* Address translation */ 196 /* Address translation */
199 switch (cmd) { 197 switch (cmd) {
@@ -245,6 +243,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
245 } 243 }
246 244
247 if (page != -1) { 245 if (page != -1) {
246 /* Now we use page size operation */
247 int sectors = 4, count = 4;
248 int dataram; 248 int dataram;
249 249
250 switch (cmd) { 250 switch (cmd) {
@@ -914,6 +914,10 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
914 void __iomem *dataram0, *dataram1; 914 void __iomem *dataram0, *dataram1;
915 int ret = 0; 915 int ret = 0;
916 916
917 /* In partial page write, just skip it */
918 if ((addr & (mtd->writesize - 1)) != 0)
919 return 0;
920
917 this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); 921 this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
918 922
919 ret = this->wait(mtd, FL_READING); 923 ret = this->wait(mtd, FL_READING);
@@ -936,7 +940,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
936#define onenand_verify_oob(...) (0) 940#define onenand_verify_oob(...) (0)
937#endif 941#endif
938 942
939#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) 943#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
940 944
941/** 945/**
942 * onenand_write - [MTD Interface] write buffer to FLASH 946 * onenand_write - [MTD Interface] write buffer to FLASH
@@ -954,6 +958,7 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
954 struct onenand_chip *this = mtd->priv; 958 struct onenand_chip *this = mtd->priv;
955 int written = 0; 959 int written = 0;
956 int ret = 0; 960 int ret = 0;
961 int column, subpage;
957 962
958 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); 963 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
959 964
@@ -972,45 +977,61 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
972 return -EINVAL; 977 return -EINVAL;
973 } 978 }
974 979
980 column = to & (mtd->writesize - 1);
981 subpage = column || (len & (mtd->writesize - 1));
982
975 /* Grab the lock and see if the device is available */ 983 /* Grab the lock and see if the device is available */
976 onenand_get_device(mtd, FL_WRITING); 984 onenand_get_device(mtd, FL_WRITING);
977 985
978 /* Loop until all data write */ 986 /* Loop until all data write */
979 while (written < len) { 987 while (written < len) {
980 int thislen = min_t(int, mtd->writesize, len - written); 988 int bytes = mtd->writesize;
981 989 int thislen = min_t(int, bytes, len - written);
982 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); 990 u_char *wbuf = (u_char *) buf;
991
992 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes);
993
994 /* Partial page write */
995 if (subpage) {
996 bytes = min_t(int, bytes - column, (int) len);
997 memset(this->page_buf, 0xff, mtd->writesize);
998 memcpy(this->page_buf + column, buf, bytes);
999 wbuf = this->page_buf;
1000 /* Even though partial write, we need page size */
1001 thislen = mtd->writesize;
1002 }
983 1003
984 this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); 1004 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen);
985 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); 1005 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
986 1006
987 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); 1007 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
988 1008
989 onenand_update_bufferram(mtd, to, 1); 1009 /* In partial page write we don't update bufferram */
1010 onenand_update_bufferram(mtd, to, !subpage);
990 1011
991 ret = this->wait(mtd, FL_WRITING); 1012 ret = this->wait(mtd, FL_WRITING);
992 if (ret) { 1013 if (ret) {
993 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); 1014 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
994 goto out; 1015 break;
995 } 1016 }
996 1017
997 written += thislen;
998
999 /* Only check verify write turn on */ 1018 /* Only check verify write turn on */
1000 ret = onenand_verify_page(mtd, (u_char *) buf, to); 1019 ret = onenand_verify_page(mtd, (u_char *) wbuf, to);
1001 if (ret) { 1020 if (ret) {
1002 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); 1021 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
1003 goto out; 1022 break;
1004 } 1023 }
1005 1024
1025 written += thislen;
1026
1006 if (written == len) 1027 if (written == len)
1007 break; 1028 break;
1008 1029
1030 column = 0;
1009 to += thislen; 1031 to += thislen;
1010 buf += thislen; 1032 buf += thislen;
1011 } 1033 }
1012 1034
1013out:
1014 /* Deselect and wake up anyone waiting on the device */ 1035 /* Deselect and wake up anyone waiting on the device */
1015 onenand_release_device(mtd); 1036 onenand_release_device(mtd);
1016 1037
@@ -2021,23 +2042,30 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
2021 init_waitqueue_head(&this->wq); 2042 init_waitqueue_head(&this->wq);
2022 spin_lock_init(&this->chip_lock); 2043 spin_lock_init(&this->chip_lock);
2023 2044
2045 /*
2046 * Allow subpage writes up to oobsize.
2047 */
2024 switch (mtd->oobsize) { 2048 switch (mtd->oobsize) {
2025 case 64: 2049 case 64:
2026 this->ecclayout = &onenand_oob_64; 2050 this->ecclayout = &onenand_oob_64;
2051 mtd->subpage_sft = 2;
2027 break; 2052 break;
2028 2053
2029 case 32: 2054 case 32:
2030 this->ecclayout = &onenand_oob_32; 2055 this->ecclayout = &onenand_oob_32;
2056 mtd->subpage_sft = 1;
2031 break; 2057 break;
2032 2058
2033 default: 2059 default:
2034 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", 2060 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
2035 mtd->oobsize); 2061 mtd->oobsize);
2062 mtd->subpage_sft = 0;
2036 /* To prevent kernel oops */ 2063 /* To prevent kernel oops */
2037 this->ecclayout = &onenand_oob_32; 2064 this->ecclayout = &onenand_oob_32;
2038 break; 2065 break;
2039 } 2066 }
2040 2067
2068 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
2041 mtd->ecclayout = this->ecclayout; 2069 mtd->ecclayout = this->ecclayout;
2042 2070
2043 /* Fill in remaining MTD driver data */ 2071 /* Fill in remaining MTD driver data */
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 62ca0f429822..fe3500d7d4bb 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -88,6 +88,7 @@ struct onenand_bufferram {
88 * operation is in progress 88 * operation is in progress
89 * @state: [INTERN] the current state of the OneNAND device 89 * @state: [INTERN] the current state of the OneNAND device
90 * @page_buf: data buffer 90 * @page_buf: data buffer
91 * @subpagesize: [INTERN] holds the subpagesize
91 * @ecclayout: [REPLACEABLE] the default ecc placement scheme 92 * @ecclayout: [REPLACEABLE] the default ecc placement scheme
92 * @bbm: [REPLACEABLE] pointer to Bad Block Management 93 * @bbm: [REPLACEABLE] pointer to Bad Block Management
93 * @priv: [OPTIONAL] pointer to private chip date 94 * @priv: [OPTIONAL] pointer to private chip date
@@ -128,6 +129,7 @@ struct onenand_chip {
128 onenand_state_t state; 129 onenand_state_t state;
129 unsigned char *page_buf; 130 unsigned char *page_buf;
130 131
132 int subpagesize;
131 struct nand_ecclayout *ecclayout; 133 struct nand_ecclayout *ecclayout;
132 134
133 void *bbm; 135 void *bbm;