diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/alauda.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe_nand.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 25 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 31 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 339 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 269 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/sharpsl.c | 247 |
10 files changed, 602 insertions, 339 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f8ae0400c49c..8b12e6e109d3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC | |||
163 | incorrect ECC generation, and if using these, the default of | 163 | incorrect ECC generation, and if using these, the default of |
164 | software ECC is preferable. | 164 | software ECC is preferable. |
165 | 165 | ||
166 | config MTD_NAND_NDFC | ||
167 | tristate "NDFC NanD Flash Controller" | ||
168 | depends on 4xx | ||
169 | select MTD_NAND_ECC_SMC | ||
170 | help | ||
171 | NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs | ||
172 | |||
166 | config MTD_NAND_S3C2410_CLKSTOP | 173 | config MTD_NAND_S3C2410_CLKSTOP |
167 | bool "S3C2410 NAND IDLE clock stop" | 174 | bool "S3C2410 NAND IDLE clock stop" |
168 | depends on MTD_NAND_S3C2410 | 175 | depends on MTD_NAND_S3C2410 |
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index 962380394855..6d9649159a18 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c | |||
@@ -676,11 +676,11 @@ static int alauda_probe(struct usb_interface *interface, | |||
676 | goto error; | 676 | goto error; |
677 | 677 | ||
678 | al->write_out = usb_sndbulkpipe(al->dev, | 678 | al->write_out = usb_sndbulkpipe(al->dev, |
679 | ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 679 | usb_endpoint_num(ep_wr)); |
680 | al->bulk_in = usb_rcvbulkpipe(al->dev, | 680 | al->bulk_in = usb_rcvbulkpipe(al->dev, |
681 | ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 681 | usb_endpoint_num(ep_in)); |
682 | al->bulk_out = usb_sndbulkpipe(al->dev, | 682 | al->bulk_out = usb_sndbulkpipe(al->dev, |
683 | ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 683 | usb_endpoint_num(ep_out)); |
684 | 684 | ||
685 | /* second device is identical up to now */ | 685 | /* second device is identical up to now */ |
686 | memcpy(al+1, al, sizeof(*al)); | 686 | memcpy(al+1, al, sizeof(*al)); |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index b8064bf3aee4..22a6b2e50e91 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
@@ -90,7 +90,7 @@ static int timing[3]; | |||
90 | module_param_array(timing, int, &numtimings, 0644); | 90 | module_param_array(timing, int, &numtimings, 0644); |
91 | 91 | ||
92 | #ifdef CONFIG_MTD_PARTITIONS | 92 | #ifdef CONFIG_MTD_PARTITIONS |
93 | static const char *part_probes[] = { "RedBoot", NULL }; | 93 | static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; |
94 | #endif | 94 | #endif |
95 | 95 | ||
96 | /* Hrm. Why isn't this already conditional on something in the struct device? */ | 96 | /* Hrm. Why isn't this already conditional on something in the struct device? */ |
@@ -805,10 +805,13 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
805 | add_mtd_device(mtd); | 805 | add_mtd_device(mtd); |
806 | 806 | ||
807 | #ifdef CONFIG_MTD_PARTITIONS | 807 | #ifdef CONFIG_MTD_PARTITIONS |
808 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
809 | mtd->name = "cafe_nand"; | ||
810 | #endif | ||
808 | nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); | 811 | nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); |
809 | if (nr_parts > 0) { | 812 | if (nr_parts > 0) { |
810 | cafe->parts = parts; | 813 | cafe->parts = parts; |
811 | dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts); | 814 | dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); |
812 | add_mtd_partitions(mtd, parts, nr_parts); | 815 | add_mtd_partitions(mtd, parts, nr_parts); |
813 | } | 816 | } |
814 | #endif | 817 | #endif |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4aa5bd6158da..65929db29446 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -777,7 +777,9 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
777 | /* Fill in fsl_elbc_mtd structure */ | 777 | /* Fill in fsl_elbc_mtd structure */ |
778 | priv->mtd.priv = chip; | 778 | priv->mtd.priv = chip; |
779 | priv->mtd.owner = THIS_MODULE; | 779 | priv->mtd.owner = THIS_MODULE; |
780 | priv->fmr = 0; /* rest filled in later */ | 780 | |
781 | /* Set the ECCM according to the settings in bootloader.*/ | ||
782 | priv->fmr = in_be32(&lbc->fmr) & FMR_ECCM; | ||
781 | 783 | ||
782 | /* fill in nand_chip structure */ | 784 | /* fill in nand_chip structure */ |
783 | /* set up function call table */ | 785 | /* set up function call table */ |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0a9c9cd33f96..0c3afccde8a2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2014,13 +2014,14 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2014 | int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | 2014 | int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, |
2015 | int allowbbt) | 2015 | int allowbbt) |
2016 | { | 2016 | { |
2017 | int page, len, status, pages_per_block, ret, chipnr; | 2017 | int page, status, pages_per_block, ret, chipnr; |
2018 | struct nand_chip *chip = mtd->priv; | 2018 | struct nand_chip *chip = mtd->priv; |
2019 | int rewrite_bbt[NAND_MAX_CHIPS]={0}; | 2019 | loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; |
2020 | unsigned int bbt_masked_page = 0xffffffff; | 2020 | unsigned int bbt_masked_page = 0xffffffff; |
2021 | loff_t len; | ||
2021 | 2022 | ||
2022 | DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", | 2023 | DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n", |
2023 | (unsigned int)instr->addr, (unsigned int)instr->len); | 2024 | (unsigned long long)instr->addr, (unsigned long long)instr->len); |
2024 | 2025 | ||
2025 | /* Start address must align on block boundary */ | 2026 | /* Start address must align on block boundary */ |
2026 | if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { | 2027 | if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { |
@@ -2116,7 +2117,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2116 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " | 2117 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " |
2117 | "Failed erase, page 0x%08x\n", page); | 2118 | "Failed erase, page 0x%08x\n", page); |
2118 | instr->state = MTD_ERASE_FAILED; | 2119 | instr->state = MTD_ERASE_FAILED; |
2119 | instr->fail_addr = (page << chip->page_shift); | 2120 | instr->fail_addr = |
2121 | ((loff_t)page << chip->page_shift); | ||
2120 | goto erase_exit; | 2122 | goto erase_exit; |
2121 | } | 2123 | } |
2122 | 2124 | ||
@@ -2126,7 +2128,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2126 | */ | 2128 | */ |
2127 | if (bbt_masked_page != 0xffffffff && | 2129 | if (bbt_masked_page != 0xffffffff && |
2128 | (page & BBT_PAGE_MASK) == bbt_masked_page) | 2130 | (page & BBT_PAGE_MASK) == bbt_masked_page) |
2129 | rewrite_bbt[chipnr] = (page << chip->page_shift); | 2131 | rewrite_bbt[chipnr] = |
2132 | ((loff_t)page << chip->page_shift); | ||
2130 | 2133 | ||
2131 | /* Increment page address and decrement length */ | 2134 | /* Increment page address and decrement length */ |
2132 | len -= (1 << chip->phys_erase_shift); | 2135 | len -= (1 << chip->phys_erase_shift); |
@@ -2173,7 +2176,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2173 | continue; | 2176 | continue; |
2174 | /* update the BBT for chip */ | 2177 | /* update the BBT for chip */ |
2175 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " | 2178 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " |
2176 | "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], | 2179 | "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], |
2177 | chip->bbt_td->pages[chipnr]); | 2180 | chip->bbt_td->pages[chipnr]); |
2178 | nand_update_bbt(mtd, rewrite_bbt[chipnr]); | 2181 | nand_update_bbt(mtd, rewrite_bbt[chipnr]); |
2179 | } | 2182 | } |
@@ -2365,7 +2368,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2365 | if (!mtd->name) | 2368 | if (!mtd->name) |
2366 | mtd->name = type->name; | 2369 | mtd->name = type->name; |
2367 | 2370 | ||
2368 | chip->chipsize = type->chipsize << 20; | 2371 | chip->chipsize = (uint64_t)type->chipsize << 20; |
2369 | 2372 | ||
2370 | /* Newer devices have all the information in additional id bytes */ | 2373 | /* Newer devices have all the information in additional id bytes */ |
2371 | if (!type->pagesize) { | 2374 | if (!type->pagesize) { |
@@ -2423,7 +2426,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2423 | 2426 | ||
2424 | chip->bbt_erase_shift = chip->phys_erase_shift = | 2427 | chip->bbt_erase_shift = chip->phys_erase_shift = |
2425 | ffs(mtd->erasesize) - 1; | 2428 | ffs(mtd->erasesize) - 1; |
2426 | chip->chip_shift = ffs(chip->chipsize) - 1; | 2429 | if (chip->chipsize & 0xffffffff) |
2430 | chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; | ||
2431 | else | ||
2432 | chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; | ||
2427 | 2433 | ||
2428 | /* Set the bad block position */ | 2434 | /* Set the bad block position */ |
2429 | chip->badblockpos = mtd->writesize > 512 ? | 2435 | chip->badblockpos = mtd->writesize > 512 ? |
@@ -2517,7 +2523,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) | |||
2517 | /** | 2523 | /** |
2518 | * nand_scan_tail - [NAND Interface] Scan for the NAND device | 2524 | * nand_scan_tail - [NAND Interface] Scan for the NAND device |
2519 | * @mtd: MTD device structure | 2525 | * @mtd: MTD device structure |
2520 | * @maxchips: Number of chips to scan for | ||
2521 | * | 2526 | * |
2522 | * This is the second phase of the normal nand_scan() function. It | 2527 | * This is the second phase of the normal nand_scan() function. It |
2523 | * fills out all the uninitialized function pointers with the defaults | 2528 | * fills out all the uninitialized function pointers with the defaults |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 0b1c48595f12..55c23e5cd210 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
171 | if (tmp == msk) | 171 | if (tmp == msk) |
172 | continue; | 172 | continue; |
173 | if (reserved_block_code && (tmp == reserved_block_code)) { | 173 | if (reserved_block_code && (tmp == reserved_block_code)) { |
174 | printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", | 174 | printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", |
175 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 175 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
176 | this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); | 176 | this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); |
177 | mtd->ecc_stats.bbtblocks++; | 177 | mtd->ecc_stats.bbtblocks++; |
178 | continue; | 178 | continue; |
179 | } | 179 | } |
180 | /* Leave it for now, if its matured we can move this | 180 | /* Leave it for now, if its matured we can move this |
181 | * message to MTD_DEBUG_LEVEL0 */ | 181 | * message to MTD_DEBUG_LEVEL0 */ |
182 | printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", | 182 | printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", |
183 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 183 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
184 | /* Factory marked bad or worn out ? */ | 184 | /* Factory marked bad or worn out ? */ |
185 | if (tmp == 0) | 185 | if (tmp == 0) |
186 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); | 186 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); |
@@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, | |||
284 | 284 | ||
285 | /* Read the primary version, if available */ | 285 | /* Read the primary version, if available */ |
286 | if (td->options & NAND_BBT_VERSION) { | 286 | if (td->options & NAND_BBT_VERSION) { |
287 | scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, | 287 | scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, |
288 | mtd->writesize); | 288 | mtd->writesize); |
289 | td->version[0] = buf[mtd->writesize + td->veroffs]; | 289 | td->version[0] = buf[mtd->writesize + td->veroffs]; |
290 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", | 290 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
@@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, | |||
293 | 293 | ||
294 | /* Read the mirror version, if available */ | 294 | /* Read the mirror version, if available */ |
295 | if (md && (md->options & NAND_BBT_VERSION)) { | 295 | if (md && (md->options & NAND_BBT_VERSION)) { |
296 | scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, | 296 | scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, |
297 | mtd->writesize); | 297 | mtd->writesize); |
298 | md->version[0] = buf[mtd->writesize + md->veroffs]; | 298 | md->version[0] = buf[mtd->writesize + md->veroffs]; |
299 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", | 299 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
@@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
411 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); | 411 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); |
412 | startblock = chip * numblocks; | 412 | startblock = chip * numblocks; |
413 | numblocks += startblock; | 413 | numblocks += startblock; |
414 | from = startblock << (this->bbt_erase_shift - 1); | 414 | from = (loff_t)startblock << (this->bbt_erase_shift - 1); |
415 | } | 415 | } |
416 | 416 | ||
417 | for (i = startblock; i < numblocks;) { | 417 | for (i = startblock; i < numblocks;) { |
@@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
428 | 428 | ||
429 | if (ret) { | 429 | if (ret) { |
430 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 430 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
431 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 431 | printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", |
432 | i >> 1, (unsigned int)from); | 432 | i >> 1, (unsigned long long)from); |
433 | mtd->ecc_stats.badblocks++; | 433 | mtd->ecc_stats.badblocks++; |
434 | } | 434 | } |
435 | 435 | ||
@@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
495 | for (block = 0; block < td->maxblocks; block++) { | 495 | for (block = 0; block < td->maxblocks; block++) { |
496 | 496 | ||
497 | int actblock = startblock + dir * block; | 497 | int actblock = startblock + dir * block; |
498 | loff_t offs = actblock << this->bbt_erase_shift; | 498 | loff_t offs = (loff_t)actblock << this->bbt_erase_shift; |
499 | 499 | ||
500 | /* Read first page */ | 500 | /* Read first page */ |
501 | scan_read_raw(mtd, buf, offs, mtd->writesize); | 501 | scan_read_raw(mtd, buf, offs, mtd->writesize); |
@@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
719 | 719 | ||
720 | memset(&einfo, 0, sizeof(einfo)); | 720 | memset(&einfo, 0, sizeof(einfo)); |
721 | einfo.mtd = mtd; | 721 | einfo.mtd = mtd; |
722 | einfo.addr = (unsigned long)to; | 722 | einfo.addr = to; |
723 | einfo.len = 1 << this->bbt_erase_shift; | 723 | einfo.len = 1 << this->bbt_erase_shift; |
724 | res = nand_erase_nand(mtd, &einfo, 1); | 724 | res = nand_erase_nand(mtd, &einfo, 1); |
725 | if (res < 0) | 725 | if (res < 0) |
@@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
729 | if (res < 0) | 729 | if (res < 0) |
730 | goto outerr; | 730 | goto outerr; |
731 | 731 | ||
732 | printk(KERN_DEBUG "Bad block table written to 0x%08x, version " | 732 | printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " |
733 | "0x%02X\n", (unsigned int)to, td->version[chip]); | 733 | "0x%02X\n", (unsigned long long)to, td->version[chip]); |
734 | 734 | ||
735 | /* Mark it as used */ | 735 | /* Mark it as used */ |
736 | td->pages[chip] = page; | 736 | td->pages[chip] = page; |
@@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
910 | newval = oldval | (0x2 << (block & 0x06)); | 910 | newval = oldval | (0x2 << (block & 0x06)); |
911 | this->bbt[(block >> 3)] = newval; | 911 | this->bbt[(block >> 3)] = newval; |
912 | if ((oldval != newval) && td->reserved_block_code) | 912 | if ((oldval != newval) && td->reserved_block_code) |
913 | nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); | 913 | nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); |
914 | continue; | 914 | continue; |
915 | } | 915 | } |
916 | update = 0; | 916 | update = 0; |
@@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
931 | new ones have been marked, then we need to update the stored | 931 | new ones have been marked, then we need to update the stored |
932 | bbts. This should only happen once. */ | 932 | bbts. This should only happen once. */ |
933 | if (update && td->reserved_block_code) | 933 | if (update && td->reserved_block_code) |
934 | nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); | 934 | nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); |
935 | } | 935 | } |
936 | } | 936 | } |
937 | 937 | ||
@@ -1027,7 +1027,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) | |||
1027 | if (!this->bbt || !td) | 1027 | if (!this->bbt || !td) |
1028 | return -EINVAL; | 1028 | return -EINVAL; |
1029 | 1029 | ||
1030 | len = mtd->size >> (this->bbt_erase_shift + 2); | ||
1031 | /* Allocate a temporary buffer for one eraseblock incl. oob */ | 1030 | /* Allocate a temporary buffer for one eraseblock incl. oob */ |
1032 | len = (1 << this->bbt_erase_shift); | 1031 | len = (1 << this->bbt_erase_shift); |
1033 | len += (len >> this->page_shift) * mtd->oobsize; | 1032 | len += (len >> this->page_shift) * mtd->oobsize; |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index ae7c57781a68..cd0711b83ac4 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -38,6 +38,9 @@ | |||
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/list.h> | 39 | #include <linux/list.h> |
40 | #include <linux/random.h> | 40 | #include <linux/random.h> |
41 | #include <linux/sched.h> | ||
42 | #include <linux/fs.h> | ||
43 | #include <linux/pagemap.h> | ||
41 | 44 | ||
42 | /* Default simulator parameters values */ | 45 | /* Default simulator parameters values */ |
43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 46 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -100,6 +103,7 @@ static unsigned int bitflips = 0; | |||
100 | static char *gravepages = NULL; | 103 | static char *gravepages = NULL; |
101 | static unsigned int rptwear = 0; | 104 | static unsigned int rptwear = 0; |
102 | static unsigned int overridesize = 0; | 105 | static unsigned int overridesize = 0; |
106 | static char *cache_file = NULL; | ||
103 | 107 | ||
104 | module_param(first_id_byte, uint, 0400); | 108 | module_param(first_id_byte, uint, 0400); |
105 | module_param(second_id_byte, uint, 0400); | 109 | module_param(second_id_byte, uint, 0400); |
@@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400); | |||
122 | module_param(gravepages, charp, 0400); | 126 | module_param(gravepages, charp, 0400); |
123 | module_param(rptwear, uint, 0400); | 127 | module_param(rptwear, uint, 0400); |
124 | module_param(overridesize, uint, 0400); | 128 | module_param(overridesize, uint, 0400); |
129 | module_param(cache_file, charp, 0400); | ||
125 | 130 | ||
126 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | 131 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); |
127 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 132 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
128 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); | 133 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); |
129 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); | 134 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); |
130 | MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); | 135 | MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); |
131 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); | 136 | MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); |
132 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); | 137 | MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); |
133 | MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); | 138 | MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); |
@@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if | |||
153 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | 158 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " |
154 | "The size is specified in erase blocks and as the exponent of a power of two" | 159 | "The size is specified in erase blocks and as the exponent of a power of two" |
155 | " e.g. 5 means a size of 32 erase blocks"); | 160 | " e.g. 5 means a size of 32 erase blocks"); |
161 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); | ||
156 | 162 | ||
157 | /* The largest possible page size */ | 163 | /* The largest possible page size */ |
158 | #define NS_LARGEST_PAGE_SIZE 2048 | 164 | #define NS_LARGEST_PAGE_SIZE 2048 |
@@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I | |||
266 | */ | 272 | */ |
267 | #define NS_MAX_PREVSTATES 1 | 273 | #define NS_MAX_PREVSTATES 1 |
268 | 274 | ||
275 | /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ | ||
276 | #define NS_MAX_HELD_PAGES 16 | ||
277 | |||
269 | /* | 278 | /* |
270 | * A union to represent flash memory contents and flash buffer. | 279 | * A union to represent flash memory contents and flash buffer. |
271 | */ | 280 | */ |
@@ -295,6 +304,9 @@ struct nandsim { | |||
295 | /* The simulated NAND flash pages array */ | 304 | /* The simulated NAND flash pages array */ |
296 | union ns_mem *pages; | 305 | union ns_mem *pages; |
297 | 306 | ||
307 | /* Slab allocator for nand pages */ | ||
308 | struct kmem_cache *nand_pages_slab; | ||
309 | |||
298 | /* Internal buffer of page + OOB size bytes */ | 310 | /* Internal buffer of page + OOB size bytes */ |
299 | union ns_mem buf; | 311 | union ns_mem buf; |
300 | 312 | ||
@@ -335,6 +347,13 @@ struct nandsim { | |||
335 | int ale; /* address Latch Enable */ | 347 | int ale; /* address Latch Enable */ |
336 | int wp; /* write Protect */ | 348 | int wp; /* write Protect */ |
337 | } lines; | 349 | } lines; |
350 | |||
351 | /* Fields needed when using a cache file */ | ||
352 | struct file *cfile; /* Open file */ | ||
353 | unsigned char *pages_written; /* Which pages have been written */ | ||
354 | void *file_buf; | ||
355 | struct page *held_pages[NS_MAX_HELD_PAGES]; | ||
356 | int held_cnt; | ||
338 | }; | 357 | }; |
339 | 358 | ||
340 | /* | 359 | /* |
@@ -420,25 +439,69 @@ static struct mtd_info *nsmtd; | |||
420 | static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; | 439 | static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; |
421 | 440 | ||
422 | /* | 441 | /* |
423 | * Allocate array of page pointers and initialize the array to NULL | 442 | * Allocate array of page pointers, create slab allocation for an array |
424 | * pointers. | 443 | * and initialize the array by NULL pointers. |
425 | * | 444 | * |
426 | * RETURNS: 0 if success, -ENOMEM if memory alloc fails. | 445 | * RETURNS: 0 if success, -ENOMEM if memory alloc fails. |
427 | */ | 446 | */ |
428 | static int alloc_device(struct nandsim *ns) | 447 | static int alloc_device(struct nandsim *ns) |
429 | { | 448 | { |
430 | int i; | 449 | struct file *cfile; |
450 | int i, err; | ||
451 | |||
452 | if (cache_file) { | ||
453 | cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); | ||
454 | if (IS_ERR(cfile)) | ||
455 | return PTR_ERR(cfile); | ||
456 | if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { | ||
457 | NS_ERR("alloc_device: cache file not readable\n"); | ||
458 | err = -EINVAL; | ||
459 | goto err_close; | ||
460 | } | ||
461 | if (!cfile->f_op->write && !cfile->f_op->aio_write) { | ||
462 | NS_ERR("alloc_device: cache file not writeable\n"); | ||
463 | err = -EINVAL; | ||
464 | goto err_close; | ||
465 | } | ||
466 | ns->pages_written = vmalloc(ns->geom.pgnum); | ||
467 | if (!ns->pages_written) { | ||
468 | NS_ERR("alloc_device: unable to allocate pages written array\n"); | ||
469 | err = -ENOMEM; | ||
470 | goto err_close; | ||
471 | } | ||
472 | ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); | ||
473 | if (!ns->file_buf) { | ||
474 | NS_ERR("alloc_device: unable to allocate file buf\n"); | ||
475 | err = -ENOMEM; | ||
476 | goto err_free; | ||
477 | } | ||
478 | ns->cfile = cfile; | ||
479 | memset(ns->pages_written, 0, ns->geom.pgnum); | ||
480 | return 0; | ||
481 | } | ||
431 | 482 | ||
432 | ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); | 483 | ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); |
433 | if (!ns->pages) { | 484 | if (!ns->pages) { |
434 | NS_ERR("alloc_map: unable to allocate page array\n"); | 485 | NS_ERR("alloc_device: unable to allocate page array\n"); |
435 | return -ENOMEM; | 486 | return -ENOMEM; |
436 | } | 487 | } |
437 | for (i = 0; i < ns->geom.pgnum; i++) { | 488 | for (i = 0; i < ns->geom.pgnum; i++) { |
438 | ns->pages[i].byte = NULL; | 489 | ns->pages[i].byte = NULL; |
439 | } | 490 | } |
491 | ns->nand_pages_slab = kmem_cache_create("nandsim", | ||
492 | ns->geom.pgszoob, 0, 0, NULL); | ||
493 | if (!ns->nand_pages_slab) { | ||
494 | NS_ERR("cache_create: unable to create kmem_cache\n"); | ||
495 | return -ENOMEM; | ||
496 | } | ||
440 | 497 | ||
441 | return 0; | 498 | return 0; |
499 | |||
500 | err_free: | ||
501 | vfree(ns->pages_written); | ||
502 | err_close: | ||
503 | filp_close(cfile, NULL); | ||
504 | return err; | ||
442 | } | 505 | } |
443 | 506 | ||
444 | /* | 507 | /* |
@@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns) | |||
448 | { | 511 | { |
449 | int i; | 512 | int i; |
450 | 513 | ||
514 | if (ns->cfile) { | ||
515 | kfree(ns->file_buf); | ||
516 | vfree(ns->pages_written); | ||
517 | filp_close(ns->cfile, NULL); | ||
518 | return; | ||
519 | } | ||
520 | |||
451 | if (ns->pages) { | 521 | if (ns->pages) { |
452 | for (i = 0; i < ns->geom.pgnum; i++) { | 522 | for (i = 0; i < ns->geom.pgnum; i++) { |
453 | if (ns->pages[i].byte) | 523 | if (ns->pages[i].byte) |
454 | kfree(ns->pages[i].byte); | 524 | kmem_cache_free(ns->nand_pages_slab, |
525 | ns->pages[i].byte); | ||
455 | } | 526 | } |
527 | kmem_cache_destroy(ns->nand_pages_slab); | ||
456 | vfree(ns->pages); | 528 | vfree(ns->pages); |
457 | } | 529 | } |
458 | } | 530 | } |
@@ -464,7 +536,7 @@ static char *get_partition_name(int i) | |||
464 | return kstrdup(buf, GFP_KERNEL); | 536 | return kstrdup(buf, GFP_KERNEL); |
465 | } | 537 | } |
466 | 538 | ||
467 | static u_int64_t divide(u_int64_t n, u_int32_t d) | 539 | static uint64_t divide(uint64_t n, uint32_t d) |
468 | { | 540 | { |
469 | do_div(n, d); | 541 | do_div(n, d); |
470 | return n; | 542 | return n; |
@@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
480 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 552 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
481 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 553 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
482 | int i, ret = 0; | 554 | int i, ret = 0; |
483 | u_int64_t remains; | 555 | uint64_t remains; |
484 | u_int64_t next_offset; | 556 | uint64_t next_offset; |
485 | 557 | ||
486 | if (NS_IS_INITIALIZED(ns)) { | 558 | if (NS_IS_INITIALIZED(ns)) { |
487 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 559 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
548 | remains = ns->geom.totsz; | 620 | remains = ns->geom.totsz; |
549 | next_offset = 0; | 621 | next_offset = 0; |
550 | for (i = 0; i < parts_num; ++i) { | 622 | for (i = 0; i < parts_num; ++i) { |
551 | u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; | 623 | uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz; |
552 | 624 | ||
553 | if (!part_sz || part_sz > remains) { | 625 | if (!part_sz || part_sz > remains) { |
554 | NS_ERR("bad partition size.\n"); | 626 | NS_ERR("bad partition size.\n"); |
@@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag) | |||
1211 | return -1; | 1283 | return -1; |
1212 | } | 1284 | } |
1213 | 1285 | ||
1286 | static void put_pages(struct nandsim *ns) | ||
1287 | { | ||
1288 | int i; | ||
1289 | |||
1290 | for (i = 0; i < ns->held_cnt; i++) | ||
1291 | page_cache_release(ns->held_pages[i]); | ||
1292 | } | ||
1293 | |||
1294 | /* Get page cache pages in advance to provide NOFS memory allocation */ | ||
1295 | static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) | ||
1296 | { | ||
1297 | pgoff_t index, start_index, end_index; | ||
1298 | struct page *page; | ||
1299 | struct address_space *mapping = file->f_mapping; | ||
1300 | |||
1301 | start_index = pos >> PAGE_CACHE_SHIFT; | ||
1302 | end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT; | ||
1303 | if (end_index - start_index + 1 > NS_MAX_HELD_PAGES) | ||
1304 | return -EINVAL; | ||
1305 | ns->held_cnt = 0; | ||
1306 | for (index = start_index; index <= end_index; index++) { | ||
1307 | page = find_get_page(mapping, index); | ||
1308 | if (page == NULL) { | ||
1309 | page = find_or_create_page(mapping, index, GFP_NOFS); | ||
1310 | if (page == NULL) { | ||
1311 | write_inode_now(mapping->host, 1); | ||
1312 | page = find_or_create_page(mapping, index, GFP_NOFS); | ||
1313 | } | ||
1314 | if (page == NULL) { | ||
1315 | put_pages(ns); | ||
1316 | return -ENOMEM; | ||
1317 | } | ||
1318 | unlock_page(page); | ||
1319 | } | ||
1320 | ns->held_pages[ns->held_cnt++] = page; | ||
1321 | } | ||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | static int set_memalloc(void) | ||
1326 | { | ||
1327 | if (current->flags & PF_MEMALLOC) | ||
1328 | return 0; | ||
1329 | current->flags |= PF_MEMALLOC; | ||
1330 | return 1; | ||
1331 | } | ||
1332 | |||
1333 | static void clear_memalloc(int memalloc) | ||
1334 | { | ||
1335 | if (memalloc) | ||
1336 | current->flags &= ~PF_MEMALLOC; | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) | ||
1340 | { | ||
1341 | mm_segment_t old_fs; | ||
1342 | ssize_t tx; | ||
1343 | int err, memalloc; | ||
1344 | |||
1345 | err = get_pages(ns, file, count, *pos); | ||
1346 | if (err) | ||
1347 | return err; | ||
1348 | old_fs = get_fs(); | ||
1349 | set_fs(get_ds()); | ||
1350 | memalloc = set_memalloc(); | ||
1351 | tx = vfs_read(file, (char __user *)buf, count, pos); | ||
1352 | clear_memalloc(memalloc); | ||
1353 | set_fs(old_fs); | ||
1354 | put_pages(ns); | ||
1355 | return tx; | ||
1356 | } | ||
1357 | |||
1358 | static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) | ||
1359 | { | ||
1360 | mm_segment_t old_fs; | ||
1361 | ssize_t tx; | ||
1362 | int err, memalloc; | ||
1363 | |||
1364 | err = get_pages(ns, file, count, *pos); | ||
1365 | if (err) | ||
1366 | return err; | ||
1367 | old_fs = get_fs(); | ||
1368 | set_fs(get_ds()); | ||
1369 | memalloc = set_memalloc(); | ||
1370 | tx = vfs_write(file, (char __user *)buf, count, pos); | ||
1371 | clear_memalloc(memalloc); | ||
1372 | set_fs(old_fs); | ||
1373 | put_pages(ns); | ||
1374 | return tx; | ||
1375 | } | ||
1376 | |||
1214 | /* | 1377 | /* |
1215 | * Returns a pointer to the current page. | 1378 | * Returns a pointer to the current page. |
1216 | */ | 1379 | */ |
@@ -1227,6 +1390,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns) | |||
1227 | return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; | 1390 | return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; |
1228 | } | 1391 | } |
1229 | 1392 | ||
1393 | int do_read_error(struct nandsim *ns, int num) | ||
1394 | { | ||
1395 | unsigned int page_no = ns->regs.row; | ||
1396 | |||
1397 | if (read_error(page_no)) { | ||
1398 | int i; | ||
1399 | memset(ns->buf.byte, 0xFF, num); | ||
1400 | for (i = 0; i < num; ++i) | ||
1401 | ns->buf.byte[i] = random32(); | ||
1402 | NS_WARN("simulating read error in page %u\n", page_no); | ||
1403 | return 1; | ||
1404 | } | ||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | void do_bit_flips(struct nandsim *ns, int num) | ||
1409 | { | ||
1410 | if (bitflips && random32() < (1 << 22)) { | ||
1411 | int flips = 1; | ||
1412 | if (bitflips > 1) | ||
1413 | flips = (random32() % (int) bitflips) + 1; | ||
1414 | while (flips--) { | ||
1415 | int pos = random32() % (num * 8); | ||
1416 | ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); | ||
1417 | NS_WARN("read_page: flipping bit %d in page %d " | ||
1418 | "reading from %d ecc: corrected=%u failed=%u\n", | ||
1419 | pos, ns->regs.row, ns->regs.column + ns->regs.off, | ||
1420 | nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); | ||
1421 | } | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1230 | /* | 1425 | /* |
1231 | * Fill the NAND buffer with data read from the specified page. | 1426 | * Fill the NAND buffer with data read from the specified page. |
1232 | */ | 1427 | */ |
@@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num) | |||
1234 | { | 1429 | { |
1235 | union ns_mem *mypage; | 1430 | union ns_mem *mypage; |
1236 | 1431 | ||
1432 | if (ns->cfile) { | ||
1433 | if (!ns->pages_written[ns->regs.row]) { | ||
1434 | NS_DBG("read_page: page %d not written\n", ns->regs.row); | ||
1435 | memset(ns->buf.byte, 0xFF, num); | ||
1436 | } else { | ||
1437 | loff_t pos; | ||
1438 | ssize_t tx; | ||
1439 | |||
1440 | NS_DBG("read_page: page %d written, reading from %d\n", | ||
1441 | ns->regs.row, ns->regs.column + ns->regs.off); | ||
1442 | if (do_read_error(ns, num)) | ||
1443 | return; | ||
1444 | pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; | ||
1445 | tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos); | ||
1446 | if (tx != num) { | ||
1447 | NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1448 | return; | ||
1449 | } | ||
1450 | do_bit_flips(ns, num); | ||
1451 | } | ||
1452 | return; | ||
1453 | } | ||
1454 | |||
1237 | mypage = NS_GET_PAGE(ns); | 1455 | mypage = NS_GET_PAGE(ns); |
1238 | if (mypage->byte == NULL) { | 1456 | if (mypage->byte == NULL) { |
1239 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); | 1457 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); |
1240 | memset(ns->buf.byte, 0xFF, num); | 1458 | memset(ns->buf.byte, 0xFF, num); |
1241 | } else { | 1459 | } else { |
1242 | unsigned int page_no = ns->regs.row; | ||
1243 | NS_DBG("read_page: page %d allocated, reading from %d\n", | 1460 | NS_DBG("read_page: page %d allocated, reading from %d\n", |
1244 | ns->regs.row, ns->regs.column + ns->regs.off); | 1461 | ns->regs.row, ns->regs.column + ns->regs.off); |
1245 | if (read_error(page_no)) { | 1462 | if (do_read_error(ns, num)) |
1246 | int i; | ||
1247 | memset(ns->buf.byte, 0xFF, num); | ||
1248 | for (i = 0; i < num; ++i) | ||
1249 | ns->buf.byte[i] = random32(); | ||
1250 | NS_WARN("simulating read error in page %u\n", page_no); | ||
1251 | return; | 1463 | return; |
1252 | } | ||
1253 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); | 1464 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); |
1254 | if (bitflips && random32() < (1 << 22)) { | 1465 | do_bit_flips(ns, num); |
1255 | int flips = 1; | ||
1256 | if (bitflips > 1) | ||
1257 | flips = (random32() % (int) bitflips) + 1; | ||
1258 | while (flips--) { | ||
1259 | int pos = random32() % (num * 8); | ||
1260 | ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); | ||
1261 | NS_WARN("read_page: flipping bit %d in page %d " | ||
1262 | "reading from %d ecc: corrected=%u failed=%u\n", | ||
1263 | pos, ns->regs.row, ns->regs.column + ns->regs.off, | ||
1264 | nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); | ||
1265 | } | ||
1266 | } | ||
1267 | } | 1466 | } |
1268 | } | 1467 | } |
1269 | 1468 | ||
@@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns) | |||
1275 | union ns_mem *mypage; | 1474 | union ns_mem *mypage; |
1276 | int i; | 1475 | int i; |
1277 | 1476 | ||
1477 | if (ns->cfile) { | ||
1478 | for (i = 0; i < ns->geom.pgsec; i++) | ||
1479 | if (ns->pages_written[ns->regs.row + i]) { | ||
1480 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); | ||
1481 | ns->pages_written[ns->regs.row + i] = 0; | ||
1482 | } | ||
1483 | return; | ||
1484 | } | ||
1485 | |||
1278 | mypage = NS_GET_PAGE(ns); | 1486 | mypage = NS_GET_PAGE(ns); |
1279 | for (i = 0; i < ns->geom.pgsec; i++) { | 1487 | for (i = 0; i < ns->geom.pgsec; i++) { |
1280 | if (mypage->byte != NULL) { | 1488 | if (mypage->byte != NULL) { |
1281 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); | 1489 | NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); |
1282 | kfree(mypage->byte); | 1490 | kmem_cache_free(ns->nand_pages_slab, mypage->byte); |
1283 | mypage->byte = NULL; | 1491 | mypage->byte = NULL; |
1284 | } | 1492 | } |
1285 | mypage++; | 1493 | mypage++; |
@@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num) | |||
1295 | union ns_mem *mypage; | 1503 | union ns_mem *mypage; |
1296 | u_char *pg_off; | 1504 | u_char *pg_off; |
1297 | 1505 | ||
1506 | if (ns->cfile) { | ||
1507 | loff_t off, pos; | ||
1508 | ssize_t tx; | ||
1509 | int all; | ||
1510 | |||
1511 | NS_DBG("prog_page: writing page %d\n", ns->regs.row); | ||
1512 | pg_off = ns->file_buf + ns->regs.column + ns->regs.off; | ||
1513 | off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; | ||
1514 | if (!ns->pages_written[ns->regs.row]) { | ||
1515 | all = 1; | ||
1516 | memset(ns->file_buf, 0xff, ns->geom.pgszoob); | ||
1517 | } else { | ||
1518 | all = 0; | ||
1519 | pos = off; | ||
1520 | tx = read_file(ns, ns->cfile, pg_off, num, &pos); | ||
1521 | if (tx != num) { | ||
1522 | NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1523 | return -1; | ||
1524 | } | ||
1525 | } | ||
1526 | for (i = 0; i < num; i++) | ||
1527 | pg_off[i] &= ns->buf.byte[i]; | ||
1528 | if (all) { | ||
1529 | pos = (loff_t)ns->regs.row * ns->geom.pgszoob; | ||
1530 | tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); | ||
1531 | if (tx != ns->geom.pgszoob) { | ||
1532 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1533 | return -1; | ||
1534 | } | ||
1535 | ns->pages_written[ns->regs.row] = 1; | ||
1536 | } else { | ||
1537 | pos = off; | ||
1538 | tx = write_file(ns, ns->cfile, pg_off, num, &pos); | ||
1539 | if (tx != num) { | ||
1540 | NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); | ||
1541 | return -1; | ||
1542 | } | ||
1543 | } | ||
1544 | return 0; | ||
1545 | } | ||
1546 | |||
1298 | mypage = NS_GET_PAGE(ns); | 1547 | mypage = NS_GET_PAGE(ns); |
1299 | if (mypage->byte == NULL) { | 1548 | if (mypage->byte == NULL) { |
1300 | NS_DBG("prog_page: allocating page %d\n", ns->regs.row); | 1549 | NS_DBG("prog_page: allocating page %d\n", ns->regs.row); |
1301 | /* | 1550 | /* |
1302 | * We allocate memory with GFP_NOFS because a flash FS may | 1551 | * We allocate memory with GFP_NOFS because a flash FS may |
1303 | * utilize this. If it is holding an FS lock, then gets here, | 1552 | * utilize this. If it is holding an FS lock, then gets here, |
1304 | * then kmalloc runs writeback which goes to the FS again | 1553 | * then kernel memory alloc runs writeback which goes to the FS |
1305 | * and deadlocks. This was seen in practice. | 1554 | * again and deadlocks. This was seen in practice. |
1306 | */ | 1555 | */ |
1307 | mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); | 1556 | mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS); |
1308 | if (mypage->byte == NULL) { | 1557 | if (mypage->byte == NULL) { |
1309 | NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); | 1558 | NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); |
1310 | return -1; | 1559 | return -1; |
@@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1736 | 1985 | ||
1737 | /* Check if chip is expecting command */ | 1986 | /* Check if chip is expecting command */ |
1738 | if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { | 1987 | if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { |
1739 | /* | 1988 | /* Do not warn if only 2 id bytes are read */ |
1740 | * We are in situation when something else (not command) | 1989 | if (!(ns->regs.command == NAND_CMD_READID && |
1741 | * was expected but command was input. In this case ignore | 1990 | NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) { |
1742 | * previous command(s)/state(s) and accept the last one. | 1991 | /* |
1743 | */ | 1992 | * We are in situation when something else (not command) |
1744 | NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " | 1993 | * was expected but command was input. In this case ignore |
1745 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | 1994 | * previous command(s)/state(s) and accept the last one. |
1995 | */ | ||
1996 | NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " | ||
1997 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | ||
1998 | } | ||
1746 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1999 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1747 | } | 2000 | } |
1748 | 2001 | ||
@@ -2044,7 +2297,7 @@ static int __init ns_init_module(void) | |||
2044 | } | 2297 | } |
2045 | 2298 | ||
2046 | if (overridesize) { | 2299 | if (overridesize) { |
2047 | u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; | 2300 | uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; |
2048 | if (new_size >> overridesize != nsmtd->erasesize) { | 2301 | if (new_size >> overridesize != nsmtd->erasesize) { |
2049 | NS_ERR("overridesize is too big\n"); | 2302 | NS_ERR("overridesize is too big\n"); |
2050 | goto err_exit; | 2303 | goto err_exit; |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 955959eb02d4..582cf80f555a 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -2,12 +2,20 @@ | |||
2 | * drivers/mtd/ndfc.c | 2 | * drivers/mtd/ndfc.c |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Platform independend driver for NDFC (NanD Flash Controller) | 5 | * Platform independent driver for NDFC (NanD Flash Controller) |
6 | * integrated into EP440 cores | 6 | * integrated into EP440 cores |
7 | * | 7 | * |
8 | * Ported to an OF platform driver by Sean MacLennan | ||
9 | * | ||
10 | * The NDFC supports multiple chips, but this driver only supports a | ||
11 | * single chip since I do not have access to any boards with | ||
12 | * multiple chips. | ||
13 | * | ||
8 | * Author: Thomas Gleixner | 14 | * Author: Thomas Gleixner |
9 | * | 15 | * |
10 | * Copyright 2006 IBM | 16 | * Copyright 2006 IBM |
17 | * Copyright 2008 PIKA Technologies | ||
18 | * Sean MacLennan <smaclennan@pikatech.com> | ||
11 | * | 19 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 20 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 21 | * under the terms of the GNU General Public License as published by the |
@@ -21,27 +29,20 @@ | |||
21 | #include <linux/mtd/partitions.h> | 29 | #include <linux/mtd/partitions.h> |
22 | #include <linux/mtd/ndfc.h> | 30 | #include <linux/mtd/ndfc.h> |
23 | #include <linux/mtd/mtd.h> | 31 | #include <linux/mtd/mtd.h> |
24 | #include <linux/platform_device.h> | 32 | #include <linux/of_platform.h> |
25 | |||
26 | #include <asm/io.h> | 33 | #include <asm/io.h> |
27 | #ifdef CONFIG_40x | ||
28 | #include <asm/ibm405.h> | ||
29 | #else | ||
30 | #include <asm/ibm44x.h> | ||
31 | #endif | ||
32 | |||
33 | struct ndfc_nand_mtd { | ||
34 | struct mtd_info mtd; | ||
35 | struct nand_chip chip; | ||
36 | struct platform_nand_chip *pl_chip; | ||
37 | }; | ||
38 | 34 | ||
39 | static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS]; | ||
40 | 35 | ||
41 | struct ndfc_controller { | 36 | struct ndfc_controller { |
42 | void __iomem *ndfcbase; | 37 | struct of_device *ofdev; |
43 | struct nand_hw_control ndfc_control; | 38 | void __iomem *ndfcbase; |
44 | atomic_t childs_active; | 39 | struct mtd_info mtd; |
40 | struct nand_chip chip; | ||
41 | int chip_select; | ||
42 | struct nand_hw_control ndfc_control; | ||
43 | #ifdef CONFIG_MTD_PARTITIONS | ||
44 | struct mtd_partition *parts; | ||
45 | #endif | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static struct ndfc_controller ndfc_ctrl; | 48 | static struct ndfc_controller ndfc_ctrl; |
@@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) | |||
50 | { | 51 | { |
51 | uint32_t ccr; | 52 | uint32_t ccr; |
52 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 53 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
53 | struct nand_chip *nandchip = mtd->priv; | ||
54 | struct ndfc_nand_mtd *nandmtd = nandchip->priv; | ||
55 | struct platform_nand_chip *pchip = nandmtd->pl_chip; | ||
56 | 54 | ||
57 | ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); | 55 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
58 | if (chip >= 0) { | 56 | if (chip >= 0) { |
59 | ccr &= ~NDFC_CCR_BS_MASK; | 57 | ccr &= ~NDFC_CCR_BS_MASK; |
60 | ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); | 58 | ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); |
61 | } else | 59 | } else |
62 | ccr |= NDFC_CCR_RESET_CE; | 60 | ccr |= NDFC_CCR_RESET_CE; |
63 | __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); | 61 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
64 | } | 62 | } |
65 | 63 | ||
66 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 64 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
@@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd) | |||
80 | { | 78 | { |
81 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 79 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
82 | 80 | ||
83 | return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; | 81 | return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; |
84 | } | 82 | } |
85 | 83 | ||
86 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | 84 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) |
@@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | |||
88 | uint32_t ccr; | 86 | uint32_t ccr; |
89 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 87 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
90 | 88 | ||
91 | ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); | 89 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
92 | ccr |= NDFC_CCR_RESET_ECC; | 90 | ccr |= NDFC_CCR_RESET_ECC; |
93 | __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); | 91 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
94 | wmb(); | 92 | wmb(); |
95 | } | 93 | } |
96 | 94 | ||
@@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, | |||
102 | uint8_t *p = (uint8_t *)&ecc; | 100 | uint8_t *p = (uint8_t *)&ecc; |
103 | 101 | ||
104 | wmb(); | 102 | wmb(); |
105 | ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); | 103 | ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); |
106 | ecc_code[0] = p[1]; | 104 | /* The NDFC uses Smart Media (SMC) bytes order */ |
107 | ecc_code[1] = p[2]; | 105 | ecc_code[0] = p[2]; |
106 | ecc_code[1] = p[1]; | ||
108 | ecc_code[2] = p[3]; | 107 | ecc_code[2] = p[3]; |
109 | 108 | ||
110 | return 0; | 109 | return 0; |
@@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | |||
123 | uint32_t *p = (uint32_t *) buf; | 122 | uint32_t *p = (uint32_t *) buf; |
124 | 123 | ||
125 | for(;len > 0; len -= 4) | 124 | for(;len > 0; len -= 4) |
126 | *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); | 125 | *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); |
127 | } | 126 | } |
128 | 127 | ||
129 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 128 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
@@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
132 | uint32_t *p = (uint32_t *) buf; | 131 | uint32_t *p = (uint32_t *) buf; |
133 | 132 | ||
134 | for(;len > 0; len -= 4) | 133 | for(;len > 0; len -= 4) |
135 | __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); | 134 | out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); |
136 | } | 135 | } |
137 | 136 | ||
138 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 137 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
@@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
141 | uint32_t *p = (uint32_t *) buf; | 140 | uint32_t *p = (uint32_t *) buf; |
142 | 141 | ||
143 | for(;len > 0; len -= 4) | 142 | for(;len > 0; len -= 4) |
144 | if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) | 143 | if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA)) |
145 | return -EFAULT; | 144 | return -EFAULT; |
146 | return 0; | 145 | return 0; |
147 | } | 146 | } |
@@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
149 | /* | 148 | /* |
150 | * Initialize chip structure | 149 | * Initialize chip structure |
151 | */ | 150 | */ |
152 | static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | 151 | static int ndfc_chip_init(struct ndfc_controller *ndfc, |
152 | struct device_node *node) | ||
153 | { | 153 | { |
154 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 154 | #ifdef CONFIG_MTD_PARTITIONS |
155 | struct nand_chip *chip = &mtd->chip; | 155 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
156 | static const char *part_types[] = { "cmdlinepart", NULL }; | ||
157 | #else | ||
158 | static const char *part_types[] = { NULL }; | ||
159 | #endif | ||
160 | #endif | ||
161 | struct device_node *flash_np; | ||
162 | struct nand_chip *chip = &ndfc->chip; | ||
163 | int ret; | ||
156 | 164 | ||
157 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; | 165 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; |
158 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; | 166 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; |
@@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | |||
160 | chip->dev_ready = ndfc_ready; | 168 | chip->dev_ready = ndfc_ready; |
161 | chip->select_chip = ndfc_select_chip; | 169 | chip->select_chip = ndfc_select_chip; |
162 | chip->chip_delay = 50; | 170 | chip->chip_delay = 50; |
163 | chip->priv = mtd; | ||
164 | chip->options = mtd->pl_chip->options; | ||
165 | chip->controller = &ndfc->ndfc_control; | 171 | chip->controller = &ndfc->ndfc_control; |
166 | chip->read_buf = ndfc_read_buf; | 172 | chip->read_buf = ndfc_read_buf; |
167 | chip->write_buf = ndfc_write_buf; | 173 | chip->write_buf = ndfc_write_buf; |
@@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | |||
172 | chip->ecc.mode = NAND_ECC_HW; | 178 | chip->ecc.mode = NAND_ECC_HW; |
173 | chip->ecc.size = 256; | 179 | chip->ecc.size = 256; |
174 | chip->ecc.bytes = 3; | 180 | chip->ecc.bytes = 3; |
175 | chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout; | ||
176 | mtd->mtd.priv = chip; | ||
177 | mtd->mtd.owner = THIS_MODULE; | ||
178 | } | ||
179 | |||
180 | static int ndfc_chip_probe(struct platform_device *pdev) | ||
181 | { | ||
182 | struct platform_nand_chip *nc = pdev->dev.platform_data; | ||
183 | struct ndfc_chip_settings *settings = nc->priv; | ||
184 | struct ndfc_controller *ndfc = &ndfc_ctrl; | ||
185 | struct ndfc_nand_mtd *nandmtd; | ||
186 | |||
187 | if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS) | ||
188 | return -EINVAL; | ||
189 | |||
190 | /* Set the bank settings */ | ||
191 | __raw_writel(settings->bank_settings, | ||
192 | ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2)); | ||
193 | 181 | ||
194 | nandmtd = &ndfc_mtd[pdev->id]; | 182 | ndfc->mtd.priv = chip; |
195 | if (nandmtd->pl_chip) | 183 | ndfc->mtd.owner = THIS_MODULE; |
196 | return -EBUSY; | ||
197 | 184 | ||
198 | nandmtd->pl_chip = nc; | 185 | flash_np = of_get_next_child(node, NULL); |
199 | ndfc_chip_init(nandmtd); | 186 | if (!flash_np) |
200 | |||
201 | /* Scan for chips */ | ||
202 | if (nand_scan(&nandmtd->mtd, nc->nr_chips)) { | ||
203 | nandmtd->pl_chip = NULL; | ||
204 | return -ENODEV; | 187 | return -ENODEV; |
188 | |||
189 | ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", | ||
190 | ndfc->ofdev->dev.bus_id, flash_np->name); | ||
191 | if (!ndfc->mtd.name) { | ||
192 | ret = -ENOMEM; | ||
193 | goto err; | ||
205 | } | 194 | } |
206 | 195 | ||
207 | #ifdef CONFIG_MTD_PARTITIONS | 196 | ret = nand_scan(&ndfc->mtd, 1); |
208 | printk("Number of partitions %d\n", nc->nr_partitions); | 197 | if (ret) |
209 | if (nc->nr_partitions) { | 198 | goto err; |
210 | /* Add the full device, so complete dumps can be made */ | ||
211 | add_mtd_device(&nandmtd->mtd); | ||
212 | add_mtd_partitions(&nandmtd->mtd, nc->partitions, | ||
213 | nc->nr_partitions); | ||
214 | 199 | ||
215 | } else | 200 | #ifdef CONFIG_MTD_PARTITIONS |
216 | #else | 201 | ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); |
217 | add_mtd_device(&nandmtd->mtd); | 202 | if (ret < 0) |
203 | goto err; | ||
204 | |||
205 | #ifdef CONFIG_MTD_OF_PARTS | ||
206 | if (ret == 0) { | ||
207 | ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, | ||
208 | &ndfc->parts); | ||
209 | if (ret < 0) | ||
210 | goto err; | ||
211 | } | ||
218 | #endif | 212 | #endif |
219 | 213 | ||
220 | atomic_inc(&ndfc->childs_active); | 214 | if (ret > 0) |
221 | return 0; | 215 | ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret); |
222 | } | 216 | else |
217 | #endif | ||
218 | ret = add_mtd_device(&ndfc->mtd); | ||
223 | 219 | ||
224 | static int ndfc_chip_remove(struct platform_device *pdev) | 220 | err: |
225 | { | 221 | of_node_put(flash_np); |
226 | return 0; | 222 | if (ret) |
223 | kfree(ndfc->mtd.name); | ||
224 | return ret; | ||
227 | } | 225 | } |
228 | 226 | ||
229 | static int ndfc_nand_probe(struct platform_device *pdev) | 227 | static int __devinit ndfc_probe(struct of_device *ofdev, |
228 | const struct of_device_id *match) | ||
230 | { | 229 | { |
231 | struct platform_nand_ctrl *nc = pdev->dev.platform_data; | ||
232 | struct ndfc_controller_settings *settings = nc->priv; | ||
233 | struct resource *res = pdev->resource; | ||
234 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 230 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
235 | unsigned long long phys = settings->ndfc_erpn | res->start; | 231 | const u32 *reg; |
232 | u32 ccr; | ||
233 | int err, len; | ||
236 | 234 | ||
237 | #ifndef CONFIG_PHYS_64BIT | 235 | spin_lock_init(&ndfc->ndfc_control.lock); |
238 | ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); | 236 | init_waitqueue_head(&ndfc->ndfc_control.wq); |
239 | #else | 237 | ndfc->ofdev = ofdev; |
240 | ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); | 238 | dev_set_drvdata(&ofdev->dev, ndfc); |
241 | #endif | 239 | |
240 | /* Read the reg property to get the chip select */ | ||
241 | reg = of_get_property(ofdev->node, "reg", &len); | ||
242 | if (reg == NULL || len != 12) { | ||
243 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); | ||
244 | return -ENOENT; | ||
245 | } | ||
246 | ndfc->chip_select = reg[0]; | ||
247 | |||
248 | ndfc->ndfcbase = of_iomap(ofdev->node, 0); | ||
242 | if (!ndfc->ndfcbase) { | 249 | if (!ndfc->ndfcbase) { |
243 | printk(KERN_ERR "NDFC: ioremap failed\n"); | 250 | dev_err(&ofdev->dev, "failed to get memory\n"); |
244 | return -EIO; | 251 | return -EIO; |
245 | } | 252 | } |
246 | 253 | ||
247 | __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); | 254 | ccr = NDFC_CCR_BS(ndfc->chip_select); |
248 | 255 | ||
249 | spin_lock_init(&ndfc->ndfc_control.lock); | 256 | /* It is ok if ccr does not exist - just default to 0 */ |
250 | init_waitqueue_head(&ndfc->ndfc_control.wq); | 257 | reg = of_get_property(ofdev->node, "ccr", NULL); |
258 | if (reg) | ||
259 | ccr |= *reg; | ||
251 | 260 | ||
252 | platform_set_drvdata(pdev, ndfc); | 261 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
253 | 262 | ||
254 | printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", | 263 | /* Set the bank settings if given */ |
255 | __raw_readl(ndfc->ndfcbase + NDFC_REVID)); | 264 | reg = of_get_property(ofdev->node, "bank-settings", NULL); |
265 | if (reg) { | ||
266 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); | ||
267 | out_be32(ndfc->ndfcbase + offset, *reg); | ||
268 | } | ||
269 | |||
270 | err = ndfc_chip_init(ndfc, ofdev->node); | ||
271 | if (err) { | ||
272 | iounmap(ndfc->ndfcbase); | ||
273 | return err; | ||
274 | } | ||
256 | 275 | ||
257 | return 0; | 276 | return 0; |
258 | } | 277 | } |
259 | 278 | ||
260 | static int ndfc_nand_remove(struct platform_device *pdev) | 279 | static int __devexit ndfc_remove(struct of_device *ofdev) |
261 | { | 280 | { |
262 | struct ndfc_controller *ndfc = platform_get_drvdata(pdev); | 281 | struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); |
263 | 282 | ||
264 | if (atomic_read(&ndfc->childs_active)) | 283 | nand_release(&ndfc->mtd); |
265 | return -EBUSY; | ||
266 | 284 | ||
267 | if (ndfc) { | ||
268 | platform_set_drvdata(pdev, NULL); | ||
269 | iounmap(ndfc_ctrl.ndfcbase); | ||
270 | ndfc_ctrl.ndfcbase = NULL; | ||
271 | } | ||
272 | return 0; | 285 | return 0; |
273 | } | 286 | } |
274 | 287 | ||
275 | /* driver device registration */ | 288 | static const struct of_device_id ndfc_match[] = { |
276 | 289 | { .compatible = "ibm,ndfc", }, | |
277 | static struct platform_driver ndfc_chip_driver = { | 290 | {} |
278 | .probe = ndfc_chip_probe, | ||
279 | .remove = ndfc_chip_remove, | ||
280 | .driver = { | ||
281 | .name = "ndfc-chip", | ||
282 | .owner = THIS_MODULE, | ||
283 | }, | ||
284 | }; | 291 | }; |
292 | MODULE_DEVICE_TABLE(of, ndfc_match); | ||
285 | 293 | ||
286 | static struct platform_driver ndfc_nand_driver = { | 294 | static struct of_platform_driver ndfc_driver = { |
287 | .probe = ndfc_nand_probe, | 295 | .driver = { |
288 | .remove = ndfc_nand_remove, | 296 | .name = "ndfc", |
289 | .driver = { | ||
290 | .name = "ndfc-nand", | ||
291 | .owner = THIS_MODULE, | ||
292 | }, | 297 | }, |
298 | .match_table = ndfc_match, | ||
299 | .probe = ndfc_probe, | ||
300 | .remove = __devexit_p(ndfc_remove), | ||
293 | }; | 301 | }; |
294 | 302 | ||
295 | static int __init ndfc_nand_init(void) | 303 | static int __init ndfc_nand_init(void) |
296 | { | 304 | { |
297 | int ret; | 305 | return of_register_platform_driver(&ndfc_driver); |
298 | |||
299 | spin_lock_init(&ndfc_ctrl.ndfc_control.lock); | ||
300 | init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq); | ||
301 | |||
302 | ret = platform_driver_register(&ndfc_nand_driver); | ||
303 | if (!ret) | ||
304 | ret = platform_driver_register(&ndfc_chip_driver); | ||
305 | return ret; | ||
306 | } | 306 | } |
307 | 307 | ||
308 | static void __exit ndfc_nand_exit(void) | 308 | static void __exit ndfc_nand_exit(void) |
309 | { | 309 | { |
310 | platform_driver_unregister(&ndfc_chip_driver); | 310 | of_unregister_platform_driver(&ndfc_driver); |
311 | platform_driver_unregister(&ndfc_nand_driver); | ||
312 | } | 311 | } |
313 | 312 | ||
314 | module_init(ndfc_nand_init); | 313 | module_init(ndfc_nand_init); |
@@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit); | |||
316 | 315 | ||
317 | MODULE_LICENSE("GPL"); | 316 | MODULE_LICENSE("GPL"); |
318 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); | 317 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); |
319 | MODULE_DESCRIPTION("Platform driver for NDFC"); | 318 | MODULE_DESCRIPTION("OF Platform driver for NDFC"); |
320 | MODULE_ALIAS("platform:ndfc-chip"); | ||
321 | MODULE_ALIAS("platform:ndfc-nand"); | ||
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index fc4144495610..cc55cbc2b308 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -298,7 +298,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { | |||
298 | #define NDTR1_tAR(c) (min((c), 15) << 0) | 298 | #define NDTR1_tAR(c) (min((c), 15) << 0) |
299 | 299 | ||
300 | /* convert nano-seconds to nand flash controller clock cycles */ | 300 | /* convert nano-seconds to nand flash controller clock cycles */ |
301 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) | 301 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) |
302 | 302 | ||
303 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | 303 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, |
304 | const struct pxa3xx_nand_timing *t) | 304 | const struct pxa3xx_nand_timing *t) |
@@ -368,14 +368,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | |||
368 | /* large block, 2 cycles for column address | 368 | /* large block, 2 cycles for column address |
369 | * row address starts from 3rd cycle | 369 | * row address starts from 3rd cycle |
370 | */ | 370 | */ |
371 | info->ndcb1 |= (page_addr << 16) | (column & 0xffff); | 371 | info->ndcb1 |= page_addr << 16; |
372 | if (info->row_addr_cycles == 3) | 372 | if (info->row_addr_cycles == 3) |
373 | info->ndcb2 = (page_addr >> 16) & 0xff; | 373 | info->ndcb2 = (page_addr >> 16) & 0xff; |
374 | } else | 374 | } else |
375 | /* small block, 1 cycles for column address | 375 | /* small block, 1 cycles for column address |
376 | * row address starts from 2nd cycle | 376 | * row address starts from 2nd cycle |
377 | */ | 377 | */ |
378 | info->ndcb1 = (page_addr << 8) | (column & 0xff); | 378 | info->ndcb1 = page_addr << 8; |
379 | 379 | ||
380 | if (cmd == cmdset->program) | 380 | if (cmd == cmdset->program) |
381 | info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; | 381 | info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; |
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 30a518e211bd..54ec7542a7b7 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * drivers/mtd/nand/sharpsl.c | 2 | * drivers/mtd/nand/sharpsl.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
5 | * Copyright (C) 2008 Dmitry Baryshkov | ||
5 | * | 6 | * |
6 | * Based on Sharp's NAND driver sharp_sl.c | 7 | * Based on Sharp's NAND driver sharp_sl.c |
7 | * | 8 | * |
@@ -19,22 +20,31 @@ | |||
19 | #include <linux/mtd/nand.h> | 20 | #include <linux/mtd/nand.h> |
20 | #include <linux/mtd/nand_ecc.h> | 21 | #include <linux/mtd/nand_ecc.h> |
21 | #include <linux/mtd/partitions.h> | 22 | #include <linux/mtd/partitions.h> |
23 | #include <linux/mtd/sharpsl.h> | ||
22 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/platform_device.h> | ||
26 | |||
23 | #include <asm/io.h> | 27 | #include <asm/io.h> |
24 | #include <mach/hardware.h> | 28 | #include <mach/hardware.h> |
25 | #include <asm/mach-types.h> | 29 | #include <asm/mach-types.h> |
26 | 30 | ||
27 | static void __iomem *sharpsl_io_base; | 31 | struct sharpsl_nand { |
28 | static int sharpsl_phys_base = 0x0C000000; | 32 | struct mtd_info mtd; |
33 | struct nand_chip chip; | ||
34 | |||
35 | void __iomem *io; | ||
36 | }; | ||
37 | |||
38 | #define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd) | ||
29 | 39 | ||
30 | /* register offset */ | 40 | /* register offset */ |
31 | #define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ | 41 | #define ECCLPLB 0x00 /* line parity 7 - 0 bit */ |
32 | #define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ | 42 | #define ECCLPUB 0x04 /* line parity 15 - 8 bit */ |
33 | #define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ | 43 | #define ECCCP 0x08 /* column parity 5 - 0 bit */ |
34 | #define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ | 44 | #define ECCCNTR 0x0C /* ECC byte counter */ |
35 | #define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ | 45 | #define ECCCLRR 0x10 /* cleare ECC */ |
36 | #define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ | 46 | #define FLASHIO 0x14 /* Flash I/O */ |
37 | #define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ | 47 | #define FLASHCTL 0x18 /* Flash Control */ |
38 | 48 | ||
39 | /* Flash control bit */ | 49 | /* Flash control bit */ |
40 | #define FLRYBY (1 << 5) | 50 | #define FLRYBY (1 << 5) |
@@ -45,35 +55,6 @@ static int sharpsl_phys_base = 0x0C000000; | |||
45 | #define FLCE0 (1 << 0) | 55 | #define FLCE0 (1 << 0) |
46 | 56 | ||
47 | /* | 57 | /* |
48 | * MTD structure for SharpSL | ||
49 | */ | ||
50 | static struct mtd_info *sharpsl_mtd = NULL; | ||
51 | |||
52 | /* | ||
53 | * Define partitions for flash device | ||
54 | */ | ||
55 | #define DEFAULT_NUM_PARTITIONS 3 | ||
56 | |||
57 | static int nr_partitions; | ||
58 | static struct mtd_partition sharpsl_nand_default_partition_info[] = { | ||
59 | { | ||
60 | .name = "System Area", | ||
61 | .offset = 0, | ||
62 | .size = 7 * 1024 * 1024, | ||
63 | }, | ||
64 | { | ||
65 | .name = "Root Filesystem", | ||
66 | .offset = 7 * 1024 * 1024, | ||
67 | .size = 30 * 1024 * 1024, | ||
68 | }, | ||
69 | { | ||
70 | .name = "Home Filesystem", | ||
71 | .offset = MTDPART_OFS_APPEND, | ||
72 | .size = MTDPART_SIZ_FULL, | ||
73 | }, | ||
74 | }; | ||
75 | |||
76 | /* | ||
77 | * hardware specific access to control-lines | 58 | * hardware specific access to control-lines |
78 | * ctrl: | 59 | * ctrl: |
79 | * NAND_CNE: bit 0 -> ! bit 0 & 4 | 60 | * NAND_CNE: bit 0 -> ! bit 0 & 4 |
@@ -84,6 +65,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { | |||
84 | static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, | 65 | static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, |
85 | unsigned int ctrl) | 66 | unsigned int ctrl) |
86 | { | 67 | { |
68 | struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); | ||
87 | struct nand_chip *chip = mtd->priv; | 69 | struct nand_chip *chip = mtd->priv; |
88 | 70 | ||
89 | if (ctrl & NAND_CTRL_CHANGE) { | 71 | if (ctrl & NAND_CTRL_CHANGE) { |
@@ -93,103 +75,97 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, | |||
93 | 75 | ||
94 | bits ^= 0x11; | 76 | bits ^= 0x11; |
95 | 77 | ||
96 | writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL); | 78 | writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL); |
97 | } | 79 | } |
98 | 80 | ||
99 | if (cmd != NAND_CMD_NONE) | 81 | if (cmd != NAND_CMD_NONE) |
100 | writeb(cmd, chip->IO_ADDR_W); | 82 | writeb(cmd, chip->IO_ADDR_W); |
101 | } | 83 | } |
102 | 84 | ||
103 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
104 | |||
105 | static struct nand_bbt_descr sharpsl_bbt = { | ||
106 | .options = 0, | ||
107 | .offs = 4, | ||
108 | .len = 2, | ||
109 | .pattern = scan_ff_pattern | ||
110 | }; | ||
111 | |||
112 | static struct nand_bbt_descr sharpsl_akita_bbt = { | ||
113 | .options = 0, | ||
114 | .offs = 4, | ||
115 | .len = 1, | ||
116 | .pattern = scan_ff_pattern | ||
117 | }; | ||
118 | |||
119 | static struct nand_ecclayout akita_oobinfo = { | ||
120 | .eccbytes = 24, | ||
121 | .eccpos = { | ||
122 | 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, | ||
123 | 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, | ||
124 | 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, | ||
125 | .oobfree = {{0x08, 0x09}} | ||
126 | }; | ||
127 | |||
128 | static int sharpsl_nand_dev_ready(struct mtd_info *mtd) | 85 | static int sharpsl_nand_dev_ready(struct mtd_info *mtd) |
129 | { | 86 | { |
130 | return !((readb(FLASHCTL) & FLRYBY) == 0); | 87 | struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); |
88 | return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0); | ||
131 | } | 89 | } |
132 | 90 | ||
133 | static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) | 91 | static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) |
134 | { | 92 | { |
135 | writeb(0, ECCCLRR); | 93 | struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); |
94 | writeb(0, sharpsl->io + ECCCLRR); | ||
136 | } | 95 | } |
137 | 96 | ||
138 | static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) | 97 | static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) |
139 | { | 98 | { |
140 | ecc_code[0] = ~readb(ECCLPUB); | 99 | struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); |
141 | ecc_code[1] = ~readb(ECCLPLB); | 100 | ecc_code[0] = ~readb(sharpsl->io + ECCLPUB); |
142 | ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; | 101 | ecc_code[1] = ~readb(sharpsl->io + ECCLPLB); |
143 | return readb(ECCCNTR) != 0; | 102 | ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03; |
103 | return readb(sharpsl->io + ECCCNTR) != 0; | ||
144 | } | 104 | } |
145 | 105 | ||
146 | #ifdef CONFIG_MTD_PARTITIONS | 106 | #ifdef CONFIG_MTD_PARTITIONS |
147 | const char *part_probes[] = { "cmdlinepart", NULL }; | 107 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
148 | #endif | 108 | #endif |
149 | 109 | ||
150 | /* | 110 | /* |
151 | * Main initialization routine | 111 | * Main initialization routine |
152 | */ | 112 | */ |
153 | static int __init sharpsl_nand_init(void) | 113 | static int __devinit sharpsl_nand_probe(struct platform_device *pdev) |
154 | { | 114 | { |
155 | struct nand_chip *this; | 115 | struct nand_chip *this; |
116 | #ifdef CONFIG_MTD_PARTITIONS | ||
156 | struct mtd_partition *sharpsl_partition_info; | 117 | struct mtd_partition *sharpsl_partition_info; |
118 | int nr_partitions; | ||
119 | #endif | ||
120 | struct resource *r; | ||
157 | int err = 0; | 121 | int err = 0; |
122 | struct sharpsl_nand *sharpsl; | ||
123 | struct sharpsl_nand_platform_data *data = pdev->dev.platform_data; | ||
124 | |||
125 | if (!data) { | ||
126 | dev_err(&pdev->dev, "no platform data!\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
158 | 129 | ||
159 | /* Allocate memory for MTD device structure and private data */ | 130 | /* Allocate memory for MTD device structure and private data */ |
160 | sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | 131 | sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); |
161 | if (!sharpsl_mtd) { | 132 | if (!sharpsl) { |
162 | printk("Unable to allocate SharpSL NAND MTD device structure.\n"); | 133 | printk("Unable to allocate SharpSL NAND MTD device structure.\n"); |
163 | return -ENOMEM; | 134 | return -ENOMEM; |
164 | } | 135 | } |
165 | 136 | ||
137 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
138 | if (!r) { | ||
139 | dev_err(&pdev->dev, "no io memory resource defined!\n"); | ||
140 | err = -ENODEV; | ||
141 | goto err_get_res; | ||
142 | } | ||
143 | |||
166 | /* map physical address */ | 144 | /* map physical address */ |
167 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); | 145 | sharpsl->io = ioremap(r->start, resource_size(r)); |
168 | if (!sharpsl_io_base) { | 146 | if (!sharpsl->io) { |
169 | printk("ioremap to access Sharp SL NAND chip failed\n"); | 147 | printk("ioremap to access Sharp SL NAND chip failed\n"); |
170 | kfree(sharpsl_mtd); | 148 | err = -EIO; |
171 | return -EIO; | 149 | goto err_ioremap; |
172 | } | 150 | } |
173 | 151 | ||
174 | /* Get pointer to private data */ | 152 | /* Get pointer to private data */ |
175 | this = (struct nand_chip *)(&sharpsl_mtd[1]); | 153 | this = (struct nand_chip *)(&sharpsl->chip); |
176 | |||
177 | /* Initialize structures */ | ||
178 | memset(sharpsl_mtd, 0, sizeof(struct mtd_info)); | ||
179 | memset(this, 0, sizeof(struct nand_chip)); | ||
180 | 154 | ||
181 | /* Link the private data with the MTD structure */ | 155 | /* Link the private data with the MTD structure */ |
182 | sharpsl_mtd->priv = this; | 156 | sharpsl->mtd.priv = this; |
183 | sharpsl_mtd->owner = THIS_MODULE; | 157 | sharpsl->mtd.owner = THIS_MODULE; |
158 | |||
159 | platform_set_drvdata(pdev, sharpsl); | ||
184 | 160 | ||
185 | /* | 161 | /* |
186 | * PXA initialize | 162 | * PXA initialize |
187 | */ | 163 | */ |
188 | writeb(readb(FLASHCTL) | FLWP, FLASHCTL); | 164 | writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL); |
189 | 165 | ||
190 | /* Set address of NAND IO lines */ | 166 | /* Set address of NAND IO lines */ |
191 | this->IO_ADDR_R = FLASHIO; | 167 | this->IO_ADDR_R = sharpsl->io + FLASHIO; |
192 | this->IO_ADDR_W = FLASHIO; | 168 | this->IO_ADDR_W = sharpsl->io + FLASHIO; |
193 | /* Set address of hardware control function */ | 169 | /* Set address of hardware control function */ |
194 | this->cmd_ctrl = sharpsl_nand_hwcontrol; | 170 | this->cmd_ctrl = sharpsl_nand_hwcontrol; |
195 | this->dev_ready = sharpsl_nand_dev_ready; | 171 | this->dev_ready = sharpsl_nand_dev_ready; |
@@ -199,68 +175,89 @@ static int __init sharpsl_nand_init(void) | |||
199 | this->ecc.mode = NAND_ECC_HW; | 175 | this->ecc.mode = NAND_ECC_HW; |
200 | this->ecc.size = 256; | 176 | this->ecc.size = 256; |
201 | this->ecc.bytes = 3; | 177 | this->ecc.bytes = 3; |
202 | this->badblock_pattern = &sharpsl_bbt; | 178 | this->badblock_pattern = data->badblock_pattern; |
203 | if (machine_is_akita() || machine_is_borzoi()) { | 179 | this->ecc.layout = data->ecc_layout; |
204 | this->badblock_pattern = &sharpsl_akita_bbt; | ||
205 | this->ecc.layout = &akita_oobinfo; | ||
206 | } | ||
207 | this->ecc.hwctl = sharpsl_nand_enable_hwecc; | 180 | this->ecc.hwctl = sharpsl_nand_enable_hwecc; |
208 | this->ecc.calculate = sharpsl_nand_calculate_ecc; | 181 | this->ecc.calculate = sharpsl_nand_calculate_ecc; |
209 | this->ecc.correct = nand_correct_data; | 182 | this->ecc.correct = nand_correct_data; |
210 | 183 | ||
211 | /* Scan to find existence of the device */ | 184 | /* Scan to find existence of the device */ |
212 | err = nand_scan(sharpsl_mtd, 1); | 185 | err = nand_scan(&sharpsl->mtd, 1); |
213 | if (err) { | 186 | if (err) |
214 | iounmap(sharpsl_io_base); | 187 | goto err_scan; |
215 | kfree(sharpsl_mtd); | ||
216 | return err; | ||
217 | } | ||
218 | 188 | ||
219 | /* Register the partitions */ | 189 | /* Register the partitions */ |
220 | sharpsl_mtd->name = "sharpsl-nand"; | 190 | sharpsl->mtd.name = "sharpsl-nand"; |
221 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); | 191 | #ifdef CONFIG_MTD_PARTITIONS |
222 | 192 | nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); | |
223 | if (nr_partitions <= 0) { | 193 | if (nr_partitions <= 0) { |
224 | nr_partitions = DEFAULT_NUM_PARTITIONS; | 194 | nr_partitions = data->nr_partitions; |
225 | sharpsl_partition_info = sharpsl_nand_default_partition_info; | 195 | sharpsl_partition_info = data->partitions; |
226 | if (machine_is_poodle()) { | ||
227 | sharpsl_partition_info[1].size = 22 * 1024 * 1024; | ||
228 | } else if (machine_is_corgi() || machine_is_shepherd()) { | ||
229 | sharpsl_partition_info[1].size = 25 * 1024 * 1024; | ||
230 | } else if (machine_is_husky()) { | ||
231 | sharpsl_partition_info[1].size = 53 * 1024 * 1024; | ||
232 | } else if (machine_is_spitz()) { | ||
233 | sharpsl_partition_info[1].size = 5 * 1024 * 1024; | ||
234 | } else if (machine_is_akita()) { | ||
235 | sharpsl_partition_info[1].size = 58 * 1024 * 1024; | ||
236 | } else if (machine_is_borzoi()) { | ||
237 | sharpsl_partition_info[1].size = 32 * 1024 * 1024; | ||
238 | } | ||
239 | } | 196 | } |
240 | 197 | ||
241 | add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); | 198 | if (nr_partitions > 0) |
199 | err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions); | ||
200 | else | ||
201 | #endif | ||
202 | err = add_mtd_device(&sharpsl->mtd); | ||
203 | if (err) | ||
204 | goto err_add; | ||
242 | 205 | ||
243 | /* Return happy */ | 206 | /* Return happy */ |
244 | return 0; | 207 | return 0; |
245 | } | ||
246 | 208 | ||
247 | module_init(sharpsl_nand_init); | 209 | err_add: |
210 | nand_release(&sharpsl->mtd); | ||
211 | |||
212 | err_scan: | ||
213 | platform_set_drvdata(pdev, NULL); | ||
214 | iounmap(sharpsl->io); | ||
215 | err_ioremap: | ||
216 | err_get_res: | ||
217 | kfree(sharpsl); | ||
218 | return err; | ||
219 | } | ||
248 | 220 | ||
249 | /* | 221 | /* |
250 | * Clean up routine | 222 | * Clean up routine |
251 | */ | 223 | */ |
252 | static void __exit sharpsl_nand_cleanup(void) | 224 | static int __devexit sharpsl_nand_remove(struct platform_device *pdev) |
253 | { | 225 | { |
226 | struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); | ||
227 | |||
254 | /* Release resources, unregister device */ | 228 | /* Release resources, unregister device */ |
255 | nand_release(sharpsl_mtd); | 229 | nand_release(&sharpsl->mtd); |
256 | 230 | ||
257 | iounmap(sharpsl_io_base); | 231 | platform_set_drvdata(pdev, NULL); |
232 | |||
233 | iounmap(sharpsl->io); | ||
258 | 234 | ||
259 | /* Free the MTD device structure */ | 235 | /* Free the MTD device structure */ |
260 | kfree(sharpsl_mtd); | 236 | kfree(sharpsl); |
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static struct platform_driver sharpsl_nand_driver = { | ||
242 | .driver = { | ||
243 | .name = "sharpsl-nand", | ||
244 | .owner = THIS_MODULE, | ||
245 | }, | ||
246 | .probe = sharpsl_nand_probe, | ||
247 | .remove = __devexit_p(sharpsl_nand_remove), | ||
248 | }; | ||
249 | |||
250 | static int __init sharpsl_nand_init(void) | ||
251 | { | ||
252 | return platform_driver_register(&sharpsl_nand_driver); | ||
261 | } | 253 | } |
254 | module_init(sharpsl_nand_init); | ||
262 | 255 | ||
263 | module_exit(sharpsl_nand_cleanup); | 256 | static void __exit sharpsl_nand_exit(void) |
257 | { | ||
258 | platform_driver_unregister(&sharpsl_nand_driver); | ||
259 | } | ||
260 | module_exit(sharpsl_nand_exit); | ||
264 | 261 | ||
265 | MODULE_LICENSE("GPL"); | 262 | MODULE_LICENSE("GPL"); |
266 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | 263 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); |