Thread (12 messages) 12 messages, 4 authors, 2010-09-21
STALE5740d

[PATCH 2/6] pxa3xx_nand: rework irq logic

From: Eric Miao <hidden>
Date: 2010-09-17 02:47:28

+ ? ? ? STATE_PAGE_DONE ? ? ? ? = (1 << 3),
+ ? ? ? STATE_CMD_DONE ? ? ? ? ?= (1 << 4),
+ ? ? ? STATE_READY ? ? ? ? ? ? = (1 << 5),
+ ? ? ? STATE_CMD_PREPARED ? ? ?= (1 << 6),
+ ? ? ? STATE_IS_WRITE ? ? ? ? ?= (1 << 7),
State isn't supposed to be a bit-or'ed value, if you have to use this in
the code, it just means the logic is broken. You should check it again.
quoted hunk ↗ jump to hunk
?};

?struct pxa3xx_nand_info {
@@ -292,7 +296,47 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
? ? ? ?}
?}

-static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
+/**
+ * NOTE: it is a must to set ND_RUN firstly, then write
+ * command buffer, otherwise, it does not work.
+ * We enable all the interrupt at the same time, and
+ * let pxa3xx_nand_irq to handle all logic.
+ */
+static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
+{
+ ? ? ? uint32_t ndcr;
+
+ ? ? ? ndcr = info->reg_ndcr;
+ ? ? ? ndcr |= NDCR_ECC_EN;
+ ? ? ? ndcr |= info->use_dma ? NDCR_DMA_EN : NDCR_STOP_ON_UNCOR;
+ ? ? ? ndcr |= NDCR_ND_RUN;
+
+ ? ? ? /* clear status bits and run */
+ ? ? ? nand_writel(info, NDCR, 0);
+ ? ? ? nand_writel(info, NDSR, NDSR_MASK);
+ ? ? ? nand_writel(info, NDCR, ndcr);
+}
+
+static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
+{
+ ? ? ? uint32_t ndcr;
+ ? ? ? int timeout = NAND_STOP_DELAY;
+
+ ? ? ? /* wait RUN bit in NDCR become 0 */
+ ? ? ? do {
+ ? ? ? ? ? ? ? /* clear status bits */
+ ? ? ? ? ? ? ? nand_writel(info, NDSR, NDSR_MASK);
Why clearing status bits every time before reading NDCR, does it have
some impact to the NDCR_ND_RUN bit?
+ ? ? ? ? ? ? ? ndcr = nand_readl(info, NDCR);
+ ? ? ? ? ? ? ? udelay(1);
Check the NDCR_ND_RUN bit before udelay() would be better, that would
leave a chance that udelay() will not be called at all if the bit is
already cleared (which is most likely the case in my understanding).
+ ? ? ? } while ((ndcr & NDCR_ND_RUN) && (timeout -- > 0));
+
+ ? ? ? if (timeout <= 0) {
+ ? ? ? ? ? ? ? ndcr &= ~(NDCR_ND_RUN);
Feel picky, but no parentheses are needed here for a single constant.
quoted hunk ↗ jump to hunk
+ ? ? ? ? ? ? ? nand_writel(info, NDCR, ndcr);
+ ? ? ? }
+}
+
+static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
? ? ? ? ? ? ? ?uint16_t cmd, int column, int page_addr)
?{
? ? ? ?const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
@@ -319,21 +363,18 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
? ? ? ?if (cmd == cmdset->program)
? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
-
- ? ? ? return 0;
?}

