diff options
-rw-r--r-- | arch/arm/mach-mmp/aspenite.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/cm-x300.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/colibri-pxa3xx.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/littleton.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mxm8x10.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-pxa/raumfeld.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-pxa/zylonite.c | 5 | ||||
-rw-r--r-- | arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | 20 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 173 |
9 files changed, 164 insertions, 68 deletions
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 06b5fa853c93..c4996f3dba3b 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c | |||
@@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = { | |||
167 | 167 | ||
168 | static struct pxa3xx_nand_platform_data aspenite_nand_info = { | 168 | static struct pxa3xx_nand_platform_data aspenite_nand_info = { |
169 | .enable_arbiter = 1, | 169 | .enable_arbiter = 1, |
170 | .parts = aspenite_nand_partitions, | 170 | .num_cs = 1, |
171 | .nr_parts = ARRAY_SIZE(aspenite_nand_partitions), | 171 | .parts[0] = aspenite_nand_partitions, |
172 | .nr_parts[0] = ARRAY_SIZE(aspenite_nand_partitions), | ||
172 | }; | 173 | }; |
173 | 174 | ||
174 | static struct i2c_board_info aspenite_i2c_info[] __initdata = { | 175 | static struct i2c_board_info aspenite_i2c_info[] __initdata = { |
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index b6a51340270b..eac3846ce42c 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c | |||
@@ -424,8 +424,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = { | |||
424 | static struct pxa3xx_nand_platform_data cm_x300_nand_info = { | 424 | static struct pxa3xx_nand_platform_data cm_x300_nand_info = { |
425 | .enable_arbiter = 1, | 425 | .enable_arbiter = 1, |
426 | .keep_config = 1, | 426 | .keep_config = 1, |
427 | .parts = cm_x300_nand_partitions, | 427 | .num_cs = 1, |
428 | .nr_parts = ARRAY_SIZE(cm_x300_nand_partitions), | 428 | .parts[0] = cm_x300_nand_partitions, |
429 | .nr_parts[0] = ARRAY_SIZE(cm_x300_nand_partitions), | ||
429 | }; | 430 | }; |
430 | 431 | ||
431 | static void __init cm_x300_init_nand(void) | 432 | static void __init cm_x300_init_nand(void) |
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index 3f9be419959d..2b8ca0de8a3d 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c | |||
@@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = { | |||
139 | static struct pxa3xx_nand_platform_data colibri_nand_info = { | 139 | static struct pxa3xx_nand_platform_data colibri_nand_info = { |
140 | .enable_arbiter = 1, | 140 | .enable_arbiter = 1, |
141 | .keep_config = 1, | 141 | .keep_config = 1, |
142 | .parts = colibri_nand_partitions, | 142 | .num_cs = 1, |
143 | .nr_parts = ARRAY_SIZE(colibri_nand_partitions), | 143 | .parts[0] = colibri_nand_partitions, |
144 | .nr_parts[0] = ARRAY_SIZE(colibri_nand_partitions), | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | void __init colibri_pxa3xx_init_nand(void) | 147 | void __init colibri_pxa3xx_init_nand(void) |
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 8f97e15e86e5..cd9fda3c9e65 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c | |||
@@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = { | |||
325 | 325 | ||
326 | static struct pxa3xx_nand_platform_data littleton_nand_info = { | 326 | static struct pxa3xx_nand_platform_data littleton_nand_info = { |
327 | .enable_arbiter = 1, | 327 | .enable_arbiter = 1, |
328 | .parts = littleton_nand_partitions, | 328 | .num_cs = 1, |
329 | .nr_parts = ARRAY_SIZE(littleton_nand_partitions), | 329 | .parts[0] = littleton_nand_partitions, |
330 | .nr_parts[0] = ARRAY_SIZE(littleton_nand_partitions), | ||
330 | }; | 331 | }; |
331 | 332 | ||
332 | static void __init littleton_init_nand(void) | 333 | static void __init littleton_init_nand(void) |
diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index b5a8fd3fce04..90928d6e1a5b 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c | |||
@@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = { | |||
389 | }; | 389 | }; |
390 | 390 | ||
391 | static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = { | 391 | static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = { |
392 | .enable_arbiter = 1, | 392 | .enable_arbiter = 1, |
393 | .keep_config = 1, | 393 | .keep_config = 1, |
394 | .parts = mxm_8x10_nand_partitions, | 394 | .num_cs = 1, |
395 | .nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions) | 395 | .parts[0] = mxm_8x10_nand_partitions, |
396 | .nr_parts[0] = ARRAY_SIZE(mxm_8x10_nand_partitions) | ||
396 | }; | 397 | }; |
397 | 398 | ||
398 | static void __init mxm_8x10_nand_init(void) | 399 | static void __init mxm_8x10_nand_init(void) |
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index bbcd90562ebe..6a2f353de39a 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c | |||
@@ -346,8 +346,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = { | |||
346 | static struct pxa3xx_nand_platform_data raumfeld_nand_info = { | 346 | static struct pxa3xx_nand_platform_data raumfeld_nand_info = { |
347 | .enable_arbiter = 1, | 347 | .enable_arbiter = 1, |
348 | .keep_config = 1, | 348 | .keep_config = 1, |
349 | .parts = raumfeld_nand_partitions, | 349 | .num_cs = 1, |
350 | .nr_parts = ARRAY_SIZE(raumfeld_nand_partitions), | 350 | .parts[0] = raumfeld_nand_partitions, |
351 | .nr_parts[0] = ARRAY_SIZE(raumfeld_nand_partitions), | ||
351 | }; | 352 | }; |
352 | 353 | ||
353 | /** | 354 | /** |
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 15ec66b3471a..90fbf879c019 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c | |||
@@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = { | |||
366 | 366 | ||
367 | static struct pxa3xx_nand_platform_data zylonite_nand_info = { | 367 | static struct pxa3xx_nand_platform_data zylonite_nand_info = { |
368 | .enable_arbiter = 1, | 368 | .enable_arbiter = 1, |
369 | .parts = zylonite_nand_partitions, | 369 | .num_cs = 1, |
370 | .nr_parts = ARRAY_SIZE(zylonite_nand_partitions), | 370 | .parts[0] = zylonite_nand_partitions, |
371 | .nr_parts[0] = ARRAY_SIZE(zylonite_nand_partitions), | ||
371 | }; | 372 | }; |
372 | 373 | ||
373 | static void __init zylonite_init_nand(void) | 374 | static void __init zylonite_init_nand(void) |
diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 442301fe48b4..c42f39f20195 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | |||
@@ -41,6 +41,19 @@ struct pxa3xx_nand_flash { | |||
41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | 41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ |
42 | }; | 42 | }; |
43 | 43 | ||
44 | /* | ||
45 | * Current pxa3xx_nand controller has two chip select which | ||
46 | * both be workable. | ||
47 | * | ||
48 | * Notice should be taken that: | ||
49 | * When you want to use this feature, you should not enable the | ||
50 | * keep configuration feature, for two chip select could be | ||
51 | * attached with different nand chip. The different page size | ||
52 | * and timing requirement make the keep configuration impossible. | ||
53 | */ | ||
54 | |||
55 | /* The max num of chip select current support */ | ||
56 | #define NUM_CHIP_SELECT (2) | ||
44 | struct pxa3xx_nand_platform_data { | 57 | struct pxa3xx_nand_platform_data { |
45 | 58 | ||
46 | /* the data flash bus is shared between the Static Memory | 59 | /* the data flash bus is shared between the Static Memory |
@@ -52,8 +65,11 @@ struct pxa3xx_nand_platform_data { | |||
52 | /* allow platform code to keep OBM/bootloader defined NFC config */ | 65 | /* allow platform code to keep OBM/bootloader defined NFC config */ |
53 | int keep_config; | 66 | int keep_config; |
54 | 67 | ||
55 | const struct mtd_partition *parts; | 68 | /* indicate how many chip selects will be used */ |
56 | unsigned int nr_parts; | 69 | int num_cs; |
70 | |||
71 | const struct mtd_partition *parts[NUM_CHIP_SELECT]; | ||
72 | unsigned int nr_parts[NUM_CHIP_SELECT]; | ||
57 | 73 | ||
58 | const struct pxa3xx_nand_flash * flash; | 74 | const struct pxa3xx_nand_flash * flash; |
59 | size_t num_flash; | 75 | size_t num_flash; |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 97b689499119..9eb7f879969e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -130,6 +130,7 @@ struct pxa3xx_nand_host { | |||
130 | /* page size of attached chip */ | 130 | /* page size of attached chip */ |
131 | unsigned int page_size; | 131 | unsigned int page_size; |
132 | int use_ecc; | 132 | int use_ecc; |
133 | int cs; | ||
133 | 134 | ||
134 | /* calculated from pxa3xx_nand_flash data */ | 135 | /* calculated from pxa3xx_nand_flash data */ |
135 | unsigned int col_addr_cycles; | 136 | unsigned int col_addr_cycles; |
@@ -165,9 +166,10 @@ struct pxa3xx_nand_info { | |||
165 | struct pxa_dma_desc *data_desc; | 166 | struct pxa_dma_desc *data_desc; |
166 | dma_addr_t data_desc_addr; | 167 | dma_addr_t data_desc_addr; |
167 | 168 | ||
168 | struct pxa3xx_nand_host *host; | 169 | struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; |
169 | unsigned int state; | 170 | unsigned int state; |
170 | 171 | ||
172 | int cs; | ||
171 | int use_ecc; /* use HW ECC ? */ | 173 | int use_ecc; /* use HW ECC ? */ |
172 | int use_dma; /* use DMA ? */ | 174 | int use_dma; /* use DMA ? */ |
173 | int is_ready; | 175 | int is_ready; |
@@ -226,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { | |||
226 | /* Define a default flash type setting serve as flash detecting only */ | 228 | /* Define a default flash type setting serve as flash detecting only */ |
227 | #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) | 229 | #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) |
228 | 230 | ||
229 | const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; | 231 | const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; |
230 | 232 | ||
231 | #define NDTR0_tCH(c) (min((c), 7) << 19) | 233 | #define NDTR0_tCH(c) (min((c), 7) << 19) |
232 | #define NDTR0_tCS(c) (min((c), 7) << 16) | 234 | #define NDTR0_tCS(c) (min((c), 7) << 16) |
@@ -268,7 +270,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, | |||
268 | 270 | ||
269 | static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) | 271 | static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) |
270 | { | 272 | { |
271 | struct pxa3xx_nand_host *host = info->host; | 273 | struct pxa3xx_nand_host *host = info->host[info->cs]; |
272 | int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; | 274 | int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; |
273 | 275 | ||
274 | info->data_size = host->page_size; | 276 | info->data_size = host->page_size; |
@@ -295,7 +297,7 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) | |||
295 | */ | 297 | */ |
296 | static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) | 298 | static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) |
297 | { | 299 | { |
298 | struct pxa3xx_nand_host *host = info->host; | 300 | struct pxa3xx_nand_host *host = info->host[info->cs]; |
299 | uint32_t ndcr; | 301 | uint32_t ndcr; |
300 | 302 | ||
301 | ndcr = host->reg_ndcr; | 303 | ndcr = host->reg_ndcr; |
@@ -420,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
420 | { | 422 | { |
421 | struct pxa3xx_nand_info *info = devid; | 423 | struct pxa3xx_nand_info *info = devid; |
422 | unsigned int status, is_completed = 0; | 424 | unsigned int status, is_completed = 0; |
425 | unsigned int ready, cmd_done; | ||
426 | |||
427 | if (info->cs == 0) { | ||
428 | ready = NDSR_FLASH_RDY; | ||
429 | cmd_done = NDSR_CS0_CMDD; | ||
430 | } else { | ||
431 | ready = NDSR_RDY; | ||
432 | cmd_done = NDSR_CS1_CMDD; | ||
433 | } | ||
423 | 434 | ||
424 | status = nand_readl(info, NDSR); | 435 | status = nand_readl(info, NDSR); |
425 | 436 | ||
@@ -441,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
441 | handle_data_pio(info); | 452 | handle_data_pio(info); |
442 | } | 453 | } |
443 | } | 454 | } |
444 | if (status & NDSR_CS0_CMDD) { | 455 | if (status & cmd_done) { |
445 | info->state = STATE_CMD_DONE; | 456 | info->state = STATE_CMD_DONE; |
446 | is_completed = 1; | 457 | is_completed = 1; |
447 | } | 458 | } |
448 | if (status & NDSR_FLASH_RDY) { | 459 | if (status & ready) { |
449 | info->is_ready = 1; | 460 | info->is_ready = 1; |
450 | info->state = STATE_READY; | 461 | info->state = STATE_READY; |
451 | } | 462 | } |
@@ -480,9 +491,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, | |||
480 | { | 491 | { |
481 | uint16_t cmd; | 492 | uint16_t cmd; |
482 | int addr_cycle, exec_cmd; | 493 | int addr_cycle, exec_cmd; |
483 | struct pxa3xx_nand_host *host = info->host; | 494 | struct pxa3xx_nand_host *host; |
484 | struct mtd_info *mtd = host->mtd; | 495 | struct mtd_info *mtd; |
485 | 496 | ||
497 | host = info->host[info->cs]; | ||
498 | mtd = host->mtd; | ||
486 | addr_cycle = 0; | 499 | addr_cycle = 0; |
487 | exec_cmd = 1; | 500 | exec_cmd = 1; |
488 | 501 | ||
@@ -492,8 +505,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, | |||
492 | info->oob_size = 0; | 505 | info->oob_size = 0; |
493 | info->use_ecc = 0; | 506 | info->use_ecc = 0; |
494 | info->is_ready = 0; | 507 | info->is_ready = 0; |
495 | info->ndcb0 = 0; | ||
496 | info->retcode = ERR_NONE; | 508 | info->retcode = ERR_NONE; |
509 | if (info->cs != 0) | ||
510 | info->ndcb0 = NDCB0_CSEL; | ||
511 | else | ||
512 | info->ndcb0 = 0; | ||
497 | 513 | ||
498 | switch (command) { | 514 | switch (command) { |
499 | case NAND_CMD_READ0: | 515 | case NAND_CMD_READ0: |
@@ -637,6 +653,17 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
637 | if (host->reg_ndcr & NDCR_DWIDTH_M) | 653 | if (host->reg_ndcr & NDCR_DWIDTH_M) |
638 | column /= 2; | 654 | column /= 2; |
639 | 655 | ||
656 | /* | ||
657 | * There may be different NAND chip hooked to | ||
658 | * different chip select, so check whether | ||
659 | * chip select has been changed, if yes, reset the timing | ||
660 | */ | ||
661 | if (info->cs != host->cs) { | ||
662 | info->cs = host->cs; | ||
663 | nand_writel(info, NDTR0CS0, host->ndtr0cs0); | ||
664 | nand_writel(info, NDTR1CS0, host->ndtr1cs0); | ||
665 | } | ||
666 | |||
640 | info->state = STATE_PREPARED; | 667 | info->state = STATE_PREPARED; |
641 | exec_cmd = prepare_command_pool(info, command, column, page_addr); | 668 | exec_cmd = prepare_command_pool(info, command, column, page_addr); |
642 | if (exec_cmd) { | 669 | if (exec_cmd) { |
@@ -778,7 +805,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
778 | { | 805 | { |
779 | struct platform_device *pdev = info->pdev; | 806 | struct platform_device *pdev = info->pdev; |
780 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; | 807 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; |
781 | struct pxa3xx_nand_host *host = info->host; | 808 | struct pxa3xx_nand_host *host = info->host[info->cs]; |
782 | uint32_t ndcr = 0x0; /* enable all interrupts */ | 809 | uint32_t ndcr = 0x0; /* enable all interrupts */ |
783 | 810 | ||
784 | if (f->page_size != 2048 && f->page_size != 512) { | 811 | if (f->page_size != 2048 && f->page_size != 512) { |
@@ -822,7 +849,11 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
822 | 849 | ||
823 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | 850 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) |
824 | { | 851 | { |
825 | struct pxa3xx_nand_host *host = info->host; | 852 | /* |
853 | * We set 0 by hard coding here, for we don't support keep_config | ||
854 | * when there is more than one chip attached to the controller | ||
855 | */ | ||
856 | struct pxa3xx_nand_host *host = info->host[0]; | ||
826 | uint32_t ndcr = nand_readl(info, NDCR); | 857 | uint32_t ndcr = nand_readl(info, NDCR); |
827 | 858 | ||
828 | if (ndcr & NDCR_PAGE_SZ) { | 859 | if (ndcr & NDCR_PAGE_SZ) { |
@@ -884,9 +915,9 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) | |||
884 | 915 | ||
885 | static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) | 916 | static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) |
886 | { | 917 | { |
887 | struct mtd_info *mtd = info->host->mtd; | 918 | struct mtd_info *mtd; |
888 | int ret; | 919 | int ret; |
889 | 920 | mtd = info->host[info->cs]->mtd; | |
890 | /* use the common timing to make a try */ | 921 | /* use the common timing to make a try */ |
891 | ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); | 922 | ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); |
892 | if (ret) | 923 | if (ret) |
@@ -917,7 +948,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) | |||
917 | 948 | ||
918 | ret = pxa3xx_nand_sensing(info); | 949 | ret = pxa3xx_nand_sensing(info); |
919 | if (ret) { | 950 | if (ret) { |
920 | dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n"); | 951 | dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", |
952 | info->cs); | ||
921 | 953 | ||
922 | return ret; | 954 | return ret; |
923 | } | 955 | } |
@@ -996,41 +1028,47 @@ KEEP_CONFIG: | |||
996 | 1028 | ||
997 | static int alloc_nand_resource(struct platform_device *pdev) | 1029 | static int alloc_nand_resource(struct platform_device *pdev) |
998 | { | 1030 | { |
1031 | struct pxa3xx_nand_platform_data *pdata; | ||
999 | struct pxa3xx_nand_info *info; | 1032 | struct pxa3xx_nand_info *info; |
1000 | struct pxa3xx_nand_host *host; | 1033 | struct pxa3xx_nand_host *host; |
1001 | struct nand_chip *chip; | 1034 | struct nand_chip *chip; |
1002 | struct mtd_info *mtd; | 1035 | struct mtd_info *mtd; |
1003 | struct resource *r; | 1036 | struct resource *r; |
1004 | int ret, irq; | 1037 | int ret, irq, cs; |
1005 | 1038 | ||
1006 | info = kzalloc(sizeof(*info) + sizeof(*mtd) + sizeof(*host), | 1039 | pdata = pdev->dev.platform_data; |
1007 | GFP_KERNEL); | 1040 | info = kzalloc(sizeof(*info) + (sizeof(*mtd) + |
1041 | sizeof(*host)) * pdata->num_cs, GFP_KERNEL); | ||
1008 | if (!info) { | 1042 | if (!info) { |
1009 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 1043 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
1010 | return -ENOMEM; | 1044 | return -ENOMEM; |
1011 | } | 1045 | } |
1012 | 1046 | ||
1013 | mtd = (struct mtd_info *)(&info[1]); | ||
1014 | chip = (struct nand_chip *)(&mtd[1]); | ||
1015 | host = (struct pxa3xx_nand_host *)chip; | ||
1016 | info->pdev = pdev; | 1047 | info->pdev = pdev; |
1017 | info->host = host; | 1048 | for (cs = 0; cs < pdata->num_cs; cs++) { |
1018 | host->mtd = mtd; | 1049 | mtd = (struct mtd_info *)((unsigned int)&info[1] + |
1019 | host->info_data = info; | 1050 | (sizeof(*mtd) + sizeof(*host)) * cs); |
1020 | mtd->priv = host; | 1051 | chip = (struct nand_chip *)(&mtd[1]); |
1021 | mtd->owner = THIS_MODULE; | 1052 | host = (struct pxa3xx_nand_host *)chip; |
1022 | 1053 | info->host[cs] = host; | |
1023 | chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; | 1054 | host->mtd = mtd; |
1024 | chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; | 1055 | host->cs = cs; |
1025 | chip->controller = &info->controller; | 1056 | host->info_data = info; |
1026 | chip->waitfunc = pxa3xx_nand_waitfunc; | 1057 | mtd->priv = host; |
1027 | chip->select_chip = pxa3xx_nand_select_chip; | 1058 | mtd->owner = THIS_MODULE; |
1028 | chip->cmdfunc = pxa3xx_nand_cmdfunc; | 1059 | |
1029 | chip->read_word = pxa3xx_nand_read_word; | 1060 | chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; |
1030 | chip->read_byte = pxa3xx_nand_read_byte; | 1061 | chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; |
1031 | chip->read_buf = pxa3xx_nand_read_buf; | 1062 | chip->controller = &info->controller; |
1032 | chip->write_buf = pxa3xx_nand_write_buf; | 1063 | chip->waitfunc = pxa3xx_nand_waitfunc; |
1033 | chip->verify_buf = pxa3xx_nand_verify_buf; | 1064 | chip->select_chip = pxa3xx_nand_select_chip; |
1065 | chip->cmdfunc = pxa3xx_nand_cmdfunc; | ||
1066 | chip->read_word = pxa3xx_nand_read_word; | ||
1067 | chip->read_byte = pxa3xx_nand_read_byte; | ||
1068 | chip->read_buf = pxa3xx_nand_read_buf; | ||
1069 | chip->write_buf = pxa3xx_nand_write_buf; | ||
1070 | chip->verify_buf = pxa3xx_nand_verify_buf; | ||
1071 | } | ||
1034 | 1072 | ||
1035 | spin_lock_init(&chip->controller->lock); | 1073 | spin_lock_init(&chip->controller->lock); |
1036 | init_waitqueue_head(&chip->controller->wq); | 1074 | init_waitqueue_head(&chip->controller->wq); |
@@ -1128,12 +1166,14 @@ fail_free_mtd: | |||
1128 | static int pxa3xx_nand_remove(struct platform_device *pdev) | 1166 | static int pxa3xx_nand_remove(struct platform_device *pdev) |
1129 | { | 1167 | { |
1130 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); | 1168 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1169 | struct pxa3xx_nand_platform_data *pdata; | ||
1131 | struct resource *r; | 1170 | struct resource *r; |
1132 | int irq; | 1171 | int irq, cs; |
1133 | 1172 | ||
1134 | if (!info) | 1173 | if (!info) |
1135 | return 0; | 1174 | return 0; |
1136 | 1175 | ||
1176 | pdata = pdev->dev.platform_data; | ||
1137 | platform_set_drvdata(pdev, NULL); | 1177 | platform_set_drvdata(pdev, NULL); |
1138 | 1178 | ||
1139 | irq = platform_get_irq(pdev, 0); | 1179 | irq = platform_get_irq(pdev, 0); |
@@ -1153,7 +1193,8 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) | |||
1153 | clk_disable(info->clk); | 1193 | clk_disable(info->clk); |
1154 | clk_put(info->clk); | 1194 | clk_put(info->clk); |
1155 | 1195 | ||
1156 | nand_release(info->host->mtd); | 1196 | for (cs = 0; cs < pdata->num_cs; cs++) |
1197 | nand_release(info->host[cs]->mtd); | ||
1157 | kfree(info); | 1198 | kfree(info); |
1158 | return 0; | 1199 | return 0; |
1159 | } | 1200 | } |
@@ -1162,7 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) | |||
1162 | { | 1203 | { |
1163 | struct pxa3xx_nand_platform_data *pdata; | 1204 | struct pxa3xx_nand_platform_data *pdata; |
1164 | struct pxa3xx_nand_info *info; | 1205 | struct pxa3xx_nand_info *info; |
1165 | int ret; | 1206 | int ret, cs, probe_success; |
1166 | 1207 | ||
1167 | pdata = pdev->dev.platform_data; | 1208 | pdata = pdev->dev.platform_data; |
1168 | if (!pdata) { | 1209 | if (!pdata) { |
@@ -1177,41 +1218,69 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) | |||
1177 | } | 1218 | } |
1178 | 1219 | ||
1179 | info = platform_get_drvdata(pdev); | 1220 | info = platform_get_drvdata(pdev); |
1180 | if (pxa3xx_nand_scan(info->host->mtd)) { | 1221 | probe_success = 0; |
1181 | dev_err(&pdev->dev, "failed to scan nand\n"); | 1222 | for (cs = 0; cs < pdata->num_cs; cs++) { |
1223 | info->cs = cs; | ||
1224 | ret = pxa3xx_nand_scan(info->host[cs]->mtd); | ||
1225 | if (ret) { | ||
1226 | dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", | ||
1227 | cs); | ||
1228 | continue; | ||
1229 | } | ||
1230 | |||
1231 | ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, | ||
1232 | pdata->parts[cs], pdata->nr_parts[cs]); | ||
1233 | if (!ret) | ||
1234 | probe_success = 1; | ||
1235 | } | ||
1236 | |||
1237 | if (!probe_success) { | ||
1182 | pxa3xx_nand_remove(pdev); | 1238 | pxa3xx_nand_remove(pdev); |
1183 | return -ENODEV; | 1239 | return -ENODEV; |
1184 | } | 1240 | } |
1185 | 1241 | ||
1186 | return mtd_device_parse_register(info->host->mtd, NULL, 0, | 1242 | return 0; |
1187 | pdata->parts, pdata->nr_parts); | ||
1188 | } | 1243 | } |
1189 | 1244 | ||
1190 | #ifdef CONFIG_PM | 1245 | #ifdef CONFIG_PM |
1191 | static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) | 1246 | static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) |
1192 | { | 1247 | { |
1193 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); | 1248 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1194 | struct mtd_info *mtd = info->mtd; | 1249 | struct pxa3xx_nand_platform_data *pdata; |
1250 | struct mtd_info *mtd; | ||
1251 | int cs; | ||
1195 | 1252 | ||
1253 | pdata = pdev->dev.platform_data; | ||
1196 | if (info->state) { | 1254 | if (info->state) { |
1197 | dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); | 1255 | dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); |
1198 | return -EAGAIN; | 1256 | return -EAGAIN; |
1199 | } | 1257 | } |
1200 | 1258 | ||
1201 | mtd->suspend(mtd); | 1259 | for (cs = 0; cs < pdata->num_cs; cs++) { |
1260 | mtd = info->host[cs]->mtd; | ||
1261 | mtd->suspend(mtd); | ||
1262 | } | ||
1263 | |||
1202 | return 0; | 1264 | return 0; |
1203 | } | 1265 | } |
1204 | 1266 | ||
1205 | static int pxa3xx_nand_resume(struct platform_device *pdev) | 1267 | static int pxa3xx_nand_resume(struct platform_device *pdev) |
1206 | { | 1268 | { |
1207 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); | 1269 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1208 | struct mtd_info *mtd = info->mtd; | 1270 | struct pxa3xx_nand_platform_data *pdata; |
1271 | struct mtd_info *mtd; | ||
1272 | int cs; | ||
1209 | 1273 | ||
1274 | pdata = pdev->dev.platform_data; | ||
1210 | /* We don't want to handle interrupt without calling mtd routine */ | 1275 | /* We don't want to handle interrupt without calling mtd routine */ |
1211 | disable_int(info, NDCR_INT_MASK); | 1276 | disable_int(info, NDCR_INT_MASK); |
1212 | 1277 | ||
1213 | nand_writel(info, NDTR0CS0, info->host->ndtr0cs0); | 1278 | /* |
1214 | nand_writel(info, NDTR1CS0, info->host->ndtr1cs0); | 1279 | * Directly set the chip select to a invalid value, |
1280 | * then the driver would reset the timing according | ||
1281 | * to current chip select at the beginning of cmdfunc | ||
1282 | */ | ||
1283 | info->cs = 0xff; | ||
1215 | 1284 | ||
1216 | /* | 1285 | /* |
1217 | * As the spec says, the NDSR would be updated to 0x1800 when | 1286 | * As the spec says, the NDSR would be updated to 0x1800 when |
@@ -1220,7 +1289,11 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) | |||
1220 | * all status before resume | 1289 | * all status before resume |
1221 | */ | 1290 | */ |
1222 | nand_writel(info, NDSR, NDSR_MASK); | 1291 | nand_writel(info, NDSR, NDSR_MASK); |
1223 | mtd->resume(mtd); | 1292 | for (cs = 0; cs < pdata->num_cs; cs++) { |
1293 | mtd = info->host[cs]->mtd; | ||
1294 | mtd->resume(mtd); | ||
1295 | } | ||
1296 | |||
1224 | return 0; | 1297 | return 0; |
1225 | } | 1298 | } |
1226 | #else | 1299 | #else |