[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