-static int prepare_erase_cmd(struct pxa3xx_nand_info *info,
+static void prepare_erase_cmd(struct pxa3xx_nand_info *info,
? ? ? ? ? ? ? ? ? ? ? ?uint16_t cmd, int page_addr)
?{
? ? ? ?info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
? ? ? ?info->ndcb1 = page_addr;
? ? ? ?info->ndcb2 = 0;
- ? ? ? return 0;
?}

-static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
+static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
?{
? ? ? ?const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
@@ -351,10 +392,7 @@ static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
? ? ? ?} else if (cmd == cmdset->reset || cmd == cmdset->lock ||
? ? ? ? ? ? ? ? ? cmd == cmdset->unlock) {
? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(5);
- ? ? ? } else
- ? ? ? ? ? ? ? return -EINVAL;
-
- ? ? ? return 0;
+ ? ? ? }
?}
If we want to remove the return type here, we must make sure that no
exception cases will happen, e.g. the *info and cmd passed to these
functions are absolute correct.
quoted hunk ↗ jump to hunk
?static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
@@ -402,41 +440,22 @@ static int write_cmd(struct pxa3xx_nand_info *info)
? ? ? ?return 0;
?}

-static int handle_data_pio(struct pxa3xx_nand_info *info)
+static void handle_data_pio(struct pxa3xx_nand_info *info)
?{
- ? ? ? int ret, timeout = CHIP_DELAY_TIMEOUT;
-
- ? ? ? switch (info->state) {
- ? ? ? case STATE_PIO_WRITING:
+ ? ? ? if (info->state & STATE_IS_WRITE) {
As mentioned, this isn't a correct state encoding. Taking an example, a
state here can never be STATE_IS_WRITE | STATE_IS_READING. Try avoid
using states like this.
quoted hunk ↗ jump to hunk
? ? ? ? ? ? ? ?__raw_writesl(info->mmio_base + NDDB, info->data_buff,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->data_size, 4));
? ? ? ? ? ? ? ?if (info->oob_size > 0)
? ? ? ? ? ? ? ? ? ? ? ?__raw_writesl(info->mmio_base + NDDB, info->oob_buff,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->oob_size, 4));
-
- ? ? ? ? ? ? ? enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
-
- ? ? ? ? ? ? ? ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
- ? ? ? ? ? ? ? if (!ret) {
- ? ? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "program command time out\n");
- ? ? ? ? ? ? ? ? ? ? ? return -1;
- ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? break;
- ? ? ? case STATE_PIO_READING:
+ ? ? ? }
+ ? ? ? else {
? ? ? ? ? ? ? ?__raw_readsl(info->mmio_base + NDDB, info->data_buff,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->data_size, 4));
? ? ? ? ? ? ? ?if (info->oob_size > 0)
? ? ? ? ? ? ? ? ? ? ? ?__raw_readsl(info->mmio_base + NDDB, info->oob_buff,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->oob_size, 4));
- ? ? ? ? ? ? ? break;
- ? ? ? default:
- ? ? ? ? ? ? ? printk(KERN_ERR "%s: invalid state %d\n", __func__,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->state);
- ? ? ? ? ? ? ? return -EINVAL;
? ? ? ?}
-
- ? ? ? info->state = STATE_READY;
- ? ? ? return 0;
?}

?static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out)
@@ -472,93 +491,59 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data)
? ? ? ?if (dcsr & DCSR_BUSERR) {
? ? ? ? ? ? ? ?info->retcode = ERR_DMABUSERR;
- ? ? ? ? ? ? ? complete(&info->cmd_complete);
? ? ? ?}

- ? ? ? if (info->state == STATE_DMA_WRITING) {
- ? ? ? ? ? ? ? info->state = STATE_DMA_DONE;
- ? ? ? ? ? ? ? enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
- ? ? ? } else {
- ? ? ? ? ? ? ? info->state = STATE_READY;
- ? ? ? ? ? ? ? complete(&info->cmd_complete);
- ? ? ? }
+ ? ? ? enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
?}

?static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
?{
? ? ? ?struct pxa3xx_nand_info *info = devid;
- ? ? ? unsigned int status;
+ ? ? ? unsigned int status, is_completed = 0;

? ? ? ?status = nand_readl(info, NDSR);

- ? ? ? if (status & (NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR)) {
- ? ? ? ? ? ? ? if (status & NDSR_DBERR)
- ? ? ? ? ? ? ? ? ? ? ? info->retcode = ERR_DBERR;
- ? ? ? ? ? ? ? else if (status & NDSR_SBERR)
- ? ? ? ? ? ? ? ? ? ? ? info->retcode = ERR_SBERR;
-
- ? ? ? ? ? ? ? disable_int(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR);
+ ? ? ? if (status & NDSR_DBERR)
+ ? ? ? ? ? ? ? info->retcode = ERR_DBERR;
+ ? ? ? if (status & NDSR_SBERR)
+ ? ? ? ? ? ? ? info->retcode = ERR_SBERR;
+ ? ? ? if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {

+ ? ? ? ? ? ? ? info->state |= STATE_DATA_PROCESSING;
+ ? ? ? ? ? ? ? /* whether use dma to transfer data */
? ? ? ? ? ? ? ?if (info->use_dma) {
- ? ? ? ? ? ? ? ? ? ? ? info->state = STATE_DMA_READING;
+ ? ? ? ? ? ? ? ? ? ? ? disable_int(info, NDSR_WRDREQ);
? ? ? ? ? ? ? ? ? ? ? ?start_data_dma(info, 0);
- ? ? ? ? ? ? ? } else {
- ? ? ? ? ? ? ? ? ? ? ? info->state = STATE_PIO_READING;
- ? ? ? ? ? ? ? ? ? ? ? complete(&info->cmd_complete);
- ? ? ? ? ? ? ? }
- ? ? ? } else if (status & NDSR_WRDREQ) {
- ? ? ? ? ? ? ? disable_int(info, NDSR_WRDREQ);
- ? ? ? ? ? ? ? if (info->use_dma) {
- ? ? ? ? ? ? ? ? ? ? ? info->state = STATE_DMA_WRITING;
- ? ? ? ? ? ? ? ? ? ? ? start_data_dma(info, 1);
- ? ? ? ? ? ? ? } else {
- ? ? ? ? ? ? ? ? ? ? ? info->state = STATE_PIO_WRITING;
- ? ? ? ? ? ? ? ? ? ? ? complete(&info->cmd_complete);
- ? ? ? ? ? ? ? }
- ? ? ? } else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) {
- ? ? ? ? ? ? ? if (status & NDSR_CS0_BBD)
- ? ? ? ? ? ? ? ? ? ? ? info->retcode = ERR_BBERR;
+ ? ? ? ? ? ? ? ? ? ? ? goto NORMAL_IRQ_EXIT;
+ ? ? ? ? ? ? ? } else
+ ? ? ? ? ? ? ? ? ? ? ? handle_data_pio(info);

- ? ? ? ? ? ? ? disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
- ? ? ? ? ? ? ? info->state = STATE_READY;
- ? ? ? ? ? ? ? complete(&info->cmd_complete);
+ ? ? ? ? ? ? ? info->state |= STATE_DATA_DONE;
? ? ? ?}
- ? ? ? nand_writel(info, NDSR, status);
- ? ? ? return IRQ_HANDLED;
-}
-
-static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event)
-{
- ? ? ? uint32_t ndcr;
- ? ? ? int ret, timeout = CHIP_DELAY_TIMEOUT;
-
- ? ? ? if (write_cmd(info)) {
- ? ? ? ? ? ? ? info->retcode = ERR_SENDCMD;
- ? ? ? ? ? ? ? goto fail_stop;
+ ? ? ? if (status & NDSR_CS0_CMDD) {
+ ? ? ? ? ? ? ? info->state |= STATE_CMD_DONE;
+ ? ? ? ? ? ? ? is_completed = 1;
? ? ? ?}
-
- ? ? ? info->state = STATE_CMD_HANDLE;
-
- ? ? ? enable_int(info, event);
-
- ? ? ? ret = wait_for_completion_timeout(&info->cmd_complete, timeout);
- ? ? ? if (!ret) {
- ? ? ? ? ? ? ? printk(KERN_ERR "command execution timed out\n");
- ? ? ? ? ? ? ? info->retcode = ERR_SENDCMD;
- ? ? ? ? ? ? ? goto fail_stop;
+ ? ? ? if (status & NDSR_FLASH_RDY)
+ ? ? ? ? ? ? ? info->state |= STATE_READY;
+ ? ? ? if (status & NDSR_CS0_PAGED)
+ ? ? ? ? ? ? ? info->state |= STATE_PAGE_DONE;
+
+ ? ? ? if (status & NDSR_WRCMDREQ) {
+ ? ? ? ? ? ? ? nand_writel(info, NDSR, NDSR_WRCMDREQ);
+ ? ? ? ? ? ? ? status &= ~NDSR_WRCMDREQ;
+ ? ? ? ? ? ? ? info->state |= STATE_CMD_WAIT_DONE;
+ ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb0);
+ ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb1);
+ ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb2);
? ? ? ?}

