From mboxrd@z Thu Jan 1 00:00:00 1970 From: adrian.wenl@gmail.com (Lei Wen) Date: Fri, 08 Jul 2011 17:38:13 -0000 Subject: [PATCH] MTD: pxa3xx_nand: enable multiple chip select support In-Reply-To: References: <1308712645-5986-1-git-send-email-leiwen@marvell.com> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Daniel, On Wed, Jun 22, 2011 at 7:39 PM, Daniel Mack wrote: > On Wed, Jun 22, 2011 at 5:17 AM, Lei Wen wrote: >> Current pxa3xx_nand controller has two chip select which >> both be workable. This patch enable this feature. >> >> Update platform driver to support this feature. >> >> Another notice should be taken that: >> When you want to use this feature, you should not enable the >> keep configuration feature, for two chip select could be >> attached with different nand chip. The different page size >> and timing requirement make the keep configuration impossible. >> >> Signed-off-by: Lei Wen >> --- >> ?arch/arm/mach-mmp/aspenite.c ? ? ? ? ? ? ? ? | ? ?5 +- >> ?arch/arm/mach-pxa/cm-x300.c ? ? ? ? ? ? ? ? ?| ? ?5 +- >> ?arch/arm/mach-pxa/colibri-pxa3xx.c ? ? ? ? ? | ? ?5 +- >> ?arch/arm/mach-pxa/littleton.c ? ? ? ? ? ? ? ?| ? ?5 +- >> ?arch/arm/mach-pxa/mxm8x10.c ? ? ? ? ? ? ? ? ?| ? ?9 +- >> ?arch/arm/mach-pxa/raumfeld.c ? ? ? ? ? ? ? ? | ? ?5 +- >> ?arch/arm/mach-pxa/zylonite.c ? ? ? ? ? ? ? ? | ? ?5 +- >> ?arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | ? ?8 +- >> ?drivers/mtd/nand/pxa3xx_nand.c ? ? ? ? ? ? ? | ?735 +++++++++++++++----------- >> ?9 files changed, 444 insertions(+), 338 deletions(-) > > This patch doesn't apply for me on top of Linus' master branch. Which > tree are you based on currently? Actually it is based on Linux 3.0-rc2 and add two patches pending to l2-mtd-2.6.git already: mtd: pxa3xx_nand: fix nand detection issue mtd: pxa3xx_nand: Fix blank page ECC mismatch > > [...] > >> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c >> index 30689cc..259b8d5 100644 >> --- a/drivers/mtd/nand/pxa3xx_nand.c >> +++ b/drivers/mtd/nand/pxa3xx_nand.c >> @@ -92,11 +92,13 @@ >> ?#define NDCB0_ADDR_CYC_SHIFT ? (16) >> >> ?/* macros for registers read/write */ >> -#define nand_writel(info, off, val) ? ?\ >> - ? ? ? __raw_writel((val), (info)->mmio_base + (off)) >> +#define nand_writel(nand, off, val) ? ?\ >> + ? ? ? __raw_writel((val), (nand)->mmio_base + (off)) >> >> -#define nand_readl(info, off) ? ? ? ? ?\ >> - ? ? ? __raw_readl((info)->mmio_base + (off)) >> +#define nand_readl(nand, off) ? ? ? ? ?\ >> + ? ? ? __raw_readl((nand)->mmio_base + (off)) >> +#define get_mtd_by_info(info) ? ? ? ? ?\ >> + ? ? ? (struct mtd_info *)((void *)info - sizeof(struct mtd_info)) >> >> ?/* error code and state */ >> ?enum { >> @@ -110,6 +112,7 @@ enum { >> >> ?enum { >> ? ? ? ?STATE_IDLE = 0, >> + ? ? ? STATE_PREPARED, >> ? ? ? ?STATE_CMD_HANDLE, >> ? ? ? ?STATE_DMA_READING, >> ? ? ? ?STATE_DMA_WRITING, >> @@ -123,63 +126,63 @@ enum { >> ?struct pxa3xx_nand_info { >> ? ? ? ?struct nand_chip ? ? ? ?nand_chip; >> >> - ? ? ? struct nand_hw_control ?controller; >> - ? ? ? struct platform_device ? *pdev; >> ? ? ? ?struct pxa3xx_nand_cmdset *cmdset; >> + ? ? ? /* page size of attached chip */ >> + ? ? ? uint16_t ? ? ? ? ? ? ? ?page_size; >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? chip_select; >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? use_ecc; >> + >> + ? ? ? /* calculated from pxa3xx_nand_flash data */ >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? col_addr_cycles; >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? row_addr_cycles; >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? read_id_bytes; >> + >> + ? ? ? /* cached register value */ >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr; >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr0cs0; >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr1cs0; >> >> + ? ? ? void ? ? ? ? ? ? ? ? ? ?*nand_data; >> +}; >> + >> +struct pxa3xx_nand { >> ? ? ? ?struct clk ? ? ? ? ? ? ?*clk; >> ? ? ? ?void __iomem ? ? ? ? ? ?*mmio_base; >> ? ? ? ?unsigned long ? ? ? ? ? mmio_phys; >> + ? ? ? struct nand_hw_control ?controller; >> + ? ? ? struct completion ? ? ? cmd_complete; >> + ? ? ? struct platform_device ? *pdev; >> >> - ? ? ? unsigned int ? ? ? ? ? ?buf_start; >> - ? ? ? unsigned int ? ? ? ? ? ?buf_count; >> - >> - ? ? ? struct mtd_info ? ? ? ? *mtd; >> ? ? ? ?/* DMA information */ >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_dat; >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_cmd; >> - >> - ? ? ? unsigned char ? ? ? ? ? *data_buff; >> - ? ? ? unsigned char ? ? ? ? ? *oob_buff; >> - ? ? ? dma_addr_t ? ? ? ? ? ? ?data_buff_phys; >> - ? ? ? size_t ? ? ? ? ? ? ? ? ?data_buff_size; >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? data_dma_ch; >> - ? ? ? struct pxa_dma_desc ? ? *data_desc; >> + ? ? ? dma_addr_t ? ? ? ? ? ? ?data_buff_phys; >> ? ? ? ?dma_addr_t ? ? ? ? ? ? ?data_desc_addr; >> + ? ? ? struct pxa_dma_desc ? ? *data_desc; >> >> - ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr; >> - >> - ? ? ? /* saved column/page_addr during CMD_SEQIN */ >> - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_column; >> - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_page_addr; >> + ? ? ? struct pxa3xx_nand_info *info[NUM_CHIP_SELECT]; >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?command; >> + ? ? ? uint16_t ? ? ? ? ? ? ? ?data_size; ? ? ?/* data size in FIFO */ >> + ? ? ? uint16_t ? ? ? ? ? ? ? ?oob_size; >> + ? ? ? unsigned char ? ? ? ? ? *data_buff; >> + ? ? ? unsigned char ? ? ? ? ? *oob_buff; >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?buf_start; >> + ? ? ? uint32_t ? ? ? ? ? ? ? ?buf_count; >> >> ? ? ? ?/* relate to the command */ >> ? ? ? ?unsigned int ? ? ? ? ? ?state; >> - >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? chip_select; >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? use_ecc; ? ? ? ?/* use HW ECC ? */ >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? use_dma; ? ? ? ?/* use DMA ? */ >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? is_ready; >> - >> - ? ? ? unsigned int ? ? ? ? ? ?page_size; ? ? ?/* page size of attached chip */ >> - ? ? ? unsigned int ? ? ? ? ? ?data_size; ? ? ?/* data size in FIFO */ >> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? retcode; >> - ? ? ? struct completion ? ? ? cmd_complete; >> >> ? ? ? ?/* generated NDCBx register values */ >> + ? ? ? uint8_t ? ? ? ? ? ? ? ? total_cmds; >> ? ? ? ?uint32_t ? ? ? ? ? ? ? ?ndcb0; >> ? ? ? ?uint32_t ? ? ? ? ? ? ? ?ndcb1; >> ? ? ? ?uint32_t ? ? ? ? ? ? ? ?ndcb2; >> - >> - ? ? ? /* timing calcuted from setting */ >> - ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr0cs0; >> - ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr1cs0; >> - >> - ? ? ? /* calculated from pxa3xx_nand_flash data */ >> - ? ? ? size_t ? ? ? ? ?oob_size; >> - ? ? ? size_t ? ? ? ? ?read_id_bytes; >> - >> - ? ? ? unsigned int ? ?col_addr_cycles; >> - ? ? ? unsigned int ? ?row_addr_cycles; >> ?}; >> >> ?static int use_dma = 1; >> @@ -225,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { >> ?/* Define a default flash type setting serve as flash detecting only */ >> ?#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) >> >> -const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; >> +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; >> >> ?#define NDTR0_tCH(c) ? (min((c), 7) << 19) >> ?#define NDTR0_tCS(c) ? (min((c), 7) << 16) >> @@ -244,9 +247,11 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; >> ?static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct pxa3xx_nand_timing *t) >> ?{ >> - ? ? ? unsigned long nand_clk = clk_get_rate(info->clk); >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? unsigned long nand_clk; >> ? ? ? ?uint32_t ndtr0, ndtr1; >> >> + ? ? ? nand_clk = clk_get_rate(nand->clk); >> ? ? ? ?ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | >> ? ? ? ? ? ? ? ?NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | >> ? ? ? ? ? ? ? ?NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) | >> @@ -260,26 +265,27 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, >> >> ? ? ? ?info->ndtr0cs0 = ndtr0; >> ? ? ? ?info->ndtr1cs0 = ndtr1; >> - ? ? ? nand_writel(info, NDTR0CS0, ndtr0); >> - ? ? ? nand_writel(info, NDTR1CS0, ndtr1); >> + ? ? ? nand_writel(nand, NDTR0CS0, ndtr0); >> + ? ? ? nand_writel(nand, NDTR1CS0, ndtr1); >> ?} >> >> ?static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) >> ?{ >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> ? ? ? ?int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; >> >> - ? ? ? info->data_size = info->page_size; >> + ? ? ? nand->data_size = info->page_size; >> ? ? ? ?if (!oob_enable) { >> - ? ? ? ? ? ? ? info->oob_size = 0; >> + ? ? ? ? ? ? ? nand->oob_size = 0; >> ? ? ? ? ? ? ? ?return; >> ? ? ? ?} >> >> ? ? ? ?switch (info->page_size) { >> ? ? ? ?case 2048: >> - ? ? ? ? ? ? ? info->oob_size = (info->use_ecc) ? 40 : 64; >> + ? ? ? ? ? ? ? nand->oob_size = (info->use_ecc) ? 40 : 64; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case 512: >> - ? ? ? ? ? ? ? info->oob_size = (info->use_ecc) ? 8 : 16; >> + ? ? ? ? ? ? ? nand->oob_size = (info->use_ecc) ? 8 : 16; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?} >> ?} >> @@ -290,185 +296,189 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) >> ?* 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) >> +static void pxa3xx_nand_start(struct pxa3xx_nand *nand) >> ?{ >> + ? ? ? struct pxa3xx_nand_info *info; >> ? ? ? ?uint32_t ndcr; >> >> + ? ? ? info = nand->info[nand->chip_select]; >> ? ? ? ?ndcr = info->reg_ndcr; >> - ? ? ? ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; >> - ? ? ? ndcr |= info->use_dma ? NDCR_DMA_EN : 0; >> + ? ? ? ndcr |= nand->use_ecc ? NDCR_ECC_EN : 0; >> + ? ? ? ndcr |= nand->use_dma ? NDCR_DMA_EN : 0; >> ? ? ? ?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); >> + ? ? ? nand_writel(nand, NDCR, 0); >> + ? ? ? nand_writel(nand, NDSR, NDSR_MASK); >> + ? ? ? nand_writel(nand, NDCR, ndcr); >> ?} >> >> -static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) >> +static void pxa3xx_nand_stop(struct pxa3xx_nand *nand) >> ?{ >> ? ? ? ?uint32_t ndcr; >> ? ? ? ?int timeout = NAND_STOP_DELAY; >> >> ? ? ? ?/* wait RUN bit in NDCR become 0 */ >> - ? ? ? ndcr = nand_readl(info, NDCR); >> + ? ? ? ndcr = nand_readl(nand, NDCR); >> ? ? ? ?while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) { >> - ? ? ? ? ? ? ? ndcr = nand_readl(info, NDCR); >> + ? ? ? ? ? ? ? ndcr = nand_readl(nand, NDCR); >> ? ? ? ? ? ? ? ?udelay(1); >> ? ? ? ?} >> >> ? ? ? ?if (timeout <= 0) { >> ? ? ? ? ? ? ? ?ndcr &= ~NDCR_ND_RUN; >> - ? ? ? ? ? ? ? nand_writel(info, NDCR, ndcr); >> + ? ? ? ? ? ? ? nand_writel(nand, NDCR, ndcr); >> ? ? ? ?} >> ? ? ? ?/* clear status bits */ >> - ? ? ? nand_writel(info, NDSR, NDSR_MASK); >> + ? ? ? nand_writel(nand, NDSR, NDSR_MASK); >> ?} >> >> -static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) >> +static void enable_int(struct pxa3xx_nand *nand, uint32_t int_mask) >> ?{ >> ? ? ? ?uint32_t ndcr; >> >> - ? ? ? ndcr = nand_readl(info, NDCR); >> - ? ? ? nand_writel(info, NDCR, ndcr & ~int_mask); >> + ? ? ? ndcr = nand_readl(nand, NDCR); >> + ? ? ? nand_writel(nand, NDCR, ndcr & ~int_mask); >> ?} >> >> -static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) >> +static void disable_int(struct pxa3xx_nand *nand, uint32_t int_mask) >> ?{ >> ? ? ? ?uint32_t ndcr; >> >> - ? ? ? ndcr = nand_readl(info, NDCR); >> - ? ? ? nand_writel(info, NDCR, ndcr | int_mask); >> + ? ? ? ndcr = nand_readl(nand, NDCR); >> + ? ? ? nand_writel(nand, NDCR, ndcr | int_mask); >> ?} >> >> -static void handle_data_pio(struct pxa3xx_nand_info *info) >> +static void handle_data_pio(struct pxa3xx_nand *nand) >> ?{ >> - ? ? ? switch (info->state) { >> + ? ? ? switch (nand->state) { >> ? ? ? ?case STATE_PIO_WRITING: >> - ? ? ? ? ? ? ? __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)); >> + ? ? ? ? ? ? ? __raw_writesl(nand->mmio_base + NDDB, nand->data_buff, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DIV_ROUND_UP(nand->data_size, 4)); >> + ? ? ? ? ? ? ? if (nand->oob_size > 0) >> + ? ? ? ? ? ? ? ? ? ? ? __raw_writesl(nand->mmio_base + NDDB, nand->oob_buff, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DIV_ROUND_UP(nand->oob_size, 4)); >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case STATE_PIO_READING: >> - ? ? ? ? ? ? ? __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)); >> + ? ? ? ? ? ? ? __raw_readsl(nand->mmio_base + NDDB, nand->data_buff, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DIV_ROUND_UP(nand->data_size, 4)); >> + ? ? ? ? ? ? ? if (nand->oob_size > 0) >> + ? ? ? ? ? ? ? ? ? ? ? __raw_readsl(nand->mmio_base + NDDB, nand->oob_buff, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DIV_ROUND_UP(nand->oob_size, 4)); >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?default: >> ? ? ? ? ? ? ? ?printk(KERN_ERR "%s: invalid state %d\n", __func__, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->state); >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nand->state); > > Can't you use dev_err() here? Good suggestion, I would make this change. > >> ? ? ? ? ? ? ? ?BUG(); > > Is crashing the entire kernel really necessary here? > >> ? ? ? ?} >> ?} >> >> -static void start_data_dma(struct pxa3xx_nand_info *info) >> +static void start_data_dma(struct pxa3xx_nand *nand) >> ?{ >> - ? ? ? struct pxa_dma_desc *desc = info->data_desc; >> - ? ? ? int dma_len = ALIGN(info->data_size + info->oob_size, 32); >> + ? ? ? struct pxa_dma_desc *desc = nand->data_desc; >> + ? ? ? int dma_len = ALIGN(nand->data_size + nand->oob_size, 32); >> >> ? ? ? ?desc->ddadr = DDADR_STOP; >> ? ? ? ?desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; >> >> - ? ? ? switch (info->state) { >> + ? ? ? switch (nand->state) { >> ? ? ? ?case STATE_DMA_WRITING: >> - ? ? ? ? ? ? ? desc->dsadr = info->data_buff_phys; >> - ? ? ? ? ? ? ? desc->dtadr = info->mmio_phys + NDDB; >> + ? ? ? ? ? ? ? desc->dsadr = nand->data_buff_phys; >> + ? ? ? ? ? ? ? desc->dtadr = nand->mmio_phys + NDDB; >> ? ? ? ? ? ? ? ?desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case STATE_DMA_READING: >> - ? ? ? ? ? ? ? desc->dtadr = info->data_buff_phys; >> - ? ? ? ? ? ? ? desc->dsadr = info->mmio_phys + NDDB; >> + ? ? ? ? ? ? ? desc->dtadr = nand->data_buff_phys; >> + ? ? ? ? ? ? ? desc->dsadr = nand->mmio_phys + NDDB; >> ? ? ? ? ? ? ? ?desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?default: >> ? ? ? ? ? ? ? ?printk(KERN_ERR "%s: invalid state %d\n", __func__, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->state); >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nand->state); >> ? ? ? ? ? ? ? ?BUG(); >> ? ? ? ?} >> >> - ? ? ? DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; >> - ? ? ? DDADR(info->data_dma_ch) = info->data_desc_addr; >> - ? ? ? DCSR(info->data_dma_ch) |= DCSR_RUN; >> + ? ? ? DRCMR(nand->drcmr_dat) = DRCMR_MAPVLD | nand->data_dma_ch; >> + ? ? ? DDADR(nand->data_dma_ch) = nand->data_desc_addr; >> + ? ? ? DCSR(nand->data_dma_ch) |= DCSR_RUN; >> ?} >> >> ?static void pxa3xx_nand_data_dma_irq(int channel, void *data) >> ?{ >> - ? ? ? struct pxa3xx_nand_info *info = data; >> + ? ? ? struct pxa3xx_nand *nand = data; >> ? ? ? ?uint32_t dcsr; >> >> ? ? ? ?dcsr = DCSR(channel); >> ? ? ? ?DCSR(channel) = dcsr; >> >> ? ? ? ?if (dcsr & DCSR_BUSERR) { >> - ? ? ? ? ? ? ? info->retcode = ERR_DMABUSERR; >> + ? ? ? ? ? ? ? nand->retcode = ERR_DMABUSERR; >> ? ? ? ?} >> >> - ? ? ? info->state = STATE_DMA_DONE; >> - ? ? ? enable_int(info, NDCR_INT_MASK); >> - ? ? ? nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); >> + ? ? ? nand->state = STATE_DMA_DONE; >> + ? ? ? enable_int(nand, NDCR_INT_MASK); >> + ? ? ? nand_writel(nand, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); >> ?} >> >> ?static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) >> ?{ >> - ? ? ? struct pxa3xx_nand_info *info = devid; >> - ? ? ? unsigned int status, is_completed = 0; >> + ? ? ? struct pxa3xx_nand *nand = devid; >> + ? ? ? struct pxa3xx_nand_info *info; >> + ? ? ? unsigned int status, is_completed = 0, cs; >> + ? ? ? unsigned int ready, cmd_done, page_done, badblock_detect; >> >> - ? ? ? status = nand_readl(info, NDSR); >> + ? ? ? cs ? ? ? ? ? ? ?= nand->chip_select; >> + ? ? ? ready ? ? ? ? ? = (cs) ? NDSR_RDY : NDSR_FLASH_RDY; >> + ? ? ? cmd_done ? ? ? ?= (cs) ? NDSR_CS1_CMDD : NDSR_CS0_CMDD; >> + ? ? ? page_done ? ? ? = (cs) ? NDSR_CS1_PAGED : NDSR_CS0_PAGED; >> + ? ? ? badblock_detect = (cs) ? NDSR_CS1_BBD : NDSR_CS0_BBD; >> + ? ? ? info ? ? ? ? ? ?= nand->info[cs]; >> >> + ? ? ? status = nand_readl(nand, NDSR); >> ? ? ? ?if (status & NDSR_DBERR) >> - ? ? ? ? ? ? ? info->retcode = ERR_DBERR; >> + ? ? ? ? ? ? ? nand->retcode = ERR_DBERR; >> ? ? ? ?if (status & NDSR_SBERR) >> - ? ? ? ? ? ? ? info->retcode = ERR_SBERR; >> + ? ? ? ? ? ? ? nand->retcode = ERR_SBERR; >> ? ? ? ?if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { >> ? ? ? ? ? ? ? ?/* whether use dma to transfer data */ >> - ? ? ? ? ? ? ? if (info->use_dma) { >> - ? ? ? ? ? ? ? ? ? ? ? disable_int(info, NDCR_INT_MASK); >> - ? ? ? ? ? ? ? ? ? ? ? info->state = (status & NDSR_RDDREQ) ? >> + ? ? ? ? ? ? ? if (nand->use_dma) { >> + ? ? ? ? ? ? ? ? ? ? ? disable_int(nand, NDCR_INT_MASK); >> + ? ? ? ? ? ? ? ? ? ? ? nand->state = (status & NDSR_RDDREQ) ? >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?STATE_DMA_READING : STATE_DMA_WRITING; >> - ? ? ? ? ? ? ? ? ? ? ? start_data_dma(info); >> + ? ? ? ? ? ? ? ? ? ? ? start_data_dma(nand); >> ? ? ? ? ? ? ? ? ? ? ? ?goto NORMAL_IRQ_EXIT; >> ? ? ? ? ? ? ? ?} else { >> - ? ? ? ? ? ? ? ? ? ? ? info->state = (status & NDSR_RDDREQ) ? >> + ? ? ? ? ? ? ? ? ? ? ? nand->state = (status & NDSR_RDDREQ) ? >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?STATE_PIO_READING : STATE_PIO_WRITING; >> - ? ? ? ? ? ? ? ? ? ? ? handle_data_pio(info); >> + ? ? ? ? ? ? ? ? ? ? ? handle_data_pio(nand); >> ? ? ? ? ? ? ? ?} >> ? ? ? ?} >> - ? ? ? if (status & NDSR_CS0_CMDD) { >> - ? ? ? ? ? ? ? info->state = STATE_CMD_DONE; >> + ? ? ? if (status & cmd_done) { >> + ? ? ? ? ? ? ? nand->state = STATE_CMD_DONE; >> ? ? ? ? ? ? ? ?is_completed = 1; >> ? ? ? ?} >> - ? ? ? if (status & NDSR_FLASH_RDY) { >> - ? ? ? ? ? ? ? info->is_ready = 1; >> - ? ? ? ? ? ? ? info->state = STATE_READY; >> + ? ? ? if (status & ready) { >> + ? ? ? ? ? ? ? nand->is_ready = 1; >> + ? ? ? ? ? ? ? nand->state = STATE_READY; >> ? ? ? ?} >> >> ? ? ? ?if (status & NDSR_WRCMDREQ) { >> - ? ? ? ? ? ? ? nand_writel(info, NDSR, NDSR_WRCMDREQ); >> + ? ? ? ? ? ? ? nand_writel(nand, NDSR, NDSR_WRCMDREQ); >> ? ? ? ? ? ? ? ?status &= ~NDSR_WRCMDREQ; >> - ? ? ? ? ? ? ? info->state = STATE_CMD_HANDLE; >> - ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb0); >> - ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb1); >> - ? ? ? ? ? ? ? nand_writel(info, NDCB0, info->ndcb2); >> + ? ? ? ? ? ? ? nand->state = STATE_CMD_HANDLE; >> + ? ? ? ? ? ? ? nand_writel(nand, NDCB0, nand->ndcb0); >> + ? ? ? ? ? ? ? nand_writel(nand, NDCB0, nand->ndcb1); >> + ? ? ? ? ? ? ? nand_writel(nand, NDCB0, nand->ndcb2); >> ? ? ? ?} >> >> ? ? ? ?/* clear NDSR to let the controller exit the IRQ */ >> - ? ? ? nand_writel(info, NDSR, status); >> + ? ? ? nand_writel(nand, NDSR, status); >> ? ? ? ?if (is_completed) >> - ? ? ? ? ? ? ? complete(&info->cmd_complete); >> + ? ? ? ? ? ? ? complete(&nand->cmd_complete); >> ?NORMAL_IRQ_EXIT: >> ? ? ? ?return IRQ_HANDLED; >> ?} >> >> -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) >> -{ >> - ? ? ? struct pxa3xx_nand_info *info = mtd->priv; >> - ? ? ? return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; >> -} >> - >> ?static inline int is_buf_blank(uint8_t *buf, size_t len) >> ?{ >> ? ? ? ?for (; len > 0; len--) >> @@ -477,42 +487,49 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) >> ? ? ? ?return 1; >> ?} >> >> -static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, >> +static int prepare_command_pool(struct pxa3xx_nand *nand, int command, >> ? ? ? ? ? ? ? ?uint16_t column, int page_addr) >> ?{ >> ? ? ? ?uint16_t cmd; >> ? ? ? ?int addr_cycle, exec_cmd, ndcb0; >> - ? ? ? struct mtd_info *mtd = info->mtd; >> + ? ? ? struct mtd_info *mtd; >> + ? ? ? struct pxa3xx_nand_info *info = nand->info[nand->chip_select]; >> >> - ? ? ? ndcb0 = 0; >> + ? ? ? mtd = get_mtd_by_info(info); >> + ? ? ? ndcb0 = (nand->chip_select) ? NDCB0_CSEL : 0; >> ? ? ? ?addr_cycle = 0; >> ? ? ? ?exec_cmd = 1; >> >> ? ? ? ?/* reset data and oob column point to handle data */ >> - ? ? ? info->buf_start ? ? ? ? = 0; >> - ? ? ? info->buf_count ? ? ? ? = 0; >> - ? ? ? info->oob_size ? ? ? ? ?= 0; >> - ? ? ? info->use_ecc ? ? ? ? ? = 0; >> - ? ? ? info->is_ready ? ? ? ? ?= 0; >> - ? ? ? info->retcode ? ? ? ? ? = ERR_NONE; >> + ? ? ? nand->buf_start ? ? ? ? = 0; >> + ? ? ? nand->buf_count ? ? ? ? = 0; >> + ? ? ? nand->oob_size ? ? ? ? ?= 0; >> + ? ? ? nand->use_ecc ? ? ? ? ? = 0; >> + ? ? ? nand->is_ready ? ? ? ? ?= 0; >> + ? ? ? nand->retcode ? ? ? ? ? = ERR_NONE; >> + ? ? ? nand->data_size ? ? ? ? = 0; >> + ? ? ? nand->use_dma ? ? ? ? ? = 0; >> + ? ? ? nand->command ? ? ? ? ? = command; >> >> ? ? ? ?switch (command) { >> ? ? ? ?case NAND_CMD_READ0: >> ? ? ? ?case NAND_CMD_PAGEPROG: >> - ? ? ? ? ? ? ? info->use_ecc = 1; >> + ? ? ? ? ? ? ? nand->use_ecc = 1; >> ? ? ? ?case NAND_CMD_READOOB: >> ? ? ? ? ? ? ? ?pxa3xx_set_datasize(info); >> + ? ? ? ? ? ? ? nand->oob_buff = nand->data_buff + nand->data_size; >> + ? ? ? ? ? ? ? nand->use_dma = use_dma; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case NAND_CMD_SEQIN: >> ? ? ? ? ? ? ? ?exec_cmd = 0; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?default: >> - ? ? ? ? ? ? ? info->ndcb1 = 0; >> - ? ? ? ? ? ? ? info->ndcb2 = 0; >> + ? ? ? ? ? ? ? nand->ndcb1 = 0; >> + ? ? ? ? ? ? ? nand->ndcb2 = 0; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?} >> >> - ? ? ? info->ndcb0 = ndcb0; >> + ? ? ? nand->ndcb0 = ndcb0; >> ? ? ? ?addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?+ info->col_addr_cycles); >> >> @@ -521,16 +538,16 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, >> ? ? ? ?case NAND_CMD_READ0: >> ? ? ? ? ? ? ? ?cmd = info->cmdset->read1; >> ? ? ? ? ? ? ? ?if (command == NAND_CMD_READOOB) >> - ? ? ? ? ? ? ? ? ? ? ? info->buf_start = mtd->writesize + column; >> + ? ? ? ? ? ? ? ? ? ? ? nand->buf_start = mtd->writesize + column; >> ? ? ? ? ? ? ? ?else >> - ? ? ? ? ? ? ? ? ? ? ? info->buf_start = column; >> + ? ? ? ? ? ? ? ? ? ? ? nand->buf_start = column; >> >> ? ? ? ? ? ? ? ?if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) >> - ? ? ? ? ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(0) >> + ? ? ? ? ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(0) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| addr_cycle >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (cmd & NDCB0_CMD1_MASK); >> ? ? ? ? ? ? ? ?else >> - ? ? ? ? ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(0) >> + ? ? ? ? ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(0) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_DBC >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| addr_cycle >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; >> @@ -538,34 +555,34 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, >> ? ? ? ?case NAND_CMD_SEQIN: >> ? ? ? ? ? ? ? ?/* small page addr setting */ >> ? ? ? ? ? ? ? ?if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { >> - ? ? ? ? ? ? ? ? ? ? ? info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) >> + ? ? ? ? ? ? ? ? ? ? ? nand->ndcb1 = ((page_addr & 0xFFFFFF) << 8) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (column & 0xFF); >> >> - ? ? ? ? ? ? ? ? ? ? ? info->ndcb2 = 0; >> + ? ? ? ? ? ? ? ? ? ? ? nand->ndcb2 = 0; >> ? ? ? ? ? ? ? ?} else { >> - ? ? ? ? ? ? ? ? ? ? ? info->ndcb1 = ((page_addr & 0xFFFF) << 16) >> + ? ? ? ? ? ? ? ? ? ? ? nand->ndcb1 = ((page_addr & 0xFFFF) << 16) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (column & 0xFFFF); >> >> ? ? ? ? ? ? ? ? ? ? ? ?if (page_addr & 0xFF0000) >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->ndcb2 = (page_addr & 0xFF0000) >> 16; >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nand->ndcb2 = (page_addr & 0xFF0000) >> 16; >> ? ? ? ? ? ? ? ? ? ? ? ?else >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->ndcb2 = 0; >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nand->ndcb2 = 0; >> ? ? ? ? ? ? ? ?} >> >> - ? ? ? ? ? ? ? info->buf_count = mtd->writesize + mtd->oobsize; >> - ? ? ? ? ? ? ? memset(info->data_buff, 0xFF, info->buf_count); >> + ? ? ? ? ? ? ? nand->buf_count = mtd->writesize + mtd->oobsize; >> + ? ? ? ? ? ? ? memset(nand->data_buff, 0xFF, nand->buf_count); >> >> ? ? ? ? ? ? ? ?break; >> >> ? ? ? ?case NAND_CMD_PAGEPROG: >> - ? ? ? ? ? ? ? if (is_buf_blank(info->data_buff, >> + ? ? ? ? ? ? ? if (is_buf_blank(nand->data_buff, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(mtd->writesize + mtd->oobsize))) { >> ? ? ? ? ? ? ? ? ? ? ? ?exec_cmd = 0; >> ? ? ? ? ? ? ? ? ? ? ? ?break; >> ? ? ? ? ? ? ? ?} >> >> ? ? ? ? ? ? ? ?cmd = info->cmdset->program; >> - ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(0x1) >> + ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(0x1) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ST_ROW_EN >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_DBC >> @@ -575,37 +592,37 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, >> >> ? ? ? ?case NAND_CMD_READID: >> ? ? ? ? ? ? ? ?cmd = info->cmdset->read_id; >> - ? ? ? ? ? ? ? info->buf_count = info->read_id_bytes; >> - ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(3) >> + ? ? ? ? ? ? ? nand->buf_count = info->read_id_bytes; >> + ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(3) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; >> >> - ? ? ? ? ? ? ? info->data_size = 8; >> + ? ? ? ? ? ? ? nand->data_size = 8; >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case NAND_CMD_STATUS: >> ? ? ? ? ? ? ? ?cmd = info->cmdset->read_status; >> - ? ? ? ? ? ? ? info->buf_count = 1; >> - ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(4) >> + ? ? ? ? ? ? ? nand->buf_count = 1; >> + ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(4) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; >> >> - ? ? ? ? ? ? ? info->data_size = 8; >> + ? ? ? ? ? ? ? nand->data_size = 8; >> ? ? ? ? ? ? ? ?break; >> >> ? ? ? ?case NAND_CMD_ERASE1: >> ? ? ? ? ? ? ? ?cmd = info->cmdset->erase; >> - ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(2) >> + ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(2) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(3) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_DBC >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; >> - ? ? ? ? ? ? ? info->ndcb1 = page_addr; >> - ? ? ? ? ? ? ? info->ndcb2 = 0; >> + ? ? ? ? ? ? ? nand->ndcb1 = page_addr; >> + ? ? ? ? ? ? ? nand->ndcb2 = 0; >> >> ? ? ? ? ? ? ? ?break; >> ? ? ? ?case NAND_CMD_RESET: >> ? ? ? ? ? ? ? ?cmd = info->cmdset->reset; >> - ? ? ? ? ? ? ? info->ndcb0 |= NDCB0_CMD_TYPE(5) >> + ? ? ? ? ? ? ? nand->ndcb0 |= NDCB0_CMD_TYPE(5) >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; >> >> ? ? ? ? ? ? ? ?break; >> @@ -628,6 +645,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int column, int page_addr) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> ? ? ? ?int ret, exec_cmd; >> >> ? ? ? ?/* >> @@ -638,20 +656,32 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, >> ? ? ? ?if (info->reg_ndcr & NDCR_DWIDTH_M) >> ? ? ? ? ? ? ? ?column /= 2; >> >> - ? ? ? exec_cmd = prepare_command_pool(info, command, column, page_addr); >> + ? ? ? /* >> + ? ? ? ?* There may be different NAND chip hooked to >> + ? ? ? ?* different chip select, so check whether >> + ? ? ? ?* chip select has been changed, if yes, reset the timing >> + ? ? ? ?*/ >> + ? ? ? if (nand->chip_select != info->chip_select) { >> + ? ? ? ? ? ? ? nand->chip_select = info->chip_select; >> + ? ? ? ? ? ? ? nand_writel(nand, NDTR0CS0, info->ndtr0cs0); >> + ? ? ? ? ? ? ? nand_writel(nand, NDTR1CS0, info->ndtr1cs0); >> + ? ? ? } >> + >> + ? ? ? nand->state = STATE_PREPARED; >> + ? ? ? exec_cmd = prepare_command_pool(nand, command, column, page_addr); >> ? ? ? ?if (exec_cmd) { >> - ? ? ? ? ? ? ? init_completion(&info->cmd_complete); >> - ? ? ? ? ? ? ? pxa3xx_nand_start(info); >> + ? ? ? ? ? ? ? init_completion(&nand->cmd_complete); >> + ? ? ? ? ? ? ? pxa3xx_nand_start(nand); >> >> - ? ? ? ? ? ? ? ret = wait_for_completion_timeout(&info->cmd_complete, >> + ? ? ? ? ? ? ? ret = wait_for_completion_timeout(&nand->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); >> + ? ? ? ? ? ? ? ? ? ? ? pxa3xx_nand_stop(nand); >> ? ? ? ? ? ? ? ?} >> - ? ? ? ? ? ? ? info->state = STATE_IDLE; >> ? ? ? ?} >> + ? ? ? nand->state = STATE_IDLE; >> ?} >> >> ?static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, >> @@ -665,11 +695,12 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, >> ? ? ? ? ? ? ? ?struct nand_chip *chip, uint8_t *buf, int page) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> >> ? ? ? ?chip->read_buf(mtd, buf, mtd->writesize); >> ? ? ? ?chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); >> >> - ? ? ? if (info->retcode == ERR_SBERR) { >> + ? ? ? if (nand->retcode == ERR_SBERR) { >> ? ? ? ? ? ? ? ?switch (info->use_ecc) { >> ? ? ? ? ? ? ? ?case 1: >> ? ? ? ? ? ? ? ? ? ? ? ?mtd->ecc_stats.corrected++; >> @@ -678,14 +709,14 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, >> ? ? ? ? ? ? ? ?default: >> ? ? ? ? ? ? ? ? ? ? ? ?break; >> ? ? ? ? ? ? ? ?} >> - ? ? ? } else if (info->retcode == ERR_DBERR) { >> + ? ? ? } else if (nand->retcode == ERR_DBERR) { >> ? ? ? ? ? ? ? ?/* >> ? ? ? ? ? ? ? ? * for blank page (all 0xff), HW will calculate its ECC as >> ? ? ? ? ? ? ? ? * 0, which is different from the ECC information within >> ? ? ? ? ? ? ? ? * OOB, ignore such double bit errors >> ? ? ? ? ? ? ? ? */ >> ? ? ? ? ? ? ? ?if (is_buf_blank(buf, mtd->writesize)) >> - ? ? ? ? ? ? ? ? ? ? ? info->retcode = ERR_NONE; >> + ? ? ? ? ? ? ? ? ? ? ? nand->retcode = ERR_NONE; >> ? ? ? ? ? ? ? ?else >> ? ? ? ? ? ? ? ? ? ? ? ?mtd->ecc_stats.failed++; >> ? ? ? ?} >> @@ -696,11 +727,12 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, >> ?static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> ? ? ? ?char retval = 0xFF; >> >> - ? ? ? if (info->buf_start < info->buf_count) >> + ? ? ? if (nand->buf_start < nand->buf_count) >> ? ? ? ? ? ? ? ?/* Has just send a new command? */ >> - ? ? ? ? ? ? ? retval = info->data_buff[info->buf_start++]; >> + ? ? ? ? ? ? ? retval = nand->data_buff[nand->buf_start++]; >> >> ? ? ? ?return retval; >> ?} >> @@ -708,11 +740,12 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) >> ?static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> ? ? ? ?u16 retval = 0xFFFF; >> >> - ? ? ? if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { >> - ? ? ? ? ? ? ? retval = *((u16 *)(info->data_buff+info->buf_start)); >> - ? ? ? ? ? ? ? info->buf_start += 2; >> + ? ? ? if (!(nand->buf_start & 0x01) && nand->buf_start < nand->buf_count) { >> + ? ? ? ? ? ? ? retval = *((u16 *)(nand->data_buff+nand->buf_start)); >> + ? ? ? ? ? ? ? nand->buf_start += 2; >> ? ? ? ?} >> ? ? ? ?return retval; >> ?} >> @@ -720,20 +753,22 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) >> ?static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> - ? ? ? int real_len = min_t(size_t, len, info->buf_count - info->buf_start); >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? int real_len = min_t(size_t, len, nand->buf_count - nand->buf_start); >> >> - ? ? ? memcpy(buf, info->data_buff + info->buf_start, real_len); >> - ? ? ? info->buf_start += real_len; >> + ? ? ? memcpy(buf, nand->data_buff + nand->buf_start, real_len); >> + ? ? ? nand->buf_start += real_len; >> ?} >> >> ?static void pxa3xx_nand_write_buf(struct mtd_info *mtd, >> ? ? ? ? ? ? ? ?const uint8_t *buf, int len) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> - ? ? ? int real_len = min_t(size_t, len, info->buf_count - info->buf_start); >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? int real_len = min_t(size_t, len, nand->buf_count - nand->buf_start); >> >> - ? ? ? memcpy(info->data_buff + info->buf_start, buf, real_len); >> - ? ? ? info->buf_start += real_len; >> + ? ? ? memcpy(nand->data_buff + nand->buf_start, buf, real_len); >> + ? ? ? nand->buf_start += real_len; >> ?} >> >> ?static int pxa3xx_nand_verify_buf(struct mtd_info *mtd, >> @@ -750,10 +785,11 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) >> ?static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> >> ? ? ? ?/* pxa3xx_nand_send_command has waited for command complete */ >> ? ? ? ?if (this->state == FL_WRITING || this->state == FL_ERASING) { >> - ? ? ? ? ? ? ? if (info->retcode == ERR_NONE) >> + ? ? ? ? ? ? ? if (nand->retcode == ERR_NONE) >> ? ? ? ? ? ? ? ? ? ? ? ?return 0; >> ? ? ? ? ? ? ? ?else { >> ? ? ? ? ? ? ? ? ? ? ? ?/* >> @@ -770,7 +806,8 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) >> ?static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const struct pxa3xx_nand_flash *f) >> ?{ >> - ? ? ? struct platform_device *pdev = info->pdev; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? struct platform_device *pdev = nand->pdev; >> ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; >> ? ? ? ?uint32_t ndcr = 0x0; /* enable all interrupts */ >> >> @@ -804,6 +841,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, >> ? ? ? ?ndcr |= NDCR_SPARE_EN; /* enable spare by default */ >> >> ? ? ? ?info->reg_ndcr = ndcr; >> + ? ? ? info->use_ecc = 1; >> >> ? ? ? ?pxa3xx_nand_set_timing(info, f->timing); >> ? ? ? ?return 0; >> @@ -811,15 +849,22 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, >> >> ?static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) >> ?{ >> - ? ? ? uint32_t ndcr = nand_readl(info, NDCR); >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? uint32_t ndcr = nand_readl(nand, NDCR); >> + >> + ? ? ? if (info->chip_select > 0) { >> + ? ? ? ? ? ? ? printk(KERN_ERR "We could not detect configure" >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? " if more than one cs is supported!!\n"); >> + ? ? ? ? ? ? ? BUG(); >> + ? ? ? } >> ? ? ? ?info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; >> ? ? ? ?/* set info fields needed to read id */ >> ? ? ? ?info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; >> ? ? ? ?info->reg_ndcr = ndcr & ~NDCR_INT_MASK; >> ? ? ? ?info->cmdset = &default_cmdset; >> >> - ? ? ? info->ndtr0cs0 = nand_readl(info, NDTR0CS0); >> - ? ? ? info->ndtr1cs0 = nand_readl(info, NDTR1CS0); >> + ? ? ? info->ndtr0cs0 = nand_readl(nand, NDTR0CS0); >> + ? ? ? info->ndtr1cs0 = nand_readl(nand, NDTR1CS0); >> >> ? ? ? ?return 0; >> ?} >> @@ -830,50 +875,31 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) >> ?*/ >> ?#define MAX_BUFF_SIZE ?PAGE_SIZE >> >> -static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) >> +static void free_cs_resource(struct pxa3xx_nand_info *info, int cs) >> ?{ >> - ? ? ? struct platform_device *pdev = info->pdev; >> - ? ? ? int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc); >> - >> - ? ? ? if (use_dma == 0) { >> - ? ? ? ? ? ? ? info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); >> - ? ? ? ? ? ? ? if (info->data_buff == NULL) >> - ? ? ? ? ? ? ? ? ? ? ? return -ENOMEM; >> - ? ? ? ? ? ? ? return 0; >> - ? ? ? } >> - >> - ? ? ? info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &info->data_buff_phys, GFP_KERNEL); >> - ? ? ? if (info->data_buff == NULL) { >> - ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to allocate dma buffer\n"); >> - ? ? ? ? ? ? ? return -ENOMEM; >> - ? ? ? } >> - >> - ? ? ? info->data_buff_size = MAX_BUFF_SIZE; >> - ? ? ? info->data_desc = (void *)info->data_buff + data_desc_offset; >> - ? ? ? info->data_desc_addr = info->data_buff_phys + data_desc_offset; >> + ? ? ? struct pxa3xx_nand *nand; >> + ? ? ? struct mtd_info *mtd; >> >> - ? ? ? info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pxa3xx_nand_data_dma_irq, info); >> - ? ? ? if (info->data_dma_ch < 0) { >> - ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to request data dma\n"); >> - ? ? ? ? ? ? ? dma_free_coherent(&pdev->dev, info->data_buff_size, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->data_buff, info->data_buff_phys); >> - ? ? ? ? ? ? ? return info->data_dma_ch; >> - ? ? ? } >> + ? ? ? if (!info) >> + ? ? ? ? ? ? ? return; >> >> - ? ? ? return 0; >> + ? ? ? nand = info->nand_data; >> + ? ? ? mtd = get_mtd_by_info(info); >> + ? ? ? kfree(mtd); >> + ? ? ? nand->info[cs] = NULL; >> ?} >> >> ?static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) >> ?{ >> - ? ? ? struct mtd_info *mtd = info->mtd; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? struct mtd_info *mtd = get_mtd_by_info(info); >> ? ? ? ?struct nand_chip *chip = mtd->priv; >> >> ? ? ? ?/* use the common timing to make a try */ >> - ? ? ? pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); >> + ? ? ? if (pxa3xx_nand_config_flash(info, &builtin_flash_types[0])) >> + ? ? ? ? ? ? ? return 0; >> ? ? ? ?chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); >> - ? ? ? if (info->is_ready) >> + ? ? ? if (nand->is_ready) >> ? ? ? ? ? ? ? ?return 1; >> ? ? ? ?else >> ? ? ? ? ? ? ? ?return 0; >> @@ -882,7 +908,8 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) >> ?static int pxa3xx_nand_scan(struct mtd_info *mtd) >> ?{ >> ? ? ? ?struct pxa3xx_nand_info *info = mtd->priv; >> - ? ? ? struct platform_device *pdev = info->pdev; >> + ? ? ? struct pxa3xx_nand *nand = info->nand_data; >> + ? ? ? struct platform_device *pdev = nand->pdev; >> ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; >> ? ? ? ?struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; >> ? ? ? ?const struct pxa3xx_nand_flash *f = NULL; >> @@ -891,27 +918,25 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) >> ? ? ? ?uint64_t chipsize; >> ? ? ? ?int i, ret, num; >> >> + ? ? ? nand->chip_select = info->chip_select; >> ? ? ? ?if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) >> ? ? ? ? ? ? ? ?goto KEEP_CONFIG; >> >> ? ? ? ?ret = pxa3xx_nand_sensing(info); >> ? ? ? ?if (!ret) { >> - ? ? ? ? ? ? ? kfree(mtd); >> - ? ? ? ? ? ? ? info->mtd = NULL; >> - ? ? ? ? ? ? ? printk(KERN_INFO "There is no nand chip on cs 0!\n"); >> + ? ? ? ? ? ? ? free_cs_resource(info, nand->chip_select); >> + ? ? ? ? ? ? ? printk(KERN_INFO "There is no nand chip on cs %d!\n", >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? nand->chip_select); > > dev_err()? > >> >> ? ? ? ? ? ? ? ?return -EINVAL; >> ? ? ? ?} >> >> ? ? ? ?chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); >> - ? ? ? id = *((uint16_t *)(info->data_buff)); >> + ? ? ? id = *((uint16_t *)(nand->data_buff)); >> ? ? ? ?if (id != 0) >> ? ? ? ? ? ? ? ?printk(KERN_INFO "Detect a flash id %x\n", id); >> ? ? ? ?else { >> - ? ? ? ? ? ? ? kfree(mtd); >> - ? ? ? ? ? ? ? info->mtd = NULL; >> - ? ? ? ? ? ? ? printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); >> - >> + ? ? ? ? ? ? ? free_cs_resource(info, nand->chip_select); >> ? ? ? ? ? ? ? ?return -EINVAL; >> ? ? ? ?} >> >> @@ -928,14 +953,16 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) >> ? ? ? ?} >> >> ? ? ? ?if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { >> - ? ? ? ? ? ? ? kfree(mtd); >> - ? ? ? ? ? ? ? info->mtd = NULL; >> + ? ? ? ? ? ? ? free_cs_resource(info, nand->chip_select); >> ? ? ? ? ? ? ? ?printk(KERN_ERR "ERROR!! flash not defined!!!\n"); > > Also here. > >> >> ? ? ? ? ? ? ? ?return -EINVAL; >> ? ? ? ?} >> >> - ? ? ? pxa3xx_nand_config_flash(info, f); >> + ? ? ? if (pxa3xx_nand_config_flash(info, f)) { >> + ? ? ? ? ? ? ? printk(KERN_ERR "ERROR! Configure failed\n"); > > And here. Giving no hint about which driver or function causes this > message makes debugging harder than it should be. > > [...] > >> ?#ifdef CONFIG_PM >> @@ -1183,8 +1278,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) >> ? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); >> ? ? ? ?struct mtd_info *mtd = info->mtd; >> >> - ? ? ? nand_writel(info, NDTR0CS0, info->ndtr0cs0); >> - ? ? ? nand_writel(info, NDTR1CS0, info->ndtr1cs0); >> + ? ? ? nand_writel(nand, NDTR0CS0, info->ndtr0cs0); >> + ? ? ? nand_writel(nand, NDTR1CS0, info->ndtr1cs0); >> ? ? ? ?clk_enable(info->clk); > > This won't compile. Could you post your build log? Thanks, Lei ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/