From mboxrd@z Thu Jan 1 00:00:00 1970 From: zonque@gmail.com (Daniel Mack) Date: Sat, 25 Jun 2011 14:32:17 +0200 Subject: [PATCH] MTD: pxa3xx_nand: enable multiple chip select support In-Reply-To: <1309000666-5242-1-git-send-email-leiwen@marvell.com> References: <4E031900.50108@compulab.co.il> <1309000666-5242-1-git-send-email-leiwen@marvell.com> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On Sat, Jun 25, 2011 at 1:17 PM, 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 I tested this on a PXA303 platform with one chipselect only, at at least I can say that this patch doesn't seem to cause any regression here. But I couldn't test the new feature it adds. So, FWIW: Tested-by: Daniel Mack Thanks! Daniel > --- > ?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 | ? 19 +- > ?drivers/mtd/nand/pxa3xx_nand.c ? ? ? ? ? ? ? | ?512 +++++++++++++++----------- > ?9 files changed, 346 insertions(+), 224 deletions(-) > > diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c > index 06b5fa8..c4996f3 100644 > --- a/arch/arm/mach-mmp/aspenite.c > +++ b/arch/arm/mach-mmp/aspenite.c > @@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = { > > ?static struct pxa3xx_nand_platform_data aspenite_nand_info = { > ? ? ? ?.enable_arbiter = 1, > - ? ? ? .parts ? ? ? ? ?= aspenite_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(aspenite_nand_partitions), > + ? ? ? .num_cs = 1, > + ? ? ? .parts[0] ? ? ? = aspenite_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(aspenite_nand_partitions), > ?}; > > ?static struct i2c_board_info aspenite_i2c_info[] __initdata = { > diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c > index b2248e7..969d252 100644 > --- a/arch/arm/mach-pxa/cm-x300.c > +++ b/arch/arm/mach-pxa/cm-x300.c > @@ -423,8 +423,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = { > ?static struct pxa3xx_nand_platform_data cm_x300_nand_info = { > ? ? ? ?.enable_arbiter = 1, > ? ? ? ?.keep_config ? ?= 1, > - ? ? ? .parts ? ? ? ? ?= cm_x300_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(cm_x300_nand_partitions), > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = cm_x300_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(cm_x300_nand_partitions), > ?}; > > ?static void __init cm_x300_init_nand(void) > diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c > index 3f9be41..2b8ca0d 100644 > --- a/arch/arm/mach-pxa/colibri-pxa3xx.c > +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c > @@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = { > ?static struct pxa3xx_nand_platform_data colibri_nand_info = { > ? ? ? ?.enable_arbiter = 1, > ? ? ? ?.keep_config ? ?= 1, > - ? ? ? .parts ? ? ? ? ?= colibri_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(colibri_nand_partitions), > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = colibri_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(colibri_nand_partitions), > ?}; > > ?void __init colibri_pxa3xx_init_nand(void) > diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c > index e5e326d..f6d1f9d 100644 > --- a/arch/arm/mach-pxa/littleton.c > +++ b/arch/arm/mach-pxa/littleton.c > @@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = { > > ?static struct pxa3xx_nand_platform_data littleton_nand_info = { > ? ? ? ?.enable_arbiter = 1, > - ? ? ? .parts ? ? ? ? ?= littleton_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(littleton_nand_partitions), > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = littleton_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(littleton_nand_partitions), > ?}; > > ?static void __init littleton_init_nand(void) > diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c > index b5a8fd3..90928d6 100644 > --- a/arch/arm/mach-pxa/mxm8x10.c > +++ b/arch/arm/mach-pxa/mxm8x10.c > @@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = { > ?}; > > ?static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = { > - ? ? ? .enable_arbiter = 1, > - ? ? ? .keep_config = 1, > - ? ? ? .parts = mxm_8x10_nand_partitions, > - ? ? ? .nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions) > + ? ? ? .enable_arbiter = 1, > + ? ? ? .keep_config ? ?= 1, > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = mxm_8x10_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(mxm_8x10_nand_partitions) > ?}; > > ?static void __init mxm_8x10_nand_init(void) > diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c > index d130f77..c7ec847 100644 > --- a/arch/arm/mach-pxa/raumfeld.c > +++ b/arch/arm/mach-pxa/raumfeld.c > @@ -349,8 +349,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = { > ?static struct pxa3xx_nand_platform_data raumfeld_nand_info = { > ? ? ? ?.enable_arbiter = 1, > ? ? ? ?.keep_config ? ?= 1, > - ? ? ? .parts ? ? ? ? ?= raumfeld_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(raumfeld_nand_partitions), > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = raumfeld_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(raumfeld_nand_partitions), > ?}; > > ?/** > diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c > index 5821185..64fdac9 100644 > --- a/arch/arm/mach-pxa/zylonite.c > +++ b/arch/arm/mach-pxa/zylonite.c > @@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = { > > ?static struct pxa3xx_nand_platform_data zylonite_nand_info = { > ? ? ? ?.enable_arbiter = 1, > - ? ? ? .parts ? ? ? ? ?= zylonite_nand_partitions, > - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(zylonite_nand_partitions), > + ? ? ? .num_cs ? ? ? ? = 1, > + ? ? ? .parts[0] ? ? ? = zylonite_nand_partitions, > + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(zylonite_nand_partitions), > ?}; > > ?static void __init zylonite_init_nand(void) > diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h > index 442301f..4e17309 100644 > --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h > +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h > @@ -41,6 +41,19 @@ struct pxa3xx_nand_flash { > ? ? ? ?struct pxa3xx_nand_timing *timing; ? ? ?/* NAND Flash timing */ > ?}; > > +/* > + * Current pxa3xx_nand controller has two chip select which > + * both be workable. > + * > + * 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. > + */ > + > +/* The max num of chip select current support */ > +#define NUM_CHIP_SELECT ? ? ? ? ? ? ? ?(2) > ?struct pxa3xx_nand_platform_data { > > ? ? ? ?/* the data flash bus is shared between the Static Memory > @@ -52,8 +65,10 @@ struct pxa3xx_nand_platform_data { > ? ? ? ?/* allow platform code to keep OBM/bootloader defined NFC config */ > ? ? ? ?int ? ? keep_config; > > - ? ? ? const struct mtd_partition ? ? ? ? ? ? ?*parts; > - ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ? ? ? ? ?nr_parts; > + ? ? ? /* indicate how many chip selects will be used */ > + ? ? ? int ? ? num_cs; > + ? ? ? const struct mtd_partition ? ? ? ? ? ? ?*parts[NUM_CHIP_SELECT]; > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ? ? ? ? ?nr_parts[NUM_CHIP_SELECT]; > > ? ? ? ?const struct pxa3xx_nand_flash * ? ? ? ?flash; > ? ? ? ?size_t ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_flash; > diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c > index b7db1b2..0825b7d 100644 > --- a/drivers/mtd/nand/pxa3xx_nand.c > +++ b/drivers/mtd/nand/pxa3xx_nand.c > @@ -110,6 +110,7 @@ enum { > > ?enum { > ? ? ? ?STATE_IDLE = 0, > + ? ? ? STATE_PREPARED, > ? ? ? ?STATE_CMD_HANDLE, > ? ? ? ?STATE_DMA_READING, > ? ? ? ?STATE_DMA_WRITING, > @@ -120,21 +121,40 @@ enum { > ? ? ? ?STATE_READY, > ?}; > > -struct pxa3xx_nand_info { > - ? ? ? struct nand_chip ? ? ? ?nand_chip; > +struct pxa3xx_nand_host { > + ? ? ? struct nand_chip ? ? ? ?chip; > + ? ? ? struct pxa3xx_nand_cmdset *cmdset; > + ? ? ? struct mtd_info ? ? ? ? *mtd; > + ? ? ? void ? ? ? ? ? ? ? ? ? ?*info_data; > > + ? ? ? /* page size of attached chip */ > + ? ? ? unsigned int ? ? ? ? ? ?page_size; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? cs; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? use_ecc; > + > + ? ? ? /* calculated from pxa3xx_nand_flash data */ > + ? ? ? unsigned int ? ? ? ? ? ?col_addr_cycles; > + ? ? ? unsigned int ? ? ? ? ? ?row_addr_cycles; > + ? ? ? size_t ? ? ? ? ? ? ? ? ?read_id_bytes; > + > + ? ? ? /* cached register value */ > + ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr; > + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr0cs0; > + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr1cs0; > +}; > + > +struct pxa3xx_nand_info { > ? ? ? ?struct nand_hw_control ?controller; > ? ? ? ?struct platform_device ? *pdev; > - ? ? ? struct pxa3xx_nand_cmdset *cmdset; > > ? ? ? ?struct clk ? ? ? ? ? ? ?*clk; > ? ? ? ?void __iomem ? ? ? ? ? ?*mmio_base; > ? ? ? ?unsigned long ? ? ? ? ? mmio_phys; > + ? ? ? struct completion ? ? ? cmd_complete; > > ? ? ? ?unsigned int ? ? ? ? ? ?buf_start; > ? ? ? ?unsigned int ? ? ? ? ? ?buf_count; > > - ? ? ? struct mtd_info ? ? ? ? *mtd; > ? ? ? ?/* DMA information */ > ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_dat; > ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_cmd; > @@ -142,44 +162,27 @@ struct pxa3xx_nand_info { > ? ? ? ?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_desc_addr; > > - ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr; > - > - ? ? ? /* saved column/page_addr during CMD_SEQIN */ > - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_column; > - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_page_addr; > - > + ? ? ? struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; > ? ? ? ?/* relate to the command */ > ? ? ? ?unsigned int ? ? ? ? ? ?state; > > + ? ? ? int ? ? ? ? ? ? ? ? ? ? cs; > ? ? ? ?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 */ > + ? ? ? unsigned int ? ? ? ? ? ?oob_size; > ? ? ? ?int ? ? ? ? ? ? ? ? ? ? retcode; > - ? ? ? struct completion ? ? ? cmd_complete; > > ? ? ? ?/* generated NDCBx register values */ > ? ? ? ?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) > @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; > ?/* convert nano-seconds to nand flash controller clock cycles */ > ?#define ns2cycle(ns, clk) ? ? ?(int)((ns) * (clk / 1000000) / 1000) > > -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, > +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct pxa3xx_nand_timing *t) > ?{ > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?unsigned long nand_clk = clk_get_rate(info->clk); > ? ? ? ?uint32_t ndtr0, ndtr1; > > @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, > ? ? ? ? ? ? ? ?NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | > ? ? ? ? ? ? ? ?NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); > > - ? ? ? info->ndtr0cs0 = ndtr0; > - ? ? ? info->ndtr1cs0 = ndtr1; > + ? ? ? host->ndtr0cs0 = ndtr0; > + ? ? ? host->ndtr1cs0 = ndtr1; > ? ? ? ?nand_writel(info, NDTR0CS0, ndtr0); > ? ? ? ?nand_writel(info, NDTR1CS0, ndtr1); > ?} > > ?static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) > ?{ > - ? ? ? int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; > + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs]; > + ? ? ? int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; > > - ? ? ? info->data_size = info->page_size; > + ? ? ? info->data_size = host->page_size; > ? ? ? ?if (!oob_enable) { > ? ? ? ? ? ? ? ?info->oob_size = 0; > ? ? ? ? ? ? ? ?return; > ? ? ? ?} > > - ? ? ? switch (info->page_size) { > + ? ? ? switch (host->page_size) { > ? ? ? ?case 2048: > ? ? ? ? ? ? ? ?info->oob_size = (info->use_ecc) ? 40 : 64; > ? ? ? ? ? ? ? ?break; > @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) > ?*/ > ?static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) > ?{ > + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs]; > ? ? ? ?uint32_t ndcr; > > - ? ? ? ndcr = info->reg_ndcr; > + ? ? ? ndcr = host->reg_ndcr; > ? ? ? ?ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; > ? ? ? ?ndcr |= info->use_dma ? NDCR_DMA_EN : 0; > ? ? ? ?ndcr |= NDCR_ND_RUN; > @@ -359,8 +365,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->oob_size, 4)); > ? ? ? ? ? ? ? ?break; > ? ? ? ?default: > - ? ? ? ? ? ? ? printk(KERN_ERR "%s: invalid state %d\n", __func__, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->state); > + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, > + ? ? ? ? ? ? ? ? ? ? ? info->state); > ? ? ? ? ? ? ? ?BUG(); > ? ? ? ?} > ?} > @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) > ? ? ? ? ? ? ? ?desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; > ? ? ? ? ? ? ? ?break; > ? ? ? ?default: > - ? ? ? ? ? ? ? printk(KERN_ERR "%s: invalid state %d\n", __func__, > + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->state); > ? ? ? ? ? ? ? ?BUG(); > ? ? ? ?} > @@ -416,9 +422,17 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) > ?{ > ? ? ? ?struct pxa3xx_nand_info *info = devid; > ? ? ? ?unsigned int status, is_completed = 0; > + ? ? ? unsigned int ready, cmd_done; > + > + ? ? ? if (info->cs == 0) { > + ? ? ? ? ? ? ? ready ? ? ? ? ? = NDSR_FLASH_RDY; > + ? ? ? ? ? ? ? cmd_done ? ? ? ?= NDSR_CS0_CMDD; > + ? ? ? } else { > + ? ? ? ? ? ? ? ready ? ? ? ? ? = NDSR_RDY; > + ? ? ? ? ? ? ? cmd_done ? ? ? ?= NDSR_CS1_CMDD; > + ? ? ? } > > ? ? ? ?status = nand_readl(info, NDSR); > - > ? ? ? ?if (status & NDSR_DBERR) > ? ? ? ? ? ? ? ?info->retcode = ERR_DBERR; > ? ? ? ?if (status & NDSR_SBERR) > @@ -437,11 +451,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) > ? ? ? ? ? ? ? ? ? ? ? ?handle_data_pio(info); > ? ? ? ? ? ? ? ?} > ? ? ? ?} > - ? ? ? if (status & NDSR_CS0_CMDD) { > + ? ? ? if (status & cmd_done) { > ? ? ? ? ? ? ? ?info->state = STATE_CMD_DONE; > ? ? ? ? ? ? ? ?is_completed = 1; > ? ? ? ?} > - ? ? ? if (status & NDSR_FLASH_RDY) { > + ? ? ? if (status & ready) { > ? ? ? ? ? ? ? ?info->is_ready = 1; > ? ? ? ? ? ? ? ?info->state = STATE_READY; > ? ? ? ?} > @@ -463,12 +477,6 @@ 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--) > @@ -481,10 +489,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ?uint16_t column, int page_addr) > ?{ > ? ? ? ?uint16_t cmd; > - ? ? ? int addr_cycle, exec_cmd, ndcb0; > - ? ? ? struct mtd_info *mtd = info->mtd; > + ? ? ? int addr_cycle, exec_cmd; > + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs]; > + ? ? ? struct mtd_info *mtd = host->mtd; > > - ? ? ? ndcb0 = 0; > ? ? ? ?addr_cycle = 0; > ? ? ? ?exec_cmd = 1; > > @@ -495,6 +503,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ?info->use_ecc ? ? ? ? ? = 0; > ? ? ? ?info->is_ready ? ? ? ? ?= 0; > ? ? ? ?info->retcode ? ? ? ? ? = ERR_NONE; > + ? ? ? if (info->cs != 0) > + ? ? ? ? ? ? ? info->ndcb0 = NDCB0_CSEL; > + ? ? ? else > + ? ? ? ? ? ? ? info->ndcb0 = 0; > > ? ? ? ?switch (command) { > ? ? ? ?case NAND_CMD_READ0: > @@ -512,20 +524,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ?break; > ? ? ? ?} > > - ? ? ? info->ndcb0 = ndcb0; > - ? ? ? addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + info->col_addr_cycles); > + ? ? ? addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + host->col_addr_cycles); > > ? ? ? ?switch (command) { > ? ? ? ?case NAND_CMD_READOOB: > ? ? ? ?case NAND_CMD_READ0: > - ? ? ? ? ? ? ? cmd = info->cmdset->read1; > + ? ? ? ? ? ? ? cmd = host->cmdset->read1; > ? ? ? ? ? ? ? ?if (command == NAND_CMD_READOOB) > ? ? ? ? ? ? ? ? ? ? ? ?info->buf_start = mtd->writesize + column; > ? ? ? ? ? ? ? ?else > ? ? ? ? ? ? ? ? ? ? ? ?info->buf_start = column; > > - ? ? ? ? ? ? ? if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) > + ? ? ? ? ? ? ? if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) > ? ? ? ? ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(0) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| addr_cycle > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (cmd & NDCB0_CMD1_MASK); > @@ -537,7 +548,7 @@ 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)) { > + ? ? ? ? ? ? ? if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { > ? ? ? ? ? ? ? ? ? ? ? ?info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (column & 0xFF); > > @@ -564,7 +575,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ? ? ? ? ?break; > ? ? ? ? ? ? ? ?} > > - ? ? ? ? ? ? ? cmd = info->cmdset->program; > + ? ? ? ? ? ? ? cmd = host->cmdset->program; > ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(0x1) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ST_ROW_EN > @@ -574,8 +585,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ?break; > > ? ? ? ?case NAND_CMD_READID: > - ? ? ? ? ? ? ? cmd = info->cmdset->read_id; > - ? ? ? ? ? ? ? info->buf_count = info->read_id_bytes; > + ? ? ? ? ? ? ? cmd = host->cmdset->read_id; > + ? ? ? ? ? ? ? info->buf_count = host->read_id_bytes; > ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(3) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; > @@ -583,7 +594,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ?info->data_size = 8; > ? ? ? ? ? ? ? ?break; > ? ? ? ?case NAND_CMD_STATUS: > - ? ? ? ? ? ? ? cmd = info->cmdset->read_status; > + ? ? ? ? ? ? ? cmd = host->cmdset->read_status; > ? ? ? ? ? ? ? ?info->buf_count = 1; > ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(4) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1) > @@ -593,7 +604,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ? ? ? ? ? ? ? ?break; > > ? ? ? ?case NAND_CMD_ERASE1: > - ? ? ? ? ? ? ? cmd = info->cmdset->erase; > + ? ? ? ? ? ? ? cmd = host->cmdset->erase; > ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(2) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(3) > @@ -604,7 +615,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > > ? ? ? ? ? ? ? ?break; > ? ? ? ?case NAND_CMD_RESET: > - ? ? ? ? ? ? ? cmd = info->cmdset->reset; > + ? ? ? ? ? ? ? cmd = host->cmdset->reset; > ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(5) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd; > > @@ -616,7 +627,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > > ? ? ? ?default: > ? ? ? ? ? ? ? ?exec_cmd = 0; > - ? ? ? ? ? ? ? printk(KERN_ERR "pxa3xx-nand: non-supported" > + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "pxa3xx-nand: non-supported" > ? ? ? ? ? ? ? ? ? ? ? ?" command %x\n", command); > ? ? ? ? ? ? ? ?break; > ? ? ? ?} > @@ -627,7 +638,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, > ?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_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?int ret, exec_cmd; > > ? ? ? ?/* > @@ -635,9 +647,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, > ? ? ? ? * "byte" address into a "word" address appropriate > ? ? ? ? * for indexing a word-oriented device > ? ? ? ? */ > - ? ? ? if (info->reg_ndcr & NDCR_DWIDTH_M) > + ? ? ? if (host->reg_ndcr & NDCR_DWIDTH_M) > ? ? ? ? ? ? ? ?column /= 2; > > + ? ? ? /* > + ? ? ? ?* 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 (info->cs != host->cs) { > + ? ? ? ? ? ? ? info->cs = host->cs; > + ? ? ? ? ? ? ? nand_writel(info, NDTR0CS0, host->ndtr0cs0); > + ? ? ? ? ? ? ? nand_writel(info, NDTR1CS0, host->ndtr1cs0); > + ? ? ? } > + > + ? ? ? info->state = STATE_PREPARED; > ? ? ? ?exec_cmd = prepare_command_pool(info, command, column, page_addr); > ? ? ? ?if (exec_cmd) { > ? ? ? ? ? ? ? ?init_completion(&info->cmd_complete); > @@ -646,12 +670,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, > ? ? ? ? ? ? ? ?ret = wait_for_completion_timeout(&info->cmd_complete, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?CHIP_DELAY_TIMEOUT); > ? ? ? ? ? ? ? ?if (!ret) { > - ? ? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "Wait time out!!!\n"); > + ? ? ? ? ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "Wait time out!!!\n"); > ? ? ? ? ? ? ? ? ? ? ? ?/* Stop State Machine for next command cycle */ > ? ? ? ? ? ? ? ? ? ? ? ?pxa3xx_nand_stop(info); > ? ? ? ? ? ? ? ?} > - ? ? ? ? ? ? ? info->state = STATE_IDLE; > ? ? ? ?} > + ? ? ? info->state = STATE_IDLE; > ?} > > ?static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, > @@ -664,7 +688,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, > ?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_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > > ? ? ? ?chip->read_buf(mtd, buf, mtd->writesize); > ? ? ? ?chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); > @@ -695,7 +720,8 @@ 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_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?char retval = 0xFF; > > ? ? ? ?if (info->buf_start < info->buf_count) > @@ -707,7 +733,8 @@ 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_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?u16 retval = 0xFFFF; > > ? ? ? ?if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { > @@ -719,7 +746,8 @@ 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; > + ? ? ? struct pxa3xx_nand_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?int real_len = min_t(size_t, len, info->buf_count - info->buf_start); > > ? ? ? ?memcpy(buf, info->data_buff + info->buf_start, real_len); > @@ -729,7 +757,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) > ?static void pxa3xx_nand_write_buf(struct mtd_info *mtd, > ? ? ? ? ? ? ? ?const uint8_t *buf, int len) > ?{ > - ? ? ? struct pxa3xx_nand_info *info = mtd->priv; > + ? ? ? struct pxa3xx_nand_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?int real_len = min_t(size_t, len, info->buf_count - info->buf_start); > > ? ? ? ?memcpy(info->data_buff + info->buf_start, buf, real_len); > @@ -749,7 +778,8 @@ 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_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > > ? ? ? ?/* pxa3xx_nand_send_command has waited for command complete */ > ? ? ? ?if (this->state == FL_WRITING || this->state == FL_ERASING) { > @@ -772,54 +802,69 @@ 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; > + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs]; > ? ? ? ?uint32_t ndcr = 0x0; /* enable all interrupts */ > > - ? ? ? if (f->page_size != 2048 && f->page_size != 512) > + ? ? ? if (f->page_size != 2048 && f->page_size != 512) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "Current only support 2048 and 512 size\n"); > ? ? ? ? ? ? ? ?return -EINVAL; > + ? ? ? } > > - ? ? ? if (f->flash_width != 16 && f->flash_width != 8) > + ? ? ? if (f->flash_width != 16 && f->flash_width != 8) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n"); > ? ? ? ? ? ? ? ?return -EINVAL; > + ? ? ? } > > ? ? ? ?/* calculate flash information */ > - ? ? ? info->cmdset = &default_cmdset; > - ? ? ? info->page_size = f->page_size; > - ? ? ? info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; > + ? ? ? host->cmdset = &default_cmdset; > + ? ? ? host->page_size = f->page_size; > + ? ? ? host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; > > ? ? ? ?/* calculate addressing information */ > - ? ? ? info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; > + ? ? ? host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; > > ? ? ? ?if (f->num_blocks * f->page_per_block > 65536) > - ? ? ? ? ? ? ? info->row_addr_cycles = 3; > + ? ? ? ? ? ? ? host->row_addr_cycles = 3; > ? ? ? ?else > - ? ? ? ? ? ? ? info->row_addr_cycles = 2; > + ? ? ? ? ? ? ? host->row_addr_cycles = 2; > > ? ? ? ?ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; > - ? ? ? ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; > + ? ? ? ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; > ? ? ? ?ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; > ? ? ? ?ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; > ? ? ? ?ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; > ? ? ? ?ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; > > - ? ? ? ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); > + ? ? ? ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); > ? ? ? ?ndcr |= NDCR_SPARE_EN; /* enable spare by default */ > > - ? ? ? info->reg_ndcr = ndcr; > + ? ? ? host->reg_ndcr = ndcr; > > - ? ? ? pxa3xx_nand_set_timing(info, f->timing); > + ? ? ? pxa3xx_nand_set_timing(host, f->timing); > ? ? ? ?return 0; > ?} > > ?static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) > ?{ > + ? ? ? /* > + ? ? ? ?* We set 0 by hard coding here, for we don't support keep_config > + ? ? ? ?* when there is more than one chip attached to the controller > + ? ? ? ?*/ > + ? ? ? struct pxa3xx_nand_host *host = info->host[0]; > ? ? ? ?uint32_t ndcr = nand_readl(info, NDCR); > - ? ? ? 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); > + ? ? ? if (ndcr & NDCR_PAGE_SZ) { > + ? ? ? ? ? ? ? host->page_size = 2048; > + ? ? ? ? ? ? ? host->read_id_bytes = 4; > + ? ? ? } else { > + ? ? ? ? ? ? ? host->page_size = 512; > + ? ? ? ? ? ? ? host->read_id_bytes = 2; > + ? ? ? } > + ? ? ? host->reg_ndcr = ndcr & ~NDCR_INT_MASK; > + ? ? ? host->cmdset = &default_cmdset; > + > + ? ? ? host->ndtr0cs0 = nand_readl(info, NDTR0CS0); > + ? ? ? host->ndtr1cs0 = nand_readl(info, NDTR1CS0); > > ? ? ? ?return 0; > ?} > @@ -829,59 +874,41 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) > ?* data buffer and the DMA descriptor > ?*/ > ?#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_host *host; > + ? ? ? 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->host[cs]) > + ? ? ? ? ? ? ? return; > > - ? ? ? return 0; > + ? ? ? host = info->host[cs]; > + ? ? ? mtd = host->mtd; > + ? ? ? kfree(mtd); > + ? ? ? info->host[cs] = NULL; > ?} > > ?static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) > ?{ > - ? ? ? struct mtd_info *mtd = info->mtd; > - ? ? ? struct nand_chip *chip = mtd->priv; > + ? ? ? struct mtd_info *mtd = info->host[info->cs]->mtd; > + ? ? ? int ret; > > ? ? ? ?/* use the common timing to make a try */ > - ? ? ? pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); > - ? ? ? chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); > + ? ? ? ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); > + ? ? ? if (ret) > + ? ? ? ? ? ? ? return ret; > + > + ? ? ? pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); > ? ? ? ?if (info->is_ready) > - ? ? ? ? ? ? ? return 1; > - ? ? ? else > ? ? ? ? ? ? ? ?return 0; > + > + ? ? ? return -ENODEV; > ?} > > ?static int pxa3xx_nand_scan(struct mtd_info *mtd) > ?{ > - ? ? ? struct pxa3xx_nand_info *info = mtd->priv; > + ? ? ? struct pxa3xx_nand_host *host = mtd->priv; > + ? ? ? struct pxa3xx_nand_info *info = host->info_data; > ? ? ? ?struct platform_device *pdev = info->pdev; > ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; > ? ? ? ?struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; > @@ -891,26 +918,26 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) > ? ? ? ?uint64_t chipsize; > ? ? ? ?int i, ret, num; > > + ? ? ? info->cs = host->cs; > ? ? ? ?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"); > + ? ? ? if (ret) { > + ? ? ? ? ? ? ? free_cs_resource(info, info->cs); > + ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); > > - ? ? ? ? ? ? ? return -EINVAL; > + ? ? ? ? ? ? ? return ret; > ? ? ? ?} > > ? ? ? ?chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); > ? ? ? ?id = *((uint16_t *)(info->data_buff)); > ? ? ? ?if (id != 0) > - ? ? ? ? ? ? ? printk(KERN_INFO "Detect a flash id %x\n", id); > + ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "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, info->cs); > + ? ? ? ? ? ? ? dev_warn(&info->pdev->dev, "Read out ID 0, " > + ? ? ? ? ? ? ? ? ? ? ? ?"potential timing set wrong!!\n"); > > ? ? ? ? ? ? ? ?return -EINVAL; > ? ? ? ?} > @@ -928,14 +955,17 @@ 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; > - ? ? ? ? ? ? ? printk(KERN_ERR "ERROR!! flash not defined!!!\n"); > + ? ? ? ? ? ? ? free_cs_resource(info, info->cs); > + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); > > ? ? ? ? ? ? ? ?return -EINVAL; > ? ? ? ?} > > - ? ? ? pxa3xx_nand_config_flash(info, f); > + ? ? ? ret = pxa3xx_nand_config_flash(info, f); > + ? ? ? if (ret) { > + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); > + ? ? ? ? ? ? ? return ret; > + ? ? ? } > ? ? ? ?pxa3xx_flash_ids[0].name = f->name; > ? ? ? ?pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; > ? ? ? ?pxa3xx_flash_ids[0].pagesize = f->page_size; > @@ -950,66 +980,51 @@ KEEP_CONFIG: > ? ? ? ?if (nand_scan_ident(mtd, 1, def)) > ? ? ? ? ? ? ? ?return -ENODEV; > ? ? ? ?/* calculate addressing information */ > - ? ? ? info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; > + ? ? ? if (mtd->writesize >= 2048) > + ? ? ? ? ? ? ? host->col_addr_cycles = 2; > + ? ? ? else > + ? ? ? ? ? ? ? host->col_addr_cycles = 1; > ? ? ? ?info->oob_buff = info->data_buff + mtd->writesize; > ? ? ? ?if ((mtd->size >> chip->page_shift) > 65536) > - ? ? ? ? ? ? ? info->row_addr_cycles = 3; > + ? ? ? ? ? ? ? host->row_addr_cycles = 3; > ? ? ? ?else > - ? ? ? ? ? ? ? info->row_addr_cycles = 2; > - ? ? ? mtd->name = mtd_names[0]; > + ? ? ? ? ? ? ? host->row_addr_cycles = 2; > + ? ? ? mtd->name = mtd_names[info->cs]; > ? ? ? ?chip->ecc.mode = NAND_ECC_HW; > - ? ? ? chip->ecc.size = info->page_size; > + ? ? ? chip->ecc.size = host->page_size; > > - ? ? ? chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0; > + ? ? ? chip->options = 0; > + ? ? ? if (host->reg_ndcr & NDCR_DWIDTH_M) > + ? ? ? ? ? ? ? chip->options = NAND_BUSWIDTH_16; > ? ? ? ?chip->options |= NAND_NO_AUTOINCR; > ? ? ? ?chip->options |= NAND_NO_READRDY; > > ? ? ? ?return nand_scan_tail(mtd); > ?} > > -static > -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) > +static int alloc_nand_resource(struct platform_device *pdev) > ?{ > + ? ? ? struct pxa3xx_nand_platform_data *pdata; > ? ? ? ?struct pxa3xx_nand_info *info; > + ? ? ? struct pxa3xx_nand_host *host; > ? ? ? ?struct nand_chip *chip; > ? ? ? ?struct mtd_info *mtd; > ? ? ? ?struct resource *r; > - ? ? ? int ret, irq; > + ? ? ? int ret, irq, cs; > + ? ? ? int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc); > > - ? ? ? mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), > - ? ? ? ? ? ? ? ? ? ? ? GFP_KERNEL); > - ? ? ? if (!mtd) { > + ? ? ? pdata = pdev->dev.platform_data; > + ? ? ? info = kzalloc(sizeof(struct pxa3xx_nand_info), GFP_KERNEL); > + ? ? ? if (!info) { > ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to allocate memory\n"); > - ? ? ? ? ? ? ? return NULL; > + ? ? ? ? ? ? ? return -ENOMEM; > ? ? ? ?} > - > - ? ? ? info = (struct pxa3xx_nand_info *)(&mtd[1]); > - ? ? ? chip = (struct nand_chip *)(&mtd[1]); > ? ? ? ?info->pdev = pdev; > - ? ? ? info->mtd = mtd; > - ? ? ? mtd->priv = info; > - ? ? ? mtd->owner = THIS_MODULE; > - > - ? ? ? chip->ecc.read_page ? ? = pxa3xx_nand_read_page_hwecc; > - ? ? ? chip->ecc.write_page ? ?= pxa3xx_nand_write_page_hwecc; > - ? ? ? chip->controller ? ? ? ?= &info->controller; > - ? ? ? chip->waitfunc ? ? ? ? ?= pxa3xx_nand_waitfunc; > - ? ? ? chip->select_chip ? ? ? = pxa3xx_nand_select_chip; > - ? ? ? chip->dev_ready ? ? ? ? = pxa3xx_nand_dev_ready; > - ? ? ? chip->cmdfunc ? ? ? ? ? = pxa3xx_nand_cmdfunc; > - ? ? ? chip->read_word ? ? ? ? = pxa3xx_nand_read_word; > - ? ? ? chip->read_byte ? ? ? ? = pxa3xx_nand_read_byte; > - ? ? ? chip->read_buf ? ? ? ? ?= pxa3xx_nand_read_buf; > - ? ? ? chip->write_buf ? ? ? ? = pxa3xx_nand_write_buf; > - ? ? ? chip->verify_buf ? ? ? ?= pxa3xx_nand_verify_buf; > - > - ? ? ? spin_lock_init(&chip->controller->lock); > - ? ? ? init_waitqueue_head(&chip->controller->wq); > ? ? ? ?info->clk = clk_get(&pdev->dev, NULL); > ? ? ? ?if (IS_ERR(info->clk)) { > ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to get nand clock\n"); > ? ? ? ? ? ? ? ?ret = PTR_ERR(info->clk); > - ? ? ? ? ? ? ? goto fail_free_mtd; > + ? ? ? ? ? ? ? goto fail_alloc; > ? ? ? ?} > ? ? ? ?clk_enable(info->clk); > > @@ -1058,10 +1073,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) > ? ? ? ?} > ? ? ? ?info->mmio_phys = r->start; > > - ? ? ? ret = pxa3xx_nand_init_buff(info); > - ? ? ? if (ret) > - ? ? ? ? ? ? ? goto fail_free_io; > - > ? ? ? ?/* initialize all interrupts to be disabled */ > ? ? ? ?disable_int(info, NDSR_MASK); > > @@ -1069,21 +1080,80 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) > ? ? ? ? ? ? ? ? ? ? ? ? ?pdev->name, info); > ? ? ? ?if (ret < 0) { > ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to request IRQ\n"); > - ? ? ? ? ? ? ? goto fail_free_buf; > + ? ? ? ? ? ? ? ret = ENXIO; > + ? ? ? ? ? ? ? goto fail_free_io; > ? ? ? ?} > > ? ? ? ?platform_set_drvdata(pdev, info); > > - ? ? ? return info; > + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) { > + ? ? ? ? ? ? ? mtd = kzalloc(sizeof(struct mtd_info) > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + sizeof(struct pxa3xx_nand_host), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? GFP_KERNEL); > + ? ? ? ? ? ? ? if (!mtd) { > + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to allocate memory\n"); > + ? ? ? ? ? ? ? ? ? ? ? ret = -ENOMEM; > + ? ? ? ? ? ? ? ? ? ? ? goto fail_free_irq; > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? host = (struct pxa3xx_nand_host *)(&mtd[1]); > + ? ? ? ? ? ? ? host->info_data = info; > + ? ? ? ? ? ? ? host->cs = cs; > + ? ? ? ? ? ? ? host->mtd = mtd; > + ? ? ? ? ? ? ? mtd->priv = host; > + ? ? ? ? ? ? ? mtd->owner = THIS_MODULE; > + ? ? ? ? ? ? ? info->host[cs] = host; > + > + ? ? ? ? ? ? ? chip = (struct nand_chip *)(&mtd[1]); > + ? ? ? ? ? ? ? chip->ecc.read_page ? ? = pxa3xx_nand_read_page_hwecc; > + ? ? ? ? ? ? ? chip->ecc.write_page ? ?= pxa3xx_nand_write_page_hwecc; > + ? ? ? ? ? ? ? chip->waitfunc ? ? ? ? ?= pxa3xx_nand_waitfunc; > + ? ? ? ? ? ? ? chip->select_chip ? ? ? = pxa3xx_nand_select_chip; > + ? ? ? ? ? ? ? chip->cmdfunc ? ? ? ? ? = pxa3xx_nand_cmdfunc; > + ? ? ? ? ? ? ? chip->read_word ? ? ? ? = pxa3xx_nand_read_word; > + ? ? ? ? ? ? ? chip->read_byte ? ? ? ? = pxa3xx_nand_read_byte; > + ? ? ? ? ? ? ? chip->read_buf ? ? ? ? ?= pxa3xx_nand_read_buf; > + ? ? ? ? ? ? ? chip->write_buf ? ? ? ? = pxa3xx_nand_write_buf; > + ? ? ? ? ? ? ? chip->verify_buf ? ? ? ?= pxa3xx_nand_verify_buf; > + ? ? ? } > + > + ? ? ? if (use_dma == 0) { > + ? ? ? ? ? ? ? info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); > + ? ? ? ? ? ? ? if (info->data_buff == NULL) { > + ? ? ? ? ? ? ? ? ? ? ? ret = -ENOMEM; > + ? ? ? ? ? ? ? ? ? ? ? goto fail_free_buf; > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? goto success_exit; > + ? ? ? } > + > + ? ? ? 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"); > + ? ? ? ? ? ? ? ret = -ENOMEM; > + ? ? ? ? ? ? ? goto fail_free_buf; > + ? ? ? } > + > + ? ? ? info->data_desc = (void *)info->data_buff + data_desc_offset; > + ? ? ? info->data_desc_addr = info->data_buff_phys + data_desc_offset; > + ? ? ? 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"); > + ? ? ? ? ? ? ? ret = -ENXIO; > + ? ? ? ? ? ? ? goto fail_free_dma_buf; > + ? ? ? } > +success_exit: > + ? ? ? return 0; > > +fail_free_dma_buf: > + ? ? ? dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, > + ? ? ? ? ? ? ? ? ? ? ? info->data_buff, info->data_buff_phys); > ?fail_free_buf: > + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) > + ? ? ? ? ? ? ? free_cs_resource(info, cs); > +fail_free_irq: > ? ? ? ?free_irq(irq, info); > - ? ? ? if (use_dma) { > - ? ? ? ? ? ? ? pxa_free_dma(info->data_dma_ch); > - ? ? ? ? ? ? ? dma_free_coherent(&pdev->dev, info->data_buff_size, > - ? ? ? ? ? ? ? ? ? ? ? info->data_buff, info->data_buff_phys); > - ? ? ? } else > - ? ? ? ? ? ? ? kfree(info->data_buff); > ?fail_free_io: > ? ? ? ?iounmap(info->mmio_base); > ?fail_free_res: > @@ -1091,18 +1161,20 @@ fail_free_res: > ?fail_put_clk: > ? ? ? ?clk_disable(info->clk); > ? ? ? ?clk_put(info->clk); > -fail_free_mtd: > - ? ? ? kfree(mtd); > - ? ? ? return NULL; > +fail_alloc: > + ? ? ? kfree(info); > + ? ? ? return ret; > ?} > > ?static int pxa3xx_nand_remove(struct platform_device *pdev) > ?{ > ? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); > - ? ? ? struct mtd_info *mtd = info->mtd; > + ? ? ? struct pxa3xx_nand_platform_data *pdata; > + ? ? ? struct pxa3xx_nand_host *host; > ? ? ? ?struct resource *r; > - ? ? ? int irq; > + ? ? ? int irq, cs; > > + ? ? ? pdata = pdev->dev.platform_data; > ? ? ? ?platform_set_drvdata(pdev, NULL); > > ? ? ? ?irq = platform_get_irq(pdev, 0); > @@ -1110,7 +1182,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) > ? ? ? ? ? ? ? ?free_irq(irq, info); > ? ? ? ?if (use_dma) { > ? ? ? ? ? ? ? ?pxa_free_dma(info->data_dma_ch); > - ? ? ? ? ? ? ? dma_free_writecombine(&pdev->dev, info->data_buff_size, > + ? ? ? ? ? ? ? dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->data_buff, info->data_buff_phys); > ? ? ? ?} else > ? ? ? ? ? ? ? ?kfree(info->data_buff); > @@ -1122,9 +1194,12 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) > ? ? ? ?clk_disable(info->clk); > ? ? ? ?clk_put(info->clk); > > - ? ? ? if (mtd) { > - ? ? ? ? ? ? ? nand_release(mtd); > - ? ? ? ? ? ? ? kfree(mtd); > + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) { > + ? ? ? ? ? ? ? host = info->host[cs]; > + ? ? ? ? ? ? ? if (!host) > + ? ? ? ? ? ? ? ? ? ? ? continue; > + ? ? ? ? ? ? ? nand_release(host->mtd); > + ? ? ? ? ? ? ? free_cs_resource(info, cs); > ? ? ? ?} > ? ? ? ?return 0; > ?} > @@ -1133,6 +1208,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) > ?{ > ? ? ? ?struct pxa3xx_nand_platform_data *pdata; > ? ? ? ?struct pxa3xx_nand_info *info; > + ? ? ? int cs, ret, probe_success = 0; > > ? ? ? ?pdata = pdev->dev.platform_data; > ? ? ? ?if (!pdata) { > @@ -1140,18 +1216,38 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) > ? ? ? ? ? ? ? ?return -ENODEV; > ? ? ? ?} > > - ? ? ? info = alloc_nand_resource(pdev); > - ? ? ? if (info == NULL) > - ? ? ? ? ? ? ? return -ENOMEM; > + ? ? ? if (pdata->keep_config && pdata->num_cs > 1) { > + ? ? ? ? ? ? ? dev_warn(&pdev->dev, "keep_config is prohibited with multiple" > + ? ? ? ? ? ? ? ? ? ? ? ?" chip selects feature!\n"); > + ? ? ? ? ? ? ? pdata->keep_config = 0; > + ? ? ? } > + > + ? ? ? ret = alloc_nand_resource(pdev); > + ? ? ? if (ret) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "alloc nand resource failed\n"); > + ? ? ? ? ? ? ? return ret; > + ? ? ? } > + > + ? ? ? info = platform_get_drvdata(pdev); > + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) { > + ? ? ? ? ? ? ? ret = pxa3xx_nand_scan(info->host[cs]->mtd); > + ? ? ? ? ? ? ? if (ret) { > + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to scan nand\n"); > + ? ? ? ? ? ? ? ? ? ? ? continue; > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, > + ? ? ? ? ? ? ? ? ? ? ? pdata->parts[cs], pdata->nr_parts[cs]); > + ? ? ? ? ? ? ? if (!ret) > + ? ? ? ? ? ? ? ? ? ? ? probe_success = 1; > + ? ? ? } > > - ? ? ? if (pxa3xx_nand_scan(info->mtd)) { > - ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to scan nand\n"); > + ? ? ? if (!probe_success) { > ? ? ? ? ? ? ? ?pxa3xx_nand_remove(pdev); > ? ? ? ? ? ? ? ?return -ENODEV; > ? ? ? ?} > > - ? ? ? return mtd_device_parse_register(info->mtd, NULL, 0, > - ? ? ? ? ? ? ? ? ? ? ? pdata->parts, pdata->nr_parts); > + ? ? ? return 0; > ?} > > ?#ifdef CONFIG_PM > @@ -1171,8 +1267,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) > ?{ > ? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); > > - ? ? ? nand_writel(info, NDTR0CS0, info->ndtr0cs0); > - ? ? ? nand_writel(info, NDTR1CS0, info->ndtr1cs0); > + ? ? ? /* > + ? ? ? ?* Directly set the chip select to a invalid value, > + ? ? ? ?* then the driver would reset the timing according > + ? ? ? ?* to current chip select at the beginning of cmdfunc > + ? ? ? ?*/ > + ? ? ? info->cs = 0xff; > ? ? ? ?clk_enable(info->clk); > > ? ? ? ?return 0; > -- > 1.7.0.4 > >