Newer
Older
/* Loop through and verify the data */
for (i = col; i < last; i++) {
if (nand->data_buf[i] != readb (nand->IO_ADDR)) {
printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page);
return -1;
}
}
#ifdef CONFIG_MTD_NAND_ECC
/*
* We also want to check that the ECC bytes wrote
* correctly for the same reasons stated above.
*/
NanD_Command(nand, NAND_CMD_READOOB);
NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);
for (i = 0; i < nand->oobsize; i++)
nand->data_buf[i] = readb (nand->IO_ADDR);
for (i = 0; i < ecc_bytes; i++) {
if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {
printf ("%s: Failed ECC write "
"verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
return -1;
}
}
#endif
#endif
return 0;
}
static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * ecc_code)
{
int i, page, col, cnt, ret = 0;
/* Do not allow write past end of device */
if ((to + len) > nand->totlen) {
printf ("%s: Attempt to write past end of page\n", __FUNCTION__);
return -1;
}
/* Shift to get page */
page = ((int) to) >> nand->page_shift;
/* Get the starting column */
col = to & (nand->oobblock - 1);
/* Initialize return length value */
*retlen = 0;
/* Select the NAND device */
NAND_ENABLE_CE(nand); /* set pin low */
NanD_Command(nand, NAND_CMD_STATUS);
if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
printf ("%s: Device is write protected!!!\n", __FUNCTION__);
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
ret = -1;
goto out;
}
/* Loop until all data is written */
while (*retlen < len) {
/* Invalidate cache, if we write to this page */
if (nand->cache_page == page)
nand->cache_page = -1;
/* Write data into buffer */
if ((col + len) >= nand->oobblock)
for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++)
nand->data_buf[i] = buf[(*retlen + cnt)];
else
for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)
nand->data_buf[i] = buf[(*retlen + cnt)];
/* We use the same function for write and writev !) */
ret = nand_write_page (nand, page, col, i, ecc_code);
if (ret)
goto out;
/* Next data start at page boundary */
col = 0;
/* Update written bytes count */
*retlen += cnt;
/* Increment page address */
page++;
}
/* Return happy */
*retlen = len;
out:
/* De-select the NAND device */
NAND_DISABLE_CE(nand); /* set pin high */
/* read from the 16 bytes of oob data that correspond to a 512 byte
* page or 2 256-byte pages.
*/
static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
mychip = &nand->chips[ofs >> nand->chipshift];
/* update address for 2M x 8bit devices. OOB starts on the second */
/* page to maintain compatibility with nand_read_ecc. */
if (nand->page256) {
if (!(ofs & 0x8))
ofs += 0x100;
else
ofs -= 0x8;
}
NAND_ENABLE_CE(nand); /* set pin low */
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
NanD_Command(nand, NAND_CMD_READOOB);
NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
/* treat crossing 8-byte OOB data for 2M x 8bit devices */
/* Note: datasheet says it should automaticaly wrap to the */
/* next OOB block, but it didn't work here. mf. */
if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
len256 = (ofs | 0x7) + 1 - ofs;
NanD_ReadBuf(nand, buf, len256);
NanD_Command(nand, NAND_CMD_READOOB);
NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
}
NanD_ReadBuf(nand, &buf[len256], len - len256);
*retlen = len;
/* Reading the full OOB data drops us off of the end of the page,
* causing the flash device to go into busy mode, so we need
* to wait until ready 11.4.1 and Toshiba TC58256FT nands */
ret = NanD_WaitReady(nand);
NAND_DISABLE_CE(nand); /* set pin high */
/* write to the 16 bytes of oob data that correspond to a 512 byte
* page or 2 256-byte pages.
*/
static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
size_t * retlen, const u_char * buf)
{
int len256 = 0;
unsigned long nandptr = nand->IO_ADDR;
#ifdef PSYCHO_DEBUG
printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
(long)ofs, len, buf[0], buf[1], buf[2], buf[3],
buf[8], buf[9], buf[14],buf[15]);
#endif
NAND_ENABLE_CE(nand); /* set pin low to enable chip */
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
/* Reset the chip */
NanD_Command(nand, NAND_CMD_RESET);
/* issue the Read2 command to set the pointer to the Spare Data Area. */
NanD_Command(nand, NAND_CMD_READOOB);
NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
/* update address for 2M x 8bit devices. OOB starts on the second */
/* page to maintain compatibility with nand_read_ecc. */
if (nand->page256) {
if (!(ofs & 0x8))
ofs += 0x100;
else
ofs -= 0x8;
}
/* issue the Serial Data In command to initial the Page Program process */
NanD_Command(nand, NAND_CMD_SEQIN);
NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
/* treat crossing 8-byte OOB data for 2M x 8bit devices */
/* Note: datasheet says it should automaticaly wrap to the */
/* next OOB block, but it didn't work here. mf. */
if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
len256 = (ofs | 0x7) + 1 - ofs;
for (i = 0; i < len256; i++)
WRITE_NAND(buf[i], nandptr);
NanD_Command(nand, NAND_CMD_PAGEPROG);
NanD_Command(nand, NAND_CMD_STATUS);
/* NanD_WaitReady() is implicit in NanD_Command */
if (READ_NAND(nandptr) & 1) {
puts ("Error programming oob data\n");
/* There was an error */
NAND_DISABLE_CE(nand); /* set pin high */
*retlen = 0;
return -1;
}
NanD_Command(nand, NAND_CMD_SEQIN);
NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
}
for (i = len256; i < len; i++)
WRITE_NAND(buf[i], nandptr);
NanD_Command(nand, NAND_CMD_PAGEPROG);
NanD_Command(nand, NAND_CMD_STATUS);
/* NanD_WaitReady() is implicit in NanD_Command */
if (READ_NAND(nandptr) & 1) {
puts ("Error programming oob data\n");
/* There was an error */
NAND_DISABLE_CE(nand); /* set pin high */
*retlen = 0;
return -1;
}
NAND_DISABLE_CE(nand); /* set pin high */
*retlen = len;
return 0;
}
static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
/* This is defined as a structure so it will work on any system
* using native endian jffs2 (the default).
*/
static struct jffs2_unknown_node clean_marker = {
JFFS2_MAGIC_BITMASK,
JFFS2_NODETYPE_CLEANMARKER,
8 /* 8 bytes in this node */
};
unsigned long nandptr;
struct Nand *mychip;
if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) {
printf ("Offset and size must be sector aligned, erasesize = %d\n",
(int) nand->erasesize);
return -1;
}
nandptr = nand->IO_ADDR;
/* Select the NAND device */
NAND_ENABLE_CE(nand); /* set pin low */
/* Check the WP bit */
NanD_Command(nand, NAND_CMD_STATUS);
if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
printf ("nand_write_ecc: Device is write protected!!!\n");
ret = -1;
goto out;
}
/* Check the WP bit */
NanD_Command(nand, NAND_CMD_STATUS);
if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
printf ("%s: Device is write protected!!!\n", __FUNCTION__);
ret = -1;
goto out;
}
/* FIXME: Do nand in the background. Use timers or schedule_task() */
while(len) {
/*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
mychip = &nand->chips[ofs >> nand->chipshift];
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
/* always check for bad block first, genuine bad blocks
* should _never_ be erased.
*/
if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {
/* Select the NAND device */
NAND_ENABLE_CE(nand); /* set pin low */
NanD_Command(nand, NAND_CMD_ERASE1);
NanD_Address(nand, ADDR_PAGE, ofs);
NanD_Command(nand, NAND_CMD_ERASE2);
NanD_Command(nand, NAND_CMD_STATUS);
if (READ_NAND(nandptr) & 1) {
printf ("%s: Error erasing at 0x%lx\n",
__FUNCTION__, (long)ofs);
/* There was an error */
ret = -1;
goto out;
}
if (clean) {
int n; /* return value not used */
int p, l;
/* clean marker position and size depend
* on the page size, since 256 byte pages
* only have 8 bytes of oob data
*/
if (nand->page256) {
p = NAND_JFFS2_OOB8_FSDAPOS;
l = NAND_JFFS2_OOB8_FSDALEN;
}
else {
p = NAND_JFFS2_OOB16_FSDAPOS;
l = NAND_JFFS2_OOB16_FSDALEN;
}
ret = nand_write_oob(nand, ofs + p, l, &n,
(u_char *)&clean_marker);
/* quit here if write failed */
if (ret)
goto out;
}
}
ofs += nand->erasesize;
len -= nand->erasesize;
}
out:
/* De-select the NAND device */
NAND_DISABLE_CE(nand); /* set pin high */
return ret;
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
}
static inline int nandcheck(unsigned long potential, unsigned long physadr)
{
return 0;
}
void nand_probe(unsigned long physadr)
{
struct nand_chip *nand = NULL;
int i = 0, ChipID = 1;
#ifdef CONFIG_MTD_NAND_ECC_JFFS2
oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0;
oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1;
oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2;
oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3;
oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4;
oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;
oob_config.eccvalid_pos = 4;
#else
oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0;
oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1;
oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2;
oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3;
oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4;
oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;
oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;
#endif
for (i=0; i<CFG_MAX_NAND_DEVICE; i++) {
if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) {
nand = nand_dev_desc + i;
break;
}
}
memset((char *)nand, 0, sizeof(struct nand_chip));
nand->cache_page = -1; /* init the cache page */
if (nand->totlen == 0) {
/* no chips found, clean up and quit */
memset((char *)nand, 0, sizeof(struct nand_chip));
nand->ChipID = NAND_ChipID_UNKNOWN;
return;
}
nand->ChipID = ChipID;
if (curr_device == -1)
curr_device = i;
nand->data_buf = malloc (nand->oobblock + nand->oobsize);
if (!nand->data_buf) {
puts ("Cannot allocate memory for data structures.\n");
return;
}
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
}
#ifdef CONFIG_MTD_NAND_ECC
/*
* Pre-calculated 256-way 1 byte column parity
*/
static const u_char nand_ecc_precalc_table[] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
};
/*
* Creates non-inverted ECC code from line parity
*/
static void nand_trans_result(u_char reg2, u_char reg3,
u_char *ecc_code)
{
u_char a, b, i, tmp1, tmp2;
/* Initialize variables */
a = b = 0x80;
tmp1 = tmp2 = 0;
/* Calculate first ECC byte */
for (i = 0; i < 4; i++) {
if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
tmp1 |= b;
b >>= 1;
if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
tmp1 |= b;
b >>= 1;
a >>= 1;
}
/* Calculate second ECC byte */
b = 0x80;
for (i = 0; i < 4; i++) {
if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
tmp2 |= b;
b >>= 1;
if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
tmp2 |= b;
b >>= 1;
a >>= 1;
}
/* Store two of the ECC bytes */
ecc_code[0] = tmp1;
ecc_code[1] = tmp2;
}
/*
* Calculate 3 byte ECC code for 256 byte block
*/
static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
{
int j;
/* Initialize variables */
ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
/* Build up column parity */
for(j = 0; j < 256; j++) {
/* Get CP0 - CP5 from table */
idx = nand_ecc_precalc_table[dat[j]];
/* All bit XOR = 1 ? */
if (idx & 0x40) {
reg3 ^= (u_char) j;
}
}
/* Create non-inverted ECC code from line parity */
nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
/* Calculate final ECC code */
ecc_code[0] = ~ecc_code[0];
ecc_code[1] = ~ecc_code[1];
ecc_code[2] = ((~reg1) << 2) | 0x03;
}
/*
* Detect and correct a 1 bit error for 256 byte block
*/
static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
{
u_char a, b, c, d1, d2, d3, add, bit, i;
/* Do error detection */
d1 = calc_ecc[0] ^ read_ecc[0];
d2 = calc_ecc[1] ^ read_ecc[1];
d3 = calc_ecc[2] ^ read_ecc[2];
if ((d1 | d2 | d3) == 0) {
/* No errors */
return 0;
}
else {
a = (d1 ^ (d1 >> 1)) & 0x55;
b = (d2 ^ (d2 >> 1)) & 0x55;
c = (d3 ^ (d3 >> 1)) & 0x54;
/* Found and will correct single bit error in the data */
if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
c = 0x80;
add = 0;
a = 0x80;
for (i=0; i<4; i++) {
if (d1 & c)
add |= a;
c >>= 2;
a >>= 1;
}
c = 0x80;
for (i=0; i<4; i++) {
if (d2 & c)
add |= a;
c >>= 2;
a >>= 1;
}
bit = 0;
b = 0x04;
c = 0x80;
for (i=0; i<3; i++) {
if (d3 & c)
bit |= b;
c >>= 2;
b >>= 1;
}
b = 0x01;
a = dat[add];
a ^= (b << bit);
dat[add] = a;
return 1;
}
else {
i = 0;
while (d1) {
if (d1 & 0x01)
++i;
d1 >>= 1;
}
while (d2) {
if (d2 & 0x01)
++i;
d2 >>= 1;
}
while (d3) {
if (d3 & 0x01)
++i;
d3 >>= 1;
}
if (i == 1) {
/* ECC Code Error Correction */
read_ecc[0] = calc_ecc[0];
read_ecc[1] = calc_ecc[1];
read_ecc[2] = calc_ecc[2];
return 2;
}
else {
/* Uncorrectable Error */
return -1;
}
}
}
/* Should never happen */
return -1;
}
#endif
#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */