diff options
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 199 |
1 files changed, 158 insertions, 41 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1b0b32011415..8d7d21be1541 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/delay.h> | ||
21 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
22 | #include <linux/jiffies.h> | 23 | #include <linux/jiffies.h> |
23 | #include <linux/mtd/mtd.h> | 24 | #include <linux/mtd/mtd.h> |
@@ -170,6 +171,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
170 | } | 171 | } |
171 | 172 | ||
172 | /** | 173 | /** |
174 | * onenand_get_density - [DEFAULT] Get OneNAND density | ||
175 | * @param dev_id OneNAND device ID | ||
176 | * | ||
177 | * Get OneNAND density from device ID | ||
178 | */ | ||
179 | static inline int onenand_get_density(int dev_id) | ||
180 | { | ||
181 | int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
182 | return (density & ONENAND_DEVICE_DENSITY_MASK); | ||
183 | } | ||
184 | |||
185 | /** | ||
173 | * onenand_command - [DEFAULT] Send command to OneNAND device | 186 | * onenand_command - [DEFAULT] Send command to OneNAND device |
174 | * @param mtd MTD device structure | 187 | * @param mtd MTD device structure |
175 | * @param cmd the command to be sent | 188 | * @param cmd the command to be sent |
@@ -182,8 +195,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
182 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | 195 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) |
183 | { | 196 | { |
184 | struct onenand_chip *this = mtd->priv; | 197 | struct onenand_chip *this = mtd->priv; |
185 | int value, readcmd = 0, block_cmd = 0; | 198 | int value, block, page; |
186 | int block, page; | ||
187 | 199 | ||
188 | /* Address translation */ | 200 | /* Address translation */ |
189 | switch (cmd) { | 201 | switch (cmd) { |
@@ -198,7 +210,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
198 | case ONENAND_CMD_ERASE: | 210 | case ONENAND_CMD_ERASE: |
199 | case ONENAND_CMD_BUFFERRAM: | 211 | case ONENAND_CMD_BUFFERRAM: |
200 | case ONENAND_CMD_OTP_ACCESS: | 212 | case ONENAND_CMD_OTP_ACCESS: |
201 | block_cmd = 1; | ||
202 | block = (int) (addr >> this->erase_shift); | 213 | block = (int) (addr >> this->erase_shift); |
203 | page = -1; | 214 | page = -1; |
204 | break; | 215 | break; |
@@ -240,11 +251,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
240 | value = onenand_block_address(this, block); | 251 | value = onenand_block_address(this, block); |
241 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | 252 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); |
242 | 253 | ||
243 | if (block_cmd) { | 254 | /* Select DataRAM for DDP */ |
244 | /* Select DataRAM for DDP */ | 255 | value = onenand_bufferram_address(this, block); |
245 | value = onenand_bufferram_address(this, block); | 256 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); |
246 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
247 | } | ||
248 | } | 257 | } |
249 | 258 | ||
250 | if (page != -1) { | 259 | if (page != -1) { |
@@ -256,7 +265,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
256 | case ONENAND_CMD_READ: | 265 | case ONENAND_CMD_READ: |
257 | case ONENAND_CMD_READOOB: | 266 | case ONENAND_CMD_READOOB: |
258 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); | 267 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); |
259 | readcmd = 1; | ||
260 | break; | 268 | break; |
261 | 269 | ||
262 | default: | 270 | default: |
@@ -273,12 +281,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
273 | /* Write 'BSA, BSC' of DataRAM */ | 281 | /* Write 'BSA, BSC' of DataRAM */ |
274 | value = onenand_buffer_address(dataram, sectors, count); | 282 | value = onenand_buffer_address(dataram, sectors, count); |
275 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); | 283 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); |
276 | |||
277 | if (readcmd) { | ||
278 | /* Select DataRAM for DDP */ | ||
279 | value = onenand_bufferram_address(this, block); | ||
280 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
281 | } | ||
282 | } | 284 | } |
283 | 285 | ||
284 | /* Interrupt clear */ | 286 | /* Interrupt clear */ |
@@ -855,6 +857,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
855 | this->command(mtd, ONENAND_CMD_READ, from, writesize); | 857 | this->command(mtd, ONENAND_CMD_READ, from, writesize); |
856 | ret = this->wait(mtd, FL_READING); | 858 | ret = this->wait(mtd, FL_READING); |
857 | onenand_update_bufferram(mtd, from, !ret); | 859 | onenand_update_bufferram(mtd, from, !ret); |
860 | if (ret == -EBADMSG) | ||
861 | ret = 0; | ||
858 | } | 862 | } |
859 | } | 863 | } |
860 | 864 | ||
@@ -913,6 +917,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
913 | /* Now wait for load */ | 917 | /* Now wait for load */ |
914 | ret = this->wait(mtd, FL_READING); | 918 | ret = this->wait(mtd, FL_READING); |
915 | onenand_update_bufferram(mtd, from, !ret); | 919 | onenand_update_bufferram(mtd, from, !ret); |
920 | if (ret == -EBADMSG) | ||
921 | ret = 0; | ||
916 | } | 922 | } |
917 | 923 | ||
918 | /* | 924 | /* |
@@ -923,12 +929,12 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
923 | ops->retlen = read; | 929 | ops->retlen = read; |
924 | ops->oobretlen = oobread; | 930 | ops->oobretlen = oobread; |
925 | 931 | ||
926 | if (mtd->ecc_stats.failed - stats.failed) | ||
927 | return -EBADMSG; | ||
928 | |||
929 | if (ret) | 932 | if (ret) |
930 | return ret; | 933 | return ret; |
931 | 934 | ||
935 | if (mtd->ecc_stats.failed - stats.failed) | ||
936 | return -EBADMSG; | ||
937 | |||
932 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 938 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; |
933 | } | 939 | } |
934 | 940 | ||
@@ -944,6 +950,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
944 | struct mtd_oob_ops *ops) | 950 | struct mtd_oob_ops *ops) |
945 | { | 951 | { |
946 | struct onenand_chip *this = mtd->priv; | 952 | struct onenand_chip *this = mtd->priv; |
953 | struct mtd_ecc_stats stats; | ||
947 | int read = 0, thislen, column, oobsize; | 954 | int read = 0, thislen, column, oobsize; |
948 | size_t len = ops->ooblen; | 955 | size_t len = ops->ooblen; |
949 | mtd_oob_mode_t mode = ops->mode; | 956 | mtd_oob_mode_t mode = ops->mode; |
@@ -977,6 +984,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
977 | return -EINVAL; | 984 | return -EINVAL; |
978 | } | 985 | } |
979 | 986 | ||
987 | stats = mtd->ecc_stats; | ||
988 | |||
980 | while (read < len) { | 989 | while (read < len) { |
981 | cond_resched(); | 990 | cond_resched(); |
982 | 991 | ||
@@ -988,18 +997,16 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
988 | onenand_update_bufferram(mtd, from, 0); | 997 | onenand_update_bufferram(mtd, from, 0); |
989 | 998 | ||
990 | ret = this->wait(mtd, FL_READING); | 999 | ret = this->wait(mtd, FL_READING); |
991 | /* First copy data and check return value for ECC handling */ | 1000 | if (ret && ret != -EBADMSG) { |
1001 | printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); | ||
1002 | break; | ||
1003 | } | ||
992 | 1004 | ||
993 | if (mode == MTD_OOB_AUTO) | 1005 | if (mode == MTD_OOB_AUTO) |
994 | onenand_transfer_auto_oob(mtd, buf, column, thislen); | 1006 | onenand_transfer_auto_oob(mtd, buf, column, thislen); |
995 | else | 1007 | else |
996 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 1008 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); |
997 | 1009 | ||
998 | if (ret) { | ||
999 | printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); | ||
1000 | break; | ||
1001 | } | ||
1002 | |||
1003 | read += thislen; | 1010 | read += thislen; |
1004 | 1011 | ||
1005 | if (read == len) | 1012 | if (read == len) |
@@ -1016,7 +1023,14 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
1016 | } | 1023 | } |
1017 | 1024 | ||
1018 | ops->oobretlen = read; | 1025 | ops->oobretlen = read; |
1019 | return ret; | 1026 | |
1027 | if (ret) | ||
1028 | return ret; | ||
1029 | |||
1030 | if (mtd->ecc_stats.failed - stats.failed) | ||
1031 | return -EBADMSG; | ||
1032 | |||
1033 | return 0; | ||
1020 | } | 1034 | } |
1021 | 1035 | ||
1022 | /** | 1036 | /** |
@@ -1106,12 +1120,10 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1106 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1120 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
1107 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1121 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
1108 | 1122 | ||
1123 | /* Initial bad block case: 0x2400 or 0x0400 */ | ||
1109 | if (ctrl & ONENAND_CTRL_ERROR) { | 1124 | if (ctrl & ONENAND_CTRL_ERROR) { |
1110 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | 1125 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); |
1111 | /* Initial bad block case */ | 1126 | return ONENAND_BBT_READ_ERROR; |
1112 | if (ctrl & ONENAND_CTRL_LOAD) | ||
1113 | return ONENAND_BBT_READ_ERROR; | ||
1114 | return ONENAND_BBT_READ_FATAL_ERROR; | ||
1115 | } | 1127 | } |
1116 | 1128 | ||
1117 | if (interrupt & ONENAND_INT_READ) { | 1129 | if (interrupt & ONENAND_INT_READ) { |
@@ -1206,7 +1218,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1206 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) | 1218 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
1207 | { | 1219 | { |
1208 | struct onenand_chip *this = mtd->priv; | 1220 | struct onenand_chip *this = mtd->priv; |
1209 | char oobbuf[64]; | 1221 | u_char *oob_buf = this->oob_buf; |
1210 | int status, i; | 1222 | int status, i; |
1211 | 1223 | ||
1212 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | 1224 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); |
@@ -1215,9 +1227,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1215 | if (status) | 1227 | if (status) |
1216 | return status; | 1228 | return status; |
1217 | 1229 | ||
1218 | this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | 1230 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); |
1219 | for (i = 0; i < mtd->oobsize; i++) | 1231 | for (i = 0; i < mtd->oobsize; i++) |
1220 | if (buf[i] != 0xFF && buf[i] != oobbuf[i]) | 1232 | if (buf[i] != 0xFF && buf[i] != oob_buf[i]) |
1221 | return -EBADMSG; | 1233 | return -EBADMSG; |
1222 | 1234 | ||
1223 | return 0; | 1235 | return 0; |
@@ -1273,6 +1285,112 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, | |||
1273 | 1285 | ||
1274 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) | 1286 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) |
1275 | 1287 | ||
1288 | static void onenand_panic_wait(struct mtd_info *mtd) | ||
1289 | { | ||
1290 | struct onenand_chip *this = mtd->priv; | ||
1291 | unsigned int interrupt; | ||
1292 | int i; | ||
1293 | |||
1294 | for (i = 0; i < 2000; i++) { | ||
1295 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
1296 | if (interrupt & ONENAND_INT_MASTER) | ||
1297 | break; | ||
1298 | udelay(10); | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1302 | /** | ||
1303 | * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context | ||
1304 | * @param mtd MTD device structure | ||
1305 | * @param to offset to write to | ||
1306 | * @param len number of bytes to write | ||
1307 | * @param retlen pointer to variable to store the number of written bytes | ||
1308 | * @param buf the data to write | ||
1309 | * | ||
1310 | * Write with ECC | ||
1311 | */ | ||
1312 | static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
1313 | size_t *retlen, const u_char *buf) | ||
1314 | { | ||
1315 | struct onenand_chip *this = mtd->priv; | ||
1316 | int column, subpage; | ||
1317 | int written = 0; | ||
1318 | int ret = 0; | ||
1319 | |||
1320 | if (this->state == FL_PM_SUSPENDED) | ||
1321 | return -EBUSY; | ||
1322 | |||
1323 | /* Wait for any existing operation to clear */ | ||
1324 | onenand_panic_wait(mtd); | ||
1325 | |||
1326 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_panic_write: to = 0x%08x, len = %i\n", | ||
1327 | (unsigned int) to, (int) len); | ||
1328 | |||
1329 | /* Initialize retlen, in case of early exit */ | ||
1330 | *retlen = 0; | ||
1331 | |||
1332 | /* Do not allow writes past end of device */ | ||
1333 | if (unlikely((to + len) > mtd->size)) { | ||
1334 | printk(KERN_ERR "onenand_panic_write: Attempt write to past end of device\n"); | ||
1335 | return -EINVAL; | ||
1336 | } | ||
1337 | |||
1338 | /* Reject writes, which are not page aligned */ | ||
1339 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | ||
1340 | printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n"); | ||
1341 | return -EINVAL; | ||
1342 | } | ||
1343 | |||
1344 | column = to & (mtd->writesize - 1); | ||
1345 | |||
1346 | /* Loop until all data write */ | ||
1347 | while (written < len) { | ||
1348 | int thislen = min_t(int, mtd->writesize - column, len - written); | ||
1349 | u_char *wbuf = (u_char *) buf; | ||
1350 | |||
1351 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); | ||
1352 | |||
1353 | /* Partial page write */ | ||
1354 | subpage = thislen < mtd->writesize; | ||
1355 | if (subpage) { | ||
1356 | memset(this->page_buf, 0xff, mtd->writesize); | ||
1357 | memcpy(this->page_buf + column, buf, thislen); | ||
1358 | wbuf = this->page_buf; | ||
1359 | } | ||
1360 | |||
1361 | this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); | ||
1362 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
1363 | |||
1364 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | ||
1365 | |||
1366 | onenand_panic_wait(mtd); | ||
1367 | |||
1368 | /* In partial page write we don't update bufferram */ | ||
1369 | onenand_update_bufferram(mtd, to, !ret && !subpage); | ||
1370 | if (ONENAND_IS_2PLANE(this)) { | ||
1371 | ONENAND_SET_BUFFERRAM1(this); | ||
1372 | onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); | ||
1373 | } | ||
1374 | |||
1375 | if (ret) { | ||
1376 | printk(KERN_ERR "onenand_panic_write: write failed %d\n", ret); | ||
1377 | break; | ||
1378 | } | ||
1379 | |||
1380 | written += thislen; | ||
1381 | |||
1382 | if (written == len) | ||
1383 | break; | ||
1384 | |||
1385 | column = 0; | ||
1386 | to += thislen; | ||
1387 | buf += thislen; | ||
1388 | } | ||
1389 | |||
1390 | *retlen = written; | ||
1391 | return ret; | ||
1392 | } | ||
1393 | |||
1276 | /** | 1394 | /** |
1277 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer | 1395 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer |
1278 | * @param mtd MTD device structure | 1396 | * @param mtd MTD device structure |
@@ -1419,7 +1537,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1419 | } | 1537 | } |
1420 | 1538 | ||
1421 | /* Only check verify write turn on */ | 1539 | /* Only check verify write turn on */ |
1422 | ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); | 1540 | ret = onenand_verify(mtd, buf, to, thislen); |
1423 | if (ret) { | 1541 | if (ret) { |
1424 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); | 1542 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); |
1425 | break; | 1543 | break; |
@@ -1435,9 +1553,6 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1435 | buf += thislen; | 1553 | buf += thislen; |
1436 | } | 1554 | } |
1437 | 1555 | ||
1438 | /* Deselect and wake up anyone waiting on the device */ | ||
1439 | onenand_release_device(mtd); | ||
1440 | |||
1441 | ops->retlen = written; | 1556 | ops->retlen = written; |
1442 | 1557 | ||
1443 | return ret; | 1558 | return ret; |
@@ -2148,7 +2263,7 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | |||
2148 | 2263 | ||
2149 | *retlen = 0; | 2264 | *retlen = 0; |
2150 | 2265 | ||
2151 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2266 | density = onenand_get_density(this->device_id); |
2152 | if (density < ONENAND_DEVICE_DENSITY_512Mb) | 2267 | if (density < ONENAND_DEVICE_DENSITY_512Mb) |
2153 | otp_pages = 20; | 2268 | otp_pages = 20; |
2154 | else | 2269 | else |
@@ -2299,7 +2414,8 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, | |||
2299 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, | 2414 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, |
2300 | size_t len) | 2415 | size_t len) |
2301 | { | 2416 | { |
2302 | unsigned char oob_buf[64]; | 2417 | struct onenand_chip *this = mtd->priv; |
2418 | u_char *oob_buf = this->oob_buf; | ||
2303 | size_t retlen; | 2419 | size_t retlen; |
2304 | int ret; | 2420 | int ret; |
2305 | 2421 | ||
@@ -2339,7 +2455,7 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
2339 | unsigned int density, process; | 2455 | unsigned int density, process; |
2340 | 2456 | ||
2341 | /* Lock scheme depends on density and process */ | 2457 | /* Lock scheme depends on density and process */ |
2342 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2458 | density = onenand_get_density(this->device_id); |
2343 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; | 2459 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; |
2344 | 2460 | ||
2345 | /* Lock scheme */ | 2461 | /* Lock scheme */ |
@@ -2388,7 +2504,7 @@ static void onenand_print_device_info(int device, int version) | |||
2388 | vcc = device & ONENAND_DEVICE_VCC_MASK; | 2504 | vcc = device & ONENAND_DEVICE_VCC_MASK; |
2389 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; | 2505 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; |
2390 | ddp = device & ONENAND_DEVICE_IS_DDP; | 2506 | ddp = device & ONENAND_DEVICE_IS_DDP; |
2391 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | 2507 | density = onenand_get_density(device); |
2392 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", | 2508 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", |
2393 | demuxed ? "" : "Muxed ", | 2509 | demuxed ? "" : "Muxed ", |
2394 | ddp ? "(DDP)" : "", | 2510 | ddp ? "(DDP)" : "", |
@@ -2480,7 +2596,7 @@ static int onenand_probe(struct mtd_info *mtd) | |||
2480 | this->device_id = dev_id; | 2596 | this->device_id = dev_id; |
2481 | this->version_id = ver_id; | 2597 | this->version_id = ver_id; |
2482 | 2598 | ||
2483 | density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2599 | density = onenand_get_density(dev_id); |
2484 | this->chipsize = (16 << density) << 20; | 2600 | this->chipsize = (16 << density) << 20; |
2485 | /* Set density mask. it is used for DDP */ | 2601 | /* Set density mask. it is used for DDP */ |
2486 | if (ONENAND_IS_DDP(this)) | 2602 | if (ONENAND_IS_DDP(this)) |
@@ -2664,6 +2780,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2664 | mtd->write = onenand_write; | 2780 | mtd->write = onenand_write; |
2665 | mtd->read_oob = onenand_read_oob; | 2781 | mtd->read_oob = onenand_read_oob; |
2666 | mtd->write_oob = onenand_write_oob; | 2782 | mtd->write_oob = onenand_write_oob; |
2783 | mtd->panic_write = onenand_panic_write; | ||
2667 | #ifdef CONFIG_MTD_ONENAND_OTP | 2784 | #ifdef CONFIG_MTD_ONENAND_OTP |
2668 | mtd->get_fact_prot_info = onenand_get_fact_prot_info; | 2785 | mtd->get_fact_prot_info = onenand_get_fact_prot_info; |
2669 | mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; | 2786 | mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; |