Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 176933
b: refs/heads/master
c: 7207302
h: refs/heads/master
i:
  176931: dc58325
v: v3
  • Loading branch information
Mika Korhonen authored and David Woodhouse committed Nov 30, 2009
1 parent 5f12a96 commit 6d238b2
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 73885aeaca046a21183db598c2da46529e46fdab
refs/heads/master: 72073027ee95d059eb5a064da4a978efab36d4ab
22 changes: 18 additions & 4 deletions trunk/drivers/mtd/onenand/omap2.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,24 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
unsigned long timeout;
u32 syscfg;

if (state == FL_RESETING) {
int i;
if (state == FL_RESETING || state == FL_PREPARING_ERASE ||
state == FL_VERIFYING_ERASE) {
int i = 21;
unsigned int intr_flags = ONENAND_INT_MASTER;

switch (state) {
case FL_RESETING:
intr_flags |= ONENAND_INT_RESET;
break;
case FL_PREPARING_ERASE:
intr_flags |= ONENAND_INT_ERASE;
break;
case FL_VERIFYING_ERASE:
i = 101;
break;
}

for (i = 0; i < 20; i++) {
while (--i) {
udelay(1);
intr = read_reg(c, ONENAND_REG_INTERRUPT);
if (intr & ONENAND_INT_MASTER)
Expand All @@ -126,7 +140,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
wait_err("controller error", state, ctrl, intr);
return -EIO;
}
if (!(intr & ONENAND_INT_RESET)) {
if ((intr & intr_flags) != intr_flags) {
wait_err("timeout", state, ctrl, intr);
return -EIO;
}
Expand Down
173 changes: 171 additions & 2 deletions trunk/drivers/mtd/onenand/onenand_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@

#include <asm/io.h>

/*
* Multiblock erase if number of blocks to erase is 2 or more.
* Maximum number of blocks for simultaneous erase is 64.
*/
#define MB_ERASE_MIN_BLK_COUNT 2
#define MB_ERASE_MAX_BLK_COUNT 64

/* Default Flex-OneNAND boundary and lock respectively */
static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 };

Expand Down Expand Up @@ -353,6 +360,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
break;

case ONENAND_CMD_ERASE:
case ONENAND_CMD_MULTIBLOCK_ERASE:
case ONENAND_CMD_ERASE_VERIFY:
case ONENAND_CMD_BUFFERRAM:
case ONENAND_CMD_OTP_ACCESS:
block = onenand_block(this, addr);
Expand Down Expand Up @@ -497,7 +506,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
if (interrupt & flags)
break;

if (state != FL_READING)
if (state != FL_READING && state != FL_PREPARING_ERASE)
cond_resched();
}
/* To get correct interrupt status in timeout case */
Expand Down Expand Up @@ -530,6 +539,18 @@ static int onenand_wait(struct mtd_info *mtd, int state)
return -EIO;
}

if (state == FL_PREPARING_ERASE && !(interrupt & ONENAND_INT_ERASE)) {
printk(KERN_ERR "%s: mb erase timeout! ctrl=0x%04x intr=0x%04x\n",
__func__, ctrl, interrupt);
return -EIO;
}

if (!(interrupt & ONENAND_INT_MASTER)) {
printk(KERN_ERR "%s: timeout! ctrl=0x%04x intr=0x%04x\n",
__func__, ctrl, interrupt);
return -EIO;
}

/* If there's controller error, it's a real error */
if (ctrl & ONENAND_CTRL_ERROR) {
printk(KERN_ERR "%s: controller error = 0x%04x\n",
Expand Down Expand Up @@ -2182,6 +2203,148 @@ static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allo
return bbm->isbad_bbt(mtd, ofs, allowbbt);
}


static int onenand_multiblock_erase_verify(struct mtd_info *mtd,
struct erase_info *instr)
{
struct onenand_chip *this = mtd->priv;
loff_t addr = instr->addr;
int len = instr->len;
unsigned int block_size = (1 << this->erase_shift);
int ret = 0;

while (len) {
this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
ret = this->wait(mtd, FL_VERIFYING_ERASE);
if (ret) {
printk(KERN_ERR "%s: Failed verify, block %d\n",
__func__, onenand_block(this, addr));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
return -1;
}
len -= block_size;
addr += block_size;
}
return 0;
}

/**
* onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase
* @param mtd MTD device structure
* @param instr erase instruction
* @param region erase region
*
* Erase one or more blocks up to 64 block at a time
*/
static int onenand_multiblock_erase(struct mtd_info *mtd,
struct erase_info *instr,
unsigned int block_size)
{
struct onenand_chip *this = mtd->priv;
loff_t addr = instr->addr;
int len = instr->len;
int eb_count = 0;
int ret = 0;
int bdry_block = 0;

instr->state = MTD_ERASING;

if (ONENAND_IS_DDP(this)) {
loff_t bdry_addr = this->chipsize >> 1;
if (addr < bdry_addr && (addr + len) > bdry_addr)
bdry_block = bdry_addr >> this->erase_shift;
}

/* Pre-check bbs */
while (len) {
/* Check if we have a bad block, we do not erase bad blocks */
if (onenand_block_isbad_nolock(mtd, addr, 0)) {
printk(KERN_WARNING "%s: attempt to erase a bad block "
"at addr 0x%012llx\n",
__func__, (unsigned long long) addr);
instr->state = MTD_ERASE_FAILED;
return -EIO;
}
len -= block_size;
addr += block_size;
}

len = instr->len;
addr = instr->addr;

/* loop over 64 eb batches */
while (len) {
struct erase_info verify_instr = *instr;
int max_eb_count = MB_ERASE_MAX_BLK_COUNT;

verify_instr.addr = addr;
verify_instr.len = 0;

/* do not cross chip boundary */
if (bdry_block) {
int this_block = (addr >> this->erase_shift);

if (this_block < bdry_block) {
max_eb_count = min(max_eb_count,
(bdry_block - this_block));
}
}

eb_count = 0;

while (len > block_size && eb_count < (max_eb_count - 1)) {
this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE,
addr, block_size);
onenand_invalidate_bufferram(mtd, addr, block_size);

ret = this->wait(mtd, FL_PREPARING_ERASE);
if (ret) {
printk(KERN_ERR "%s: Failed multiblock erase, "
"block %d\n", __func__,
onenand_block(this, addr));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
return -EIO;
}

len -= block_size;
addr += block_size;
eb_count++;
}

/* last block of 64-eb series */
cond_resched();
this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
onenand_invalidate_bufferram(mtd, addr, block_size);

ret = this->wait(mtd, FL_ERASING);
/* Check if it is write protected */
if (ret) {
printk(KERN_ERR "%s: Failed erase, block %d\n",
__func__, onenand_block(this, addr));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
return -EIO;
}

len -= block_size;
addr += block_size;
eb_count++;

/* verify */
verify_instr.len = eb_count * block_size;
if (onenand_multiblock_erase_verify(mtd, &verify_instr)) {
instr->state = verify_instr.state;
instr->fail_addr = verify_instr.fail_addr;
return -EIO;
}

}
return 0;
}


/**
* onenand_block_by_block_erase - [Internal] erase block(s) using regular erase
* @param mtd MTD device structure
Expand Down Expand Up @@ -2315,7 +2478,13 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_ERASING);

ret = onenand_block_by_block_erase(mtd, instr, region, block_size);
if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
/* region is set for Flex-OneNAND (no mb erase) */
ret = onenand_block_by_block_erase(mtd, instr,
region, block_size);
} else {
ret = onenand_multiblock_erase(mtd, instr, block_size);
}

/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
Expand Down
4 changes: 3 additions & 1 deletion trunk/include/linux/mtd/flashchip.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ typedef enum {
/* These 2 come from nand_state_t, which has been unified here */
FL_READING,
FL_CACHEDPRG,
/* These 2 come from onenand_state_t, which has been unified here */
/* These 4 come from onenand_state_t, which has been unified here */
FL_RESETING,
FL_OTPING,
FL_PREPARING_ERASE,
FL_VERIFYING_ERASE,

FL_UNKNOWN
} flstate_t;
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/mtd/onenand_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
#define ONENAND_CMD_UNLOCK_ALL (0x27)
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_MULTIBLOCK_ERASE (0x95)
#define ONENAND_CMD_ERASE_VERIFY (0x71)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_OTP_ACCESS (0x65)
#define ONENAND_CMD_READID (0x90)
Expand Down

0 comments on commit 6d238b2

Please sign in to comment.