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