[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>

authored by Kyungmin Park and committed by Artem Bityutskiy 60d84f97 f6272487

+46 -16
+44 -16
drivers/mtd/onenand/onenand_base.c
··· 192 struct onenand_chip *this = mtd->priv; 193 int value, readcmd = 0, block_cmd = 0; 194 int block, page; 195 - /* Now we use page size operation */ 196 - int sectors = 4, count = 4; 197 198 /* Address translation */ 199 switch (cmd) { ··· 243 } 244 245 if (page != -1) { 246 int dataram; 247 248 switch (cmd) { ··· 914 void __iomem *dataram0, *dataram1; 915 int ret = 0; 916 917 this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); 918 919 ret = this->wait(mtd, FL_READING); ··· 940 #define onenand_verify_oob(...) (0) 941 #endif 942 943 - #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) 944 945 /** 946 * onenand_write - [MTD Interface] write buffer to FLASH ··· 958 struct onenand_chip *this = mtd->priv; 959 int written = 0; 960 int ret = 0; 961 962 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); 963 ··· 977 return -EINVAL; 978 } 979 980 /* Grab the lock and see if the device is available */ 981 onenand_get_device(mtd, FL_WRITING); 982 983 /* Loop until all data write */ 984 while (written < len) { 985 - int thislen = min_t(int, mtd->writesize, len - written); 986 987 - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); 988 989 - this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); 990 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); 991 992 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); 993 994 - onenand_update_bufferram(mtd, to, 1); 995 996 ret = this->wait(mtd, FL_WRITING); 997 if (ret) { 998 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); 999 - goto out; 1000 } 1001 1002 written += thislen; 1003 1004 - /* Only check verify write turn on */ 1005 - ret = onenand_verify_page(mtd, (u_char *) buf, to); 1006 - if (ret) { 1007 - DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); 1008 - goto out; 1009 - } 1010 - 1011 if (written == len) 1012 break; 1013 1014 to += thislen; 1015 buf += thislen; 1016 } 1017 1018 - out: 1019 /* Deselect and wake up anyone waiting on the device */ 1020 onenand_release_device(mtd); 1021 ··· 2042 init_waitqueue_head(&this->wq); 2043 spin_lock_init(&this->chip_lock); 2044 2045 switch (mtd->oobsize) { 2046 case 64: 2047 this->ecclayout = &onenand_oob_64; 2048 break; 2049 2050 case 32: 2051 this->ecclayout = &onenand_oob_32; 2052 break; 2053 2054 default: 2055 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", 2056 mtd->oobsize); 2057 /* To prevent kernel oops */ 2058 this->ecclayout = &onenand_oob_32; 2059 break; 2060 } 2061 2062 mtd->ecclayout = this->ecclayout; 2063 2064 /* Fill in remaining MTD driver data */
··· 192 struct onenand_chip *this = mtd->priv; 193 int value, readcmd = 0, block_cmd = 0; 194 int block, page; 195 196 /* Address translation */ 197 switch (cmd) { ··· 245 } 246 247 if (page != -1) { 248 + /* Now we use page size operation */ 249 + int sectors = 4, count = 4; 250 int dataram; 251 252 switch (cmd) { ··· 914 void __iomem *dataram0, *dataram1; 915 int ret = 0; 916 917 + /* In partial page write, just skip it */ 918 + if ((addr & (mtd->writesize - 1)) != 0) 919 + return 0; 920 + 921 this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); 922 923 ret = this->wait(mtd, FL_READING); ··· 936 #define onenand_verify_oob(...) (0) 937 #endif 938 939 + #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) 940 941 /** 942 * onenand_write - [MTD Interface] write buffer to FLASH ··· 954 struct onenand_chip *this = mtd->priv; 955 int written = 0; 956 int ret = 0; 957 + int column, subpage; 958 959 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); 960 ··· 972 return -EINVAL; 973 } 974 975 + column = to & (mtd->writesize - 1); 976 + subpage = column || (len & (mtd->writesize - 1)); 977 + 978 /* Grab the lock and see if the device is available */ 979 onenand_get_device(mtd, FL_WRITING); 980 981 /* Loop until all data write */ 982 while (written < len) { 983 + int bytes = mtd->writesize; 984 + int thislen = min_t(int, bytes, len - written); 985 + u_char *wbuf = (u_char *) buf; 986 987 + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes); 988 989 + /* Partial page write */ 990 + if (subpage) { 991 + bytes = min_t(int, bytes - column, (int) len); 992 + memset(this->page_buf, 0xff, mtd->writesize); 993 + memcpy(this->page_buf + column, buf, bytes); 994 + wbuf = this->page_buf; 995 + /* Even though partial write, we need page size */ 996 + thislen = mtd->writesize; 997 + } 998 + 999 + this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen); 1000 this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); 1001 1002 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); 1003 1004 + /* In partial page write we don't update bufferram */ 1005 + onenand_update_bufferram(mtd, to, !subpage); 1006 1007 ret = this->wait(mtd, FL_WRITING); 1008 if (ret) { 1009 DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); 1010 + break; 1011 + } 1012 + 1013 + /* Only check verify write turn on */ 1014 + ret = onenand_verify_page(mtd, (u_char *) wbuf, to); 1015 + if (ret) { 1016 + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); 1017 + break; 1018 } 1019 1020 written += thislen; 1021 1022 if (written == len) 1023 break; 1024 1025 + column = 0; 1026 to += thislen; 1027 buf += thislen; 1028 } 1029 1030 /* Deselect and wake up anyone waiting on the device */ 1031 onenand_release_device(mtd); 1032 ··· 2021 init_waitqueue_head(&this->wq); 2022 spin_lock_init(&this->chip_lock); 2023 2024 + /* 2025 + * Allow subpage writes up to oobsize. 2026 + */ 2027 switch (mtd->oobsize) { 2028 case 64: 2029 this->ecclayout = &onenand_oob_64; 2030 + mtd->subpage_sft = 2; 2031 break; 2032 2033 case 32: 2034 this->ecclayout = &onenand_oob_32; 2035 + mtd->subpage_sft = 1; 2036 break; 2037 2038 default: 2039 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", 2040 mtd->oobsize); 2041 + mtd->subpage_sft = 0; 2042 /* To prevent kernel oops */ 2043 this->ecclayout = &onenand_oob_32; 2044 break; 2045 } 2046 2047 + this->subpagesize = mtd->writesize >> mtd->subpage_sft; 2048 mtd->ecclayout = this->ecclayout; 2049 2050 /* Fill in remaining MTD driver data */
+2
include/linux/mtd/onenand.h
··· 88 * operation is in progress 89 * @state: [INTERN] the current state of the OneNAND device 90 * @page_buf: data buffer 91 * @ecclayout: [REPLACEABLE] the default ecc placement scheme 92 * @bbm: [REPLACEABLE] pointer to Bad Block Management 93 * @priv: [OPTIONAL] pointer to private chip date ··· 129 onenand_state_t state; 130 unsigned char *page_buf; 131 132 struct nand_ecclayout *ecclayout; 133 134 void *bbm;
··· 88 * operation is in progress 89 * @state: [INTERN] the current state of the OneNAND device 90 * @page_buf: data buffer 91 + * @subpagesize: [INTERN] holds the subpagesize 92 * @ecclayout: [REPLACEABLE] the default ecc placement scheme 93 * @bbm: [REPLACEABLE] pointer to Bad Block Management 94 * @priv: [OPTIONAL] pointer to private chip date ··· 128 onenand_state_t state; 129 unsigned char *page_buf; 130 131 + int subpagesize; 132 struct nand_ecclayout *ecclayout; 133 134 void *bbm;