tangled
alpha
login
or
join now
tjh.dev
/
kernel
1
fork
atom
Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1
fork
atom
overview
issues
pulls
pipelines
Merge git://git.infradead.org/~kmpark/onenand-mtd-2.6
David Woodhouse
19 years ago
103e40f6
95b93a0c
+174
-22
5 changed files
expand all
collapse all
unified
split
drivers
mtd
onenand
generic.c
onenand_base.c
onenand_bbt.c
include
linux
mtd
onenand.h
onenand_regs.h
+1
drivers/mtd/onenand/generic.c
reviewed
···
61
61
}
62
62
63
63
info->onenand.mmcontrol = pdata->mmcontrol;
64
64
+
info->onenand.irq = platform_get_irq(pdev, 0);
64
65
65
66
info->mtd.name = pdev->dev.bus_id;
66
67
info->mtd.priv = &info->onenand;
+167
-21
drivers/mtd/onenand/onenand_base.c
reviewed
···
13
13
#include <linux/module.h>
14
14
#include <linux/init.h>
15
15
#include <linux/sched.h>
16
16
+
#include <linux/interrupt.h>
16
17
#include <linux/jiffies.h>
17
18
#include <linux/mtd/mtd.h>
18
19
#include <linux/mtd/onenand.h>
···
331
330
332
331
if (interrupt & ONENAND_INT_READ) {
333
332
ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
334
334
-
if (ecc & ONENAND_ECC_2BIT_ALL) {
333
333
+
if (ecc) {
335
334
DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
336
336
-
return -EBADMSG;
335
335
+
if (ecc & ONENAND_ECC_2BIT_ALL)
336
336
+
mtd->ecc_stats.failed++;
337
337
+
else if (ecc & ONENAND_ECC_1BIT_ALL)
338
338
+
mtd->ecc_stats.corrected++;
337
339
}
338
340
}
339
341
340
342
return 0;
343
343
+
}
344
344
+
345
345
+
/*
346
346
+
* onenand_interrupt - [DEFAULT] onenand interrupt handler
347
347
+
* @param irq onenand interrupt number
348
348
+
* @param dev_id interrupt data
349
349
+
*
350
350
+
* complete the work
351
351
+
*/
352
352
+
static irqreturn_t onenand_interrupt(int irq, void *data)
353
353
+
{
354
354
+
struct onenand_chip *this = (struct onenand_chip *) data;
355
355
+
356
356
+
/* To handle shared interrupt */
357
357
+
if (!this->complete.done)
358
358
+
complete(&this->complete);
359
359
+
360
360
+
return IRQ_HANDLED;
361
361
+
}
362
362
+
363
363
+
/*
364
364
+
* onenand_interrupt_wait - [DEFAULT] wait until the command is done
365
365
+
* @param mtd MTD device structure
366
366
+
* @param state state to select the max. timeout value
367
367
+
*
368
368
+
* Wait for command done.
369
369
+
*/
370
370
+
static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
371
371
+
{
372
372
+
struct onenand_chip *this = mtd->priv;
373
373
+
374
374
+
/* To prevent soft lockup */
375
375
+
touch_softlockup_watchdog();
376
376
+
377
377
+
wait_for_completion(&this->complete);
378
378
+
379
379
+
return onenand_wait(mtd, state);
380
380
+
}
381
381
+
382
382
+
/*
383
383
+
* onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
384
384
+
* @param mtd MTD device structure
385
385
+
* @param state state to select the max. timeout value
386
386
+
*
387
387
+
* Try interrupt based wait (It is used one-time)
388
388
+
*/
389
389
+
static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
390
390
+
{
391
391
+
struct onenand_chip *this = mtd->priv;
392
392
+
unsigned long remain, timeout;
393
393
+
394
394
+
/* We use interrupt wait first */
395
395
+
this->wait = onenand_interrupt_wait;
396
396
+
397
397
+
/* To prevent soft lockup */
398
398
+
touch_softlockup_watchdog();
399
399
+
400
400
+
timeout = msecs_to_jiffies(100);
401
401
+
remain = wait_for_completion_timeout(&this->complete, timeout);
402
402
+
if (!remain) {
403
403
+
printk(KERN_INFO "OneNAND: There's no interrupt. "
404
404
+
"We use the normal wait\n");
405
405
+
406
406
+
/* Release the irq */
407
407
+
free_irq(this->irq, this);
408
408
+
409
409
+
this->wait = onenand_wait;
410
410
+
}
411
411
+
412
412
+
return onenand_wait(mtd, state);
413
413
+
}
414
414
+
415
415
+
/*
416
416
+
* onenand_setup_wait - [OneNAND Interface] setup onenand wait method
417
417
+
* @param mtd MTD device structure
418
418
+
*
419
419
+
* There's two method to wait onenand work
420
420
+
* 1. polling - read interrupt status register
421
421
+
* 2. interrupt - use the kernel interrupt method
422
422
+
*/
423
423
+
static void onenand_setup_wait(struct mtd_info *mtd)
424
424
+
{
425
425
+
struct onenand_chip *this = mtd->priv;
426
426
+
int syscfg;
427
427
+
428
428
+
init_completion(&this->complete);
429
429
+
430
430
+
if (this->irq <= 0) {
431
431
+
this->wait = onenand_wait;
432
432
+
return;
433
433
+
}
434
434
+
435
435
+
if (request_irq(this->irq, &onenand_interrupt,
436
436
+
IRQF_SHARED, "onenand", this)) {
437
437
+
/* If we can't get irq, use the normal wait */
438
438
+
this->wait = onenand_wait;
439
439
+
return;
440
440
+
}
441
441
+
442
442
+
/* Enable interrupt */
443
443
+
syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
444
444
+
syscfg |= ONENAND_SYS_CFG1_IOBE;
445
445
+
this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
446
446
+
447
447
+
this->wait = onenand_try_interrupt_wait;
341
448
}
342
449
343
450
/**
···
718
609
size_t *retlen, u_char *buf)
719
610
{
720
611
struct onenand_chip *this = mtd->priv;
612
612
+
struct mtd_ecc_stats stats;
721
613
int read = 0, column;
722
614
int thislen;
723
615
int ret = 0;
···
737
627
738
628
/* TODO handling oob */
739
629
630
630
+
stats = mtd->ecc_stats;
740
631
while (read < len) {
741
632
thislen = min_t(int, mtd->writesize, len - read);
742
633
···
779
668
* retlen == desired len and result == -EBADMSG
780
669
*/
781
670
*retlen = read;
782
782
-
return ret;
671
671
+
672
672
+
if (mtd->ecc_stats.failed - stats.failed)
673
673
+
return -EBADMSG;
674
674
+
675
675
+
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
783
676
}
784
677
785
678
/**
···
1244
1129
onenand_release_device(mtd);
1245
1130
}
1246
1131
1247
1247
-
1248
1132
/**
1249
1133
* onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
1250
1134
* @param mtd MTD device structure
···
1310
1196
}
1311
1197
1312
1198
/**
1313
1313
-
* onenand_unlock - [MTD Interface] Unlock block(s)
1199
1199
+
* onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s)
1314
1200
* @param mtd MTD device structure
1315
1201
* @param ofs offset relative to mtd start
1316
1316
-
* @param len number of bytes to unlock
1202
1202
+
* @param len number of bytes to lock or unlock
1317
1203
*
1318
1318
-
* Unlock one or more blocks
1204
1204
+
* Lock or unlock one or more blocks
1319
1205
*/
1320
1320
-
static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1206
1206
+
static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
1321
1207
{
1322
1208
struct onenand_chip *this = mtd->priv;
1323
1209
int start, end, block, value, status;
1210
1210
+
int wp_status_mask;
1324
1211
1325
1212
start = ofs >> this->erase_shift;
1326
1213
end = len >> this->erase_shift;
1214
1214
+
1215
1215
+
if (cmd == ONENAND_CMD_LOCK)
1216
1216
+
wp_status_mask = ONENAND_WP_LS;
1217
1217
+
else
1218
1218
+
wp_status_mask = ONENAND_WP_US;
1327
1219
1328
1220
/* Continuous lock scheme */
1329
1221
if (this->options & ONENAND_HAS_CONT_LOCK) {
···
1337
1217
this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1338
1218
/* Set end block address */
1339
1219
this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1340
1340
-
/* Write unlock command */
1341
1341
-
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1220
1220
+
/* Write lock command */
1221
1221
+
this->command(mtd, cmd, 0, 0);
1342
1222
1343
1223
/* There's no return value */
1344
1344
-
this->wait(mtd, FL_UNLOCKING);
1224
1224
+
this->wait(mtd, FL_LOCKING);
1345
1225
1346
1226
/* Sanity check */
1347
1227
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
···
1350
1230
1351
1231
/* Check lock status */
1352
1232
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1353
1353
-
if (!(status & ONENAND_WP_US))
1233
1233
+
if (!(status & wp_status_mask))
1354
1234
printk(KERN_ERR "wp status = 0x%x\n", status);
1355
1235
1356
1236
return 0;
···
1366
1246
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1367
1247
/* Set start block address */
1368
1248
this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1369
1369
-
/* Write unlock command */
1370
1370
-
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1249
1249
+
/* Write lock command */
1250
1250
+
this->command(mtd, cmd, 0, 0);
1371
1251
1372
1252
/* There's no return value */
1373
1373
-
this->wait(mtd, FL_UNLOCKING);
1253
1253
+
this->wait(mtd, FL_LOCKING);
1374
1254
1375
1255
/* Sanity check */
1376
1256
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
···
1379
1259
1380
1260
/* Check lock status */
1381
1261
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1382
1382
-
if (!(status & ONENAND_WP_US))
1262
1262
+
if (!(status & wp_status_mask))
1383
1263
printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
1384
1264
}
1385
1265
1386
1266
return 0;
1267
1267
+
}
1268
1268
+
1269
1269
+
/**
1270
1270
+
* onenand_lock - [MTD Interface] Lock block(s)
1271
1271
+
* @param mtd MTD device structure
1272
1272
+
* @param ofs offset relative to mtd start
1273
1273
+
* @param len number of bytes to unlock
1274
1274
+
*
1275
1275
+
* Lock one or more blocks
1276
1276
+
*/
1277
1277
+
static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
1278
1278
+
{
1279
1279
+
return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
1280
1280
+
}
1281
1281
+
1282
1282
+
/**
1283
1283
+
* onenand_unlock - [MTD Interface] Unlock block(s)
1284
1284
+
* @param mtd MTD device structure
1285
1285
+
* @param ofs offset relative to mtd start
1286
1286
+
* @param len number of bytes to unlock
1287
1287
+
*
1288
1288
+
* Unlock one or more blocks
1289
1289
+
*/
1290
1290
+
static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1291
1291
+
{
1292
1292
+
return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
1387
1293
}
1388
1294
1389
1295
/**
···
1456
1310
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
1457
1311
1458
1312
/* There's no return value */
1459
1459
-
this->wait(mtd, FL_UNLOCKING);
1313
1313
+
this->wait(mtd, FL_LOCKING);
1460
1314
1461
1315
/* Sanity check */
1462
1316
while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
···
1480
1334
return 0;
1481
1335
}
1482
1336
1483
1483
-
mtd->unlock(mtd, 0x0, this->chipsize);
1337
1337
+
onenand_unlock(mtd, 0x0, this->chipsize);
1484
1338
1485
1339
return 0;
1486
1340
}
···
1908
1762
/* Read manufacturer and device IDs from Register */
1909
1763
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1910
1764
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
1911
1911
-
ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID);
1765
1765
+
ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
1912
1766
1913
1767
/* Check OneNAND device */
1914
1768
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
···
1992
1846
if (!this->command)
1993
1847
this->command = onenand_command;
1994
1848
if (!this->wait)
1995
1995
-
this->wait = onenand_wait;
1849
1849
+
onenand_setup_wait(mtd);
1996
1850
1997
1851
if (!this->read_bufferram)
1998
1852
this->read_bufferram = onenand_read_bufferram;
···
2068
1922
mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
2069
1923
#endif
2070
1924
mtd->sync = onenand_sync;
2071
2071
-
mtd->lock = NULL;
1925
1925
+
mtd->lock = onenand_lock;
2072
1926
mtd->unlock = onenand_unlock;
2073
1927
mtd->suspend = onenand_suspend;
2074
1928
mtd->resume = onenand_resume;
+1
drivers/mtd/onenand/onenand_bbt.c
reviewed
···
100
100
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
101
101
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
102
102
i >> 1, (unsigned int) from);
103
103
+
mtd->ecc_stats.badblocks++;
103
104
break;
104
105
}
105
106
}
+4
-1
include/linux/mtd/onenand.h
reviewed
···
13
13
#define __LINUX_MTD_ONENAND_H
14
14
15
15
#include <linux/spinlock.h>
16
16
+
#include <linux/completion.h>
16
17
#include <linux/mtd/onenand_regs.h>
17
18
#include <linux/mtd/bbm.h>
18
19
···
34
33
FL_WRITING,
35
34
FL_ERASING,
36
35
FL_SYNCING,
37
37
-
FL_UNLOCKING,
38
36
FL_LOCKING,
39
37
FL_RESETING,
40
38
FL_OTPING,
···
119
119
void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
120
120
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
121
121
int (*scan_bbt)(struct mtd_info *mtd);
122
122
+
123
123
+
struct completion complete;
124
124
+
int irq;
122
125
123
126
spinlock_t chip_lock;
124
127
wait_queue_head_t wq;
+1
include/linux/mtd/onenand_regs.h
reviewed
···
179
179
* ECC Status Reigser FF00h (R)
180
180
*/
181
181
#define ONENAND_ECC_1BIT (1 << 0)
182
182
+
#define ONENAND_ECC_1BIT_ALL (0x5555)
182
183
#define ONENAND_ECC_2BIT (1 << 1)
183
184
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
184
185