- ? ? ? if (info->use_dma == 0 && info->data_size > 0)
- ? ? ? ? ? ? ? if (handle_data_pio(info))
- ? ? ? ? ? ? ? ? ? ? ? goto fail_stop;
-
- ? ? ? return 0;
-
-fail_stop:
- ? ? ? ndcr = nand_readl(info, NDCR);
- ? ? ? nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
- ? ? ? udelay(10);
- ? ? ? return -ETIMEDOUT;
+ ? ? ? /* clear NDSR to let the controller exit the IRQ */
+ ? ? ? nand_writel(info, NDSR, status);
+ ? ? ? if (is_completed)
+ ? ? ? ? ? ? ? complete(&info->cmd_complete);
+NORMAL_IRQ_EXIT:
+ ? ? ? return IRQ_HANDLED;
?}

?static int pxa3xx_nand_dev_ready(struct mtd_info *mtd)
@@ -580,14 +565,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
?{
? ? ? ?struct pxa3xx_nand_info *info = mtd->priv;
? ? ? ?const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
- ? ? ? int ret;
+ ? ? ? int ret, exec_cmd = 0;

? ? ? ?info->use_dma = (use_dma) ? 1 : 0;
? ? ? ?info->use_ecc = 0;
? ? ? ?info->data_size = 0;
- ? ? ? info->state = STATE_READY;
-
- ? ? ? init_completion(&info->cmd_complete);
+ ? ? ? info->state = 0;

? ? ? ?switch (command) {
? ? ? ?case NAND_CMD_READOOB:
@@ -596,14 +579,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
? ? ? ? ? ? ? ?info->buf_start = mtd->writesize + column;
? ? ? ? ? ? ? ?memset(info->data_buff, 0xFF, info->buf_count);

- ? ? ? ? ? ? ? if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR);
-
+ ? ? ? ? ? ? ? prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
? ? ? ? ? ? ? ?/* We only are OOB, so if the data has error, does not matter */
? ? ? ? ? ? ? ?if (info->retcode == ERR_DBERR)
? ? ? ? ? ? ? ? ? ? ? ?info->retcode = ERR_NONE;
+
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;

? ? ? ?case NAND_CMD_READ0:
@@ -613,11 +594,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
? ? ? ? ? ? ? ?info->buf_count = mtd->writesize + mtd->oobsize;
? ? ? ? ? ? ? ?memset(info->data_buff, 0xFF, info->buf_count);

- ? ? ? ? ? ? ? if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR);
-
+ ? ? ? ? ? ? ? prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
? ? ? ? ? ? ? ?if (info->retcode == ERR_DBERR) {
? ? ? ? ? ? ? ? ? ? ? ?/* for blank page (all 0xff), HW will calculate its ECC as
? ? ? ? ? ? ? ? ? ? ? ? * 0, which is different from the ECC information within
@@ -626,6 +603,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
? ? ? ? ? ? ? ? ? ? ? ?if (is_buf_blank(info->data_buff, mtd->writesize))
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->retcode = ERR_NONE;
? ? ? ? ? ? ? ?}
+
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;
? ? ? ?case NAND_CMD_SEQIN:
? ? ? ? ? ? ? ?info->buf_start = column;
@@ -639,17 +618,14 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
? ? ? ?case NAND_CMD_PAGEPROG:
? ? ? ? ? ? ? ?info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;

- ? ? ? ? ? ? ? if (prepare_read_prog_cmd(info, cmdset->program,
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->seqin_column, info->seqin_page_addr))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);
+ ? ? ? ? ? ? ? prepare_read_prog_cmd(info, cmdset->program,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->seqin_column, info->seqin_page_addr);
+ ? ? ? ? ? ? ? info->state |= STATE_IS_WRITE;
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;
? ? ? ?case NAND_CMD_ERASE1:
- ? ? ? ? ? ? ? if (prepare_erase_cmd(info, cmdset->erase, page_addr))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
+ ? ? ? ? ? ? ? prepare_erase_cmd(info, cmdset->erase, page_addr);
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;
? ? ? ?case NAND_CMD_ERASE2:
? ? ? ? ? ? ? ?break;
@@ -660,39 +636,37 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
? ? ? ? ? ? ? ?info->buf_count = (command == NAND_CMD_READID) ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->read_id_bytes : 1;

- ? ? ? ? ? ? ? if (prepare_other_cmd(info, (command == NAND_CMD_READID) ?
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cmdset->read_id : cmdset->read_status))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);
+ ? ? ? ? ? ? ? prepare_other_cmd(info, (command == NAND_CMD_READID) ?
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cmdset->read_id : cmdset->read_status);
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;
? ? ? ?case NAND_CMD_RESET:
- ? ? ? ? ? ? ? if (prepare_other_cmd(info, cmdset->reset))
- ? ? ? ? ? ? ? ? ? ? ? break;
-
- ? ? ? ? ? ? ? ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);
- ? ? ? ? ? ? ? if (ret == 0) {
- ? ? ? ? ? ? ? ? ? ? ? int timeout = 2;
- ? ? ? ? ? ? ? ? ? ? ? uint32_t ndcr;
-
- ? ? ? ? ? ? ? ? ? ? ? while (timeout--) {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (nand_readl(info, NDSR) & NDSR_RDY)
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? msleep(10);
- ? ? ? ? ? ? ? ? ? ? ? }
-
- ? ? ? ? ? ? ? ? ? ? ? ndcr = nand_readl(info, NDCR);
- ? ? ? ? ? ? ? ? ? ? ? nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);
- ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? prepare_other_cmd(info, cmdset->reset);
+ ? ? ? ? ? ? ? exec_cmd = 1;
? ? ? ? ? ? ? ?break;
? ? ? ?default:
? ? ? ? ? ? ? ?printk(KERN_ERR "non-supported command.\n");
? ? ? ? ? ? ? ?break;
? ? ? ?}

- ? ? ? if (info->retcode == ERR_DBERR) {
- ? ? ? ? ? ? ? printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
- ? ? ? ? ? ? ? info->retcode = ERR_NONE;
+ ? ? ? if (exec_cmd) {
+ ? ? ? ? ? ? ? init_completion(&info->cmd_complete);
+ ? ? ? ? ? ? ? info->state |= STATE_CMD_PREPARED;
+ ? ? ? ? ? ? ? pxa3xx_nand_start(info);
+
+ ? ? ? ? ? ? ? ret = wait_for_completion_timeout(&info->cmd_complete,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CHIP_DELAY_TIMEOUT);
+ ? ? ? ? ? ? ? if (!ret) {
+ ? ? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "Wait time out!!!\n");
+ ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? /* Stop State Machine for next command cycle */
+ ? ? ? ? ? ? ? pxa3xx_nand_stop(info);
+ ? ? ? ? ? ? ? disable_int(info, NDCR_INT_MASK);
+ ? ? ? ? ? ? ? info->state &= ~STATE_CMD_PREPARED;
+ ? ? ? ? ? ? ? if (info->retcode == ERR_DBERR) {
+ ? ? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
+ ? ? ? ? ? ? ? ? ? ? ? info->retcode = ERR_NONE;
+ ? ? ? ? ? ? ? }
? ? ? ?}
?}
@@ -807,10 +781,7 @@ static int __readid(struct pxa3xx_nand_info *info, uint32_t *id)
? ? ? ?uint32_t ndcr;
? ? ? ?uint8_t ?id_buff[8];

