MTD: pxa3xx_nand: enable multiple chip select support
Subsystems (6)
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
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.
--- 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(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = aspenite_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (aspenite_nand_partitions), };static struct i2c_board_info aspenite_i2c_info[]__initdata = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = cm_x300_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (cm_x300_nand_partitions), };static void __init cm_x300_init_nand (void )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = colibri_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (colibri_nand_partitions), };void __init colibri_pxa3xx_init_nand (void )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = littleton_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (littleton_nand_partitions), };static void __init littleton_init_nand (void )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 , + .cs_num =1 , + .parts[0 ] = mxm_8x10_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (mxm_8x10_nand_partitions) };static void __init mxm_8x10_nand_init (void )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = raumfeld_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (raumfeld_nand_partitions), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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), + .cs_num =1 , + .parts[0 ] = zylonite_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (zylonite_nand_partitions), };static void __init zylonite_init_nand (void )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +6 -2
@@ -41,6 +41,8 @@ struct pxa3xx_nand_flash {struct pxa3xx_nand_timing *timing;/* NAND Flash timing */ }; +/* 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 +54,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 select would be used for this platform */ +int cs_num; +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;
drivers/mtd/nand/pxa3xx_nand.c +415 -320
1,281 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 22 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>---
?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 +++++++++++++++-----------
Quoted 1 line
?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 282 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -92,11 +92,13 @@ ?#define NDCB0_ADDR_CYC_SHIFT ? (16)?/* macros for registers read/write */
drivers/mtd/nand/pxa3xx_nand.c +6
-4-#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 {drivers/mtd/nand/pxa3xx_nand.c +22
-6@@ -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;
- ? ? ? structpxa_dma_desc? ?*data_desc;
+ ? ? ?dma_addr_t? ? ? ? ? ? ?data_buff_phys;
? ? ? ?dma_addr_t ? ? ? ? ? ? ?data_desc_addr;
+ ? ? ? structpxa_dma_desc? ?*data_desc;- ? ? ?
uint32_t? ? ? ? ? ? ? ?reg_ndcr;
-
- ? ? ? /* saved column/page_addr duringCMD_SEQIN*/
- ? ? ? int ? ? ? ? ? ? ? ? ? ?seqin_column;
- ? ? ? int ? ? ? ? ? ? ? ? ? ?seqin_page_addr;
+ ? ? ? structpxa3xx_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;drivers/mtd/nand/pxa3xx_nand.c +0
-11- - ? ? ? /* 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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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])drivers/mtd/nand/pxa3xx_nand.c +1
-1-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)
?#defineNDTR0_tCS(c)? (min((c), 7)<< 16)drivers/mtd/nand/pxa3xx_nand.c +3
-1@@ -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)) |drivers/mtd/nand/pxa3xx_nand.c +5
-4@@ -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;
? ? ? ?}
?}drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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_irqto handle all logic. ?*/drivers/mtd/nand/pxa3xx_nand.c +1
-1-static void pxa3xx_nand_start (struct pxa3xx_nand_info *info) +static void pxa3xx_nand_start (struct pxa3xx_nand *nand)?{
+ ? ? ? structpxa3xx_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);
?}drivers/mtd/nand/pxa3xx_nand.c +1
-1-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);
?}drivers/mtd/nand/pxa3xx_nand.c +1
-1-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); ?}drivers/mtd/nand/pxa3xx_nand.c +1
-1-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); ?}drivers/mtd/nand/pxa3xx_nand.c +1
-1-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) {
? ? ? ?caseSTATE_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;
? ? ? ?caseSTATE_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));
Quoted 8 lines
+ ? ? ? ? ? ? ? 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?
Quoted 1 line
? ? ? ? ? ? ? ?BUG();
Is crashing the entire kernel really necessary here?
Quoted 610 lines
? ? ? ?}
?}drivers/mtd/nand/pxa3xx_nand.c +1
-1-static void start_data_dma (struct pxa3xx_nand_info *info) +static void start_data_dma (struct pxa3xx_nand *nand)?{
- ? ? ? structpxa_dma_desc*desc =info->data_desc;
- ? ? ? intdma_len=ALIGN(info->data_size + info->oob_size, 32);
+ ? ? ? structpxa_dma_desc*desc =nand->data_desc;
+ ? ? ? intdma_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) {
? ? ? ?caseSTATE_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;
? ? ? ?caseSTATE_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)?{
- ? ? ? structpxa3xx_nand_info*info = data;
+ ? ? ? structpxa3xx_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_tpxa3xx_nand_irq(int irq, void *devid)?{
- ? ? ? structpxa3xx_nand_info*info = devid;
- ? ? ? unsigned int status,is_completed= 0;
+ ? ? ? structpxa3xx_nand*nand = devid;
+ ? ? ? structpxa3xx_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);
? ? ? ? ? ? ? ? ? ? ? ?gotoNORMAL_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:
? ? ? ?returnIRQ_HANDLED;
?}drivers/mtd/nand/pxa3xx_nand.c +0
-6-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--)drivers/mtd/nand/pxa3xx_nand.c +5
-3@@ -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) {
? ? ? ?caseNAND_CMD_READ0:
? ? ? ?caseNAND_CMD_PAGEPROG:
- ? ? ? ? ? ? ?info->use_ecc= 1;
+ ? ? ? ? ? ? ?nand->use_ecc= 1;
? ? ? ?caseNAND_CMD_READOOB:
? ? ? ? ? ? ? ?pxa3xx_set_datasize(info);
+ ? ? ? ? ? ? ?nand->oob_buff=nand->data_buff+nand->data_size;
+ ? ? ? ? ? ? ?nand->use_dma=use_dma;
? ? ? ? ? ? ? ?break;
? ? ? ?caseNAND_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);drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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_DBCdrivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;
? ? ? ?caseNAND_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;
? ? ? ?caseNAND_CMD_RESET:
? ? ? ? ? ? ? ?cmd =info->cmdset->reset;
- ? ? ? ? ? ? ?info->ndcb0|=NDCB0_CMD_TYPE(5)
+ ? ? ? ? ? ? ?nand->ndcb0|=NDCB0_CMD_TYPE(5)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd;? ? ? ? ? ? ? ?break;
drivers/mtd/nand/pxa3xx_nand.c +1
-0@@ -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;? ? ? ?/*
drivers/mtd/nand/pxa3xx_nand.c +16
-4@@ -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,drivers/mtd/nand/pxa3xx_nand.c +2
-1@@ -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++;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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 (all0xff), 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++;
? ? ? ?}drivers/mtd/nand/pxa3xx_nand.c +2
-1@@ -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;
?}drivers/mtd/nand/pxa3xx_nand.c +13
-9@@ -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_commandhas 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 {
? ? ? ? ? ? ? ? ? ? ? ?/*drivers/mtd/nand/pxa3xx_nand.c +2
-1@@ -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 */drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +8
-1@@ -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;
?}drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -830,50 +875,31 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)?*/
?#defineMAX_BUFF_SIZE?PAGE_SIZEdrivers/mtd/nand/pxa3xx_nand.c +1
-1-static int pxa3xx_nand_init_buff (struct pxa3xx_nand_info *info) +static void free_cs_resource (struct pxa3xx_nand_info *info,int cs)?{
- ? ? ? structplatform_device*pdev =info->pdev;
- ? ? ? intdata_desc_offset=MAX_BUFF_SIZE-sizeof(struct pxa_dma_desc);drivers/mtd/nand/pxa3xx_nand.c +8
-27- - ? ? ? 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)?{
- ? ? ? structmtd_info*mtd =info->mtd;
+ ? ? ? structpxa3xx_nand*nand =info->nand_data;
+ ? ? ? structmtd_info*mtd =get_mtd_by_info(info); ? ? ? ?structnand_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;drivers/mtd/nand/pxa3xx_nand.c +3
-1@@ -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))
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 929
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-3? ? ? ? ? ? ? ?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 19 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-5? ? ? ? ? ? ? ?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; ? ? ? ?}
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 957
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-2@@ -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.
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 962
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1? ? ? ? ? ? ? ?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.
[...]
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1283
Quoted 10 lines
?#ifdef
CONFIG_PMdrivers/mtd/nand/pxa3xx_nand.c +2
-2@@ -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
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Daniel,
Quoted 25 lines · Daniel Mack
Quoted 22 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>---
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 +++++++++++++++-----------Quoted 1 line
9 files changed, 444 insertions(+), 338 deletions(-)
Quoted 2 lines
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
Quoted 287 lines
[...]
Quoted 284 lines
drivers/mtd/nand/pxa3xx_nand.c +39
-22@@ -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 ? */ intuse_dma; /* use DMA ? */
intis_ready;
-
- unsigned int page_size; /* page size of attached chip */
- unsigned int data_size; /* data size in FIFO */ int retcode;
- struct completioncmd_complete;/* generated NDCBx register values */
+uint8_ttotal_cmds;
uint32_t ndcb0;
uint32_t ndcb1;
uint32_t ndcb2;drivers/mtd/nand/pxa3xx_nand.c +0
-11- - /* 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;drivers/mtd/nand/pxa3xx_nand.c +4
-2@@ -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))|drivers/mtd/nand/pxa3xx_nand.c +5
-4@@ -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;
}
}drivers/mtd/nand/pxa3xx_nand.c +21
-19@@ -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;
caseSTATE_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,
Quoted 8 lines
Quoted 6 lines
+
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.
Quoted 675 lines
Quoted 2 lines
BUG();
Is crashing the entire kernel really necessary here?
Quoted 610 lines
}
}drivers/mtd/nand/pxa3xx_nand.c +1
-1-static void start_data_dma (struct pxa3xx_nand_info *info) +static void start_data_dma (struct pxa3xx_nand *nand){
- structpxa_dma_desc*desc =info->data_desc;
- intdma_len=ALIGN(info->data_size + info->oob_size, 32);
+ structpxa_dma_desc*desc =nand->data_desc;
+ intdma_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) {
caseSTATE_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;
caseSTATE_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){
- structpxa3xx_nand_info*info = data;
+ structpxa3xx_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_tpxa3xx_nand_irq(int irq, void *devid){
- structpxa3xx_nand_info*info = devid;
- unsigned int status,is_completed= 0;
+ structpxa3xx_nand*nand = devid;
+ structpxa3xx_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);
gotoNORMAL_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:
returnIRQ_HANDLED;
}drivers/mtd/nand/pxa3xx_nand.c +0
-6-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--)drivers/mtd/nand/pxa3xx_nand.c +14
-9@@ -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:
caseNAND_CMD_PAGEPROG:
-info->use_ecc= 1;
+nand->use_ecc= 1;
caseNAND_CMD_READOOB:
pxa3xx_set_datasize(info);
+nand->oob_buff=nand->data_buff+nand->data_size;
+nand->use_dma=use_dma;
break;
caseNAND_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);drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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_DBCdrivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;
caseNAND_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;
caseNAND_CMD_RESET:
cmd =info->cmdset->reset;
-info->ndcb0|=NDCB0_CMD_TYPE(5)
+nand->ndcb0|=NDCB0_CMD_TYPE(5)
| cmd;break;
drivers/mtd/nand/pxa3xx_nand.c +21
-7@@ -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++;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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 (all0xff), 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++;
}drivers/mtd/nand/pxa3xx_nand.c +19
-13@@ -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 */drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +24
-36@@ -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;drivers/mtd/nand/pxa3xx_nand.c +3
-1@@ -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))drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 929
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-3goto 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 19 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-5return -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; }drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 957
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-2@@ -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.
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 963
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1return -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 5 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0#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;
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1283
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-2- 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
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Lei,
Quoted 28 lines · Lei Wen
Hi Daniel,
Quoted 25 lines · Daniel Mack
Quoted 23 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>---
?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(-)
Quoted 8 lines
Quoted 2 lines
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
I have a similar setup, also with those two patches on top, but applying your patch gives me:
Applying: MTD: pxa3xx_nand: enable multiple chip select support
error: patch failed: drivers/mtd/nand/pxa3xx_nand.c:477
error: drivers/mtd/nand/pxa3xx_nand.c: patch does not apply Patch failed at 0001 MTD: pxa3xx_nand: enable multiple chip select support When you have resolved this problem run "git am --resolved". If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort".
Could you push your branch somewhere?
Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
?#ifdef
CONFIG_PM(quoted diff) +0
-0@@ -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;Quoted 7 lines
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1283
Quoted 5 lines
(quoted diff) +2
-2- ? ? ? 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.
Quoted 1 line
Could you post your build log?
I didn't compile it because I couldn't, but "nand" is certainly undefined in this context now. Did you compile and test this code with "CONFIG_PM=y"?
Thanks,
Daniel
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Daniel,
Quoted 66 lines · Daniel Mack
Hi Lei,
Quoted 28 lines · Lei Wen
Hi Daniel,
Quoted 25 lines · Daniel Mack
Quoted 23 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>---
?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(-)
Quoted 8 lines
Quoted 2 lines
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 mismatchI have a similar setup, also with those two patches on top, but applying your patch gives me:
Applying: MTD:
pxa3xx_nand: enable multiple chip select support
error: patch failed:drivers/mtd/nand/pxa3xx_nand.c:477
error:drivers/mtd/nand/pxa3xx_nand.c: patch does not apply Patch failed at 0001 MTD:pxa3xx_nand: enable multiple chip select support When you have resolved this problem run "git am --resolved". If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort".Could you push your branch somewhere?
Quoted 13 lines
Quoted 12 lines
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1283
Quoted 10 lines
?#ifdef
CONFIG_PM(quoted diff) +2
-2@@ -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.
Quoted 5 lines
Quoted 1 line
Could you post your build log?
I didn't compile it because I couldn't, but "nand" is certainly undefined in this context now. Did you compile and test this code with "
CONFIG_PM=y"?
You're right, I haven't take open PM config...
I would rebase this patch over l2-mtd-2.6.git for next post.
Thanks,
Lei
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenHi Lei,
Some comments from a quick look...
Quoted 10 lines · Lei Wen
Current
pxa3xx_nandcontroller 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.
You should _also_ put this comment inside the pxa3xx_nand.h may be even inside the pxa3xx_nand_platform_data structure, so people would not have to search the git log to find this problem.
Quoted 134 lines
Signed-off-by Lei Wen <[email protected]>--- 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(-)arch/arm/mach-mmp/aspenite.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = aspenite_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (aspenite_nand_partitions), };static struct i2c_board_info aspenite_i2c_info[]__initdata = {arch/arm/mach-pxa/cm-x300.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = cm_x300_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (cm_x300_nand_partitions), };static void __init cm_x300_init_nand (void )arch/arm/mach-pxa/colibri-pxa3xx.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = colibri_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (colibri_nand_partitions), };void __init colibri_pxa3xx_init_nand (void )arch/arm/mach-pxa/littleton.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = littleton_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (littleton_nand_partitions), };static void __init littleton_init_nand (void )arch/arm/mach-pxa/mxm8x10.c +5
-4@@ -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 , + .cs_num =1 , + .parts[0 ] = mxm_8x10_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (mxm_8x10_nand_partitions) };static void __init mxm_8x10_nand_init (void )arch/arm/mach-pxa/raumfeld.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = raumfeld_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (raumfeld_nand_partitions), };/** arch/arm/mach-pxa/zylonite.c +3
-2@@ -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), + .cs_num =1 , + .parts[0 ] = zylonite_nand_partitions, + .nr_parts[0 ] =ARRAY_SIZE (zylonite_nand_partitions), };static void __init zylonite_init_nand (void )arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +0
-0
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_flash { · line 44
Quoted 4 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-0@@ -41,6 +41,8 @@ struct pxa3xx_nand_flash {struct pxa3xx_nand_timing *timing;/* NAND Flash timing */ }; +/* The max num of chip select current support */
/* The maximum number of chip selects currently supported */
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 57
Quoted 11 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +2
-2+#define NUM_CHIP_SELECT (2)struct pxa3xx_nand_platform_data {/* the data flash bus is shared between the Static Memory @@ -52,8 +54,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 select would be used for this platform */
/* indicate how many chip selects will be used */
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 58
Quoted 1 line
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-0+int cs_num;
This name is too confusing, I think even num_cs is better or cs_count? Also, may be align it with the others?
Quoted 57 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +2
-0+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;drivers/mtd/nand/pxa3xx_nand.c +21
-6@@ -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;
drivers/mtd/nand/pxa3xx_nand.c enum { · line 154
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-0+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;
please, align
Quoted 53 lines
drivers/mtd/nand/pxa3xx_nand.c +12
-22-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 */
drivers/mtd/nand/pxa3xx_nand.c enum { · line 186
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-9-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; };
It looks like if you switch the names of the structures above, then the patch will be much shorter and cleaner,
but will it make structures meaning confusion?
Quoted 238 lines
drivers/mtd/nand/pxa3xx_nand.c +61
-57static 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);BUG (); } } -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;
drivers/mtd/nand/pxa3xx_nand.c static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) · line 434
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +8
-1+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 ;
This is confusing... do you use to ?: operator for differentiating between cs = 0 and cs = 1?
I think this is a bad idea.
Moreover, the use of ?: is discouraged among the kernel.
Quoted 83 lines
drivers/mtd/nand/pxa3xx_nand.c +23
-27+ 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)
drivers/mtd/nand/pxa3xx_nand.c static inline int is_buf_blank(uint8_t *buf, size_t len) · line 499
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-2{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 ;
This one is confusing too...
Besides, you don't need the parenthesis.
Quoted 330 lines
drivers/mtd/nand/pxa3xx_nand.c +81
-55addr_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,
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, · line 858
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-1static 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 ();
like Daniel already noticed, may be dev_err() is enough?
Quoted 69 lines
drivers/mtd/nand/pxa3xx_nand.c +14
-33+ } 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;
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) · line 905
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-2/* 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 ;
I think it is time to change this function return convention to propagate errors and not just 0 or 1, (may be in separate patch) what do you think?
Quoted 29 lines
drivers/mtd/nand/pxa3xx_nand.c +6
-4@@ -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);return -EINVAL ; }
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 913
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-4chip->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" );
Is this warning no longer needed?
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-3- +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);
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 965
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-1printk (KERN_ERR "ERROR!! flash not defined!!!\n" );return -EINVAL ; } -pxa3xx_nand_config_flash (info, f); +if (pxa3xx_nand_config_flash (info, f)) { +printk (KERN_ERR "ERROR! Configure failed\n" ); +return -EINVAL ; + }
Although, the pxa3xx_nand_config_flash() returns only 0 or -EINVAL, it is better to propagate its return value.
Quoted 292 lines
drivers/mtd/nand/pxa3xx_nand.c +124
-76pxa3xx_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,13 +977,13 @@ KEEP_CONFIG:if (nand_scan_ident (mtd,1 , def))return -ENODEV ;/* calculate addressing information */ + nand->oob_buff = nand->data_buff + mtd->writesize; info->col_addr_cycles = (mtd->writesize >=2048 ) ?2 :1 ; - info->oob_buff = info->data_buff + mtd->writesize;if ((mtd->size >> chip->page_shift) >65536 ) info->row_addr_cycles =3 ;else info->row_addr_cycles =2 ; - mtd->name = mtd_names[0 ]; + mtd->name = mtd_names[nand->chip_select]; chip->ecc.mode =NAND_ECC_HW ; chip->ecc.size = info->page_size;@@ -967,51 +994,33 @@ KEEP_CONFIG: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 nand_chip *chip;struct mtd_info *mtd; +struct pxa3xx_nand *nand;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; + nand =kzalloc (sizeof (struct mtd_info ) + +sizeof (struct pxa3xx_nand_info ),GFP_KERNEL ); +if (!nand) {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)) { + nand->pdev = pdev; + nand->clk =clk_get (&pdev->dev,NULL ); +if (IS_ERR (nand->clk)) {dev_err (&pdev->dev,"failed to get nand clock\n" ); - ret =PTR_ERR (info->clk); - goto fail_free_mtd; + ret =PTR_ERR (nand->clk); + goto fail_alloc; } -clk_enable (info->clk); +clk_enable (nand->clk); r =platform_get_resource (pdev,IORESOURCE_DMA ,0 );if (r ==NULL ) {@@ -1019,7 +1028,7 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ret = -ENXIO ; goto fail_put_clk; } - info->drcmr_dat = r->start; + nand->drcmr_dat = r->start; r =platform_get_resource (pdev,IORESOURCE_DMA ,1 );if (r ==NULL ) {@@ -1027,7 +1036,7 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ret = -ENXIO ; goto fail_put_clk; } - info->drcmr_cmd = r->start; + nand->drcmr_cmd = r->start; irq =platform_get_irq (pdev,0 );if (irq <0 ) {@@ -1050,81 +1059,147 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) goto fail_put_clk; } - info->mmio_base =ioremap (r->start,resource_size (r)); -if (info->mmio_base ==NULL ) { + nand->mmio_base =ioremap (r->start,resource_size (r)); +if (nand->mmio_base ==NULL ) {dev_err (&pdev->dev,"ioremap() failed\n" ); ret = -ENODEV ; goto fail_free_res; } - info->mmio_phys = r->start; - - ret =pxa3xx_nand_init_buff (info); -if (ret) - goto fail_free_io; + nand->mmio_phys = r->start;/* initialize all interrupts to be disabled */ -disable_int (info,NDSR_MASK ); +disable_int (nand,NDSR_MASK ); ret =request_irq (irq, pxa3xx_nand_irq,IRQF_DISABLED , - pdev->name, info); + pdev->name, nand);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, nand); + +spin_lock_init (&nand->controller.lock); +init_waitqueue_head (&nand->controller.wq); +for (cs =0 ; cs < pdata->cs_num; cs++) { + mtd =kzalloc (sizeof (struct mtd_info ) + +sizeof (struct pxa3xx_nand_info ), +GFP_KERNEL ); +if (!mtd) { +dev_err (&pdev->dev,"failed to allocate memory\n" ); + ret = -ENOMEM ; + goto fail_free_irq; + } + + info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + info->nand_data = nand; + info->chip_select = cs; + mtd->priv = info; + mtd->owner =THIS_MODULE ; + nand->info[cs] = info; + + chip = (struct nand_chip *)(&mtd[1 ]); + chip->controller = &nand->controller; + 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; } -platform_set_drvdata (pdev, info); +if (use_dma ==0 ) { + nand->data_buff =kmalloc (MAX_BUFF_SIZE ,GFP_KERNEL ); +if (nand->data_buff ==NULL ) { + ret = -ENOMEM ; + goto fail_free_buf; + } + goto success_exit; + } -return info; + nand->data_buff =dma_alloc_coherent (&pdev->dev,MAX_BUFF_SIZE , + &nand->data_buff_phys,GFP_KERNEL ); +if (nand->data_buff ==NULL ) { +dev_err (&pdev->dev,"failed to allocate dma buffer\n" ); + ret = -ENOMEM ; + goto fail_free_buf; + } + nand->data_desc = (void *)nand->data_buff + data_desc_offset; + nand->data_desc_addr = nand->data_buff_phys + data_desc_offset; + nand->data_dma_ch =pxa_request_dma ("nand-data" ,DMA_PRIO_LOW , + pxa3xx_nand_data_dma_irq, nand); +if (nand->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 , + nand->data_buff, nand->data_buff_phys); fail_free_buf: -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); +for (cs =0 ; cs < pdata->cs_num; cs++) { + info = nand->info[cs]; +free_cs_resource (info, cs); + } +fail_free_irq: +free_irq (irq, nand); fail_free_io: -iounmap (info->mmio_base); +iounmap (nand->mmio_base); fail_free_res:release_mem_region (r->start,resource_size (r)); fail_put_clk: -clk_disable (info->clk); -clk_put (info->clk); -fail_free_mtd: -kfree (mtd); -return NULL ; +clk_disable (nand->clk); +clk_put (nand->clk); +fail_alloc: +kfree (nand); +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 *nand =platform_get_drvdata (pdev); +struct pxa3xx_nand_platform_data *pdata; +struct pxa3xx_nand_info *info; +struct mtd_info *mtd;struct resource *r; -int irq; +int irq, cs;platform_set_drvdata (pdev,NULL ); + pdata = pdev->dev.platform_data; irq =platform_get_irq (pdev,0 );if (irq >=0 ) -free_irq (irq, info); +free_irq (irq, nand);if (use_dma) { -pxa_free_dma (info->data_dma_ch); -dma_free_writecombine (&pdev->dev, info->data_buff_size, - info->data_buff, info->data_buff_phys); +pxa_free_dma (nand->data_dma_ch); +dma_free_writecombine (&pdev->dev,MAX_BUFF_SIZE , + nand->data_buff, nand->data_buff_phys); }else -kfree (info->data_buff); +kfree (nand->data_buff); -iounmap (info->mmio_base); +iounmap (nand->mmio_base); r =platform_get_resource (pdev,IORESOURCE_MEM ,0 );release_mem_region (r->start,resource_size (r)); -clk_disable (info->clk); -clk_put (info->clk); +clk_disable (nand->clk); +clk_put (nand->clk); -if (mtd) { +for (cs =0 ; cs < pdata->cs_num; cs++) { + info = nand->info[cs]; +if (!info) +continue ; + mtd =get_mtd_by_info (info);mtd_device_unregister (mtd); -kfree (mtd); +free_cs_resource (info, cs); }return 0 ; }
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1216
Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-0@@ -1134,34 +1209,54 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +struct pxa3xx_nand *nand; +struct mtd_info *mtd; +int cs, ret, nr_parts, probe_success; + + probe_success =0 ;
Can this be done along with declaration?
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1225
Quoted 11 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-2pdata = pdev->dev.platform_data;if (!pdata) {dev_err (&pdev->dev,"no platform data defined\n" );return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) + ret =alloc_nand_resource (pdev); +if (ret)return -ENOMEM ;
Why not propagate the return value of alloc_nand_resource()?
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1232
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c +6
-5-if (pxa3xx_nand_scan (info->mtd)) { -dev_err (&pdev->dev,"failed to scan nand\n" ); -pxa3xx_nand_remove (pdev); -return -ENODEV ; - } + nand =platform_get_drvdata (pdev); +for (cs =0 ; cs < pdata->cs_num; cs++) { + info = nand->info[cs]; + mtd =get_mtd_by_info (info); +if (pxa3xx_nand_scan (mtd)) { +dev_err (&pdev->dev,"failed to scan nand\n" );
I think, it would be useful also to print here the return value of pxa3xx_nand_scan().
Quoted 24 lines
drivers/mtd/nand/pxa3xx_nand.c +14
-7+continue ; + } + + ret =0 ; + nr_parts =0 ; +if (mtd_has_cmdlinepart ()) { +const char *probes[] = {"cmdlinepart" ,NULL }; +struct mtd_partition *parts; -if (mtd_has_cmdlinepart ()) { -const char *probes[] = {"cmdlinepart" ,NULL }; -struct mtd_partition *parts; -int nr_parts; + nr_parts =parse_mtd_partitions (mtd, probes, &parts,0 ); - nr_parts =parse_mtd_partitions (info->mtd, probes, &parts,0 ); +if (nr_parts) + ret =mtd_device_register (mtd, parts, nr_parts); + } -if (nr_parts) -return mtd_device_register (info->mtd, parts, nr_parts); +if (!nr_parts) + ret = mtd_device_register(mtd, pdata->parts[cs],
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1258
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-1+ pdata->nr_parts[cs]); +if (!ret) + probe_success =1 ; } -return mtd_device_register (info->mtd, pdata->parts, pdata->nr_parts); +if (!probe_success) { +pxa3xx_nand_remove (pdev); +return -ENODEV ; + }else
You don't need this else statement
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-0+return 0 ; }#ifdef CONFIG_PM
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1285
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-2@@ -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);return 0 ;
I won't be able to test the patch in the near future, sorry...
Signature · 2 lines
Regards, Igor.
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Igor,
Quoted 19 lines · Igor Grinberg
Hi Lei,
Some comments from a quick look...
Quoted 10 lines · Lei Wen
Current
pxa3xx_nandcontroller 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.
Quoted 3 lines
You should _also_ put this comment inside the
pxa3xx_nand.hmay be even inside thepxa3xx_nand_platform_datastructure, so people would not have to search the git log to find this problem.
How about just throw out a BUG() to force people cannot set keep_config when supported cs num more than 1? Also appended with the comments above?
Quoted 156 lines
Quoted 138 lines
Signed-off-by Lei Wen <[email protected]>---
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(-)arch/arm/mach-mmp/aspenite.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = aspenite_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(aspenite_nand_partitions), }; static struct i2c_board_info aspenite_i2c_info[] __initdata = {arch/arm/mach-pxa/cm-x300.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = cm_x300_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(cm_x300_nand_partitions), }; static void __init cm_x300_init_nand(void)arch/arm/mach-pxa/colibri-pxa3xx.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = colibri_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(colibri_nand_partitions), }; void __init colibri_pxa3xx_init_nand(void)arch/arm/mach-pxa/littleton.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = littleton_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(littleton_nand_partitions), }; static void __init littleton_init_nand(void)arch/arm/mach-pxa/mxm8x10.c +5
-4@@ -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, + .cs_num = 1, + .parts[0] = mxm_8x10_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(mxm_8x10_nand_partitions) }; static void __init mxm_8x10_nand_init(void)arch/arm/mach-pxa/raumfeld.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = raumfeld_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(raumfeld_nand_partitions), }; /**arch/arm/mach-pxa/zylonite.c +3
-2@@ -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), + .cs_num = 1, + .parts[0] = zylonite_nand_partitions, + .nr_parts[0] = ARRAY_SIZE(zylonite_nand_partitions), }; static void __init zylonite_init_nand(void)arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +0
-0@@ -41,6 +41,8 @@ struct pxa3xx_nand_flash {struct
pxa3xx_nand_timing*timing; /* NAND Flash timing */ };Quoted 1 line
+/* The max num of chip select current support */
/* The maximum number of chip selects currently supported */
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 57
Quoted 11 lines
+#define
NUM_CHIP_SELECT(2)
structpxa3xx_nand_platform_data{/* the data flash bus is shared between the Static Memory
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-2@@ -52,8 +54,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 select would be used for this platform *//* indicate how many chip selects will be used */
Quoted 4 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 58
Quoted 1 line
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-0+ int cs_num;This name is too confusing, I think even
num_csis better orcs_count? Also, may be align it with the others?
I prefer the num_cs.
Quoted 58 lines
Quoted 58 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +2
-0+ 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;drivers/mtd/nand/pxa3xx_nand.c +21
-6@@ -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;
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c enum { · line 154
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-0+ 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;please, align
Do you still mean cs_num? What this comment refer to?
Quoted 60 lines
Quoted 60 lines
drivers/mtd/nand/pxa3xx_nand.c +11
-16- 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 ? */ intuse_dma; /* use DMA ? */
intis_ready;
-
- unsigned int page_size; /* page size of attached chip */
- unsigned int data_size; /* data size in FIFO */ int retcode;
- struct completioncmd_complete;/* generated NDCBx register values */
+uint8_ttotal_cmds;
uint32_tndcb0;
uint32_tndcb1;
uint32_tndcb2;drivers/mtd/nand/pxa3xx_nand.c +0
-8- - /* 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;
Quoted 8 lines
Quoted 4 lines
-
- unsigned int col_addr_cycles;
- unsigned int row_addr_cycles;
};It looks like if you switch the names of the structures above, then the patch will be much shorter and cleaner,
but will it make structures meaning confusion?
Could you elaborate more about this? Do you means no need to create a seperated structure?
Quoted 243 lines
Quoted 243 lines
static int
use_dma= 1;drivers/mtd/nand/pxa3xx_nand.c +4
-2@@ -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))|drivers/mtd/nand/pxa3xx_nand.c +5
-4@@ -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;
}
}drivers/mtd/nand/pxa3xx_nand.c +21
-19@@ -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;
caseSTATE_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);
BUG();
}
}drivers/mtd/nand/pxa3xx_nand.c +1
-1-static void start_data_dma (struct pxa3xx_nand_info *info) +static void start_data_dma (struct pxa3xx_nand *nand){
- structpxa_dma_desc*desc =info->data_desc;
- intdma_len=ALIGN(info->data_size + info->oob_size, 32);
+ structpxa_dma_desc*desc =nand->data_desc;
+ intdma_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) {
caseSTATE_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;
caseSTATE_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){
- structpxa3xx_nand_info*info = data;
+ structpxa3xx_nand*nand = data;
uint32_tdcsr;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_tpxa3xx_nand_irq(int irq, void *devid){
- structpxa3xx_nand_info*info = devid;
- unsigned int status,is_completed= 0;
+ structpxa3xx_nand*nand = devid;
+ structpxa3xx_nand_info*info;
+ unsigned int status,is_completed= 0, cs;
+ unsigned int ready,cmd_done,page_done,badblock_detect;
Quoted 11 lines
Quoted 6 lines
- 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;This is confusing... do you use to ?: operator for differentiating between cs = 0 and cs = 1?
I think this is a bad idea.
Moreover, the use of ?: is discouraged among the kernel.
I could use if/else to replace this statement.
Quoted 91 lines
Quoted 91 lines
+ 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);
gotoNORMAL_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:
returnIRQ_HANDLED;
}drivers/mtd/nand/pxa3xx_nand.c +0
-6-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--)drivers/mtd/nand/pxa3xx_nand.c +3
-2@@ -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];
Quoted 6 lines
drivers/mtd/nand/pxa3xx_nand.c static inline int is_buf_blank(uint8_t *buf, size_t len) · line 499
Quoted 3 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1- ndcb0 = 0; + mtd = get_mtd_by_info(info); + ndcb0 = (nand->chip_select) ? NDCB0_CSEL : 0;This one is confusing too...
Besides, you don't need the parenthesis.
Got that. I would fix it.
Quoted 331 lines
Quoted 331 lines
drivers/mtd/nand/pxa3xx_nand.c +9
-6addr_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:
caseNAND_CMD_PAGEPROG:
-info->use_ecc= 1;
+nand->use_ecc= 1;
caseNAND_CMD_READOOB:
pxa3xx_set_datasize(info);
+nand->oob_buff=nand->data_buff+nand->data_size;
+nand->use_dma=use_dma;
break;
caseNAND_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);drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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_DBCdrivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;
caseNAND_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;
caseNAND_CMD_RESET:
cmd =info->cmdset->reset;
-info->ndcb0|=NDCB0_CMD_TYPE(5)
+nand->ndcb0|=NDCB0_CMD_TYPE(5)
| cmd;break;
drivers/mtd/nand/pxa3xx_nand.c +21
-7@@ -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++;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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 (all0xff), 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++;
}drivers/mtd/nand/pxa3xx_nand.c +19
-13@@ -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_tndcr =0x0; /* enable all interrupts */drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -811,15 +849,22 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, · line 858
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-1static 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();like Daniel already noticed, may be
dev_err()is enough?
Would change to dev_err();
Quoted 70 lines
Quoted 70 lines
drivers/mtd/nand/pxa3xx_nand.c +14
-33+ } 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;
Quoted 13 lines
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-2/* 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;I think it is time to change this function return convention to propagate errors and not just 0 or 1, (may be in separate patch) what do you think?
How about return 0 when sensing the READY signal, or return -ENODEV?
Quoted 31 lines
Quoted 31 lines
drivers/mtd/nand/pxa3xx_nand.c +6
-4@@ -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); return -EINVAL; }
Quoted 11 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 913
Quoted 9 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-4chip->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");Is this warning no longer needed?
Would readd it in the next post.
Quoted 18 lines
Quoted 18 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-3- + 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"); return -EINVAL; }
Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 965
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-1- pxa3xx_nand_config_flash(info, f); + if (pxa3xx_nand_config_flash(info, f)) { + printk(KERN_ERR "ERROR! Configure failed\n"); + return -EINVAL; + }Although, the
pxa3xx_nand_config_flash()returns only 0 or-EINVAL, it is better to propagate its return value.
Ok, would apply this.
Quoted 296 lines
Quoted 296 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-1pxa3xx_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,13 +977,13 @@ KEEP_CONFIG: if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ + nand->oob_buff = nand->data_buff + mtd->writesize; info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; - info->oob_buff = info->data_buff + mtd->writesize; if ((mtd->size >> chip->page_shift) > 65536) info->row_addr_cycles = 3;else
info->row_addr_cycles= 2;
-mtd->name= mtd_names[0];
+mtd->name= mtd_names[nand->chip_select];
chip->ecc.mode=NAND_ECC_HW;
chip->ecc.size=info->page_size;drivers/mtd/nand/pxa3xx_nand.c +90
-48@@ -967,51 +994,33 @@ KEEP_CONFIG: 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 nand_chip *chip; struct mtd_info *mtd; + struct pxa3xx_nand *nand; 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; + nand = kzalloc(sizeof(struct mtd_info) + + sizeof(struct pxa3xx_nand_info), GFP_KERNEL); + if (!nand) { 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)) { + nand->pdev = pdev; + nand->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(nand->clk)) { dev_err(&pdev->dev, "failed to get nand clock\n"); - ret = PTR_ERR(info->clk); - goto fail_free_mtd; + ret = PTR_ERR(nand->clk); + goto fail_alloc; } - clk_enable(info->clk); + clk_enable(nand->clk); r = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (r == NULL) {@@ -1019,7 +1028,7 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ret = -ENXIO; goto fail_put_clk; } - info->drcmr_dat = r->start; + nand->drcmr_dat = r->start; r = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (r == NULL) {@@ -1027,7 +1036,7 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) ret = -ENXIO; goto fail_put_clk; } - info->drcmr_cmd = r->start; + nand->drcmr_cmd = r->start; irq = platform_get_irq(pdev, 0); if (irq < 0) {@@ -1050,81 +1059,147 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) goto fail_put_clk; } - info->mmio_base = ioremap(r->start, resource_size(r)); - if (info->mmio_base == NULL) { + nand->mmio_base = ioremap(r->start, resource_size(r)); + if (nand->mmio_base == NULL) { dev_err(&pdev->dev, "ioremap() failed\n"); ret = -ENODEV; goto fail_free_res; } - info->mmio_phys = r->start; - - ret = pxa3xx_nand_init_buff(info); - if (ret) - goto fail_free_io; + nand->mmio_phys = r->start; /* initialize all interrupts to be disabled */ - disable_int(info, NDSR_MASK); + disable_int(nand, NDSR_MASK); ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED, - pdev->name, info); + pdev->name, nand); 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, nand); + + spin_lock_init(&nand->controller.lock); + init_waitqueue_head(&nand->controller.wq); + for (cs = 0; cs < pdata->cs_num; cs++) { + mtd = kzalloc(sizeof(struct mtd_info) + + sizeof(struct pxa3xx_nand_info), + GFP_KERNEL); + if (!mtd) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto fail_free_irq; + } + + info = (struct pxa3xx_nand_info *)(&mtd[1]); + info->nand_data = nand; + info->chip_select = cs; + mtd->priv = info; + mtd->owner = THIS_MODULE; + nand->info[cs] = info; + + chip = (struct nand_chip *)(&mtd[1]); + chip->controller = &nand->controller; + 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; } - platform_set_drvdata(pdev, info); + if (use_dma == 0) { + nand->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); + if (nand->data_buff == NULL) { + ret = -ENOMEM; + goto fail_free_buf; + } + goto success_exit; + } - return info; + nand->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE, + &nand->data_buff_phys, GFP_KERNEL); + if (nand->data_buff == NULL) { + dev_err(&pdev->dev, "failed to allocate dma buffer\n"); + ret = -ENOMEM; + goto fail_free_buf; + } + nand->data_desc = (void *)nand->data_buff + data_desc_offset; + nand->data_desc_addr = nand->data_buff_phys + data_desc_offset; + nand->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW, + pxa3xx_nand_data_dma_irq, nand); + if (nand->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, + nand->data_buff, nand->data_buff_phys);fail_free_buf:
-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);
+ for (cs = 0; cs <pdata->cs_num; cs++) {
+ info = nand->info[cs];
+free_cs_resource(info, cs);
+ }
+fail_free_irq:
+free_irq(irq, nand);
fail_free_io:
-iounmap(info->mmio_base);
+iounmap(nand->mmio_base);
fail_free_res:
release_mem_region(r->start, resource_size(r));fail_put_clk:
-clk_disable(info->clk);
-clk_put(info->clk);drivers/mtd/nand/pxa3xx_nand.c +5
-3-fail_free_mtd: - kfree(mtd); - return NULL; + clk_disable(nand->clk); + clk_put(nand->clk); +fail_alloc: + kfree(nand); + return ret;}
static int
pxa3xx_nand_remove(struct platform_device *pdev){
- structpxa3xx_nand_info*info =platform_get_drvdata(pdev);
- structmtd_info*mtd =info->mtd;
+ structpxa3xx_nand*nand =platform_get_drvdata(pdev);
+ structpxa3xx_nand_platform_data*pdata;
+ structpxa3xx_nand_info*info;
+ structmtd_info*mtd;
struct resource *r;
- int irq;
+ int irq, cs;
platform_set_drvdata(pdev, NULL);
+ pdata =pdev->dev.platform_data;irq =
platform_get_irq(pdev, 0);
if (irq >= 0)
-free_irq(irq, info);
+free_irq(irq, nand);
if (use_dma) {
-pxa_free_dma(info->data_dma_ch);
- dma_free_writecombine(&pdev->dev,info->data_buff_size,
-info->data_buff,info->data_buff_phys);
+pxa_free_dma(nand->data_dma_ch);
+ dma_free_writecombine(&pdev->dev,MAX_BUFF_SIZE,
+nand->data_buff,nand->data_buff_phys); } else
-kfree(info->data_buff);
+kfree(nand->data_buff);-
iounmap(info->mmio_base);
+iounmap(nand->mmio_base);
r =platform_get_resource(pdev, IORESOURCE_MEM, 0);release_mem_region(r->start, resource_size(r));-
clk_disable(info->clk);
-clk_put(info->clk);
+clk_disable(nand->clk);
+clk_put(nand->clk);- if (mtd) {
+ for (cs = 0; cs <pdata->cs_num; cs++) {
+ info = nand->info[cs];
+ if (!info)
+ continue;
+ mtd =get_mtd_by_info(info);
mtd_device_unregister(mtd);
- kfree(mtd);
+free_cs_resource(info, cs);
}
return 0;
}drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -1134,34 +1209,54 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info;
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1216
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-0+ struct pxa3xx_nand *nand; + struct mtd_info *mtd; + int cs, ret, nr_parts, probe_success; + + probe_success = 0;Can this be done along with declaration?
Ok, would apply to the next post.
Quoted 7 lines
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -ENODEV; }
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1225
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-2- info = alloc_nand_resource(pdev); - if (info == NULL) + ret = alloc_nand_resource(pdev); + if (ret) return -ENOMEM;Why not propagate the return value of
alloc_nand_resource()?
Would apply propagate error to the next post.
Quoted 14 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1232
Quoted 13 lines
drivers/mtd/nand/pxa3xx_nand.c +6
-5- if (pxa3xx_nand_scan(info->mtd)) { - dev_err(&pdev->dev, "failed to scan nand\n"); - pxa3xx_nand_remove(pdev); - return -ENODEV; - } + nand = platform_get_drvdata(pdev); + for (cs = 0; cs < pdata->cs_num; cs++) { + info = nand->info[cs]; + mtd = get_mtd_by_info(info); + if (pxa3xx_nand_scan(mtd)) { + dev_err(&pdev->dev, "failed to scan nand\n");
Quoted 1 line
I think, it would be useful also to print here the return value of
pxa3xx_nand_scan().
Ok, would apply to the next post
Quoted 30 lines
Quoted 30 lines
drivers/mtd/nand/pxa3xx_nand.c +17
-7+ continue; + } + + ret = 0; + nr_parts = 0; + if (mtd_has_cmdlinepart()) { + const char *probes[] = { "cmdlinepart", NULL }; + struct mtd_partition *parts; - if (mtd_has_cmdlinepart()) { - const char *probes[] = { "cmdlinepart", NULL }; - struct mtd_partition *parts; - int nr_parts; + nr_parts = parse_mtd_partitions(mtd, probes, &parts, 0); - nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); + if (nr_parts) + ret = mtd_device_register(mtd, parts, nr_parts); + } - if (nr_parts) - return mtd_device_register(info->mtd, parts, nr_parts); + if (!nr_parts) + ret = mtd_device_register(mtd, pdata->parts[cs], + pdata->nr_parts[cs]); + if (!ret) + probe_success = 1; }
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1258
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-1- return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); + if (!probe_success) { + pxa3xx_nand_remove(pdev); + return -ENODEV; + } elseYou don't need this else statement
Would apply to the next post.
Quoted 15 lines
Quoted 15 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-2+ return 0; } #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);
Quoted 4 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1285
Quoted 1 line
drivers/mtd/nand/pxa3xx_nand.c +0
-0return 0;I won't be able to test the patch in the near future, sorry...
Thanks for comments.
Best regards,
Lei
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Lei,
Quoted 14 lines · Lei Wen
Hi Igor,
Quoted 11 lines · Igor Grinberg
Quoted 10 lines · Lei Wen
Current
pxa3xx_nandcontroller 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.
Quoted 5 lines
Quoted 3 lines
You should _also_ put this comment inside the
pxa3xx_nand.hmay be even inside thepxa3xx_nand_platform_datastructure, so people would not have to search the git log to find this problem.How about just throw out a
BUG()to force people cannot setkeep_configwhen supported cs num more than 1? Also appended with the comments above?
I don't think BUG() is a good idea, instead what you can do is force the user of the _new_ feature to _not_ use the keep_config by overriding the keep_config to 0 and printing a warning that keep_config is prohibited with multiple chip selects feature and that it will be disabled.
Of course you will still need to put a comment inside the pxa3xx_nand.h.
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Signed-off-by Lei Wen <[email protected]>--- 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(-)
[...]
Quoted 24 lines
Quoted 24 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_flash { · line 44
Quoted 9 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-0@@ -41,6 +41,8 @@ struct pxa3xx_nand_flash {struct pxa3xx_nand_timing *timing;/* NAND Flash timing */ }; +/* The max num of chip select current support */ /* The maximum number of chip selects currently supported */
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 57
Quoted 11 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +2
-2+#define NUM_CHIP_SELECT (2)struct pxa3xx_nand_platform_data {/* the data flash bus is shared between the Static Memory @@ -52,8 +54,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 select would be used for this platform */ /* indicate how many chip selects will be used */
Quoted 4 lines
Quoted 3 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h struct pxa3xx_nand_platform_data { · line 58
Quoted 1 line
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +1
-0+int cs_num;This name is too confusing, I think even
num_csis better orcs_count? Also, may be align it with the others?I prefer the
num_cs.
Good.
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +2
-0+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;drivers/mtd/nand/pxa3xx_nand.c +0
-0
[...]
Quoted 33 lines
Quoted 22 lines
Quoted 22 lines
drivers/mtd/nand/pxa3xx_nand.c +14
-2@@ -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;Quoted 11 lines
drivers/mtd/nand/pxa3xx_nand.c enum { · line 154
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-0+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;please, align
Quoted 1 line
Do you still mean
cs_num? What this comment refer to?
No, I mean the white space before *pdev - it is not aligned with all others
Quoted 65 lines
Quoted 57 lines
Quoted 57 lines
drivers/mtd/nand/pxa3xx_nand.c +12
-27-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;Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c enum { · line 186
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-4-size_t read_id_bytes; - -unsigned int col_addr_cycles; -unsigned int row_addr_cycles; };It looks like if you switch the names of the structures above, then the patch will be much shorter and cleaner,
but will it make structures meaning confusion?
Quoted 2 lines
Could you elaborate more about this? Do you means no need to create a seperated structure?
No, if you have 2 chips, then certainly you'd better have a separate structure for the chip description.
What I was wondering, is that there are many places in the patch where you change the "info" to "nand", may be this can be avoided if you keep the structure that describes the controller ("pxa3xx_nand" in the patch) named "pxa3xx_nand_info" and the new structure that describes the chip will be named something else like pxa3xx_nand_chip or anything like this. This way, your patch will not have to change the "info" to "nand" in many places (or maybe even all places) and will be much shorter and will include only functional changes.
[...]
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
drivers/mtd/nand/pxa3xx_nand.c +9
-3static 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 ;
Quoted 5 lines
Quoted 4 lines
This is confusing... do you use to ?: operator for differentiating between cs = 0 and cs = 1?
I think this is a bad idea.
Moreover, the use of ?: is discouraged among the kernel.I could use if/else to replace this statement.
or switch, what ever you like, but please, don't leave it like
if (cs) ..., because this is confusing it has a meaning of "cs is good or bad?", while actually, you want to know if it is 0 or 1 (both values are good).
[...]
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-2-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];
Quoted 6 lines
Quoted 5 lines
drivers/mtd/nand/pxa3xx_nand.c static inline int is_buf_blank(uint8_t *buf, size_t len) · line 499
Quoted 3 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1- ndcb0 =0 ; + mtd =get_mtd_by_info (info); + ndcb0 = (nand->chip_select) ?NDCB0_CSEL :0 ;This one is confusing too...
Besides, you don't need the parenthesis.Got that. I would fix it.
Good, my previous explanation also applies here.
Thanks
[...]
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
static int
pxa3xx_nand_sensing(struct pxa3xx_nand_info *info){drivers/mtd/nand/pxa3xx_nand.c +5
-3-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 ;
Quoted 3 lines
Quoted 2 lines
I think it is time to change this function return convention to propagate errors and not just 0 or 1, (may be in separate patch) what do you think?
How about return 0 when sensing the READY signal, or return
-ENODEV?
Yes, this should be fine, but also don't forget about pxa3xx_nand_config_flash() function call - it can return 0 or -EINVAL and it should also propagate instead of being squashed.
Quoted 27 lines
Quoted 27 lines
Quoted 27 lines
drivers/mtd/nand/pxa3xx_nand.c +6
-4@@ -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);
Quoted 1 line
Quoted 1 line
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 931
Quoted 1 line
drivers/mtd/nand/pxa3xx_nand.c +0
-0return -EINVAL ;
after the change of pxa3xx_nand_sensing() function, you should change the above "return -EINVAL;" into "return ret;"
[...]
Signature · 2 lines
Regards, Igor.
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
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.
--- 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(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +17 -2
@@ -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;
drivers/mtd/nand/pxa3xx_nand.c +306 -206
944 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 5 lines · Lei Wen
Current
pxa3xx_nandcontroller has two chip select which both be workable. This patch enable this feature.Update platform driver to support this feature.
Quoted 7 lines
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 <[email protected]>
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:
Thanks!
Daniel
Quoted 1,161 lines
---
?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(-)
arch/arm/mach-mmp/aspenite.c +3
-2@@ -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 = {arch/arm/mach-pxa/cm-x300.c +3
-2@@ -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)arch/arm/mach-pxa/colibri-pxa3xx.c +3
-2@@ -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)arch/arm/mach-pxa/littleton.c +3
-2@@ -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)arch/arm/mach-pxa/mxm8x10.c +5
-4@@ -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)arch/arm/mach-pxa/raumfeld.c +3
-2@@ -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), ?};?/**
arch/arm/mach-pxa/zylonite.c +3
-2@@ -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)arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +0
-0@@ -41,6 +41,19 @@ struct pxa3xx_nand_flash {? ? ? ?struct
pxa3xx_nand_timing*timing; ? ? ?/* NAND Flash timing */ ?};arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +13
-0+/* +* 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
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +0
-0@@ -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 structmtd_partition? ? ? ? ? ? ?*parts[NUM_CHIP_SELECT];
+ ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ? ? ? ? ?nr_parts[NUM_CHIP_SELECT];? ? ? ?const struct
pxa3xx_nand_flash* ? ? ? ?flash; ? ? ? ?size_t ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_flash;drivers/mtd/nand/pxa3xx_nand.c +24
-4@@ -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;drivers/mtd/nand/pxa3xx_nand.c +1
-7@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-11- - ? ? ? /* 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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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])drivers/mtd/nand/pxa3xx_nand.c +1
-1-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)
?#defineNDTR0_tCS(c)? (min((c), 7)<< 16)drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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)drivers/mtd/nand/pxa3xx_nand.c +1
-1-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) ?{
+ ? ? ? structpxa3xx_nand_info*info =host->info_data;
? ? ? ?unsigned longnand_clk=clk_get_rate(info->clk);
? ? ? ?uint32_t ndtr0, ndtr1;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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)?{
- ? ? ? intoob_enable=info->reg_ndcr&NDCR_SPARE_EN;
+ ? ? ? structpxa3xx_nand_host*host = info->host[info->cs];
+ ? ? ? intoob_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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)?*/
?static voidpxa3xx_nand_start(struct pxa3xx_nand_info *info)?{
+ ? ? ? structpxa3xx_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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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();
? ? ? ?}
?}drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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();
? ? ? ?}drivers/mtd/nand/pxa3xx_nand.c +18
-12@@ -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:drivers/mtd/nand/pxa3xx_nand.c +2
-3@@ -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:
? ? ? ?caseNAND_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);drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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);drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -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_ENdrivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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)drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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)drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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;
? ? ? ?}drivers/mtd/nand/pxa3xx_nand.c +2
-1@@ -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;? ? ? ?/*
drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -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);drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -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,drivers/mtd/nand/pxa3xx_nand.c +12
-6@@ -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_commandhas waited for command complete */ ? ? ? ?if (this->state==FL_WRITING||this->state==FL_ERASING) {drivers/mtd/nand/pxa3xx_nand.c +1
-0@@ -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 supportkeep_config
+ ? ? ? ?* when there is more than one chip attached to the controller
+ ? ? ? ?*/
+ ? ? ? structpxa3xx_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;
?}drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -829,59 +874,41 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)?* data buffer and the DMA descriptor
?*/
?#defineMAX_BUFF_SIZE?PAGE_SIZEdrivers/mtd/nand/pxa3xx_nand.c +1
-2- -static int pxa3xx_nand_init_buff (struct pxa3xx_nand_info *info) +static void free_cs_resource (struct pxa3xx_nand_info *info,int cs)?{
- ? ? ? structplatform_device*pdev =info->pdev;
- ? ? ? intdata_desc_offset=MAX_BUFF_SIZE-sizeof(struct pxa_dma_desc);drivers/mtd/nand/pxa3xx_nand.c +8
-27- - ? ? ? 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)?{
- ? ? ? structmtd_info*mtd =info->mtd;
- ? ? ? structnand_chip*chip =mtd->priv;
+ ? ? ? structmtd_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)
?{
- ? ? ? structpxa3xx_nand_info*info =mtd->priv;
+ ? ? ? structpxa3xx_nand_host*host =mtd->priv;
+ ? ? ? structpxa3xx_nand_info*info =host->info_data;
? ? ? ?structplatform_device*pdev =info->pdev;
? ? ? ?structpxa3xx_nand_platform_data*pdata =pdev->dev.platform_data; ? ? ? ?structnand_flash_devpxa3xx_flash_ids[2], *def = NULL;drivers/mtd/nand/pxa3xx_nand.c +16
-13@@ -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);
?}drivers/mtd/nand/pxa3xx_nand.c +1
-2-static -struct pxa3xx_nand_info *alloc_nand_resource (struct platform_device *pdev) +static int alloc_nand_resource (struct platform_device *pdev)?{
+ ? ? ? structpxa3xx_nand_platform_data*pdata;
? ? ? ?structpxa3xx_nand_info*info;
+ ? ? ? structpxa3xx_nand_host*host;
? ? ? ?structnand_chip*chip;
? ? ? ?structmtd_info*mtd;
? ? ? ?struct resource *r;
- ? ? ? int ret, irq;
+ ? ? ? int ret, irq, cs;
+ ? ? ? intdata_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 = (structpxa3xx_nand_info*)(&mtd[1]);
- ? ? ? chip = (structnand_chip*)(&mtd[1]);
? ? ? ?info->pdev = pdev;
- ? ? ?info->mtd= mtd;
- ? ? ?mtd->priv= info;
- ? ? ?mtd->owner=THIS_MODULE;drivers/mtd/nand/pxa3xx_nand.c +0
-16- - ? ? ? 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);
- ? ? ? ? ? ? ? gotofail_free_mtd;
+ ? ? ? ? ? ? ? gotofail_alloc;
? ? ? ?}
? ? ? ?clk_enable(info->clk);drivers/mtd/nand/pxa3xx_nand.c +0
-4@@ -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);drivers/mtd/nand/pxa3xx_nand.c +64
-2@@ -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:drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -1091,18 +1161,20 @@ fail_free_res:?fail_put_clk:
? ? ? ?clk_disable(info->clk);
? ? ? ?clk_put(info->clk);drivers/mtd/nand/pxa3xx_nand.c +3
-3-fail_free_mtd: - ? ? ? kfree(mtd); - ? ? ? return NULL; +fail_alloc: + ? ? ? kfree(info); + ? ? ? return ret;?}
?static int
pxa3xx_nand_remove(struct platform_device *pdev)?{
? ? ? ?structpxa3xx_nand_info*info =platform_get_drvdata(pdev);
- ? ? ? structmtd_info*mtd =info->mtd;
+ ? ? ? structpxa3xx_nand_platform_data*pdata;
+ ? ? ? structpxa3xx_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);drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -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);drivers/mtd/nand/pxa3xx_nand.c +34
-10@@ -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_PMdrivers/mtd/nand/pxa3xx_nand.c +6
-3@@ -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
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Hi Daniel,
Quoted 14 lines · Daniel Mack
Quoted 5 lines · Lei Wen
Current
pxa3xx_nandcontroller has two chip select which both be workable. This patch enable this feature.Update platform driver to support this feature.
Quoted 7 lines
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 <[email protected]>
Quoted 7 lines
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 <[email protected]>
Thanks for testing!
Best regards,
Lei
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenQuoted 12 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>
Quoted 11 lines
--- 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(-)
~100 lines less - nice!
[...]
Quoted 4 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0
[...]
drivers/mtd/nand/pxa3xx_nand.c static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, · line 630
Quoted 6 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -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"
If you use dev_err(), why do you still need pxa3xx-nand in the message?
Signature · 2 lines
Regards, Igor.
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenQuoted 12 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>
Quoted 11 lines
--- 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(-)
In general huge patches like this are not encouraged and it is better to split them. At least the printk changes can be in a separate patch. Then re-naming host to info probably could be another patch. Could you please rather do a series of smaller patches? Also, if you use dev_info and the like functions, you probably do not need the pxa3xx_nand prefix anymore.
Signature · 2 lines
Best Regards, Artem Bityutskiy
PATCH 1/1 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 25 lines · Artem Bityutskiy
Quoted 22 lines · Lei Wen
Current
pxa3xx_nandcontroller 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 <[email protected]>---
?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 +++++++++++++++-----------Quoted 1 line
?9 files changed, 346 insertions(+), 224 deletions(-)
Quoted 6 lines
In general huge patches like this are not encouraged and it is better to split them. At least the printk changes can be in a separate patch. Then re-naming host to info probably could be another patch. Could you please rather do a series of smaller patches? Also, if you use
dev_infoand the like functions, you probably do not need thepxa3xx_nandprefix anymore.
Hi Artem & Igor,
Thanks for your suggestion, I would seperate this patch and push back later.
Best regards,
Lei
v3 cover pxa3xx_nand: add two chip select support
In reply to Artem BityutskiyV2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
Lei Wen (9):
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: enable multiple chip select support
ARM: aspenite: fix nand platform data
ARM: cm-x300: fix nand platform data
ARM: colibri-pxa3xx: fix nand platform data
ARM: littleton: fix nand platform data
ARM: mxm8x10: fix nand platform data
ARM: raumfeld: fix nand platform data
ARM: zylonite: fix nand platform data
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(-)
v3 cover pxa3xx_nand: add two chip select support
Hi Lei,
Quoted 7 lines · Lei Wen
V2:
Choose to at most keep originalpxa3xx_nand_infostructure to reduce patch sizeV3:
Seperate original one patch into a patch set
Quoted 10 lines
Lei Wen (9):
MTD:pxa3xx_nand: convert all printk into dev_*
MTD:pxa3xx_nand: enable multiple chip select support
ARM: aspenite: fix nand platform data
ARM: cm-x300: fix nand platform data
ARM: colibri-pxa3xx: fix nand platform data
ARM: littleton: fix nand platform data
ARM: mxm8x10: fix nand platform data
ARM: raumfeld: fix nand platform data
ARM: zylonite: fix nand platform data
While I agree with Artem, that reviewing patch sets are much more easier, than a one single big patch, I think you should keep the
"fix nand platform data" changes all in one patch.
All of them do the same change, but for different boards.
Quoted 12 lines
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(-)
Signature · 2 lines
Regards, Igor.
v3 cover pxa3xx_nand: add two chip select support
Quoted 22 lines · Igor Grinberg
Hi Lei,
Quoted 7 lines · Lei Wen
V2:
Choose to at most keep originalpxa3xx_nand_infostructure to reduce patch sizeV3:
Seperate original one patch into a patch setQuoted 10 lines
Lei Wen (9):
MTD:pxa3xx_nand: convert all printk into dev_*
MTD:pxa3xx_nand: enable multiple chip select support
ARM: aspenite: fix nand platform data
ARM: cm-x300: fix nand platform data
ARM: colibri-pxa3xx: fix nand platform data
ARM: littleton: fix nand platform data
ARM: mxm8x10: fix nand platform data
ARM: raumfeld: fix nand platform data
ARM: zylonite: fix nand platform data
Quoted 4 lines
While I agree with Artem, that reviewing patch sets are much more easier, than a one single big patch, I think you should keep the
"fix nand platform data" changes all in one patch.
All of them do the same change, but for different boards.
Yeah, I did not suggest to split a large patch to a number of micro-patches plus another large patch :-) My suggestion is to have a set of easily reviewable patches. If you do the same thing in many platform data structures, it is reviewable and can be in one patch.
Signature · 2 lines
Best Regards, Artem Bityutskiy
v3 cover pxa3xx_nand: add two chip select support
Hi Artem & Igor,
Quoted 28 lines · Artem Bityutskiy
Quoted 22 lines · Igor Grinberg
Hi Lei,
Quoted 7 lines · Lei Wen
V2:
Choose to at most keep originalpxa3xx_nand_infostructure to reduce patch sizeV3:
Seperate original one patch into a patch setQuoted 10 lines
Lei Wen (9):
? MTD:pxa3xx_nand: convert all printk into dev_* ? MTD:pxa3xx_nand: enable multiple chip select support ? ARM: aspenite: fix nand platform data
? ARM: cm-x300: fix nand platform data
? ARM: colibri-pxa3xx: fix nand platform data ? ARM: littleton: fix nand platform data
? ARM: mxm8x10: fix nand platform data
? ARM: raumfeld: fix nand platform data
? ARM: zylonite: fix nand platform dataQuoted 4 lines
While I agree with Artem, that reviewing patch sets are much more easier, than a one single big patch, I think you should keep the
"fix nand platform data" changes all in one patch.
All of them do the same change, but for different boards.
Quoted 5 lines
Yeah, I did not suggest to split a large patch to a number of micro-patches plus another large patch :-) My suggestion is to have a set of easily reviewable patches. If you do the same thing in many platform data structures, it is reviewable and can be in one patch.
V4 patch set has been pushed. Hope this time would be better. :)
Thanks,
Lei
v4 cover pxa3xx_nand: add two chip select support
In reply to Lei WenV2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
V4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.
Lei Wen (4):
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: sperate each chip individual info
MTD: pxa3xx_nand: enable multiple chip select support
ARM: mmp/pxa: fix nand platform data
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 | 20 ++- drivers/mtd/nand/pxa3xx_nand.c | 414 ++++++++++++++++---------- 9 files changed, 294 insertions(+), 179 deletions(-)
v5 cover pxa3xx_nand: add two chip select support
V2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
V4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.
V5:
Merge platform change patch and two chip feature into one patch. Clean some format issue.
Lei Wen (3):
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: sperate each chip individual info
MTD: pxa3xx_nand: enable multiple chip select support
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 | 20 ++- drivers/mtd/nand/pxa3xx_nand.c | 419 ++++++++++++++++---------- 9 files changed, 298 insertions(+), 180 deletions(-)
v6 cover pxa3xx_nand: add two chip select support
V2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
V4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.
V5:
Merge platform change patch and two chip feature into one patch. Clean some format issue.
V6:
Add suspend and resume enhancement as a part of this patch set.
Lei Wen (4):
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: sperate each chip individual info
MTD: pxa3xx_nand: enable multiple chip select support
MTD: pxa3xx_nand: enhance suspend and resume routine
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 | 20 +- drivers/mtd/nand/pxa3xx_nand.c | 452 ++++++++++++++++---------- 9 files changed, 327 insertions(+), 184 deletions(-)
v7 cover pxa3xx_nand: add two chip select support
V2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
V4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.
V5:
Merge platform change patch and two chip feature into one patch. Clean some format issue.
V6:
Add suspend and resume enhancement as a part of this patch set.
V7:
Fix build bug
Fix zylonite machine cannot resume back
Lei Wen (4):
MTD: pxa3xx_nand: enhance suspend and resume routine
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: sperate each chip individual info
MTD: pxa3xx_nand: enable multiple chip select support
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 | 20 +- drivers/mtd/nand/pxa3xx_nand.c | 453 ++++++++++++++++---------- 9 files changed, 327 insertions(+), 185 deletions(-)
v8 cover pxa3xx_nand: add two chip select support
V2:
Choose to at most keep original pxa3xx_nand_info structure to reduce patch size
V3:
Seperate original one patch into a patch set
V4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.
V5:
Merge platform change patch and two chip feature into one patch. Clean some format issue.
V6:
Add suspend and resume enhancement as a part of this patch set.
V7:
Fix build bug
Fix zylonite machine cannot resume back
V8:
Fix typos and code style
Lei Wen (4):
MTD: pxa3xx_nand: enhance suspend and resume routine
MTD: pxa3xx_nand: convert all printk into dev_*
MTD: pxa3xx_nand: sperate each chip individual info
MTD: pxa3xx_nand: enable multiple chip select support
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 | 20 +- drivers/mtd/nand/pxa3xx_nand.c | 453 ++++++++++++++++---------- 9 files changed, 327 insertions(+), 185 deletions(-)
v8 cover pxa3xx_nand: add two chip select support
Quoted 19 lines · Lei Wen
V2:
Choose to at most keep originalpxa3xx_nand_infostructure to reduce patch sizeV3:
Seperate original one patch into a patch setV4:
Further seperate patch into small pieces:
Mainly change make in two patch, which seperate do the new structure definition and two chip select support add.V5:
Merge platform change patch and two chip feature into one patch. Clean some format issue.V6:
Add suspend and resume enhancement as a part of this patch set.
Quoted 6 lines
V7:
Fix build bug
Fix zylonite machine cannot resume backV8:
Fix typos and code style
Pushed the series to the l2-mtd-2.6.git, thanks.
Signature · 2 lines
Best Regards, Artem Bityutskiy
PATCH v8 1/4 MTD: pxa3xx_nand: enhance suspend and resume routine
In reply to Lei WenThis patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
--- drivers/mtd/nand/pxa3xx_nand.c | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +14 -1
@@ -1158,23 +1158,36 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)static int pxa3xx_nand_suspend (struct platform_device *pdev,pm_message_t state) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd = info->mtd;if (info->state) {dev_err (&pdev->dev,"driver busy, state = %d\n" , info->state);return -EAGAIN ; } + mtd->suspend (mtd);return 0 ; }static int pxa3xx_nand_resume (struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd = info->mtd; + +/* We don't want to handle interrupt without calling mtd routine */ +disable_int (info,NDCR_INT_MASK );nand_writel (info,NDTR0CS0 , info->ndtr0cs0);nand_writel (info,NDTR1CS0 , info->ndtr1cs0); -clk_enable (info->clk); +/* +* As the spec says, the NDSR would be updated to 0x1800 when +* doing the nand_clk disable/enable. +* To prevent it damaging state machine of the driver, clear +* all status before resume +*/ +nand_writel (info,NDSR ,NDSR_MASK ); + mtd->resume (mtd);return 0 ; }#else
Signature · 1 line
1.7.0.4
PATCH v8 2/4 MTD: pxa3xx_nand: convert all printk into dev_*
In reply to Lei WenAlso add missed warning message.
--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -11
@@ -359,7 +359,7 @@ 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__, +dev_err (&info->pdev->dev,"%s: invalid state %d\n" , __func__, info->state);BUG (); }
@@ -385,7 +385,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 (); }
@@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,default : exec_cmd =0 ; -printk (KERN_ERR "pxa3xx-nand: non-supported" -" command %x\n" , command); +dev_err (&info->pdev->dev,"non-supported command %x\n" , + command);break ; }
@@ -646,7 +646,7 @@ 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); }
@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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;
@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }
@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) 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" ); +dev_warn (&info->pdev->dev, +"Read out ID 0, potential timing set wrong!!\n" );return -EINVAL ; }
@@ -930,7 +935,7 @@ 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" ); +dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );return -EINVAL ; }
Signature · 1 line
1.7.0.4
PATCH v8 3/4 MTD: pxa3xx_nand: sperate each chip individual info
In reply to Lei WenFor support two chip select, we seperate chip specific info in this patch.
--- drivers/mtd/nand/pxa3xx_nand.c | 292 ++++++++++++++++++++++------------------ 1 files changed, 160 insertions(+), 132 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +160 -132
@@ -110,6 +110,7 @@ enum {enum {STATE_IDLE =0 , +STATE_PREPARED ,STATE_CMD_HANDLE ,STATE_DMA_READING ,STATE_DMA_WRITING ,
@@ -120,21 +121,39 @@ 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 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,18 +161,11 @@ 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; - -/* relate to the command */ +struct pxa3xx_nand_host *host;unsigned int state;int use_ecc;/* use HW ECC ? */
@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {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 ;
@@ -241,9 +242,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 +260,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; +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 +295,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;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 ;
@@ -463,12 +467,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 +479,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; +struct mtd_info *mtd = host->mtd; - ndcb0 =0 ; addr_cycle =0 ; exec_cmd =1 ;
@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size =0 ; info->use_ecc =0 ; info->is_ready =0 ; + info->ndcb0 =0 ; info->retcode =ERR_NONE ;switch (command) {
@@ -512,20 +511,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 +535,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 +562,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 +572,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 +581,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 +591,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 +602,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;
@@ -627,7 +625,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 +634,10 @@ 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 ; + info->state =STATE_PREPARED ; exec_cmd =prepare_command_pool (info, command, column, page_addr);if (exec_cmd) {init_completion (&info->cmd_complete);
@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,/* 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 +664,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 +696,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 +709,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 +722,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 +733,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 +754,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,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, {struct platform_device *pdev = info->pdev;struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +struct pxa3xx_nand_host *host = info->host;uint32_t ndcr =0x0 ;/* enable all interrupts */ if (f->page_size !=2048 && f->page_size !=512 ) {
@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, }/* 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) { +struct pxa3xx_nand_host *host = info->host;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 ; }
@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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;
@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) 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, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys);return info->data_dma_ch; }
@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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->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 ;
@@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret =pxa3xx_nand_sensing (info); -if (!ret) { -kfree (mtd); - info->mtd =NULL ; +if (ret) {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 );
@@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (id !=0 )dev_info (&info->pdev->dev,"Detect a flash id %x\n" , id);else { -kfree (mtd); - info->mtd =NULL ;dev_warn (&info->pdev->dev,"Read out ID 0, potential timing set wrong!!\n" );
@@ -933,14 +946,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 ;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;
@@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1 ].name =NULL ; def = pxa3xx_flash_ids; KEEP_CONFIG: + chip->ecc.mode =NAND_ECC_HW ; + chip->ecc.size = host->page_size; + + chip->options =NAND_NO_AUTOINCR ; + chip->options |=NAND_NO_READRDY ; +if (host->reg_ndcr &NDCR_DWIDTH_M ) + chip->options |=NAND_BUSWIDTH_16 ; +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 ]; - chip->ecc.mode =NAND_ECC_HW ; - chip->ecc.size = info->page_size; - - chip->options = (info->reg_ndcr &NDCR_DWIDTH_M ) ?NAND_BUSWIDTH_16 :0 ; - chip->options |=NAND_NO_AUTOINCR ; - chip->options |=NAND_NO_READRDY ; + host->row_addr_cycles =2 ; + mtd->name = mtd_names[0 ];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_info *info; +struct pxa3xx_nand_host *host;struct nand_chip *chip;struct mtd_info *mtd;struct resource *r;int ret, irq; - mtd =kzalloc (sizeof (struct mtd_info ) +sizeof (struct pxa3xx_nand_info ), + info =kzalloc (sizeof (*info) +sizeof (*mtd) +sizeof (*host),GFP_KERNEL ); -if (!mtd) { +if (!info) {dev_err (&pdev->dev,"failed to allocate memory\n" ); -return NULL ; +return -ENOMEM ; } - info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + mtd = (struct mtd_info *)(&info[1 ]); chip = (struct nand_chip *)(&mtd[1 ]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner =THIS_MODULE ; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) 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;
@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)platform_set_drvdata (pdev, info); -return info; +return 0 ; fail_free_buf:free_irq (irq, info);if (use_dma) {pxa_free_dma (info->data_dma_ch); -dma_free_coherent (&pdev->dev, info->data_buff_size, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys); }else kfree (info->data_buff);
@@ -1097,17 +1121,19 @@ fail_put_clk:clk_disable (info->clk);clk_put (info->clk); fail_free_mtd: -kfree (mtd); -return NULL ; +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 resource *r;int irq; +if (!info) +return 0 ; +platform_set_drvdata (pdev,NULL ); irq =platform_get_irq (pdev,0 );
@@ -1115,7 +1141,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);
@@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)clk_disable (info->clk);clk_put (info->clk); -if (mtd) { -nand_release (mtd); -kfree (mtd); - } +nand_release (info->host->mtd); +kfree (info);return 0 ; }
@@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) {struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +int ret; pdata = pdev->dev.platform_data;if (!pdata) {
@@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) -return -ENOMEM ; + ret =alloc_nand_resource (pdev); +if (ret) { +dev_err (&pdev->dev,"alloc nand resource failed\n" ); +return ret; + } -if (pxa3xx_nand_scan (info->mtd)) { + info =platform_get_drvdata (pdev); +if (pxa3xx_nand_scan (info->host->mtd)) {dev_err (&pdev->dev,"failed to scan nand\n" );pxa3xx_nand_remove (pdev);return -ENODEV ; } -return mtd_device_parse_register (info->mtd,NULL ,0 , +return mtd_device_parse_register (info->host->mtd,NULL ,0 , pdata->parts, pdata->nr_parts); }
@@ -1182,8 +1210,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)/* We don't want to handle interrupt without calling mtd routine */ disable_int (info,NDCR_INT_MASK ); -nand_writel (info,NDTR0CS0 , info->ndtr0cs0); -nand_writel (info,NDTR1CS0 , info->ndtr1cs0); +nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); +nand_writel (info,NDTR1CS0 , info->host->ndtr1cs0);/* * As the spec says, the NDSR would be updated to 0x1800 when
Signature · 1 line
1.7.0.4
PATCH v8 4/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenCurrent 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.
--- 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 | 20 +++- drivers/mtd/nand/pxa3xx_nand.c | 173 ++++++++++++++++++-------- 9 files changed, 164 insertions(+), 68 deletions(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +18 -2
@@ -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,11 @@ 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;
drivers/mtd/nand/pxa3xx_nand.c +123 -50
344 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v7 1/4 MTD: pxa3xx_nand: enhance suspend and resume routine
In reply to Lei WenThis patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
--- drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -1
@@ -1158,23 +1158,38 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)static int pxa3xx_nand_suspend (struct platform_device *pdev,pm_message_t state) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd;if (info->state) {dev_err (&pdev->dev,"driver busy, state = %d\n" , info->state);return -EAGAIN ; } + mtd = info->mtd; + mtd->suspend (mtd);return 0 ; }static int pxa3xx_nand_resume (struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd; + +/* We don't want to handle interrupt without calling mtd routine */ +disable_int (info,NDCR_INT_MASK );nand_writel (info,NDTR0CS0 , info->ndtr0cs0);nand_writel (info,NDTR1CS0 , info->ndtr1cs0); -clk_enable (info->clk); +/* +* As the spec, the NDSR would be updated to 0x1800 when +* do the nand_clk disable/enable. +* To prevent it damage state machine of the driver, clear +* all status before resume +*/ +nand_writel (info,NDSR ,NDSR_MASK ); + mtd = info->mtd; + mtd->resume (mtd);return 0 ; }#else
Signature · 1 line
1.7.0.4
PATCH v7 1/4 MTD: pxa3xx_nand: enhance suspend and resume routine
Hello.
Quoted 16 lines · Lei Wen
This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
Signed-off-by Lei Wen<[email protected]>--- drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-)drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -1158,23 +1158,38 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)static int pxa3xx_nand_suspend (struct platform_device *pdev,pm_message_t state)
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1168
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-0{struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd;if (info->state) {dev_err (&pdev->dev,"driver busy, state = %d\n" , info->state);return -EAGAIN ; } + mtd = info->mtd;
Why not make this into an initializer?
Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-0+ mtd->suspend (mtd);return 0 ; }static int pxa3xx_nand_resume (struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct mtd_info *mtd;
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1185
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-1+ +/* We don't want to handle interrupt without calling mtd routine */ +disable_int (info,NDCR_INT_MASK );nand_writel (info,NDTR0CS0 , info->ndtr0cs0);nand_writel (info,NDTR1CS0 , info->ndtr1cs0); -clk_enable (info->clk); +/* +* As the spec, the NDSR would be updated to 0x1800 when
As the spec says?
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1186
Quoted 1 line
drivers/mtd/nand/pxa3xx_nand.c +1
-0+* do the nand_clk disable/enable.
Doing.
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1187
Quoted 1 line
drivers/mtd/nand/pxa3xx_nand.c +1
-0+* To prevent it damage state machine of the driver, clear
From damaging?
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1191
Quoted 4 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-0+* all status before resume +*/ +nand_writel (info,NDSR ,NDSR_MASK ); + mtd = info->mtd;
This one too could be an initializer...
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_probe(struct platform_device *pdev) · line 1195
Quoted 4 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-0+ mtd->resume (mtd); return 0; }#else
WBR, Sergei
PATCH v7 2/4 MTD: pxa3xx_nand: convert all printk into dev_*
In reply to Lei Wen--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -11
@@ -359,7 +359,7 @@ 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__, +dev_err (&info->pdev->dev,"%s: invalid state %d\n" , __func__, info->state);BUG (); }
@@ -385,7 +385,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 (); }
@@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,default : exec_cmd =0 ; -printk (KERN_ERR "pxa3xx-nand: non-supported" -" command %x\n" , command); +dev_err (&info->pdev->dev,"non-supported command %x\n" , + command);break ; }
@@ -646,7 +646,7 @@ 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); }
@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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;
@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }
@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) 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" ); +dev_warn (&info->pdev->dev,"Read out ID 0, " +"potential timing set wrong!!\n" );return -EINVAL ; }
@@ -930,7 +935,7 @@ 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" ); +dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );return -EINVAL ; }
Signature · 1 line
1.7.0.4
PATCH v7 2/4 MTD: pxa3xx_nand: convert all printk into dev_*
Hello.
Quoted 9 lines · Lei Wen
Signed-off-by Lei Wen<[email protected]>--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)drivers/mtd/nand/pxa3xx_nand.c +0
-0
[...]
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, · line 783
Quoted 13 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-2@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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" );
So this patch not only converts printk() to dev_*() calls, it also adds
some dev_err() calls? This should have been mentioned in the change long at least...
Quoted 16 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1return -EINVAL ; + }/* calculate flash information */ info->cmdset =&default_cmdset;@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->cmdfunc (mtd,NAND_CMD_READID ,0 ,0 );
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 918
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-2id = *((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" ); +dev_warn (&info->pdev->dev,"Read out ID 0, " +"potential timing set wrong!!\n" );
Don't break the string -- this prevents grepping for it.
WBR, Sergei
PATCH v7 2/4 MTD: pxa3xx_nand: convert all printk into dev_*
Hi Sergei,
Quoted 29 lines · Sergei Shtylyov
Hello.
Quoted 10 lines · Lei Wen
Signed-off-by Lei Wen<[email protected]>---
?drivers/mtd/nand/pxa3xx_nand.c | ? 27 ++++++++++++++++----------- ?1 files changed, 16 insertions(+), 11 deletions(-)drivers/mtd/nand/pxa3xx_nand.c +0
-0[...]
Quoted 13 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(structpxa3xx_nand_info *info, ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;? ? ? ?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;
+ ? ? ? }
Quoted 7 lines
Quoted 3 lines
- ? ? ? 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");? So this patch not only converts
printk()to dev_*() calls, it also adds somedev_err()calls? This should have been mentioned in the change long at least...
What do you mean by "chang long"? Do you mean the cover letter or the patch name?
Certainly it is a good suggest to show it in the change version list.
Quoted 23 lines
Quoted 23 lines
? ? ? ? ? ? ? ?return
-EINVAL;
+ ? ? ? }? ? ? ?/* calculate flash information */
? ? ? ?info->cmdset =&default_cmdset;drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ? ? ? ?if (!ret) { ? ? ? ? ? ? ? ?kfree(mtd); ? ? ? ? ? ? ? ?info->mtd = NULL; - ? ? ? ? ? ? ? printk(KERN_INFO "There is no nand chip on cs 0!\n"); + ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); ? ? ? ? ? ? ? ?return -EINVAL;? ? ? ?}
drivers/mtd/nand/pxa3xx_nand.c +1
-1@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) ? ? ? ?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 {
Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 919
Quoted 6 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1? ? ? ? ? ? ? ?kfree(mtd); ? ? ? ? ? ? ? ?info->mtd = NULL; - ? ? ? ? ? ? ? printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); + ? ? ? ? ? ? ? dev_warn(&info->pdev->dev, "Read out ID 0, " + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "potential timing set wrong!!\n");? Don't break the string -- this prevents grepping for it.
Thanks, I would fix it.
Best regards,
Lei
PATCH v7 2/4 MTD: pxa3xx_nand: convert all printk into dev_*
Hello.
Quoted 30 lines · Lei Wen
Quoted 22 lines
Quoted 9 lines
Signed-off-by Lei Wen<[email protected]>--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)drivers/mtd/nand/pxa3xx_nand.c +0
-0[...]
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c +3
-1@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(structpxa3xx_nand_info *info, struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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 ; + }Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, · line 783
Quoted 3 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-1-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" );So this patch not only converts
printk()to dev_*() calls, it also adds
somedev_err()calls? This should have been mentioned in the change long at least...
Quoted 2 lines
What do you mean by "chang long"? Do you mean the cover letter or the patch name?
I mean the patch description (which in this patch is missing).
Quoted 1 line
Certainly it is a good suggest to show it in the change version list.
Don't quite understand what you mean here...
Quoted 2 lines
Best regards,
Lei
WBR, Sergei
PATCH v7 3/4 MTD: pxa3xx_nand: sperate each chip individual info
In reply to Lei WenFor support two chip select, we seperate chip specific info in this patch.
--- drivers/mtd/nand/pxa3xx_nand.c | 292 ++++++++++++++++++++++------------------ 1 files changed, 160 insertions(+), 132 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +160 -132
@@ -110,6 +110,7 @@ enum {enum {STATE_IDLE =0 , +STATE_PREPARED ,STATE_CMD_HANDLE ,STATE_DMA_READING ,STATE_DMA_WRITING ,
@@ -120,21 +121,39 @@ 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 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,18 +161,11 @@ 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; - -/* relate to the command */ +struct pxa3xx_nand_host *host;unsigned int state;int use_ecc;/* use HW ECC ? */
@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {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 ;
@@ -241,9 +242,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 +260,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; +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 +295,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;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 ;
@@ -463,12 +467,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 +479,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; +struct mtd_info *mtd = host->mtd; - ndcb0 =0 ; addr_cycle =0 ; exec_cmd =1 ;
@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size =0 ; info->use_ecc =0 ; info->is_ready =0 ; + info->ndcb0 =0 ; info->retcode =ERR_NONE ;switch (command) {
@@ -512,20 +511,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 +535,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 +562,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 +572,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 +581,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 +591,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 +602,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;
@@ -627,7 +625,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 +634,10 @@ 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 ; + info->state =STATE_PREPARED ; exec_cmd =prepare_command_pool (info, command, column, page_addr);if (exec_cmd) {init_completion (&info->cmd_complete);
@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,/* 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 +664,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 +696,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 +709,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 +722,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 +733,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 +754,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,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, {struct platform_device *pdev = info->pdev;struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +struct pxa3xx_nand_host *host = info->host;uint32_t ndcr =0x0 ;/* enable all interrupts */ if (f->page_size !=2048 && f->page_size !=512 ) {
@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, }/* 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) { +struct pxa3xx_nand_host *host = info->host;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 ; }
@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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;
@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) 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, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys);return info->data_dma_ch; }
@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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->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 ;
@@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret =pxa3xx_nand_sensing (info); -if (!ret) { -kfree (mtd); - info->mtd =NULL ; +if (ret) {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 );
@@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (id !=0 )dev_info (&info->pdev->dev,"Detect a flash id %x\n" , id);else { -kfree (mtd); - info->mtd =NULL ;dev_warn (&info->pdev->dev,"Read out ID 0, " "potential timing set wrong!!\n" );
@@ -933,14 +946,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 ;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;
@@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1 ].name =NULL ; def = pxa3xx_flash_ids; KEEP_CONFIG: + chip->ecc.mode =NAND_ECC_HW ; + chip->ecc.size = host->page_size; + + chip->options =NAND_NO_AUTOINCR ; + chip->options |=NAND_NO_READRDY ; +if (host->reg_ndcr &NDCR_DWIDTH_M ) + chip->options |=NAND_BUSWIDTH_16 ; +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 ]; - chip->ecc.mode =NAND_ECC_HW ; - chip->ecc.size = info->page_size; - - chip->options = (info->reg_ndcr &NDCR_DWIDTH_M ) ?NAND_BUSWIDTH_16 :0 ; - chip->options |=NAND_NO_AUTOINCR ; - chip->options |=NAND_NO_READRDY ; + host->row_addr_cycles =2 ; + mtd->name = mtd_names[0 ];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_info *info; +struct pxa3xx_nand_host *host;struct nand_chip *chip;struct mtd_info *mtd;struct resource *r;int ret, irq; - mtd =kzalloc (sizeof (struct mtd_info ) +sizeof (struct pxa3xx_nand_info ), + info =kzalloc (sizeof (*info) +sizeof (*mtd) +sizeof (*host),GFP_KERNEL ); -if (!mtd) { +if (!info) {dev_err (&pdev->dev,"failed to allocate memory\n" ); -return NULL ; +return -ENOMEM ; } - info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + mtd = (struct mtd_info *)(&info[1 ]); chip = (struct nand_chip *)(&mtd[1 ]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner =THIS_MODULE ; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) 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;
@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)platform_set_drvdata (pdev, info); -return info; +return 0 ; fail_free_buf:free_irq (irq, info);if (use_dma) {pxa_free_dma (info->data_dma_ch); -dma_free_coherent (&pdev->dev, info->data_buff_size, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys); }else kfree (info->data_buff);
@@ -1097,17 +1121,19 @@ fail_put_clk:clk_disable (info->clk);clk_put (info->clk); fail_free_mtd: -kfree (mtd); -return NULL ; +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 resource *r;int irq; +if (!info) +return 0 ; +platform_set_drvdata (pdev,NULL ); irq =platform_get_irq (pdev,0 );
@@ -1115,7 +1141,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);
@@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)clk_disable (info->clk);clk_put (info->clk); -if (mtd) { -nand_release (mtd); -kfree (mtd); - } +nand_release (info->host->mtd); +kfree (info);return 0 ; }
@@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) {struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +int ret; pdata = pdev->dev.platform_data;if (!pdata) {
@@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) -return -ENOMEM ; + ret =alloc_nand_resource (pdev); +if (ret) { +dev_err (&pdev->dev,"alloc nand resource failed\n" ); +return ret; + } -if (pxa3xx_nand_scan (info->mtd)) { + info =platform_get_drvdata (pdev); +if (pxa3xx_nand_scan (info->host->mtd)) {dev_err (&pdev->dev,"failed to scan nand\n" );pxa3xx_nand_remove (pdev);return -ENODEV ; } -return mtd_device_parse_register (info->mtd,NULL ,0 , +return mtd_device_parse_register (info->host->mtd,NULL ,0 , pdata->parts, pdata->nr_parts); }
@@ -1183,8 +1211,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)/* We don't want to handle interrupt without calling mtd routine */ disable_int (info,NDCR_INT_MASK ); -nand_writel (info,NDTR0CS0 , info->ndtr0cs0); -nand_writel (info,NDTR1CS0 , info->ndtr1cs0); +nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); +nand_writel (info,NDTR1CS0 , info->host->ndtr1cs0);/* * As the spec, the NDSR would be updated to 0x1800 when
Signature · 1 line
1.7.0.4
PATCH v7 4/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenCurrent 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.
--- 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 | 20 +++- drivers/mtd/nand/pxa3xx_nand.c | 171 ++++++++++++++++++-------- 9 files changed, 162 insertions(+), 68 deletions(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +18 -2
@@ -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,11 @@ 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;
drivers/mtd/nand/pxa3xx_nand.c +121 -50
344 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v6 1/4 MTD: pxa3xx_nand: convert all printk into dev_*
In reply to Lei Wen--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -11
@@ -359,7 +359,7 @@ 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__, +dev_err (&info->pdev->dev,"%s: invalid state %d\n" , __func__, info->state);BUG (); }
@@ -385,7 +385,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 (); }
@@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,default : exec_cmd =0 ; -printk (KERN_ERR "pxa3xx-nand: non-supported" -" command %x\n" , command); +dev_err (&info->pdev->dev,"non-supported command %x\n" , + command);break ; }
@@ -646,7 +646,7 @@ 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); }
@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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;
@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }
@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) 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" ); +dev_warn (&info->pdev->dev,"Read out ID 0, " +"potential timing set wrong!!\n" );return -EINVAL ; }
@@ -930,7 +935,7 @@ 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" ); +dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );return -EINVAL ; }
Signature · 1 line
1.7.0.4
PATCH v6 2/4 MTD: pxa3xx_nand: sperate each chip individual info
In reply to Lei WenFor support two chip select, we seperate chip specific info in this patch.
--- drivers/mtd/nand/pxa3xx_nand.c | 292 ++++++++++++++++++++++------------------ 1 files changed, 160 insertions(+), 132 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +160 -132
@@ -110,6 +110,7 @@ enum {enum {STATE_IDLE =0 , +STATE_PREPARED ,STATE_CMD_HANDLE ,STATE_DMA_READING ,STATE_DMA_WRITING ,
@@ -120,21 +121,39 @@ 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 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,18 +161,11 @@ 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; - -/* relate to the command */ +struct pxa3xx_nand_host *host;unsigned int state;int use_ecc;/* use HW ECC ? */
@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {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 ;
@@ -241,9 +242,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 +260,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; +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 +295,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;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 ;
@@ -463,12 +467,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 +479,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; +struct mtd_info *mtd = host->mtd; - ndcb0 =0 ; addr_cycle =0 ; exec_cmd =1 ;
@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size =0 ; info->use_ecc =0 ; info->is_ready =0 ; + info->ndcb0 =0 ; info->retcode =ERR_NONE ;switch (command) {
@@ -512,20 +511,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 +535,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 +562,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 +572,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 +581,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 +591,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 +602,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;
@@ -627,7 +625,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 +634,10 @@ 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 ; + info->state =STATE_PREPARED ; exec_cmd =prepare_command_pool (info, command, column, page_addr);if (exec_cmd) {init_completion (&info->cmd_complete);
@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,/* 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 +664,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 +696,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 +709,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 +722,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 +733,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 +754,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,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, {struct platform_device *pdev = info->pdev;struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +struct pxa3xx_nand_host *host = info->host;uint32_t ndcr =0x0 ;/* enable all interrupts */ if (f->page_size !=2048 && f->page_size !=512 ) {
@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, }/* 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) { +struct pxa3xx_nand_host *host = info->host;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 ; }
@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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;
@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) 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, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys);return info->data_dma_ch; }
@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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->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 ;
@@ -899,12 +916,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret =pxa3xx_nand_sensing (info); -if (!ret) { -kfree (mtd); - info->mtd =NULL ; +if (ret) {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 );
@@ -912,8 +927,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (id !=0 )dev_info (&info->pdev->dev,"Detect a flash id %x\n" , id);else { -kfree (mtd); - info->mtd =NULL ;dev_warn (&info->pdev->dev,"Read out ID 0, " "potential timing set wrong!!\n" );
@@ -933,14 +946,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 ;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;
@@ -952,47 +968,56 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1 ].name =NULL ; def = pxa3xx_flash_ids; KEEP_CONFIG: + chip->ecc.mode =NAND_ECC_HW ; + chip->ecc.size = host->page_size; + + chip->options =NAND_NO_AUTOINCR ; + chip->options |=NAND_NO_READRDY ; +if (host->reg_ndcr &NDCR_DWIDTH_M ) + chip->options |=NAND_BUSWIDTH_16 ; +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 ]; - chip->ecc.mode =NAND_ECC_HW ; - chip->ecc.size = info->page_size; - - chip->options = (info->reg_ndcr &NDCR_DWIDTH_M ) ?NAND_BUSWIDTH_16 :0 ; - chip->options |=NAND_NO_AUTOINCR ; - chip->options |=NAND_NO_READRDY ; + host->row_addr_cycles =2 ; + mtd->name = mtd_names[0 ];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_info *info; +struct pxa3xx_nand_host *host;struct nand_chip *chip;struct mtd_info *mtd;struct resource *r;int ret, irq; - mtd =kzalloc (sizeof (struct mtd_info ) +sizeof (struct pxa3xx_nand_info ), + info =kzalloc (sizeof (*info) +sizeof (*mtd) +sizeof (*host),GFP_KERNEL ); -if (!mtd) { +if (!info) {dev_err (&pdev->dev,"failed to allocate memory\n" ); -return NULL ; +return -ENOMEM ; } - info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + mtd = (struct mtd_info *)(&info[1 ]); chip = (struct nand_chip *)(&mtd[1 ]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner =THIS_MODULE ; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) 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;
@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)platform_set_drvdata (pdev, info); -return info; +return 0 ; fail_free_buf:free_irq (irq, info);if (use_dma) {pxa_free_dma (info->data_dma_ch); -dma_free_coherent (&pdev->dev, info->data_buff_size, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys); }else kfree (info->data_buff);
@@ -1097,17 +1121,19 @@ fail_put_clk:clk_disable (info->clk);clk_put (info->clk); fail_free_mtd: -kfree (mtd); -return NULL ; +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 resource *r;int irq; +if (!info) +return 0 ; +platform_set_drvdata (pdev,NULL ); irq =platform_get_irq (pdev,0 );
@@ -1115,7 +1141,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);
@@ -1127,10 +1153,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)clk_disable (info->clk);clk_put (info->clk); -if (mtd) { -nand_release (mtd); -kfree (mtd); - } +nand_release (info->host->mtd); +kfree (info);return 0 ; }
@@ -1138,6 +1162,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) {struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +int ret; pdata = pdev->dev.platform_data;if (!pdata) {
@@ -1145,17 +1170,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) -return -ENOMEM ; + ret =alloc_nand_resource (pdev); +if (ret) { +dev_err (&pdev->dev,"alloc nand resource failed\n" ); +return ret; + } -if (pxa3xx_nand_scan (info->mtd)) { + info =platform_get_drvdata (pdev); +if (pxa3xx_nand_scan (info->host->mtd)) {dev_err (&pdev->dev,"failed to scan nand\n" );pxa3xx_nand_remove (pdev);return -ENODEV ; } -return mtd_device_parse_register (info->mtd,NULL ,0 , +return mtd_device_parse_register (info->host->mtd,NULL ,0 , pdata->parts, pdata->nr_parts); }
@@ -1176,8 +1204,8 @@ 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); +nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); +nand_writel (info,NDTR1CS0 , info->host->ndtr1cs0);clk_enable (info->clk);return 0 ;
Signature · 1 line
1.7.0.4
PATCH v6 3/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenCurrent 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.
--- 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 | 20 +++- drivers/mtd/nand/pxa3xx_nand.c | 151 ++++++++++++++++++-------- 9 files changed, 146 insertions(+), 64 deletions(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +18 -2
@@ -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,11 @@ 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;
drivers/mtd/nand/pxa3xx_nand.c +105 -46
300 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v6 4/4 MTD: pxa3xx_nand: enhance suspend and resume routine
In reply to Lei WenThis patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
--- drivers/mtd/nand/pxa3xx_nand.c | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +28 -0
@@ -1246,18 +1246,34 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)static int pxa3xx_nand_suspend (struct platform_device *pdev,pm_message_t state) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct pxa3xx_nand_platform_data *pdata; +struct mtd_info *mtd; +int cs; + pdata = pdev->dev.platform_data;if (info->state) {dev_err (&pdev->dev,"driver busy, state = %d\n" , info->state);return -EAGAIN ; } +for (cs =0 ; cs < pdata->num_cs; cs ++) { + mtd = info->host[cs]->mtd; + mtd->suspend (mtd); + } + +clk_disable (info->clk);return 0 ; }static int pxa3xx_nand_resume (struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); +struct pxa3xx_nand_platform_data *pdata; +int cs; + + pdata = pdev->dev.platform_data; +/* We don't want to handle interrupt without calling mtd routine */ +disable_int (info,NDCR_INT_MASK );/* * Directly set the chip select to a invalid value,
@@ -1267,6 +1283,18 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) info->cs =0xff ;clk_enable (info->clk); +/* +* As the spec, the NDSR would be updated to 0x1800 when +* do the nand_clk disable/enable. +* To prevent it damage state machine of the driver, clear +* all status before resume +*/ +nand_writel (nand,NDSR ,NDSR_MASK ); +for (cs =0 ; cs < pdata->num_cs; cs ++) { + mtd = info->host[cs]->mtd; + mtd->resume (mtd); + } + return 0; }#else
Signature · 1 line
1.7.0.4
PATCH v6 4/4 MTD: pxa3xx_nand: enhance suspend and resume routine
Quoted 10 lines · Lei Wen
This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
Signed-off-by Lei Wen <[email protected]>---
?drivers/mtd/nand/pxa3xx_nand.c | ? 28 ++++++++++++++++++++++++++++ ?1 files changed, 28 insertions(+), 0 deletions(-)
[...]
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1292
Quoted 11 lines
(quoted diff) +7
-0@@ -1267,6 +1283,18 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ? ? ? ?info->cs = 0xff; ? ? ? ?clk_enable(info->clk); + ? ? ? /* + ? ? ? ?* As the spec, the NDSR would be updated to 0x1800 when + ? ? ? ?* do the nand_clk disable/enable. + ? ? ? ?* To prevent it damage state machine of the driver, clear + ? ? ? ?* all status before resume + ? ? ? ?*/ + ? ? ? nand_writel(nand, NDSR, NDSR_MASK);
This doesn't build:
CC drivers/mtd/nand/pxa3xx_nand.odrivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_resume':drivers/mtd/nand/pxa3xx_nand.c:1292: error: 'nand' undeclared (first use in this function)drivers/mtd/nand/pxa3xx_nand.c:1292: error: (Each undeclared identifier is reported only once drivers/mtd/nand/pxa3xx_nand.c:1292: error: for each function it appears in.) drivers/mtd/nand/pxa3xx_nand.c:1294: error: 'mtd' undeclared (first use in this function)
make[3]: *** [drivers/mtd/nand/pxa3xx_nand.o] Error 1
I guess this was not even compile tested? Anyway, I did a trivial fix-up and will test.
Daniel
PATCH v6 4/4 MTD: pxa3xx_nand: enhance suspend and resume routine
Quoted 39 lines · Daniel Mack
Quoted 10 lines · Lei Wen
This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
Signed-off-by Lei Wen <[email protected]>---
?drivers/mtd/nand/pxa3xx_nand.c | ? 28 ++++++++++++++++++++++++++++ ?1 files changed, 28 insertions(+), 0 deletions(-)[...]
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1292
Quoted 11 lines
(quoted diff) +7
-0@@ -1267,6 +1283,18 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ? ? ? ?info->cs = 0xff; ? ? ? ?clk_enable(info->clk); + ? ? ? /* + ? ? ? ?* As the spec, the NDSR would be updated to 0x1800 when + ? ? ? ?* do the nand_clk disable/enable. + ? ? ? ?* To prevent it damage state machine of the driver, clear + ? ? ? ?* all status before resume + ? ? ? ?*/ + ? ? ? nand_writel(nand, NDSR, NDSR_MASK);This doesn't build:
?CC ? ? ?drivers/mtd/nand/pxa3xx_nand.o
drivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_resume':drivers/mtd/nand/pxa3xx_nand.c:1292: error: 'nand' undeclared (first use in this function)drivers/mtd/nand/pxa3xx_nand.c:1292: error: (Each undeclared identifier is reported only oncedrivers/mtd/nand/pxa3xx_nand.c:1292: error: for each function it appears in.)drivers/mtd/nand/pxa3xx_nand.c:1294: error: 'mtd' undeclared (first use in this function)
make[3]: *** [drivers/mtd/nand/pxa3xx_nand.o] Error 1
Quoted 2 lines
I guess this was not even compile tested? Anyway, I did a trivial fix-up and will test.
Also, with this (fixed) patch applied, the system doesn't resume at all. No messages, it simply doesn't come back.
Daniel
PATCH v6 4/4 MTD: pxa3xx_nand: enhance suspend and resume routine
Quoted 38 lines · Daniel Mack
Quoted 37 lines · Daniel Mack
Quoted 10 lines · Lei Wen
This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
Signed-off-by Lei Wen <[email protected]>--- drivers/mtd/nand/pxa3xx_nand.c | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-)[...]
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1292
Quoted 11 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-0@@ -1267,6 +1283,18 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) info->cs =0xff ;clk_enable (info->clk); +/* +* As the spec, the NDSR would be updated to 0x1800 when +* do the nand_clk disable/enable. +* To prevent it damage state machine of the driver, clear +* all status before resume +*/ +nand_writel (nand,NDSR ,NDSR_MASK );This doesn't build:
CC
drivers/mtd/nand/pxa3xx_nand.odrivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_resume':drivers/mtd/nand/pxa3xx_nand.c:1292: error: 'nand' undeclared (first use in this function)drivers/mtd/nand/pxa3xx_nand.c:1292: error: (Each undeclared identifier is reported only oncedrivers/mtd/nand/pxa3xx_nand.c:1292: error: for each function it appears in.)drivers/mtd/nand/pxa3xx_nand.c:1294: error: 'mtd' undeclared (first use in this function)
make[3]: *** [drivers/mtd/nand/pxa3xx_nand.o] Error 1
Quoted 4 lines
Quoted 2 lines
I guess this was not even compile tested? Anyway, I did a trivial fix-up and will test.
Also, with this (fixed) patch applied, the system doesn't resume at all. No messages, it simply doesn't come back.
I was skeptic about the clock being disabled in Lei's patch, as I observed system hangs if that clock was disabled back then in 2.6.31, but wanted to give it a try, because things has changed since then.
Now I see, that Lei already sent v7 without clock toggling...
Signature · 2 lines
Regards, Igor.
PATCH v6 4/4 MTD: pxa3xx_nand: enhance suspend and resume routine
Quoted 42 lines · Igor Grinberg
Quoted 40 lines · Daniel Mack
Quoted 39 lines · Daniel Mack
Quoted 10 lines · Lei Wen
This patch add protection on the suspend&resume path to prevent some unexpected behavior, like interrupt occur at the very second of resume back and it don't follow normal command path, which lead to bug.
Signed-off-by Lei Wen <[email protected]>---
?drivers/mtd/nand/pxa3xx_nand.c | ? 28 ++++++++++++++++++++++++++++ ?1 files changed, 28 insertions(+), 0 deletions(-)[...]
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1292
Quoted 11 lines
(quoted diff) +7
-0@@ -1267,6 +1283,18 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ? ? ? ?info->cs = 0xff; ? ? ? ?clk_enable(info->clk); + ? ? ? /* + ? ? ? ?* As the spec, the NDSR would be updated to 0x1800 when + ? ? ? ?* do the nand_clk disable/enable. + ? ? ? ?* To prevent it damage state machine of the driver, clear + ? ? ? ?* all status before resume + ? ? ? ?*/ + ? ? ? nand_writel(nand, NDSR, NDSR_MASK);This doesn't build:
?CC ? ? ?drivers/mtd/nand/pxa3xx_nand.o
drivers/mtd/nand/pxa3xx_nand.c: In function 'pxa3xx_nand_resume':drivers/mtd/nand/pxa3xx_nand.c:1292: error: 'nand' undeclared (first use in this function)drivers/mtd/nand/pxa3xx_nand.c:1292: error: (Each undeclared identifier is reported only oncedrivers/mtd/nand/pxa3xx_nand.c:1292: error: for each function it appears in.)drivers/mtd/nand/pxa3xx_nand.c:1294: error: 'mtd' undeclared (first use in this function)
make[3]: *** [drivers/mtd/nand/pxa3xx_nand.o] Error 1I guess this was not even compile tested? Anyway, I did a trivial fix-up and will test.
Quoted 8 lines
Quoted 2 lines
Also, with this (fixed) patch applied, the system doesn't resume at all. No messages, it simply doesn't come back.
I was skeptic about the clock being disabled in Lei's patch, as I observed system hangs if that clock was disabled back then in 2.6.31, but wanted to give it a try, because things has changed since then.
Now I see, that Lei already sent v7 without clock toggling...
Yes, we debugged this quickly via Jabber, and without the clock disable, things work fine for me again.
Daniel
PATCH v5 1/3 MTD: pxa3xx_nand: convert all printk into dev_*
In reply to Lei Wen--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -11
@@ -359,7 +359,7 @@ 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__, +dev_err (&info->pdev->dev,"%s: invalid state %d\n" , __func__, info->state);BUG (); }
@@ -385,7 +385,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 (); }
@@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,default : exec_cmd =0 ; -printk (KERN_ERR "pxa3xx-nand: non-supported" -" command %x\n" , command); +dev_err (&info->pdev->dev,"non-supported command %x\n" , + command);break ; }
@@ -646,7 +646,7 @@ 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); }
@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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;
@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }
@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) 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" ); +dev_warn (&info->pdev->dev,"Read out ID 0, " +"potential timing set wrong!!\n" );return -EINVAL ; }
@@ -930,7 +935,7 @@ 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" ); +dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );return -EINVAL ; }
Signature · 1 line
1.7.0.4
PATCH v5 2/3 MTD: pxa3xx_nand: sperate each chip individual info
In reply to Lei WenFor support two chip select, we seperate chip specific info in this patch.
--- drivers/mtd/nand/pxa3xx_nand.c | 287 ++++++++++++++++++++++------------------ 1 files changed, 159 insertions(+), 128 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +159 -128
@@ -110,6 +110,7 @@ enum {enum {STATE_IDLE =0 , +STATE_PREPARED ,STATE_CMD_HANDLE ,STATE_DMA_READING ,STATE_DMA_WRITING ,
@@ -120,21 +121,39 @@ 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 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,18 +161,11 @@ 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; - -/* relate to the command */ +struct pxa3xx_nand_host *host;unsigned int state;int use_ecc;/* use HW ECC ? */
@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {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 ;
@@ -241,9 +242,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 +260,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; +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 +295,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;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 ;
@@ -463,12 +467,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 +479,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; +struct mtd_info *mtd = host->mtd; - ndcb0 =0 ; addr_cycle =0 ; exec_cmd =1 ;
@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size =0 ; info->use_ecc =0 ; info->is_ready =0 ; + info->ndcb0 =0 ; info->retcode =ERR_NONE ;switch (command) {
@@ -512,20 +511,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 +535,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 +562,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 +572,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 +581,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 +591,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 +602,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;
@@ -627,7 +625,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 +634,10 @@ 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 ; + info->state =STATE_PREPARED ; exec_cmd =prepare_command_pool (info, command, column, page_addr);if (exec_cmd) {init_completion (&info->cmd_complete);
@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,/* 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 +664,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 +696,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 +709,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 +722,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 +733,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 +754,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,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, {struct platform_device *pdev = info->pdev;struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +struct pxa3xx_nand_host *host = info->host;uint32_t ndcr =0x0 ;/* enable all interrupts */ if (f->page_size !=2048 && f->page_size !=512 ) {
@@ -785,45 +792,52 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, }/* 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) { +struct pxa3xx_nand_host *host = info->host;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 ; }
@@ -853,7 +867,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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;
@@ -861,7 +874,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) 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, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys);return info->data_dma_ch; }
@@ -871,21 +884,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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->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 ;
@@ -899,12 +916,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret =pxa3xx_nand_sensing (info); -if (!ret) { -kfree (mtd); - info->mtd =NULL ; +if (ret) { + host->mtd =NULL ;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 );
@@ -912,8 +928,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (id !=0 )dev_info (&info->pdev->dev,"Detect a flash id %x\n" , id);else { -kfree (mtd); - info->mtd =NULL ; + host->mtd =NULL ;dev_warn (&info->pdev->dev,"Read out ID 0, " "potential timing set wrong!!\n" );
@@ -933,14 +948,18 @@ 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 ; + host->mtd =NULL ;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;
@@ -955,44 +974,53 @@ 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 ; + host->row_addr_cycles =2 ; + mtd->name = mtd_names[0 ]; 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 |=NAND_NO_AUTOINCR ; + chip->options =NAND_NO_AUTOINCR ; chip->options |=NAND_NO_READRDY ; +if (host->reg_ndcr &NDCR_DWIDTH_M ) + chip->options |=NAND_BUSWIDTH_16 ;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_info *info; +struct pxa3xx_nand_host *host;struct nand_chip *chip;struct mtd_info *mtd;struct resource *r;int ret, irq; - mtd =kzalloc (sizeof (struct mtd_info ) +sizeof (struct pxa3xx_nand_info ), + info =kzalloc (sizeof (*info) +sizeof (*mtd) +sizeof (*host),GFP_KERNEL ); -if (!mtd) { +if (!info) {dev_err (&pdev->dev,"failed to allocate memory\n" ); -return NULL ; +return -ENOMEM ; } - info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + mtd = (struct mtd_info *)(&info[1 ]); chip = (struct nand_chip *)(&mtd[1 ]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner =THIS_MODULE ; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
@@ -1000,7 +1028,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) 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;
@@ -1079,13 +1106,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)platform_set_drvdata (pdev, info); -return info; +return 0 ; fail_free_buf:free_irq (irq, info);if (use_dma) {pxa_free_dma (info->data_dma_ch); -dma_free_coherent (&pdev->dev, info->data_buff_size, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys); }else kfree (info->data_buff);
@@ -1097,17 +1124,19 @@ fail_put_clk:clk_disable (info->clk);clk_put (info->clk); fail_free_mtd: -kfree (mtd); -return NULL ; +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 resource *r;int irq; +if (!info) +return 0 ; +platform_set_drvdata (pdev,NULL ); irq =platform_get_irq (pdev,0 );
@@ -1115,7 +1144,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);
@@ -1127,10 +1156,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)clk_disable (info->clk);clk_put (info->clk); -if (mtd) { -nand_release (mtd); -kfree (mtd); - } +nand_release (info->host->mtd); +kfree (info);return 0 ; }
@@ -1138,6 +1165,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) {struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +int ret; pdata = pdev->dev.platform_data;if (!pdata) {
@@ -1145,17 +1173,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) -return -ENOMEM ; + ret =alloc_nand_resource (pdev); +if (ret) { +dev_err (&pdev->dev,"alloc nand resource failed\n" ); +return ret; + } -if (pxa3xx_nand_scan (info->mtd)) { + info =platform_get_drvdata (pdev); +if (pxa3xx_nand_scan (info->host->mtd)) {dev_err (&pdev->dev,"failed to scan nand\n" );pxa3xx_nand_remove (pdev);return -ENODEV ; } -return mtd_device_parse_register (info->mtd,NULL ,0 , +return mtd_device_parse_register (info->host->mtd,NULL ,0 , pdata->parts, pdata->nr_parts); }
@@ -1176,8 +1207,8 @@ 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); +nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); +nand_writel (info,NDTR1CS0 , info->host->ndtr1cs0);clk_enable (info->clk);return 0 ;
Signature · 1 line
1.7.0.4
PATCH v5 3/3 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenCurrent 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.
--- 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 | 20 +++- drivers/mtd/nand/pxa3xx_nand.c | 151 ++++++++++++++++++-------- 9 files changed, 146 insertions(+), 64 deletions(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +18 -2
@@ -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,11 @@ 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;
drivers/mtd/nand/pxa3xx_nand.c +105 -46
300 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v4 1/4 MTD: pxa3xx_nand: convert all printk into dev_*
In reply to Lei Wen--- drivers/mtd/nand/pxa3xx_nand.c | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +16 -11
@@ -359,7 +359,7 @@ 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__, +dev_err (&info->pdev->dev,"%s: invalid state %d\n" , __func__, info->state);BUG (); }
@@ -385,7 +385,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 (); }
@@ -616,8 +616,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,default : exec_cmd =0 ; -printk (KERN_ERR "pxa3xx-nand: non-supported" -" command %x\n" , command); +dev_err (&info->pdev->dev,"non-supported command %x\n" , + command);break ; }
@@ -646,7 +646,7 @@ 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); }
@@ -774,11 +774,15 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;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;
@@ -898,7 +902,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (!ret) {kfree (mtd); info->mtd =NULL ; -printk (KERN_INFO "There is no nand chip on cs 0!\n" ); +dev_info (&info->pdev->dev,"There is no nand chip on cs 0!\n" );return -EINVAL ; }
@@ -906,11 +910,12 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) 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" ); +dev_warn (&info->pdev->dev,"Read out ID 0, " +"potential timing set wrong!!\n" );return -EINVAL ; }
@@ -930,7 +935,7 @@ 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" ); +dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );return -EINVAL ; }
Signature · 1 line
1.7.0.4
PATCH v4 2/4 MTD: pxa3xx_nand: sperate each chip individual info
In reply to Lei WenFor support two chip select, we seperate chip specific info in this patch.
--- drivers/mtd/nand/pxa3xx_nand.c | 281 ++++++++++++++++++++++------------------ 1 files changed, 154 insertions(+), 127 deletions(-)
drivers/mtd/nand/pxa3xx_nand.c +154 -127
@@ -110,6 +110,7 @@ enum {enum {STATE_IDLE =0 , +STATE_PREPARED ,STATE_CMD_HANDLE ,STATE_DMA_READING ,STATE_DMA_WRITING ,
@@ -120,21 +121,39 @@ 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 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,18 +161,11 @@ 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; - -/* relate to the command */ +struct pxa3xx_nand_host *host;unsigned int state;int use_ecc;/* use HW ECC ? */
@@ -162,24 +174,13 @@ struct pxa3xx_nand_info {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 ;
@@ -241,9 +242,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 +260,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; +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 +295,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;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 ;
@@ -463,12 +467,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 +479,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; +struct mtd_info *mtd = host->mtd; - ndcb0 =0 ; addr_cycle =0 ; exec_cmd =1 ;
@@ -494,6 +492,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size =0 ; info->use_ecc =0 ; info->is_ready =0 ; + info->ndcb0 =0 ; info->retcode =ERR_NONE ;switch (command) {
@@ -512,20 +511,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 +535,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 +562,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 +572,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 +581,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 +591,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 +602,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;
@@ -627,7 +625,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 +634,10 @@ 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 ; + info->state =STATE_PREPARED ; exec_cmd =prepare_command_pool (info, command, column, page_addr);if (exec_cmd) {init_completion (&info->cmd_complete);
@@ -650,8 +650,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,/* 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 +664,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 +696,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 +709,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 +722,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 +733,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 +754,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,6 +778,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, {struct platform_device *pdev = info->pdev;struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; +struct pxa3xx_nand_host *host = info->host;uint32_t ndcr =0x0 ;/* enable all interrupts */ if (f->page_size !=2048 && f->page_size !=512 ) {
@@ -785,45 +792,51 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, }/* 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) { +struct pxa3xx_nand_host *host = info->host;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 ; }
@@ -853,7 +866,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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;
@@ -861,7 +873,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) 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, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys);return info->data_dma_ch; }
@@ -871,21 +883,25 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)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->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 ;
@@ -899,12 +915,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret =pxa3xx_nand_sensing (info); -if (!ret) { -kfree (mtd); - info->mtd =NULL ; +if (ret) { + host->mtd =NULL ;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 );
@@ -912,8 +927,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)if (id !=0 )dev_info (&info->pdev->dev,"Detect a flash id %x\n" , id);else { -kfree (mtd); - info->mtd =NULL ; + host->mtd =NULL ;dev_warn (&info->pdev->dev,"Read out ID 0, " "potential timing set wrong!!\n" );
@@ -933,14 +947,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 ; + host->mtd =NULL ;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;
@@ -955,44 +972,52 @@ 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 ; + host->row_addr_cycles =2 ; mtd->name = mtd_names[0 ]; 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_info *info; +struct pxa3xx_nand_host *host;struct nand_chip *chip;struct mtd_info *mtd;struct resource *r;int ret, irq; - mtd =kzalloc (sizeof (struct mtd_info ) +sizeof (struct pxa3xx_nand_info ), + info =kzalloc (sizeof (*info) +sizeof (*mtd) +sizeof (*host),GFP_KERNEL ); -if (!mtd) { +if (!info) {dev_err (&pdev->dev,"failed to allocate memory\n" ); -return NULL ; +return -ENOMEM ; } - info = (struct pxa3xx_nand_info *)(&mtd[1 ]); + mtd = (struct mtd_info *)(&info[1 ]); chip = (struct nand_chip *)(&mtd[1 ]); + host = (struct pxa3xx_nand_host *)chip; info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; + info->host = host; + host->mtd = mtd; + host->info_data = info; + mtd->priv = host; mtd->owner =THIS_MODULE ; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
@@ -1000,7 +1025,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) 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;
@@ -1079,13 +1103,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)platform_set_drvdata (pdev, info); -return info; +return 0 ; fail_free_buf:free_irq (irq, info);if (use_dma) {pxa_free_dma (info->data_dma_ch); -dma_free_coherent (&pdev->dev, info->data_buff_size, +dma_free_coherent (&pdev->dev,MAX_BUFF_SIZE , info->data_buff, info->data_buff_phys); }else kfree (info->data_buff);
@@ -1097,17 +1121,18 @@ fail_put_clk:clk_disable (info->clk);clk_put (info->clk); fail_free_mtd: -kfree (mtd); -return NULL ; +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 resource *r;int irq; +if (!info) +return 0 ;platform_set_drvdata (pdev,NULL ); irq =platform_get_irq (pdev,0 );
@@ -1115,7 +1140,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);
@@ -1127,10 +1152,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)clk_disable (info->clk);clk_put (info->clk); -if (mtd) { -nand_release (mtd); -kfree (mtd); - } +nand_release (info->host->mtd); +kfree (info);return 0 ; }
@@ -1138,6 +1161,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) {struct pxa3xx_nand_platform_data *pdata;struct pxa3xx_nand_info *info; +int ret; pdata = pdev->dev.platform_data;if (!pdata) {
@@ -1145,17 +1169,20 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)return -ENODEV ; } - info =alloc_nand_resource (pdev); -if (info ==NULL ) -return -ENOMEM ; + ret =alloc_nand_resource (pdev); +if (ret) { +dev_err (&pdev->dev,"alloc nand resource failed\n" ); +return ret; + } -if (pxa3xx_nand_scan (info->mtd)) { + info =platform_get_drvdata (pdev); +if (pxa3xx_nand_scan (info->host->mtd)) {dev_err (&pdev->dev,"failed to scan nand\n" );pxa3xx_nand_remove (pdev);return -ENODEV ; } -return mtd_device_parse_register (info->mtd,NULL ,0 , +return mtd_device_parse_register (info->host->mtd,NULL ,0 , pdata->parts, pdata->nr_parts); }
@@ -1176,8 +1203,8 @@ 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); +nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); +nand_writel (info,NDTR1CS0 , info->host->ndtr1cs0);clk_enable (info->clk);return 0 ;
Signature · 1 line
1.7.0.4
PATCH 2/4 MTD: pxa3xx_nand: sperate each chip individual info
Hi Lei,
You are going to resubmit the series to merge patches 3 and 4, so
a small nitpick below
Quoted 7 lines · Lei Wen
For support two chip select, we seperate chip specific info in this patch.
Signed-off-by Lei Wen <[email protected]>--- drivers/mtd/nand/pxa3xx_nand.c | 281 ++++++++++++++++++++++------------------ 1 files changed, 154 insertions(+), 127 deletions(-)
[...]
Quoted 10 lines
static int
pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info){drivers/mtd/nand/pxa3xx_nand.c +1
-5+struct pxa3xx_nand_host *host = info->host;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;
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, · line 834
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +7
-2- 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 ; + }
empty line would be nice here
Quoted 8 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-0+ 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 ; }
[...]
Quoted 9 lines
drivers/mtd/nand/pxa3xx_nand.c +1
-2@@ -933,14 +947,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 ; + host->mtd =NULL ;dev_err (&info->pdev->dev,"ERROR!! flash not defined!!!\n" );
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 960
Quoted 10 lines
drivers/mtd/nand/pxa3xx_nand.c +5
-1return -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; + }
and here
drivers/mtd/nand/pxa3xx_nand.c KEEP_CONFIG: · line 978
Quoted 12 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-1pxa3xx_flash_ids[0 ].name = f->name; pxa3xx_flash_ids[0 ].id = (f->chip_id >>8 ) &0xffff ; pxa3xx_flash_ids[0 ].pagesize = f->page_size;@@ -955,44 +972,52 @@ 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 ;
and here
drivers/mtd/nand/pxa3xx_nand.c KEEP_CONFIG: · line 983
Quoted 7 lines
drivers/mtd/nand/pxa3xx_nand.c +2
-2info->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 ; + host->row_addr_cycles =2 ;
also here
drivers/mtd/nand/pxa3xx_nand.c KEEP_CONFIG: · line 992
Quoted 11 lines
drivers/mtd/nand/pxa3xx_nand.c +4
-2mtd->name = mtd_names[0 ]; 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 ;
here, you can just reorder the bit operations, so you won't need to do options = 0. And empty line after if, would be great.
Quoted 4 lines
drivers/mtd/nand/pxa3xx_nand.c +0
-0return nand_scan_tail (mtd); }
[...]
drivers/mtd/nand/pxa3xx_nand.c fail_put_clk: · line 1135
Quoted 9 lines
static int
pxa3xx_nand_remove(struct platform_device *pdev){drivers/mtd/nand/pxa3xx_nand.c +2
-1struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); -struct mtd_info *mtd = info->mtd;struct resource *r;int irq; +if (!info) +return 0 ;
and here (empty line)
apart from that nitpicking, the patch should be fine.
Signature · 2 lines
Regards, Igor.
PATCH v4 3/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei WenCurrent 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.
--- arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | 20 +++- drivers/mtd/nand/pxa3xx_nand.c | 152 ++++++++++++++++++-------- 2 files changed, 124 insertions(+), 48 deletions(-)
arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +18 -2
@@ -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,11 @@ 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;
drivers/mtd/nand/pxa3xx_nand.c +106 -46
300 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v8 3/4 MTD: pxa3xx_nand: enable multiple chip select support
The problem is that in this patch you change struct pxa3xx_nand_platform_data, and in the next patch you amend the platform data declarations, which means that the kernel will not compile between patches 3 and 4...
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_scan(struct mtd_info *mtd) · line 952
Quoted 2 lines · Lei Wen
drivers/mtd/nand/pxa3xx_nand.c +2
-0+dev_info (&info->pdev->dev,"There is no nand chip on cs %d!\n" + , info->cs);
Nitpick - keep the comma at the first line.
Signature · 2 lines
Best Regards, Artem Bityutskiy
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 3 lines · Artem Bityutskiy
The problem is that in this patch you change ?struct
pxa3xx_nand_platform_data, and in the next patch you amend the platform data declarations, which means that the kernel will not compile between patches 3 and 4...
So... how about merge the patch 3 and 4 together?
Quoted 6 lines · Lei Wen
Quoted 2 lines
+ ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "There is no nand chip on cs %d!\n"
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ,info->cs);Nitpick - keep the comma at the first line.
Opps, sorry for this.
Thanks,
Lei
PATCH v8 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 6 lines · Lei Wen
Quoted 3 lines · Artem Bityutskiy
The problem is that in this patch you change struct
pxa3xx_nand_platform_data, and in the next patch you amend the platform data declarations, which means that the kernel will not compile between patches 3 and 4...So... how about merge the patch 3 and 4 together?
IMO this should be OK.
Signature · 2 lines
Best Regards, Artem Bityutskiy
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Lei Wendrivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1267
Quoted 13 lines · Lei Wen
#ifdef
CONFIG_PMdrivers/mtd/nand/pxa3xx_nand.c +6
-2@@ -1203,8 +1259,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); -nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); -nand_writel (info,NDTR1CS0 , info->host->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 ;
Thinking of this for the second (or third) time, If you have keep config enabled and have only one nand chip, this will brake the keep config...
Daniel,
have you tested the suspend/resume with this patch? (and keep_config on?)
Signature · 2 lines
Regards, Igor.
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Hi Igor && Daniel,
Quoted 20 lines · Igor Grinberg
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1267
Quoted 13 lines · Lei Wen
?#ifdef
CONFIG_PM(quoted diff) +6
-2@@ -1203,8 +1259,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ?{ ? ? ? struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - ? ? nand_writel(info, NDTR0CS0, info->host->ndtr0cs0); - ? ? nand_writel(info, NDTR1CS0, info->host->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;Thinking of this for the second (or third) time, If you have keep config enabled and have only one nand chip, this will brake the keep config...
Quoted 5 lines
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)
Do you still have concern with this change?
If not, I would push the next round of patch set including merging patch 3 and 4.
Thanks,
Lei
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 22 lines · Lei Wen
Hi Igor && Daniel,
Quoted 19 lines · Igor Grinberg
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1267
Quoted 13 lines · Lei Wen
#ifdef
CONFIG_PMdrivers/mtd/nand/pxa3xx_nand.c +6
-2@@ -1203,8 +1259,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); -nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); -nand_writel (info,NDTR1CS0 , info->host->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 ;Thinking of this for the second (or third) time, If you have keep config enabled and have only one nand chip, this will brake the keep config...
Quoted 8 lines
Quoted 5 lines
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)Do you still have concern with this change?
If not, I would push the next round of patch set including merging patch 3 and 4.
Though I can't test it right now, but yes it looks like it breaks the keep_config after the resume (actually it disables the keep_config silently).
I think you need here some kind of check if keep_config is enabled. keep_config is enabled means that only one chip select is used for NAND and you don't need to reset the timings.
Signature · 2 lines
Regards, Igor.
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Hi Igor,
Quoted 33 lines · Igor Grinberg
Quoted 22 lines · Lei Wen
Hi Igor && Daniel,
Quoted 19 lines · Igor Grinberg
Review static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1267
Quoted 13 lines · Lei Wen
?#ifdef
CONFIG_PM(quoted diff) +6
-2@@ -1203,8 +1259,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) ?{ ? ? ? struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - ? ? nand_writel(info, NDTR0CS0, info->host->ndtr0cs0); - ? ? nand_writel(info, NDTR1CS0, info->host->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;Thinking of this for the second (or third) time, If you have keep config enabled and have only one nand chip, this will brake the keep config...
Quoted 8 lines
Quoted 5 lines
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)Do you still have concern with this change?
If not, I would push the next round of patch set including merging patch 3 and 4.
Quoted 6 lines
Though I can't test it right now, but yes it looks like it breaks the
keep_configafter the resume (actually it disables thekeep_configsilently).I think you need here some kind of check if
keep_configis enabled.keep_configis enabled means that only one chip select is used for NAND and you don't need to reset the timings.
It would not break anything.
The value rewrite to timing register is the one that save in the pxa3xx_nand_detect_config.
And it is the same behavior before this patch apply.
Best regards,
Lei
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 38 lines · Lei Wen
Hi Igor,
Quoted 35 lines · Igor Grinberg
Quoted 22 lines · Lei Wen
Hi Igor && Daniel,
Quoted 19 lines · Igor Grinberg
drivers/mtd/nand/pxa3xx_nand.c static int pxa3xx_nand_resume(struct platform_device *pdev) · line 1267
Quoted 13 lines · Lei Wen
#ifdef
CONFIG_PMdrivers/mtd/nand/pxa3xx_nand.c +6
-2@@ -1203,8 +1259,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) {struct pxa3xx_nand_info *info =platform_get_drvdata (pdev); -nand_writel (info,NDTR0CS0 , info->host->ndtr0cs0); -nand_writel (info,NDTR1CS0 , info->host->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 ;Thinking of this for the second (or third) time, If you have keep config enabled and have only one nand chip, this will brake the keep config...
Quoted 8 lines
Quoted 5 lines
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)Do you still have concern with this change?
If not, I would push the next round of patch set including merging patch 3 and 4.Though I can't test it right now, but yes it looks like it breaks the
keep_configafter the resume (actually it disables thekeep_configsilently).
Quoted 7 lines
Quoted 3 lines
I think you need here some kind of check if
keep_configis enabled.keep_configis enabled means that only one chip select is used for NAND and you don't need to reset the timings.It would not break anything.
The value rewrite to timing register is the one that save in thepxa3xx_nand_detect_config.
And it is the same behavior before this patch apply.
Right. I've missed this. Thanks for the explanation.
Signature · 2 lines
Regards, Igor.
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Igor GrinbergQuoted 4 lines · Igor Grinberg
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)
We did now test this with keep_config=1 and it seems that we indeed have a problem with suspend/resume after this patch. Affected machines show the following after wake up:
[ 1295.458958] PM: resume of devices complete after 296.228 msecs [ 1295.717773] Restarting tasks ... [ 1295.729639] UBI error: ubi_io_write: error -5 while writing 2048 bytes to PEB 19:59392, written 0 bytes [ 1295.761672] done. [ 1295.772706] UBI warning: ubi_eba_write_leb: failed to write data to PEB 19 [ 1295.782492] UBI: recover PEB 19, move data to PEB 405 [ 1295.849084] mmc0: new SDIO card at address 0001 [ 1295.978045] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1295.983153] UBI warning: ubi_io_read_vid_hdr: no VID header found at PEB 19, only 0xFF bytes [ 1296.015382] UBI: run torture test for PEB 405 [ 1296.024375] UBI warning: ubi_ro_mode: switch to read-only mode [ 1296.032321] UBI error: do_sync_erase: read-only mode [ 1296.037296] UBI error: erase_worker: failed to erase PEB 405, error -30 [ 1296.058363] UBIFS error (pid 1303): ubifs_wbuf_write_nolock: cannot write 424 bytes to LEB 317:55296, error -5 [ 1296.080917] UBIFS error (pid 1092): ubifs_wbuf_write_nolock: cannot write 416 bytes to LEB 317:55296, error -30 [ 1296.094470] UBIFS warning (pid 1303): ubifs_ro_mode: switched to read-only mode, error -5 [ 1296.106183] UBIFS error (pid 1092): ubifs_create: cannot create regular file, error -30 [ 1296.118007] UBI error: do_work: work failed with error code -30 [ 1296.123915] UBI error: ubi_thread: ubi_bgt0d: work failed with error code -30 [ 1296.742934] libertas_sdio mmc0:0001:1: (unregistered net_device): 00:19:88:11:db:67, fw 9.70.7p0, cap 0x00000303 [ 1296.779845] libertas_sdio mmc0:0001:1: wlan0: Marvell WLAN 802.11 adapter [ 1296.847141] ADDRCONF(NETDEV_UP): wlan0: link is not ready [ 1298.041988] ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready [ 1300.957951] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.157810] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.357874] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.557924] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.563064] UBIFS error (pid 1260): ubifs_read_node: bad node type (255 but expected 1) [ 1301.573526] UBIFS error (pid 1260): ubifs_read_node: bad node at LEB 112:18808, LEB mapping status 1 [ 1301.583586] UBIFS error (pid 1260): do_readpage: cannot read page 3 of inode 10295, error -22 [ 1301.787877] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.987891] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.187878] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.387878] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.393866] UBIFS error (pid 1260): ubifs_read_node: bad node type (255 but expected 1) [ 1302.403452] UBIFS error (pid 1260): ubifs_read_node: bad node at LEB 112:18808, LEB mapping status 1 [ 1302.413507] UBIFS error (pid 1260): do_readpage: cannot read page 3
of inode 10295, error -22
The UBIFS is very likely toast after this.
Lei, any ideas, can you reproduce this? To avoid further regressions of this driver, you really should have a system on which you can test suspend and resume after each commit.
Thanks,
Daniel
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 59 lines · Daniel Mack
Quoted 4 lines · Igor Grinberg
Daniel,
have you tested the suspend/resume with this patch? (and
keep_configon?)We did now test this with keep_config=1 and it seems that we indeed have a problem with suspend/resume after this patch. Affected machines show the following after wake up:
[ 1295.458958] PM: resume of devices complete after 296.228 msecs [ 1295.717773] Restarting tasks ... [ 1295.729639] UBI error: ubi_io_write: error -5 while writing 2048 bytes to PEB 19:59392, written 0 bytes [ 1295.761672] done. [ 1295.772706] UBI warning: ubi_eba_write_leb: failed to write data to PEB 19 [ 1295.782492] UBI: recover PEB 19, move data to PEB 405 [ 1295.849084] mmc0: new SDIO card at address 0001 [ 1295.978045] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1295.983153] UBI warning: ubi_io_read_vid_hdr: no VID header found at PEB 19, only 0xFF bytes [ 1296.015382] UBI: run torture test for PEB 405 [ 1296.024375] UBI warning: ubi_ro_mode: switch to read-only mode [ 1296.032321] UBI error: do_sync_erase: read-only mode [ 1296.037296] UBI error: erase_worker: failed to erase PEB 405, error -30 [ 1296.058363] UBIFS error (pid 1303): ubifs_wbuf_write_nolock: cannot write 424 bytes to LEB 317:55296, error -5 [ 1296.080917] UBIFS error (pid 1092): ubifs_wbuf_write_nolock: cannot write 416 bytes to LEB 317:55296, error -30 [ 1296.094470] UBIFS warning (pid 1303): ubifs_ro_mode: switched to read-only mode, error -5 [ 1296.106183] UBIFS error (pid 1092): ubifs_create: cannot create regular file, error -30 [ 1296.118007] UBI error: do_work: work failed with error code -30 [ 1296.123915] UBI error: ubi_thread: ubi_bgt0d: work failed with error code -30 [ 1296.742934] libertas_sdio mmc0:0001:1: (unregistered net_device): 00:19:88:11:db:67, fw 9.70.7p0, cap 0x00000303 [ 1296.779845] libertas_sdio mmc0:0001:1: wlan0: Marvell WLAN 802.11 adapter [ 1296.847141] ADDRCONF(NETDEV_UP): wlan0: link is not ready [ 1298.041988] ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready [ 1300.957951] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.157810] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.357874] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.557924] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.563064] UBIFS error (pid 1260): ubifs_read_node: bad node type (255 but expected 1) [ 1301.573526] UBIFS error (pid 1260): ubifs_read_node: bad node at LEB 112:18808, LEB mapping status 1 [ 1301.583586] UBIFS error (pid 1260): do_readpage: cannot read page 3 of inode 10295, error -22 [ 1301.787877] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1301.987891] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.187878] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.387878] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1302.393866] UBIFS error (pid 1260): ubifs_read_node: bad node type (255 but expected 1) [ 1302.403452] UBIFS error (pid 1260): ubifs_read_node: bad node at LEB 112:18808, LEB mapping status 1 [ 1302.413507] UBIFS error (pid 1260): do_readpage: cannot read page 3
Quoted 4 lines
of inode 10295, error -22
The UBIFS is very likely toast after this.
Heh, so I'm still sane... ;)
Quoted 3 lines
Lei, any ideas, can you reproduce this? To avoid further regressions of this driver, you really should have a system on which you can test suspend and resume after each commit.
I think the problem is that on PXA3xx resume from S2/S3 involves bootloader. If I remember correctly, the BootROM reads the bootloader from the boot device regardless of the reset cause (S2/S3 resume is kind a reset for PXA3xx). Then the bootloader must decide what should be done according to the reset cause. This means, that the BootROM already configures the NAND flash
(if it is the boot device) and pxa3xx_nand driver should just get on with it and don't try to reconfigure?
Am I still sane? ;)
Signature · 2 lines
Regards, Igor.
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 8 lines · Igor Grinberg
Quoted 3 lines · Daniel Mack
Lei, any ideas, can you reproduce this? To avoid further regressions of this driver, you really should have a system on which you can test suspend and resume after each commit.
I think the problem is that on PXA3xx resume from S2/S3 involves bootloader. If I remember correctly, the BootROM reads the bootloader from the boot device regardless of the reset cause (S2/S3 resume is kind a reset for PXA3xx).
At least not in our case. The first level bootloader is entered on resume just as it is on a POR event, with the exception that the D3S bit in the ASCR register is set in this case. We unconditionally initialize the static and dynamic memory controllers and then either jump to the routine that initializes the NAND controller, read the 2nd level loader and pass control to it. Or (in the resume case) we just jump to the address stored at the RAM address 0x80000000 (which has been set to cpu_resume previously) and thus enter the kernel again. No NAND operations in the game in this case, and this has always worked fine.
Quoted 4 lines
Then the bootloader must decide what should be done according to the reset cause. This means, that the BootROM already configures the NAND flash
(if it is the boot device) andpxa3xx_nanddriver should just get on with it and don't try to reconfigure?
I think the problem is just the opposite. The driver expects the setup registers to retain their state over suspend, and doesn't write them again, and this causes operations to fail after resume.
Daniel
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 11 lines · Daniel Mack
Quoted 7 lines · Igor Grinberg
Quoted 3 lines · Daniel Mack
Lei, any ideas, can you reproduce this? To avoid further regressions of this driver, you really should have a system on which you can test suspend and resume after each commit.
I think the problem is that on PXA3xx resume from S2/S3 involves bootloader. If I remember correctly, the BootROM reads the bootloader from the boot device regardless of the reset cause (S2/S3 resume is kind a reset for PXA3xx).
At least not in our case. The first level bootloader is entered on resume just as it is on a POR event, with the exception that the D3S bit in the ASCR register is set in this case.
You say "first level boot loader is entered"... who is loading it and where from? Indeed, it should happen as in POR case, but again, it resides on some non-volatile storage, isn't it? What storage does it reside on?
Quoted 8 lines
We unconditionally
initialize the static and dynamic memory controllers and then either jump to the routine that initializes the NAND controller, read the 2nd level loader and pass control to it. Or (in the resume case) we just jump to the address stored at the RAM address0x80000000(which has been set tocpu_resumepreviously) and thus enter the kernel again. No NAND operations in the game in this case, and this has always worked fine.
Except those to read the first stage boot loader... (if it resides on NAND). Well, our case is working similarly and both the first stage bootloader (OBM) and the second stage bootloader (U-Boot) reside on the NAND flash, therefore BootROM has to reconfigure the NAND flash, so it can boot (resume).
Quoted 7 lines
Quoted 4 lines
Then the bootloader must decide what should be done according to the reset cause. This means, that the BootROM already configures the NAND flash
(if it is the boot device) andpxa3xx_nanddriver should just get on with it and don't try to reconfigure?I think the problem is just the opposite. The driver expects the setup registers to retain their state over suspend, and doesn't write them again, and this causes operations to fail after resume.
Well, according to Lei, the driver writes back the configuration that is stored prior to suspend and that's why I agreed that it should work...
http://www.spinics.net/lists/arm-kernel/msg131942.html
Signature · 2 lines
Regards, Igor.
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 39 lines · Igor Grinberg
Quoted 11 lines · Daniel Mack
Quoted 7 lines · Igor Grinberg
Quoted 3 lines · Daniel Mack
Lei, any ideas, can you reproduce this? To avoid further regressions of this driver, you really should have a system on which you can test suspend and resume after each commit.
I think the problem is that on PXA3xx resume from S2/S3 involves bootloader. If I remember correctly, the BootROM reads the bootloader from the boot device regardless of the reset cause (S2/S3 resume is kind a reset for PXA3xx).
At least not in our case. The first level bootloader is entered on resume just as it is on a POR event, with the exception that the D3S bit in the ASCR register is set in this case.
You say "first level boot loader is entered"... who is loading it and where from? Indeed, it should happen as in POR case, but again, it resides on some non-volatile storage, isn't it? What storage does it reside on?
Quoted 8 lines
We unconditionally
initialize the static and dynamic memory controllers and then either jump to the routine that initializes the NAND controller, read the 2nd level loader and pass control to it. Or (in the resume case) we just jump to the address stored at the RAM address0x80000000(which has been set tocpu_resumepreviously) and thus enter the kernel again. No NAND operations in the game in this case, and this has always worked fine.Except those to read the first stage boot loader... (if it resides on NAND). Well, our case is working similarly and both the first stage bootloader (OBM) and the second stage bootloader (U-Boot) reside on the NAND flash, therefore BootROM has to reconfigure the NAND flash, so it can boot (resume).
Quoted 4 lines
Quoted 4 lines
Then the bootloader must decide what should be done according to the reset cause. This means, that the BootROM already configures the NAND flash
(if it is the boot device) andpxa3xx_nanddriver should just get on with it and don't try to reconfigure?
Quoted 10 lines
Quoted 3 lines
I think the problem is just the opposite. The driver expects the setup registers to retain their state over suspend, and doesn't write them again, and this causes operations to fail after resume.
Well, according to Lei, the driver writes back the configuration that is stored prior to suspend and that's why I agreed that it should work...
Daniel,
I retest with suspend&resume on my board, each time that board would reset the timing in the
begining of pxa3xx_cmdfunc as expected. So this should be ok as it is the same behavior
with original code.
However, it certainly has some potential risk in the suspend&resume process. That is in pxa3xx_nand_suspend and pxa3xx_nand_resume, it should call mtd->suspend and mtd->resume
respectively.
This implement has already existed in our code release for years, but have get into the mainline yet.
So I tend to merged into the third patch, and you could have test again whether could fix your issue.
Thanks,
Lei
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 5 lines · Lei Wen
I retest with suspend&resume on my board, each time that board would reset the timing in the
begining ofpxa3xx_cmdfuncas expected. So this should be ok as it is the same behavior
with original code.
Ok, just to be sure - as there have been quite some iterations fot this now - can you send me a link to your most current version of this patch again, please? Just to avoid confusion which version we're talking about.
Thanks,
Daniel
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Hi Daniel,
Quoted 7 lines · Daniel Mack
Quoted 5 lines · Lei Wen
I retest with suspend&resume on my board, each time that board would reset the timing in the
begining ofpxa3xx_cmdfuncas expected. So this should be ok as it is the same behavior
with original code.
Quoted 6 lines
Ok, just to be sure - as there have been quite some iterations fot this now - can you send me a link to your most current version of this patch again, please? Just to avoid confusion which version we're talking about.
Please refer to V6 patch set I just send out.
Thanks,
Lei
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 10 lines · Lei Wen
Hi Daniel,
Quoted 7 lines · Daniel Mack
Quoted 5 lines · Lei Wen
I retest with suspend&resume on my board, each time that board would reset the timing in the
begining ofpxa3xx_cmdfuncas expected. So this should be ok as it is the same behavior
with original code.
Quoted 8 lines
Quoted 6 lines
Ok, just to be sure - as there have been quite some iterations fot this now - can you send me a link to your most current version of this patch again, please? Just to avoid confusion which version we're talking about.
Please refer to V6 patch set I just send out.
I did. With all 4 patches applied, the system doesn't wake up again, as I posted as reply to this particular patch. With only the first 3 applied, we see the following messages after resume:
[ 1297.173920] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1297.373887] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1297.379014] UBIFS error (pid 1245): ubifs_read_node: bad node type (255 but expected 2) [ 1297.388521] UBIFS error (pid 1245): ubifs_read_node: bad node at LEB 435:102784, LEB mapping status 1 [ 1297.593895] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1297.793884] pxa3xx-nand pxa3xx-nand: Wait time out!!! [ 1297.994294] pxa3xx-nand pxa3xx-nand: Wait time out!!!
Daniel
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
In reply to Igor GrinbergQuoted 8 lines · Igor Grinberg
Quoted 3 lines · Daniel Mack
At least not in our case. The first level bootloader is entered on resume just as it is on a POR event, with the exception that the D3S bit in the ASCR register is set in this case.
You say "first level boot loader is entered"... who is loading it and where from? Indeed, it should happen as in POR case, but again, it resides on some non-volatile storage, isn't it? What storage does it reside on?
That is true. I was assuming that the first-stage loader remains in SRAM and is re-used later, but I think you're right, and it is loaded from NAND again after resume.
Quoted 9 lines
Quoted 8 lines
We unconditionally
initialize the static and dynamic memory controllers and then either jump to the routine that initializes the NAND controller, read the 2nd level loader and pass control to it. Or (in the resume case) we just jump to the address stored at the RAM address0x80000000(which has been set tocpu_resumepreviously) and thus enter the kernel again. No NAND operations in the game in this case, and this has always worked fine.
Quoted 4 lines
Except those to read the first stage boot loader... (if it resides on NAND). Well, our case is working similarly and both the first stage bootloader (OBM) and the second stage bootloader (U-Boot) reside on the NAND flash, therefore BootROM has to reconfigure the NAND flash, so it can boot (resume).
Well, the load of the first NAND page (where the OBM resides) is out of control for our software, as the code in PXA's internal ROM mask takes care for this. We do not, however, re-initialize the NAND controller in the resume case, just as we don't restore any other pheripheral's registers. And this has worked fine all the time, and it still does if Lei's latest patch set is not applied.
Daniel
PATCH 3/4 MTD: pxa3xx_nand: enable multiple chip select support
Quoted 20 lines · Daniel Mack
Quoted 7 lines · Igor Grinberg
Quoted 3 lines · Daniel Mack
At least not in our case. The first level bootloader is entered on resume just as it is on a POR event, with the exception that the D3S bit in the ASCR register is set in this case.
You say "first level boot loader is entered"... who is loading it and where from? Indeed, it should happen as in POR case, but again, it resides on some non-volatile storage, isn't it? What storage does it reside on?
That is true. I was assuming that the first-stage loader remains in SRAM and is re-used later, but I think you're right, and it is loaded from NAND again after resume.
Quoted 8 lines
Quoted 8 lines
We unconditionally
initialize the static and dynamic memory controllers and then either jump to the routine that initializes the NAND controller, read the 2nd level loader and pass control to it. Or (in the resume case) we just jump to the address stored at the RAM address0x80000000(which has been set tocpu_resumepreviously) and thus enter the kernel again. No NAND operations in the game in this case, and this has always worked fine.
Quoted 5 lines
Quoted 4 lines
Except those to read the first stage boot loader... (if it resides on NAND). Well, our case is working similarly and both the first stage bootloader (OBM) and the second stage bootloader (U-Boot) reside on the NAND flash, therefore BootROM has to reconfigure the NAND flash, so it can boot (resume).
Well, the load of the first NAND page (where the OBM resides)
You mean block, page is too small for the OBM to fit...
Quoted 3 lines
is out
of control for our software, as the code in PXA's internal ROM mask takes care for this.
Exactly... the BootROM is configuring the NAND controller
and (I think) that is one of the reasons we have the keep_config in first place...
Quoted 3 lines
We do not, however, re-initialize the NAND
controller in the resume case, just as we don't restore any other pheripheral's registers.
Yes, the NAND initialization is done by the BootROM, so you don't need to reinitialize it. Just the DRAM controller (may be SRAM also), so you will be able to jump back to Linux.
Quoted 2 lines
And this has worked fine all the time, and it still does if Lei's latest patch set is not applied.
Signature · 2 lines
Regards, Igor.
PATCH v4 4/4 ARM: mmp/pxa: fix nand platform data
In reply to Lei WenSince two chip select is supported, the original defined nand platform data need to be fixed accordingly.
--- 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 +++-- 7 files changed, 23 insertions(+), 16 deletions(-)
arch/arm/mach-mmp/aspenite.c +3 -2
@@ -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 = {
arch/arm/mach-pxa/cm-x300.c +3 -2
@@ -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 )
arch/arm/mach-pxa/colibri-pxa3xx.c +3 -2
@@ -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 )
arch/arm/mach-pxa/littleton.c +3 -2
@@ -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 )
arch/arm/mach-pxa/mxm8x10.c +5 -4
@@ -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 )
arch/arm/mach-pxa/raumfeld.c +3 -2
@@ -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), };/**
arch/arm/mach-pxa/zylonite.c +3 -2
@@ -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 )
Signature · 1 line
1.7.0.4