Thread (81 messages) 81 messages, 6 authors, 2011-07-20

[PATCH] MTD: pxa3xx_nand: enable multiple chip select support

From: zonque@gmail.com (Daniel Mack)
Date: 2011-06-22 11:39:33

On Wed, Jun 22, 2011 at 5:17 AM, Lei Wen [off-list ref] 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 <redacted>
---
?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?

[...]
quoted hunk ↗ jump to hunk
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?
? ? ? ? ? ? ? ?BUG();
Is crashing the entire kernel really necessary here?
quoted hunk ↗ jump to hunk
? ? ? ?}
?}

-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()?
quoted hunk ↗ jump to hunk
? ? ? ? ? ? ? ?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.

[...]
quoted hunk ↗ jump to hunk
?#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.



Daniel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help