- ? ? ? if (prepare_other_cmd(info, cmdset->read_id)) {
- ? ? ? ? ? ? ? printk(KERN_ERR "failed to prepare command\n");
- ? ? ? ? ? ? ? return -EINVAL;
- ? ? ? }
+ ? ? ? prepare_other_cmd(info, cmdset->read_id);

? ? ? ?/* Send command */
? ? ? ?if (write_cmd(info))
@@ -836,7 +807,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
?{
? ? ? ?struct platform_device *pdev = info->pdev;
? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
- ? ? ? uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
+ ? ? ? uint32_t ndcr = 0x0; /* enable all interrupts */

? ? ? ?if (f->page_size != 2048 && f->page_size != 512)
? ? ? ? ? ? ? ?return -EINVAL;
@@ -887,11 +858,12 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
? ? ? ?info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
? ? ? ?info->reg_ndcr = ndcr;

- ? ? ? if (__readid(info, &id))
+ ? ? ? pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0);
+ ? ? ? id = *((uint16_t *)(info->data_buff));
+ ? ? ? if (id == 0)
? ? ? ? ? ? ? ?return -ENODEV;

? ? ? ?/* Lookup the flash id */
- ? ? ? id = (id >> 8) & 0xff; ? ? ? ? ?/* device id is byte 2 */
? ? ? ?for (i = 0; nand_flash_ids[i].name != NULL; i++) {
? ? ? ? ? ? ? ?if (id == nand_flash_ids[i].id) {
? ? ? ? ? ? ? ? ? ? ? ?type = ?&nand_flash_ids[i];
@@ -935,8 +907,8 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
? ? ? ?/* we use default timing to detect id */
? ? ? ?f = DEFAULT_FLASH_TYPE;
? ? ? ?pxa3xx_nand_config_flash(info, f);
- ? ? ? if (__readid(info, &id))
- ? ? ? ? ? ? ? goto fail_detect;
+ ? ? ? pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0);
+ ? ? ? id = *((uint16_t *)(info->data_buff));

? ? ? ?for (i=0; i<ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; i++) {
? ? ? ? ? ? ? ?/* we first choose the flash definition from platfrom */
@@ -954,7 +926,6 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info,
? ? ? ?dev_warn(&info->pdev->dev,
? ? ? ? ? ? ? ? "failed to detect configured nand flash; found %04x instead of\n",
? ? ? ? ? ? ? ? id);
-fail_detect:
? ? ? ?return -ENODEV;
?}
@@ -1176,8 +1147,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
? ? ? ?platform_set_drvdata(pdev, NULL);

- ? ? ? del_mtd_device(mtd);
- ? ? ? del_mtd_partitions(mtd);
? ? ? ?irq = platform_get_irq(pdev, 0);
? ? ? ?if (irq >= 0)
? ? ? ? ? ? ? ?free_irq(irq, info);
@@ -1195,7 +1164,11 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
? ? ? ?clk_disable(info->clk);
? ? ? ?clk_put(info->clk);

- ? ? ? kfree(mtd);
+ ? ? ? if (mtd) {
+ ? ? ? ? ? ? ? del_mtd_device(mtd);
+ ? ? ? ? ? ? ? del_mtd_partitions(mtd);
+ ? ? ? ? ? ? ? kfree(mtd);
+ ? ? ? }
? ? ? ?return 0;
?}
@@ -1242,7 +1215,7 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
? ? ? ?struct mtd_info *mtd = info->mtd;

- ? ? ? if (info->state != STATE_READY) {
+ ? ? ? if (info->state & STATE_CMD_PREPARED) {
? ? ? ? ? ? ? ?dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
? ? ? ? ? ? ? ?return -EAGAIN;
? ? ? ?}
--
1.7.0.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help