diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-30 20:31:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-30 20:31:56 -0400 |
commit | 623ff7739e7c00fa3d55dbfd42a492a68298fd7a (patch) | |
tree | 0b7461753a1b13b27ea2958a7d48c6efb47bba54 /drivers/mtd/devices | |
parent | c39e8ede284f469971589f2e04af78216e1a771d (diff) | |
parent | 7b0e67f604e1829e5292e1ad7743eb18dc42ea7c (diff) |
Merge tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6
Pull MTD changes from David Woodhouse:
- Artem's cleanup of the MTD API continues apace.
- Fixes and improvements for ST FSMC and SuperH FLCTL NAND, amongst
others.
- More work on DiskOnChip G3, new driver for DiskOnChip G4.
- Clean up debug/warning printks in JFFS2 to use pr_<level>.
Fix up various trivial conflicts, largely due to changes in calling
conventions for things like dmaengine_prep_slave_sg() (new inline
wrapper to hide new parameter, clashing with rewrite of previously last
parameter that used to be an 'append' flag, and is now a bitmap of
'unsigned long flags').
(Also some header file fallout - like so many merges this merge window -
and silly conflicts with sparse fixes)
* tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6: (120 commits)
mtd: docg3 add protection against concurrency
mtd: docg3 refactor cascade floors structure
mtd: docg3 increase write/erase timeout
mtd: docg3 fix inbound calculations
mtd: nand: gpmi: fix function annotations
mtd: phram: fix section mismatch for phram_setup
mtd: unify initialization of erase_info->fail_addr
mtd: support ONFI multi lun NAND
mtd: sm_ftl: fix typo in major number.
mtd: add device-tree support to spear_smi
mtd: spear_smi: Remove default partition information from driver
mtd: Add device-tree support to fsmc_nand
mtd: fix section mismatch for doc_probe_device
mtd: nand/fsmc: Remove sparse warnings and errors
mtd: nand/fsmc: Add DMA support
mtd: nand/fsmc: Access the NAND device word by word whenever possible
mtd: nand/fsmc: Use dev_err to report error scenario
mtd: nand/fsmc: Use devm routines
mtd: nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform
mtd: fsmc_nand: add pm callbacks to support hibernation
...
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r-- | drivers/mtd/devices/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mtd/devices/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/devices/block2mtd.c | 28 | ||||
-rw-r--r-- | drivers/mtd/devices/doc2000.c | 25 | ||||
-rw-r--r-- | drivers/mtd/devices/doc2001.c | 22 | ||||
-rw-r--r-- | drivers/mtd/devices/doc2001plus.c | 22 | ||||
-rw-r--r-- | drivers/mtd/devices/docg3.c | 201 | ||||
-rw-r--r-- | drivers/mtd/devices/docg3.h | 20 | ||||
-rw-r--r-- | drivers/mtd/devices/lart.c | 17 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 56 | ||||
-rw-r--r-- | drivers/mtd/devices/ms02-nv.c | 12 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 50 | ||||
-rw-r--r-- | drivers/mtd/devices/mtdram.c | 35 | ||||
-rw-r--r-- | drivers/mtd/devices/phram.c | 76 | ||||
-rw-r--r-- | drivers/mtd/devices/pmc551.c | 99 | ||||
-rw-r--r-- | drivers/mtd/devices/slram.c | 41 | ||||
-rw-r--r-- | drivers/mtd/devices/spear_smi.c | 1147 | ||||
-rw-r--r-- | drivers/mtd/devices/sst25l.c | 46 |
18 files changed, 1444 insertions, 461 deletions
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 8d3dac40d7e6..4cdb2af7bf44 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -103,6 +103,13 @@ config M25PXX_USE_FAST_READ | |||
103 | help | 103 | help |
104 | This option enables FAST_READ access supported by ST M25Pxx. | 104 | This option enables FAST_READ access supported by ST M25Pxx. |
105 | 105 | ||
106 | config MTD_SPEAR_SMI | ||
107 | tristate "SPEAR MTD NOR Support through SMI controller" | ||
108 | depends on PLAT_SPEAR | ||
109 | default y | ||
110 | help | ||
111 | This enable SNOR support on SPEAR platforms using SMI controller | ||
112 | |||
106 | config MTD_SST25L | 113 | config MTD_SST25L |
107 | tristate "Support SST25L (non JEDEC) SPI Flash chips" | 114 | tristate "Support SST25L (non JEDEC) SPI Flash chips" |
108 | depends on SPI_MASTER | 115 | depends on SPI_MASTER |
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 56c7cd462f11..a4dd1d822b6c 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_LART) += lart.o | |||
17 | obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o | 17 | obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o |
18 | obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o | 18 | obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o |
19 | obj-$(CONFIG_MTD_M25P80) += m25p80.o | 19 | obj-$(CONFIG_MTD_M25P80) += m25p80.o |
20 | obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o | ||
20 | obj-$(CONFIG_MTD_SST25L) += sst25l.o | 21 | obj-$(CONFIG_MTD_SST25L) += sst25l.o |
21 | 22 | ||
22 | CFLAGS_docg3.o += -I$(src) \ No newline at end of file | 23 | CFLAGS_docg3.o += -I$(src) \ No newline at end of file |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index e7e46d1e7463..a4a80b742e65 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -104,14 +104,6 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
104 | int offset = from & (PAGE_SIZE-1); | 104 | int offset = from & (PAGE_SIZE-1); |
105 | int cpylen; | 105 | int cpylen; |
106 | 106 | ||
107 | if (from > mtd->size) | ||
108 | return -EINVAL; | ||
109 | if (from + len > mtd->size) | ||
110 | len = mtd->size - from; | ||
111 | |||
112 | if (retlen) | ||
113 | *retlen = 0; | ||
114 | |||
115 | while (len) { | 107 | while (len) { |
116 | if ((offset + len) > PAGE_SIZE) | 108 | if ((offset + len) > PAGE_SIZE) |
117 | cpylen = PAGE_SIZE - offset; // multiple pages | 109 | cpylen = PAGE_SIZE - offset; // multiple pages |
@@ -148,8 +140,6 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, | |||
148 | int offset = to & ~PAGE_MASK; // page offset | 140 | int offset = to & ~PAGE_MASK; // page offset |
149 | int cpylen; | 141 | int cpylen; |
150 | 142 | ||
151 | if (retlen) | ||
152 | *retlen = 0; | ||
153 | while (len) { | 143 | while (len) { |
154 | if ((offset+len) > PAGE_SIZE) | 144 | if ((offset+len) > PAGE_SIZE) |
155 | cpylen = PAGE_SIZE - offset; // multiple pages | 145 | cpylen = PAGE_SIZE - offset; // multiple pages |
@@ -188,13 +178,6 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
188 | struct block2mtd_dev *dev = mtd->priv; | 178 | struct block2mtd_dev *dev = mtd->priv; |
189 | int err; | 179 | int err; |
190 | 180 | ||
191 | if (!len) | ||
192 | return 0; | ||
193 | if (to >= mtd->size) | ||
194 | return -ENOSPC; | ||
195 | if (to + len > mtd->size) | ||
196 | len = mtd->size - to; | ||
197 | |||
198 | mutex_lock(&dev->write_mutex); | 181 | mutex_lock(&dev->write_mutex); |
199 | err = _block2mtd_write(dev, buf, to, len, retlen); | 182 | err = _block2mtd_write(dev, buf, to, len, retlen); |
200 | mutex_unlock(&dev->write_mutex); | 183 | mutex_unlock(&dev->write_mutex); |
@@ -283,13 +266,14 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
283 | dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; | 266 | dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; |
284 | dev->mtd.erasesize = erase_size; | 267 | dev->mtd.erasesize = erase_size; |
285 | dev->mtd.writesize = 1; | 268 | dev->mtd.writesize = 1; |
269 | dev->mtd.writebufsize = PAGE_SIZE; | ||
286 | dev->mtd.type = MTD_RAM; | 270 | dev->mtd.type = MTD_RAM; |
287 | dev->mtd.flags = MTD_CAP_RAM; | 271 | dev->mtd.flags = MTD_CAP_RAM; |
288 | dev->mtd.erase = block2mtd_erase; | 272 | dev->mtd._erase = block2mtd_erase; |
289 | dev->mtd.write = block2mtd_write; | 273 | dev->mtd._write = block2mtd_write; |
290 | dev->mtd.writev = mtd_writev; | 274 | dev->mtd._writev = mtd_writev; |
291 | dev->mtd.sync = block2mtd_sync; | 275 | dev->mtd._sync = block2mtd_sync; |
292 | dev->mtd.read = block2mtd_read; | 276 | dev->mtd._read = block2mtd_read; |
293 | dev->mtd.priv = dev; | 277 | dev->mtd.priv = dev; |
294 | dev->mtd.owner = THIS_MODULE; | 278 | dev->mtd.owner = THIS_MODULE; |
295 | 279 | ||
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index b1cdf6479019..a4eb8b5b85ec 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
@@ -562,14 +562,15 @@ void DoC2k_init(struct mtd_info *mtd) | |||
562 | 562 | ||
563 | mtd->type = MTD_NANDFLASH; | 563 | mtd->type = MTD_NANDFLASH; |
564 | mtd->flags = MTD_CAP_NANDFLASH; | 564 | mtd->flags = MTD_CAP_NANDFLASH; |
565 | mtd->writesize = 512; | 565 | mtd->writebufsize = mtd->writesize = 512; |
566 | mtd->oobsize = 16; | 566 | mtd->oobsize = 16; |
567 | mtd->ecc_strength = 2; | ||
567 | mtd->owner = THIS_MODULE; | 568 | mtd->owner = THIS_MODULE; |
568 | mtd->erase = doc_erase; | 569 | mtd->_erase = doc_erase; |
569 | mtd->read = doc_read; | 570 | mtd->_read = doc_read; |
570 | mtd->write = doc_write; | 571 | mtd->_write = doc_write; |
571 | mtd->read_oob = doc_read_oob; | 572 | mtd->_read_oob = doc_read_oob; |
572 | mtd->write_oob = doc_write_oob; | 573 | mtd->_write_oob = doc_write_oob; |
573 | this->curfloor = -1; | 574 | this->curfloor = -1; |
574 | this->curchip = -1; | 575 | this->curchip = -1; |
575 | mutex_init(&this->lock); | 576 | mutex_init(&this->lock); |
@@ -602,13 +603,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
602 | int i, len256 = 0, ret=0; | 603 | int i, len256 = 0, ret=0; |
603 | size_t left = len; | 604 | size_t left = len; |
604 | 605 | ||
605 | /* Don't allow read past end of device */ | ||
606 | if (from >= this->totlen) | ||
607 | return -EINVAL; | ||
608 | |||
609 | mutex_lock(&this->lock); | 606 | mutex_lock(&this->lock); |
610 | |||
611 | *retlen = 0; | ||
612 | while (left) { | 607 | while (left) { |
613 | len = left; | 608 | len = left; |
614 | 609 | ||
@@ -748,13 +743,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
748 | size_t left = len; | 743 | size_t left = len; |
749 | int status; | 744 | int status; |
750 | 745 | ||
751 | /* Don't allow write past end of device */ | ||
752 | if (to >= this->totlen) | ||
753 | return -EINVAL; | ||
754 | |||
755 | mutex_lock(&this->lock); | 746 | mutex_lock(&this->lock); |
756 | |||
757 | *retlen = 0; | ||
758 | while (left) { | 747 | while (left) { |
759 | len = left; | 748 | len = left; |
760 | 749 | ||
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 7543b98f46c4..f6927955dab0 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c | |||
@@ -346,14 +346,15 @@ void DoCMil_init(struct mtd_info *mtd) | |||
346 | 346 | ||
347 | /* FIXME: erase size is not always 8KiB */ | 347 | /* FIXME: erase size is not always 8KiB */ |
348 | mtd->erasesize = 0x2000; | 348 | mtd->erasesize = 0x2000; |
349 | mtd->writesize = 512; | 349 | mtd->writebufsize = mtd->writesize = 512; |
350 | mtd->oobsize = 16; | 350 | mtd->oobsize = 16; |
351 | mtd->ecc_strength = 2; | ||
351 | mtd->owner = THIS_MODULE; | 352 | mtd->owner = THIS_MODULE; |
352 | mtd->erase = doc_erase; | 353 | mtd->_erase = doc_erase; |
353 | mtd->read = doc_read; | 354 | mtd->_read = doc_read; |
354 | mtd->write = doc_write; | 355 | mtd->_write = doc_write; |
355 | mtd->read_oob = doc_read_oob; | 356 | mtd->_read_oob = doc_read_oob; |
356 | mtd->write_oob = doc_write_oob; | 357 | mtd->_write_oob = doc_write_oob; |
357 | this->curfloor = -1; | 358 | this->curfloor = -1; |
358 | this->curchip = -1; | 359 | this->curchip = -1; |
359 | 360 | ||
@@ -383,10 +384,6 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
383 | void __iomem *docptr = this->virtadr; | 384 | void __iomem *docptr = this->virtadr; |
384 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; | 385 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; |
385 | 386 | ||
386 | /* Don't allow read past end of device */ | ||
387 | if (from >= this->totlen) | ||
388 | return -EINVAL; | ||
389 | |||
390 | /* Don't allow a single read to cross a 512-byte block boundary */ | 387 | /* Don't allow a single read to cross a 512-byte block boundary */ |
391 | if (from + len > ((from | 0x1ff) + 1)) | 388 | if (from + len > ((from | 0x1ff) + 1)) |
392 | len = ((from | 0x1ff) + 1) - from; | 389 | len = ((from | 0x1ff) + 1) - from; |
@@ -494,10 +491,6 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
494 | void __iomem *docptr = this->virtadr; | 491 | void __iomem *docptr = this->virtadr; |
495 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; | 492 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; |
496 | 493 | ||
497 | /* Don't allow write past end of device */ | ||
498 | if (to >= this->totlen) | ||
499 | return -EINVAL; | ||
500 | |||
501 | #if 0 | 494 | #if 0 |
502 | /* Don't allow a single write to cross a 512-byte block boundary */ | 495 | /* Don't allow a single write to cross a 512-byte block boundary */ |
503 | if (to + len > ( (to | 0x1ff) + 1)) | 496 | if (to + len > ( (to | 0x1ff) + 1)) |
@@ -599,7 +592,6 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
599 | printk("Error programming flash\n"); | 592 | printk("Error programming flash\n"); |
600 | /* Error in programming | 593 | /* Error in programming |
601 | FIXME: implement Bad Block Replacement (in nftl.c ??) */ | 594 | FIXME: implement Bad Block Replacement (in nftl.c ??) */ |
602 | *retlen = 0; | ||
603 | ret = -EIO; | 595 | ret = -EIO; |
604 | } | 596 | } |
605 | dummy = ReadDOC(docptr, LastDataRead); | 597 | dummy = ReadDOC(docptr, LastDataRead); |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 177510d0e7ee..04eb2e4aa50f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
@@ -467,14 +467,15 @@ void DoCMilPlus_init(struct mtd_info *mtd) | |||
467 | 467 | ||
468 | mtd->type = MTD_NANDFLASH; | 468 | mtd->type = MTD_NANDFLASH; |
469 | mtd->flags = MTD_CAP_NANDFLASH; | 469 | mtd->flags = MTD_CAP_NANDFLASH; |
470 | mtd->writesize = 512; | 470 | mtd->writebufsize = mtd->writesize = 512; |
471 | mtd->oobsize = 16; | 471 | mtd->oobsize = 16; |
472 | mtd->ecc_strength = 2; | ||
472 | mtd->owner = THIS_MODULE; | 473 | mtd->owner = THIS_MODULE; |
473 | mtd->erase = doc_erase; | 474 | mtd->_erase = doc_erase; |
474 | mtd->read = doc_read; | 475 | mtd->_read = doc_read; |
475 | mtd->write = doc_write; | 476 | mtd->_write = doc_write; |
476 | mtd->read_oob = doc_read_oob; | 477 | mtd->_read_oob = doc_read_oob; |
477 | mtd->write_oob = doc_write_oob; | 478 | mtd->_write_oob = doc_write_oob; |
478 | this->curfloor = -1; | 479 | this->curfloor = -1; |
479 | this->curchip = -1; | 480 | this->curchip = -1; |
480 | 481 | ||
@@ -581,10 +582,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
581 | void __iomem * docptr = this->virtadr; | 582 | void __iomem * docptr = this->virtadr; |
582 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; | 583 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; |
583 | 584 | ||
584 | /* Don't allow read past end of device */ | ||
585 | if (from >= this->totlen) | ||
586 | return -EINVAL; | ||
587 | |||
588 | /* Don't allow a single read to cross a 512-byte block boundary */ | 585 | /* Don't allow a single read to cross a 512-byte block boundary */ |
589 | if (from + len > ((from | 0x1ff) + 1)) | 586 | if (from + len > ((from | 0x1ff) + 1)) |
590 | len = ((from | 0x1ff) + 1) - from; | 587 | len = ((from | 0x1ff) + 1) - from; |
@@ -700,10 +697,6 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
700 | void __iomem * docptr = this->virtadr; | 697 | void __iomem * docptr = this->virtadr; |
701 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; | 698 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; |
702 | 699 | ||
703 | /* Don't allow write past end of device */ | ||
704 | if (to >= this->totlen) | ||
705 | return -EINVAL; | ||
706 | |||
707 | /* Don't allow writes which aren't exactly one block (512 bytes) */ | 700 | /* Don't allow writes which aren't exactly one block (512 bytes) */ |
708 | if ((to & 0x1ff) || (len != 0x200)) | 701 | if ((to & 0x1ff) || (len != 0x200)) |
709 | return -EINVAL; | 702 | return -EINVAL; |
@@ -800,7 +793,6 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
800 | printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to); | 793 | printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to); |
801 | /* Error in programming | 794 | /* Error in programming |
802 | FIXME: implement Bad Block Replacement (in nftl.c ??) */ | 795 | FIXME: implement Bad Block Replacement (in nftl.c ??) */ |
803 | *retlen = 0; | ||
804 | ret = -EIO; | 796 | ret = -EIO; |
805 | } | 797 | } |
806 | dummy = ReadDOC(docptr, Mplus_LastDataRead); | 798 | dummy = ReadDOC(docptr, Mplus_LastDataRead); |
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index ad11ef0a81f4..8272c02668d6 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
@@ -80,14 +80,9 @@ static struct nand_ecclayout docg3_oobinfo = { | |||
80 | .oobavail = 8, | 80 | .oobavail = 8, |
81 | }; | 81 | }; |
82 | 82 | ||
83 | /** | ||
84 | * struct docg3_bch - BCH engine | ||
85 | */ | ||
86 | static struct bch_control *docg3_bch; | ||
87 | |||
88 | static inline u8 doc_readb(struct docg3 *docg3, u16 reg) | 83 | static inline u8 doc_readb(struct docg3 *docg3, u16 reg) |
89 | { | 84 | { |
90 | u8 val = readb(docg3->base + reg); | 85 | u8 val = readb(docg3->cascade->base + reg); |
91 | 86 | ||
92 | trace_docg3_io(0, 8, reg, (int)val); | 87 | trace_docg3_io(0, 8, reg, (int)val); |
93 | return val; | 88 | return val; |
@@ -95,7 +90,7 @@ static inline u8 doc_readb(struct docg3 *docg3, u16 reg) | |||
95 | 90 | ||
96 | static inline u16 doc_readw(struct docg3 *docg3, u16 reg) | 91 | static inline u16 doc_readw(struct docg3 *docg3, u16 reg) |
97 | { | 92 | { |
98 | u16 val = readw(docg3->base + reg); | 93 | u16 val = readw(docg3->cascade->base + reg); |
99 | 94 | ||
100 | trace_docg3_io(0, 16, reg, (int)val); | 95 | trace_docg3_io(0, 16, reg, (int)val); |
101 | return val; | 96 | return val; |
@@ -103,13 +98,13 @@ static inline u16 doc_readw(struct docg3 *docg3, u16 reg) | |||
103 | 98 | ||
104 | static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) | 99 | static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) |
105 | { | 100 | { |
106 | writeb(val, docg3->base + reg); | 101 | writeb(val, docg3->cascade->base + reg); |
107 | trace_docg3_io(1, 8, reg, val); | 102 | trace_docg3_io(1, 8, reg, val); |
108 | } | 103 | } |
109 | 104 | ||
110 | static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) | 105 | static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) |
111 | { | 106 | { |
112 | writew(val, docg3->base + reg); | 107 | writew(val, docg3->cascade->base + reg); |
113 | trace_docg3_io(1, 16, reg, val); | 108 | trace_docg3_io(1, 16, reg, val); |
114 | } | 109 | } |
115 | 110 | ||
@@ -643,7 +638,8 @@ static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc) | |||
643 | 638 | ||
644 | for (i = 0; i < DOC_ECC_BCH_SIZE; i++) | 639 | for (i = 0; i < DOC_ECC_BCH_SIZE; i++) |
645 | ecc[i] = bitrev8(hwecc[i]); | 640 | ecc[i] = bitrev8(hwecc[i]); |
646 | numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES, | 641 | numerrs = decode_bch(docg3->cascade->bch, NULL, |
642 | DOC_ECC_BCH_COVERED_BYTES, | ||
647 | NULL, ecc, NULL, errorpos); | 643 | NULL, ecc, NULL, errorpos); |
648 | BUG_ON(numerrs == -EINVAL); | 644 | BUG_ON(numerrs == -EINVAL); |
649 | if (numerrs < 0) | 645 | if (numerrs < 0) |
@@ -734,7 +730,7 @@ err: | |||
734 | * doc_read_page_getbytes - Reads bytes from a prepared page | 730 | * doc_read_page_getbytes - Reads bytes from a prepared page |
735 | * @docg3: the device | 731 | * @docg3: the device |
736 | * @len: the number of bytes to be read (must be a multiple of 4) | 732 | * @len: the number of bytes to be read (must be a multiple of 4) |
737 | * @buf: the buffer to be filled in | 733 | * @buf: the buffer to be filled in (or NULL is forget bytes) |
738 | * @first: 1 if first time read, DOC_READADDRESS should be set | 734 | * @first: 1 if first time read, DOC_READADDRESS should be set |
739 | * | 735 | * |
740 | */ | 736 | */ |
@@ -849,7 +845,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
849 | struct mtd_oob_ops *ops) | 845 | struct mtd_oob_ops *ops) |
850 | { | 846 | { |
851 | struct docg3 *docg3 = mtd->priv; | 847 | struct docg3 *docg3 = mtd->priv; |
852 | int block0, block1, page, ret, ofs = 0; | 848 | int block0, block1, page, ret, skip, ofs = 0; |
853 | u8 *oobbuf = ops->oobbuf; | 849 | u8 *oobbuf = ops->oobbuf; |
854 | u8 *buf = ops->datbuf; | 850 | u8 *buf = ops->datbuf; |
855 | size_t len, ooblen, nbdata, nboob; | 851 | size_t len, ooblen, nbdata, nboob; |
@@ -869,34 +865,36 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
869 | 865 | ||
870 | doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n", | 866 | doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n", |
871 | from, ops->mode, buf, len, oobbuf, ooblen); | 867 | from, ops->mode, buf, len, oobbuf, ooblen); |
872 | if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) || | 868 | if (ooblen % DOC_LAYOUT_OOB_SIZE) |
873 | (from % DOC_LAYOUT_PAGE_SIZE)) | ||
874 | return -EINVAL; | 869 | return -EINVAL; |
875 | 870 | ||
876 | ret = -EINVAL; | 871 | if (from + len > mtd->size) |
877 | calc_block_sector(from + len, &block0, &block1, &page, &ofs, | 872 | return -EINVAL; |
878 | docg3->reliable); | ||
879 | if (block1 > docg3->max_block) | ||
880 | goto err; | ||
881 | 873 | ||
882 | ops->oobretlen = 0; | 874 | ops->oobretlen = 0; |
883 | ops->retlen = 0; | 875 | ops->retlen = 0; |
884 | ret = 0; | 876 | ret = 0; |
877 | skip = from % DOC_LAYOUT_PAGE_SIZE; | ||
878 | mutex_lock(&docg3->cascade->lock); | ||
885 | while (!ret && (len > 0 || ooblen > 0)) { | 879 | while (!ret && (len > 0 || ooblen > 0)) { |
886 | calc_block_sector(from, &block0, &block1, &page, &ofs, | 880 | calc_block_sector(from - skip, &block0, &block1, &page, &ofs, |
887 | docg3->reliable); | 881 | docg3->reliable); |
888 | nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); | 882 | nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); |
889 | nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); | 883 | nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); |
890 | ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); | 884 | ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); |
891 | if (ret < 0) | 885 | if (ret < 0) |
892 | goto err; | 886 | goto out; |
893 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); | 887 | ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); |
894 | if (ret < 0) | 888 | if (ret < 0) |
895 | goto err_in_read; | 889 | goto err_in_read; |
896 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 1); | 890 | ret = doc_read_page_getbytes(docg3, skip, NULL, 1); |
891 | if (ret < skip) | ||
892 | goto err_in_read; | ||
893 | ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); | ||
897 | if (ret < nbdata) | 894 | if (ret < nbdata) |
898 | goto err_in_read; | 895 | goto err_in_read; |
899 | doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata, | 896 | doc_read_page_getbytes(docg3, |
897 | DOC_LAYOUT_PAGE_SIZE - nbdata - skip, | ||
900 | NULL, 0); | 898 | NULL, 0); |
901 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); | 899 | ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); |
902 | if (ret < nboob) | 900 | if (ret < nboob) |
@@ -950,13 +948,15 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, | |||
950 | len -= nbdata; | 948 | len -= nbdata; |
951 | ooblen -= nboob; | 949 | ooblen -= nboob; |
952 | from += DOC_LAYOUT_PAGE_SIZE; | 950 | from += DOC_LAYOUT_PAGE_SIZE; |
951 | skip = 0; | ||
953 | } | 952 | } |
954 | 953 | ||
954 | out: | ||
955 | mutex_unlock(&docg3->cascade->lock); | ||
955 | return ret; | 956 | return ret; |
956 | err_in_read: | 957 | err_in_read: |
957 | doc_read_page_finish(docg3); | 958 | doc_read_page_finish(docg3); |
958 | err: | 959 | goto out; |
959 | return ret; | ||
960 | } | 960 | } |
961 | 961 | ||
962 | /** | 962 | /** |
@@ -1114,10 +1114,10 @@ static int doc_get_op_status(struct docg3 *docg3) | |||
1114 | */ | 1114 | */ |
1115 | static int doc_write_erase_wait_status(struct docg3 *docg3) | 1115 | static int doc_write_erase_wait_status(struct docg3 *docg3) |
1116 | { | 1116 | { |
1117 | int status, ret = 0; | 1117 | int i, status, ret = 0; |
1118 | 1118 | ||
1119 | if (!doc_is_ready(docg3)) | 1119 | for (i = 0; !doc_is_ready(docg3) && i < 5; i++) |
1120 | usleep_range(3000, 3000); | 1120 | msleep(20); |
1121 | if (!doc_is_ready(docg3)) { | 1121 | if (!doc_is_ready(docg3)) { |
1122 | doc_dbg("Timeout reached and the chip is still not ready\n"); | 1122 | doc_dbg("Timeout reached and the chip is still not ready\n"); |
1123 | ret = -EAGAIN; | 1123 | ret = -EAGAIN; |
@@ -1196,18 +1196,19 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) | |||
1196 | int block0, block1, page, ret, ofs = 0; | 1196 | int block0, block1, page, ret, ofs = 0; |
1197 | 1197 | ||
1198 | doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); | 1198 | doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len); |
1199 | doc_set_device_id(docg3, docg3->device_id); | ||
1200 | 1199 | ||
1201 | info->state = MTD_ERASE_PENDING; | 1200 | info->state = MTD_ERASE_PENDING; |
1202 | calc_block_sector(info->addr + info->len, &block0, &block1, &page, | 1201 | calc_block_sector(info->addr + info->len, &block0, &block1, &page, |
1203 | &ofs, docg3->reliable); | 1202 | &ofs, docg3->reliable); |
1204 | ret = -EINVAL; | 1203 | ret = -EINVAL; |
1205 | if (block1 > docg3->max_block || page || ofs) | 1204 | if (info->addr + info->len > mtd->size || page || ofs) |
1206 | goto reset_err; | 1205 | goto reset_err; |
1207 | 1206 | ||
1208 | ret = 0; | 1207 | ret = 0; |
1209 | calc_block_sector(info->addr, &block0, &block1, &page, &ofs, | 1208 | calc_block_sector(info->addr, &block0, &block1, &page, &ofs, |
1210 | docg3->reliable); | 1209 | docg3->reliable); |
1210 | mutex_lock(&docg3->cascade->lock); | ||
1211 | doc_set_device_id(docg3, docg3->device_id); | ||
1211 | doc_set_reliable_mode(docg3); | 1212 | doc_set_reliable_mode(docg3); |
1212 | for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { | 1213 | for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { |
1213 | info->state = MTD_ERASING; | 1214 | info->state = MTD_ERASING; |
@@ -1215,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info) | |||
1215 | block0 += 2; | 1216 | block0 += 2; |
1216 | block1 += 2; | 1217 | block1 += 2; |
1217 | } | 1218 | } |
1219 | mutex_unlock(&docg3->cascade->lock); | ||
1218 | 1220 | ||
1219 | if (ret) | 1221 | if (ret) |
1220 | goto reset_err; | 1222 | goto reset_err; |
@@ -1401,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | |||
1401 | struct mtd_oob_ops *ops) | 1403 | struct mtd_oob_ops *ops) |
1402 | { | 1404 | { |
1403 | struct docg3 *docg3 = mtd->priv; | 1405 | struct docg3 *docg3 = mtd->priv; |
1404 | int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; | 1406 | int ret, autoecc, oobdelta; |
1405 | u8 *oobbuf = ops->oobbuf; | 1407 | u8 *oobbuf = ops->oobbuf; |
1406 | u8 *buf = ops->datbuf; | 1408 | u8 *buf = ops->datbuf; |
1407 | size_t len, ooblen; | 1409 | size_t len, ooblen; |
@@ -1438,12 +1440,8 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | |||
1438 | if (len && ooblen && | 1440 | if (len && ooblen && |
1439 | (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta)) | 1441 | (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta)) |
1440 | return -EINVAL; | 1442 | return -EINVAL; |
1441 | 1443 | if (ofs + len > mtd->size) | |
1442 | ret = -EINVAL; | 1444 | return -EINVAL; |
1443 | calc_block_sector(ofs + len, &block0, &block1, &page, &pofs, | ||
1444 | docg3->reliable); | ||
1445 | if (block1 > docg3->max_block) | ||
1446 | goto err; | ||
1447 | 1445 | ||
1448 | ops->oobretlen = 0; | 1446 | ops->oobretlen = 0; |
1449 | ops->retlen = 0; | 1447 | ops->retlen = 0; |
@@ -1457,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | |||
1457 | if (autoecc < 0) | 1455 | if (autoecc < 0) |
1458 | return autoecc; | 1456 | return autoecc; |
1459 | 1457 | ||
1458 | mutex_lock(&docg3->cascade->lock); | ||
1460 | while (!ret && len > 0) { | 1459 | while (!ret && len > 0) { |
1461 | memset(oob, 0, sizeof(oob)); | 1460 | memset(oob, 0, sizeof(oob)); |
1462 | if (ofs == docg3->oob_write_ofs) | 1461 | if (ofs == docg3->oob_write_ofs) |
@@ -1477,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | |||
1477 | } | 1476 | } |
1478 | ops->retlen += DOC_LAYOUT_PAGE_SIZE; | 1477 | ops->retlen += DOC_LAYOUT_PAGE_SIZE; |
1479 | } | 1478 | } |
1480 | err: | 1479 | |
1481 | doc_set_device_id(docg3, 0); | 1480 | doc_set_device_id(docg3, 0); |
1481 | mutex_unlock(&docg3->cascade->lock); | ||
1482 | return ret; | 1482 | return ret; |
1483 | } | 1483 | } |
1484 | 1484 | ||
@@ -1535,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev, | |||
1535 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | 1535 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); |
1536 | int dps0; | 1536 | int dps0; |
1537 | 1537 | ||
1538 | mutex_lock(&docg3->cascade->lock); | ||
1538 | doc_set_device_id(docg3, docg3->device_id); | 1539 | doc_set_device_id(docg3, docg3->device_id); |
1539 | dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); | 1540 | dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); |
1540 | doc_set_device_id(docg3, 0); | 1541 | doc_set_device_id(docg3, 0); |
1542 | mutex_unlock(&docg3->cascade->lock); | ||
1541 | 1543 | ||
1542 | return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); | 1544 | return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); |
1543 | } | 1545 | } |
@@ -1548,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev, | |||
1548 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | 1550 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); |
1549 | int dps1; | 1551 | int dps1; |
1550 | 1552 | ||
1553 | mutex_lock(&docg3->cascade->lock); | ||
1551 | doc_set_device_id(docg3, docg3->device_id); | 1554 | doc_set_device_id(docg3, docg3->device_id); |
1552 | dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); | 1555 | dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); |
1553 | doc_set_device_id(docg3, 0); | 1556 | doc_set_device_id(docg3, 0); |
1557 | mutex_unlock(&docg3->cascade->lock); | ||
1554 | 1558 | ||
1555 | return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); | 1559 | return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); |
1556 | } | 1560 | } |
@@ -1565,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev, | |||
1565 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) | 1569 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) |
1566 | return -EINVAL; | 1570 | return -EINVAL; |
1567 | 1571 | ||
1572 | mutex_lock(&docg3->cascade->lock); | ||
1568 | doc_set_device_id(docg3, docg3->device_id); | 1573 | doc_set_device_id(docg3, docg3->device_id); |
1569 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) | 1574 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) |
1570 | doc_writeb(docg3, buf[i], DOC_DPS0_KEY); | 1575 | doc_writeb(docg3, buf[i], DOC_DPS0_KEY); |
1571 | doc_set_device_id(docg3, 0); | 1576 | doc_set_device_id(docg3, 0); |
1577 | mutex_unlock(&docg3->cascade->lock); | ||
1572 | return count; | 1578 | return count; |
1573 | } | 1579 | } |
1574 | 1580 | ||
@@ -1582,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev, | |||
1582 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) | 1588 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) |
1583 | return -EINVAL; | 1589 | return -EINVAL; |
1584 | 1590 | ||
1591 | mutex_lock(&docg3->cascade->lock); | ||
1585 | doc_set_device_id(docg3, docg3->device_id); | 1592 | doc_set_device_id(docg3, docg3->device_id); |
1586 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) | 1593 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) |
1587 | doc_writeb(docg3, buf[i], DOC_DPS1_KEY); | 1594 | doc_writeb(docg3, buf[i], DOC_DPS1_KEY); |
1588 | doc_set_device_id(docg3, 0); | 1595 | doc_set_device_id(docg3, 0); |
1596 | mutex_unlock(&docg3->cascade->lock); | ||
1589 | return count; | 1597 | return count; |
1590 | } | 1598 | } |
1591 | 1599 | ||
@@ -1601,13 +1609,13 @@ static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = { | |||
1601 | }; | 1609 | }; |
1602 | 1610 | ||
1603 | static int doc_register_sysfs(struct platform_device *pdev, | 1611 | static int doc_register_sysfs(struct platform_device *pdev, |
1604 | struct mtd_info **floors) | 1612 | struct docg3_cascade *cascade) |
1605 | { | 1613 | { |
1606 | int ret = 0, floor, i = 0; | 1614 | int ret = 0, floor, i = 0; |
1607 | struct device *dev = &pdev->dev; | 1615 | struct device *dev = &pdev->dev; |
1608 | 1616 | ||
1609 | for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor]; | 1617 | for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && |
1610 | floor++) | 1618 | cascade->floors[floor]; floor++) |
1611 | for (i = 0; !ret && i < 4; i++) | 1619 | for (i = 0; !ret && i < 4; i++) |
1612 | ret = device_create_file(dev, &doc_sys_attrs[floor][i]); | 1620 | ret = device_create_file(dev, &doc_sys_attrs[floor][i]); |
1613 | if (!ret) | 1621 | if (!ret) |
@@ -1621,12 +1629,12 @@ static int doc_register_sysfs(struct platform_device *pdev, | |||
1621 | } | 1629 | } |
1622 | 1630 | ||
1623 | static void doc_unregister_sysfs(struct platform_device *pdev, | 1631 | static void doc_unregister_sysfs(struct platform_device *pdev, |
1624 | struct mtd_info **floors) | 1632 | struct docg3_cascade *cascade) |
1625 | { | 1633 | { |
1626 | struct device *dev = &pdev->dev; | 1634 | struct device *dev = &pdev->dev; |
1627 | int floor, i; | 1635 | int floor, i; |
1628 | 1636 | ||
1629 | for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor]; | 1637 | for (floor = 0; floor < DOC_MAX_NBFLOORS && cascade->floors[floor]; |
1630 | floor++) | 1638 | floor++) |
1631 | for (i = 0; i < 4; i++) | 1639 | for (i = 0; i < 4; i++) |
1632 | device_remove_file(dev, &doc_sys_attrs[floor][i]); | 1640 | device_remove_file(dev, &doc_sys_attrs[floor][i]); |
@@ -1640,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p) | |||
1640 | struct docg3 *docg3 = (struct docg3 *)s->private; | 1648 | struct docg3 *docg3 = (struct docg3 *)s->private; |
1641 | 1649 | ||
1642 | int pos = 0; | 1650 | int pos = 0; |
1643 | u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); | 1651 | u8 fctrl; |
1652 | |||
1653 | mutex_lock(&docg3->cascade->lock); | ||
1654 | fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); | ||
1655 | mutex_unlock(&docg3->cascade->lock); | ||
1644 | 1656 | ||
1645 | pos += seq_printf(s, | 1657 | pos += seq_printf(s, |
1646 | "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", | 1658 | "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", |
@@ -1658,9 +1670,12 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) | |||
1658 | { | 1670 | { |
1659 | struct docg3 *docg3 = (struct docg3 *)s->private; | 1671 | struct docg3 *docg3 = (struct docg3 *)s->private; |
1660 | 1672 | ||
1661 | int pos = 0; | 1673 | int pos = 0, pctrl, mode; |
1662 | int pctrl = doc_register_readb(docg3, DOC_ASICMODE); | 1674 | |
1663 | int mode = pctrl & 0x03; | 1675 | mutex_lock(&docg3->cascade->lock); |
1676 | pctrl = doc_register_readb(docg3, DOC_ASICMODE); | ||
1677 | mode = pctrl & 0x03; | ||
1678 | mutex_unlock(&docg3->cascade->lock); | ||
1664 | 1679 | ||
1665 | pos += seq_printf(s, | 1680 | pos += seq_printf(s, |
1666 | "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", | 1681 | "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", |
@@ -1692,7 +1707,11 @@ static int dbg_device_id_show(struct seq_file *s, void *p) | |||
1692 | { | 1707 | { |
1693 | struct docg3 *docg3 = (struct docg3 *)s->private; | 1708 | struct docg3 *docg3 = (struct docg3 *)s->private; |
1694 | int pos = 0; | 1709 | int pos = 0; |
1695 | int id = doc_register_readb(docg3, DOC_DEVICESELECT); | 1710 | int id; |
1711 | |||
1712 | mutex_lock(&docg3->cascade->lock); | ||
1713 | id = doc_register_readb(docg3, DOC_DEVICESELECT); | ||
1714 | mutex_unlock(&docg3->cascade->lock); | ||
1696 | 1715 | ||
1697 | pos += seq_printf(s, "DeviceId = %d\n", id); | 1716 | pos += seq_printf(s, "DeviceId = %d\n", id); |
1698 | return pos; | 1717 | return pos; |
@@ -1705,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p) | |||
1705 | int pos = 0; | 1724 | int pos = 0; |
1706 | int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; | 1725 | int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; |
1707 | 1726 | ||
1727 | mutex_lock(&docg3->cascade->lock); | ||
1708 | protect = doc_register_readb(docg3, DOC_PROTECTION); | 1728 | protect = doc_register_readb(docg3, DOC_PROTECTION); |
1709 | dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); | 1729 | dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); |
1710 | dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); | 1730 | dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW); |
@@ -1712,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p) | |||
1712 | dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); | 1732 | dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); |
1713 | dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); | 1733 | dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW); |
1714 | dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); | 1734 | dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); |
1735 | mutex_unlock(&docg3->cascade->lock); | ||
1715 | 1736 | ||
1716 | pos += seq_printf(s, "Protection = 0x%02x (", | 1737 | pos += seq_printf(s, "Protection = 0x%02x (", |
1717 | protect); | 1738 | protect); |
@@ -1804,7 +1825,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) | |||
1804 | 1825 | ||
1805 | switch (chip_id) { | 1826 | switch (chip_id) { |
1806 | case DOC_CHIPID_G3: | 1827 | case DOC_CHIPID_G3: |
1807 | mtd->name = kasprintf(GFP_KERNEL, "DiskOnChip G3 floor %d", | 1828 | mtd->name = kasprintf(GFP_KERNEL, "docg3.%d", |
1808 | docg3->device_id); | 1829 | docg3->device_id); |
1809 | docg3->max_block = 2047; | 1830 | docg3->max_block = 2047; |
1810 | break; | 1831 | break; |
@@ -1817,16 +1838,17 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) | |||
1817 | mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; | 1838 | mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; |
1818 | if (docg3->reliable == 2) | 1839 | if (docg3->reliable == 2) |
1819 | mtd->erasesize /= 2; | 1840 | mtd->erasesize /= 2; |
1820 | mtd->writesize = DOC_LAYOUT_PAGE_SIZE; | 1841 | mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE; |
1821 | mtd->oobsize = DOC_LAYOUT_OOB_SIZE; | 1842 | mtd->oobsize = DOC_LAYOUT_OOB_SIZE; |
1822 | mtd->owner = THIS_MODULE; | 1843 | mtd->owner = THIS_MODULE; |
1823 | mtd->erase = doc_erase; | 1844 | mtd->_erase = doc_erase; |
1824 | mtd->read = doc_read; | 1845 | mtd->_read = doc_read; |
1825 | mtd->write = doc_write; | 1846 | mtd->_write = doc_write; |
1826 | mtd->read_oob = doc_read_oob; | 1847 | mtd->_read_oob = doc_read_oob; |
1827 | mtd->write_oob = doc_write_oob; | 1848 | mtd->_write_oob = doc_write_oob; |
1828 | mtd->block_isbad = doc_block_isbad; | 1849 | mtd->_block_isbad = doc_block_isbad; |
1829 | mtd->ecclayout = &docg3_oobinfo; | 1850 | mtd->ecclayout = &docg3_oobinfo; |
1851 | mtd->ecc_strength = DOC_ECC_BCH_T; | ||
1830 | } | 1852 | } |
1831 | 1853 | ||
1832 | /** | 1854 | /** |
@@ -1834,6 +1856,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) | |||
1834 | * @base: the io space where the device is probed | 1856 | * @base: the io space where the device is probed |
1835 | * @floor: the floor of the probed device | 1857 | * @floor: the floor of the probed device |
1836 | * @dev: the device | 1858 | * @dev: the device |
1859 | * @cascade: the cascade of chips this devices will belong to | ||
1837 | * | 1860 | * |
1838 | * Checks whether a device at the specified IO range, and floor is available. | 1861 | * Checks whether a device at the specified IO range, and floor is available. |
1839 | * | 1862 | * |
@@ -1841,8 +1864,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) | |||
1841 | * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is | 1864 | * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is |
1842 | * launched. | 1865 | * launched. |
1843 | */ | 1866 | */ |
1844 | static struct mtd_info *doc_probe_device(void __iomem *base, int floor, | 1867 | static struct mtd_info * __init |
1845 | struct device *dev) | 1868 | doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev) |
1846 | { | 1869 | { |
1847 | int ret, bbt_nbpages; | 1870 | int ret, bbt_nbpages; |
1848 | u16 chip_id, chip_id_inv; | 1871 | u16 chip_id, chip_id_inv; |
@@ -1865,7 +1888,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor, | |||
1865 | 1888 | ||
1866 | docg3->dev = dev; | 1889 | docg3->dev = dev; |
1867 | docg3->device_id = floor; | 1890 | docg3->device_id = floor; |
1868 | docg3->base = base; | 1891 | docg3->cascade = cascade; |
1869 | doc_set_device_id(docg3, docg3->device_id); | 1892 | doc_set_device_id(docg3, docg3->device_id); |
1870 | if (!floor) | 1893 | if (!floor) |
1871 | doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); | 1894 | doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); |
@@ -1882,7 +1905,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor, | |||
1882 | switch (chip_id) { | 1905 | switch (chip_id) { |
1883 | case DOC_CHIPID_G3: | 1906 | case DOC_CHIPID_G3: |
1884 | doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n", | 1907 | doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n", |
1885 | base, floor); | 1908 | docg3->cascade->base, floor); |
1886 | break; | 1909 | break; |
1887 | default: | 1910 | default: |
1888 | doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); | 1911 | doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); |
@@ -1927,10 +1950,12 @@ static void doc_release_device(struct mtd_info *mtd) | |||
1927 | static int docg3_resume(struct platform_device *pdev) | 1950 | static int docg3_resume(struct platform_device *pdev) |
1928 | { | 1951 | { |
1929 | int i; | 1952 | int i; |
1953 | struct docg3_cascade *cascade; | ||
1930 | struct mtd_info **docg3_floors, *mtd; | 1954 | struct mtd_info **docg3_floors, *mtd; |
1931 | struct docg3 *docg3; | 1955 | struct docg3 *docg3; |
1932 | 1956 | ||
1933 | docg3_floors = platform_get_drvdata(pdev); | 1957 | cascade = platform_get_drvdata(pdev); |
1958 | docg3_floors = cascade->floors; | ||
1934 | mtd = docg3_floors[0]; | 1959 | mtd = docg3_floors[0]; |
1935 | docg3 = mtd->priv; | 1960 | docg3 = mtd->priv; |
1936 | 1961 | ||
@@ -1952,11 +1977,13 @@ static int docg3_resume(struct platform_device *pdev) | |||
1952 | static int docg3_suspend(struct platform_device *pdev, pm_message_t state) | 1977 | static int docg3_suspend(struct platform_device *pdev, pm_message_t state) |
1953 | { | 1978 | { |
1954 | int floor, i; | 1979 | int floor, i; |
1980 | struct docg3_cascade *cascade; | ||
1955 | struct mtd_info **docg3_floors, *mtd; | 1981 | struct mtd_info **docg3_floors, *mtd; |
1956 | struct docg3 *docg3; | 1982 | struct docg3 *docg3; |
1957 | u8 ctrl, pwr_down; | 1983 | u8 ctrl, pwr_down; |
1958 | 1984 | ||
1959 | docg3_floors = platform_get_drvdata(pdev); | 1985 | cascade = platform_get_drvdata(pdev); |
1986 | docg3_floors = cascade->floors; | ||
1960 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { | 1987 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { |
1961 | mtd = docg3_floors[floor]; | 1988 | mtd = docg3_floors[floor]; |
1962 | if (!mtd) | 1989 | if (!mtd) |
@@ -2006,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
2006 | struct resource *ress; | 2033 | struct resource *ress; |
2007 | void __iomem *base; | 2034 | void __iomem *base; |
2008 | int ret, floor, found = 0; | 2035 | int ret, floor, found = 0; |
2009 | struct mtd_info **docg3_floors; | 2036 | struct docg3_cascade *cascade; |
2010 | 2037 | ||
2011 | ret = -ENXIO; | 2038 | ret = -ENXIO; |
2012 | ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2039 | ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -2017,17 +2044,19 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
2017 | base = ioremap(ress->start, DOC_IOSPACE_SIZE); | 2044 | base = ioremap(ress->start, DOC_IOSPACE_SIZE); |
2018 | 2045 | ||
2019 | ret = -ENOMEM; | 2046 | ret = -ENOMEM; |
2020 | docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS, | 2047 | cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, |
2021 | GFP_KERNEL); | 2048 | GFP_KERNEL); |
2022 | if (!docg3_floors) | 2049 | if (!cascade) |
2023 | goto nomem1; | 2050 | goto nomem1; |
2024 | docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, | 2051 | cascade->base = base; |
2052 | mutex_init(&cascade->lock); | ||
2053 | cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, | ||
2025 | DOC_ECC_BCH_PRIMPOLY); | 2054 | DOC_ECC_BCH_PRIMPOLY); |
2026 | if (!docg3_bch) | 2055 | if (!cascade->bch) |
2027 | goto nomem2; | 2056 | goto nomem2; |
2028 | 2057 | ||
2029 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { | 2058 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { |
2030 | mtd = doc_probe_device(base, floor, dev); | 2059 | mtd = doc_probe_device(cascade, floor, dev); |
2031 | if (IS_ERR(mtd)) { | 2060 | if (IS_ERR(mtd)) { |
2032 | ret = PTR_ERR(mtd); | 2061 | ret = PTR_ERR(mtd); |
2033 | goto err_probe; | 2062 | goto err_probe; |
@@ -2038,7 +2067,7 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
2038 | else | 2067 | else |
2039 | continue; | 2068 | continue; |
2040 | } | 2069 | } |
2041 | docg3_floors[floor] = mtd; | 2070 | cascade->floors[floor] = mtd; |
2042 | ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, | 2071 | ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, |
2043 | 0); | 2072 | 0); |
2044 | if (ret) | 2073 | if (ret) |
@@ -2046,26 +2075,26 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
2046 | found++; | 2075 | found++; |
2047 | } | 2076 | } |
2048 | 2077 | ||
2049 | ret = doc_register_sysfs(pdev, docg3_floors); | 2078 | ret = doc_register_sysfs(pdev, cascade); |
2050 | if (ret) | 2079 | if (ret) |
2051 | goto err_probe; | 2080 | goto err_probe; |
2052 | if (!found) | 2081 | if (!found) |
2053 | goto notfound; | 2082 | goto notfound; |
2054 | 2083 | ||
2055 | platform_set_drvdata(pdev, docg3_floors); | 2084 | platform_set_drvdata(pdev, cascade); |
2056 | doc_dbg_register(docg3_floors[0]->priv); | 2085 | doc_dbg_register(cascade->floors[0]->priv); |
2057 | return 0; | 2086 | return 0; |
2058 | 2087 | ||
2059 | notfound: | 2088 | notfound: |
2060 | ret = -ENODEV; | 2089 | ret = -ENODEV; |
2061 | dev_info(dev, "No supported DiskOnChip found\n"); | 2090 | dev_info(dev, "No supported DiskOnChip found\n"); |
2062 | err_probe: | 2091 | err_probe: |
2063 | free_bch(docg3_bch); | 2092 | kfree(cascade->bch); |
2064 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) | 2093 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) |
2065 | if (docg3_floors[floor]) | 2094 | if (cascade->floors[floor]) |
2066 | doc_release_device(docg3_floors[floor]); | 2095 | doc_release_device(cascade->floors[floor]); |
2067 | nomem2: | 2096 | nomem2: |
2068 | kfree(docg3_floors); | 2097 | kfree(cascade); |
2069 | nomem1: | 2098 | nomem1: |
2070 | iounmap(base); | 2099 | iounmap(base); |
2071 | noress: | 2100 | noress: |
@@ -2080,19 +2109,19 @@ noress: | |||
2080 | */ | 2109 | */ |
2081 | static int __exit docg3_release(struct platform_device *pdev) | 2110 | static int __exit docg3_release(struct platform_device *pdev) |
2082 | { | 2111 | { |
2083 | struct mtd_info **docg3_floors = platform_get_drvdata(pdev); | 2112 | struct docg3_cascade *cascade = platform_get_drvdata(pdev); |
2084 | struct docg3 *docg3 = docg3_floors[0]->priv; | 2113 | struct docg3 *docg3 = cascade->floors[0]->priv; |
2085 | void __iomem *base = docg3->base; | 2114 | void __iomem *base = cascade->base; |
2086 | int floor; | 2115 | int floor; |
2087 | 2116 | ||
2088 | doc_unregister_sysfs(pdev, docg3_floors); | 2117 | doc_unregister_sysfs(pdev, cascade); |
2089 | doc_dbg_unregister(docg3); | 2118 | doc_dbg_unregister(docg3); |
2090 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) | 2119 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) |
2091 | if (docg3_floors[floor]) | 2120 | if (cascade->floors[floor]) |
2092 | doc_release_device(docg3_floors[floor]); | 2121 | doc_release_device(cascade->floors[floor]); |
2093 | 2122 | ||
2094 | kfree(docg3_floors); | 2123 | free_bch(docg3->cascade->bch); |
2095 | free_bch(docg3_bch); | 2124 | kfree(cascade); |
2096 | iounmap(base); | 2125 | iounmap(base); |
2097 | return 0; | 2126 | return 0; |
2098 | } | 2127 | } |
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h index db0da436b493..19fb93f96a3a 100644 --- a/drivers/mtd/devices/docg3.h +++ b/drivers/mtd/devices/docg3.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #ifndef _MTD_DOCG3_H | 22 | #ifndef _MTD_DOCG3_H |
23 | #define _MTD_DOCG3_H | 23 | #define _MTD_DOCG3_H |
24 | 24 | ||
25 | #include <linux/mtd/mtd.h> | ||
26 | |||
25 | /* | 27 | /* |
26 | * Flash memory areas : | 28 | * Flash memory areas : |
27 | * - 0x0000 .. 0x07ff : IPL | 29 | * - 0x0000 .. 0x07ff : IPL |
@@ -267,9 +269,23 @@ | |||
267 | #define DOC_LAYOUT_DPS_KEY_LENGTH 8 | 269 | #define DOC_LAYOUT_DPS_KEY_LENGTH 8 |
268 | 270 | ||
269 | /** | 271 | /** |
272 | * struct docg3_cascade - Cascade of 1 to 4 docg3 chips | ||
273 | * @floors: floors (ie. one physical docg3 chip is one floor) | ||
274 | * @base: IO space to access all chips in the cascade | ||
275 | * @bch: the BCH correcting control structure | ||
276 | * @lock: lock to protect docg3 IO space from concurrent accesses | ||
277 | */ | ||
278 | struct docg3_cascade { | ||
279 | struct mtd_info *floors[DOC_MAX_NBFLOORS]; | ||
280 | void __iomem *base; | ||
281 | struct bch_control *bch; | ||
282 | struct mutex lock; | ||
283 | }; | ||
284 | |||
285 | /** | ||
270 | * struct docg3 - DiskOnChip driver private data | 286 | * struct docg3 - DiskOnChip driver private data |
271 | * @dev: the device currently under control | 287 | * @dev: the device currently under control |
272 | * @base: mapped IO space | 288 | * @cascade: the cascade this device belongs to |
273 | * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) | 289 | * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) |
274 | * @if_cfg: if true, reads are on 16bits, else reads are on 8bits | 290 | * @if_cfg: if true, reads are on 16bits, else reads are on 8bits |
275 | 291 | ||
@@ -287,7 +303,7 @@ | |||
287 | */ | 303 | */ |
288 | struct docg3 { | 304 | struct docg3 { |
289 | struct device *dev; | 305 | struct device *dev; |
290 | void __iomem *base; | 306 | struct docg3_cascade *cascade; |
291 | unsigned int device_id:4; | 307 | unsigned int device_id:4; |
292 | unsigned int if_cfg:1; | 308 | unsigned int if_cfg:1; |
293 | unsigned int reliable:2; | 309 | unsigned int reliable:2; |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 3a11ea628e58..82bd00af5cc3 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
@@ -367,9 +367,6 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) | |||
367 | printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len); | 367 | printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len); |
368 | #endif | 368 | #endif |
369 | 369 | ||
370 | /* sanity checks */ | ||
371 | if (instr->addr + instr->len > mtd->size) return (-EINVAL); | ||
372 | |||
373 | /* | 370 | /* |
374 | * check that both start and end of the requested erase are | 371 | * check that both start and end of the requested erase are |
375 | * aligned with the erasesize at the appropriate addresses. | 372 | * aligned with the erasesize at the appropriate addresses. |
@@ -440,10 +437,6 @@ static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retle | |||
440 | printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len); | 437 | printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len); |
441 | #endif | 438 | #endif |
442 | 439 | ||
443 | /* sanity checks */ | ||
444 | if (!len) return (0); | ||
445 | if (from + len > mtd->size) return (-EINVAL); | ||
446 | |||
447 | /* we always read len bytes */ | 440 | /* we always read len bytes */ |
448 | *retlen = len; | 441 | *retlen = len; |
449 | 442 | ||
@@ -522,11 +515,8 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen | |||
522 | printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len); | 515 | printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len); |
523 | #endif | 516 | #endif |
524 | 517 | ||
525 | *retlen = 0; | ||
526 | |||
527 | /* sanity checks */ | 518 | /* sanity checks */ |
528 | if (!len) return (0); | 519 | if (!len) return (0); |
529 | if (to + len > mtd->size) return (-EINVAL); | ||
530 | 520 | ||
531 | /* first, we write a 0xFF.... padded byte until we reach a dword boundary */ | 521 | /* first, we write a 0xFF.... padded byte until we reach a dword boundary */ |
532 | if (to & (BUSWIDTH - 1)) | 522 | if (to & (BUSWIDTH - 1)) |
@@ -630,14 +620,15 @@ static int __init lart_flash_init (void) | |||
630 | mtd.name = module_name; | 620 | mtd.name = module_name; |
631 | mtd.type = MTD_NORFLASH; | 621 | mtd.type = MTD_NORFLASH; |
632 | mtd.writesize = 1; | 622 | mtd.writesize = 1; |
623 | mtd.writebufsize = 4; | ||
633 | mtd.flags = MTD_CAP_NORFLASH; | 624 | mtd.flags = MTD_CAP_NORFLASH; |
634 | mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; | 625 | mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; |
635 | mtd.erasesize = FLASH_BLOCKSIZE_MAIN; | 626 | mtd.erasesize = FLASH_BLOCKSIZE_MAIN; |
636 | mtd.numeraseregions = ARRAY_SIZE(erase_regions); | 627 | mtd.numeraseregions = ARRAY_SIZE(erase_regions); |
637 | mtd.eraseregions = erase_regions; | 628 | mtd.eraseregions = erase_regions; |
638 | mtd.erase = flash_erase; | 629 | mtd._erase = flash_erase; |
639 | mtd.read = flash_read; | 630 | mtd._read = flash_read; |
640 | mtd.write = flash_write; | 631 | mtd._write = flash_write; |
641 | mtd.owner = THIS_MODULE; | 632 | mtd.owner = THIS_MODULE; |
642 | 633 | ||
643 | #ifdef LART_DEBUG | 634 | #ifdef LART_DEBUG |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7c60dddbefc0..1924d247c1cb 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -288,9 +288,6 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
288 | __func__, (long long)instr->addr, | 288 | __func__, (long long)instr->addr, |
289 | (long long)instr->len); | 289 | (long long)instr->len); |
290 | 290 | ||
291 | /* sanity checks */ | ||
292 | if (instr->addr + instr->len > flash->mtd.size) | ||
293 | return -EINVAL; | ||
294 | div_u64_rem(instr->len, mtd->erasesize, &rem); | 291 | div_u64_rem(instr->len, mtd->erasesize, &rem); |
295 | if (rem) | 292 | if (rem) |
296 | return -EINVAL; | 293 | return -EINVAL; |
@@ -349,13 +346,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
349 | pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), | 346 | pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), |
350 | __func__, (u32)from, len); | 347 | __func__, (u32)from, len); |
351 | 348 | ||
352 | /* sanity checks */ | ||
353 | if (!len) | ||
354 | return 0; | ||
355 | |||
356 | if (from + len > flash->mtd.size) | ||
357 | return -EINVAL; | ||
358 | |||
359 | spi_message_init(&m); | 349 | spi_message_init(&m); |
360 | memset(t, 0, (sizeof t)); | 350 | memset(t, 0, (sizeof t)); |
361 | 351 | ||
@@ -371,9 +361,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
371 | t[1].len = len; | 361 | t[1].len = len; |
372 | spi_message_add_tail(&t[1], &m); | 362 | spi_message_add_tail(&t[1], &m); |
373 | 363 | ||
374 | /* Byte count starts at zero. */ | ||
375 | *retlen = 0; | ||
376 | |||
377 | mutex_lock(&flash->lock); | 364 | mutex_lock(&flash->lock); |
378 | 365 | ||
379 | /* Wait till previous write/erase is done. */ | 366 | /* Wait till previous write/erase is done. */ |
@@ -417,15 +404,6 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
417 | pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), | 404 | pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), |
418 | __func__, (u32)to, len); | 405 | __func__, (u32)to, len); |
419 | 406 | ||
420 | *retlen = 0; | ||
421 | |||
422 | /* sanity checks */ | ||
423 | if (!len) | ||
424 | return(0); | ||
425 | |||
426 | if (to + len > flash->mtd.size) | ||
427 | return -EINVAL; | ||
428 | |||
429 | spi_message_init(&m); | 407 | spi_message_init(&m); |
430 | memset(t, 0, (sizeof t)); | 408 | memset(t, 0, (sizeof t)); |
431 | 409 | ||
@@ -509,15 +487,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
509 | pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), | 487 | pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), |
510 | __func__, (u32)to, len); | 488 | __func__, (u32)to, len); |
511 | 489 | ||
512 | *retlen = 0; | ||
513 | |||
514 | /* sanity checks */ | ||
515 | if (!len) | ||
516 | return 0; | ||
517 | |||
518 | if (to + len > flash->mtd.size) | ||
519 | return -EINVAL; | ||
520 | |||
521 | spi_message_init(&m); | 490 | spi_message_init(&m); |
522 | memset(t, 0, (sizeof t)); | 491 | memset(t, 0, (sizeof t)); |
523 | 492 | ||
@@ -908,14 +877,14 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
908 | flash->mtd.writesize = 1; | 877 | flash->mtd.writesize = 1; |
909 | flash->mtd.flags = MTD_CAP_NORFLASH; | 878 | flash->mtd.flags = MTD_CAP_NORFLASH; |
910 | flash->mtd.size = info->sector_size * info->n_sectors; | 879 | flash->mtd.size = info->sector_size * info->n_sectors; |
911 | flash->mtd.erase = m25p80_erase; | 880 | flash->mtd._erase = m25p80_erase; |
912 | flash->mtd.read = m25p80_read; | 881 | flash->mtd._read = m25p80_read; |
913 | 882 | ||
914 | /* sst flash chips use AAI word program */ | 883 | /* sst flash chips use AAI word program */ |
915 | if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) | 884 | if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) |
916 | flash->mtd.write = sst_write; | 885 | flash->mtd._write = sst_write; |
917 | else | 886 | else |
918 | flash->mtd.write = m25p80_write; | 887 | flash->mtd._write = m25p80_write; |
919 | 888 | ||
920 | /* prefer "small sector" erase if possible */ | 889 | /* prefer "small sector" erase if possible */ |
921 | if (info->flags & SECT_4K) { | 890 | if (info->flags & SECT_4K) { |
@@ -932,6 +901,7 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
932 | ppdata.of_node = spi->dev.of_node; | 901 | ppdata.of_node = spi->dev.of_node; |
933 | flash->mtd.dev.parent = &spi->dev; | 902 | flash->mtd.dev.parent = &spi->dev; |
934 | flash->page_size = info->page_size; | 903 | flash->page_size = info->page_size; |
904 | flash->mtd.writebufsize = flash->page_size; | ||
935 | 905 | ||
936 | if (info->addr_width) | 906 | if (info->addr_width) |
937 | flash->addr_width = info->addr_width; | 907 | flash->addr_width = info->addr_width; |
@@ -1004,21 +974,7 @@ static struct spi_driver m25p80_driver = { | |||
1004 | */ | 974 | */ |
1005 | }; | 975 | }; |
1006 | 976 | ||
1007 | 977 | module_spi_driver(m25p80_driver); | |
1008 | static int __init m25p80_init(void) | ||
1009 | { | ||
1010 | return spi_register_driver(&m25p80_driver); | ||
1011 | } | ||
1012 | |||
1013 | |||
1014 | static void __exit m25p80_exit(void) | ||
1015 | { | ||
1016 | spi_unregister_driver(&m25p80_driver); | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | module_init(m25p80_init); | ||
1021 | module_exit(m25p80_exit); | ||
1022 | 978 | ||
1023 | MODULE_LICENSE("GPL"); | 979 | MODULE_LICENSE("GPL"); |
1024 | MODULE_AUTHOR("Mike Lavender"); | 980 | MODULE_AUTHOR("Mike Lavender"); |
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 8423fb6d4f26..182849d39c61 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c | |||
@@ -59,12 +59,8 @@ static int ms02nv_read(struct mtd_info *mtd, loff_t from, | |||
59 | { | 59 | { |
60 | struct ms02nv_private *mp = mtd->priv; | 60 | struct ms02nv_private *mp = mtd->priv; |
61 | 61 | ||
62 | if (from + len > mtd->size) | ||
63 | return -EINVAL; | ||
64 | |||
65 | memcpy(buf, mp->uaddr + from, len); | 62 | memcpy(buf, mp->uaddr + from, len); |
66 | *retlen = len; | 63 | *retlen = len; |
67 | |||
68 | return 0; | 64 | return 0; |
69 | } | 65 | } |
70 | 66 | ||
@@ -73,12 +69,8 @@ static int ms02nv_write(struct mtd_info *mtd, loff_t to, | |||
73 | { | 69 | { |
74 | struct ms02nv_private *mp = mtd->priv; | 70 | struct ms02nv_private *mp = mtd->priv; |
75 | 71 | ||
76 | if (to + len > mtd->size) | ||
77 | return -EINVAL; | ||
78 | |||
79 | memcpy(mp->uaddr + to, buf, len); | 72 | memcpy(mp->uaddr + to, buf, len); |
80 | *retlen = len; | 73 | *retlen = len; |
81 | |||
82 | return 0; | 74 | return 0; |
83 | } | 75 | } |
84 | 76 | ||
@@ -215,8 +207,8 @@ static int __init ms02nv_init_one(ulong addr) | |||
215 | mtd->size = fixsize; | 207 | mtd->size = fixsize; |
216 | mtd->name = (char *)ms02nv_name; | 208 | mtd->name = (char *)ms02nv_name; |
217 | mtd->owner = THIS_MODULE; | 209 | mtd->owner = THIS_MODULE; |
218 | mtd->read = ms02nv_read; | 210 | mtd->_read = ms02nv_read; |
219 | mtd->write = ms02nv_write; | 211 | mtd->_write = ms02nv_write; |
220 | mtd->writesize = 1; | 212 | mtd->writesize = 1; |
221 | 213 | ||
222 | ret = -EIO; | 214 | ret = -EIO; |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 236057ead0d2..928fb0e6d73a 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
@@ -164,9 +164,6 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
164 | dev_name(&spi->dev), (long long)instr->addr, | 164 | dev_name(&spi->dev), (long long)instr->addr, |
165 | (long long)instr->len); | 165 | (long long)instr->len); |
166 | 166 | ||
167 | /* Sanity checks */ | ||
168 | if (instr->addr + instr->len > mtd->size) | ||
169 | return -EINVAL; | ||
170 | div_u64_rem(instr->len, priv->page_size, &rem); | 167 | div_u64_rem(instr->len, priv->page_size, &rem); |
171 | if (rem) | 168 | if (rem) |
172 | return -EINVAL; | 169 | return -EINVAL; |
@@ -252,14 +249,6 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
252 | pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), | 249 | pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), |
253 | (unsigned)from, (unsigned)(from + len)); | 250 | (unsigned)from, (unsigned)(from + len)); |
254 | 251 | ||
255 | *retlen = 0; | ||
256 | |||
257 | /* Sanity checks */ | ||
258 | if (!len) | ||
259 | return 0; | ||
260 | if (from + len > mtd->size) | ||
261 | return -EINVAL; | ||
262 | |||
263 | /* Calculate flash page/byte address */ | 252 | /* Calculate flash page/byte address */ |
264 | addr = (((unsigned)from / priv->page_size) << priv->page_offset) | 253 | addr = (((unsigned)from / priv->page_size) << priv->page_offset) |
265 | + ((unsigned)from % priv->page_size); | 254 | + ((unsigned)from % priv->page_size); |
@@ -328,14 +317,6 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
328 | pr_debug("%s: write 0x%x..0x%x\n", | 317 | pr_debug("%s: write 0x%x..0x%x\n", |
329 | dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len)); | 318 | dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len)); |
330 | 319 | ||
331 | *retlen = 0; | ||
332 | |||
333 | /* Sanity checks */ | ||
334 | if (!len) | ||
335 | return 0; | ||
336 | if ((to + len) > mtd->size) | ||
337 | return -EINVAL; | ||
338 | |||
339 | spi_message_init(&msg); | 320 | spi_message_init(&msg); |
340 | 321 | ||
341 | x[0].tx_buf = command = priv->command; | 322 | x[0].tx_buf = command = priv->command; |
@@ -490,8 +471,6 @@ static ssize_t otp_read(struct spi_device *spi, unsigned base, | |||
490 | 471 | ||
491 | if ((off + len) > 64) | 472 | if ((off + len) > 64) |
492 | len = 64 - off; | 473 | len = 64 - off; |
493 | if (len == 0) | ||
494 | return len; | ||
495 | 474 | ||
496 | spi_message_init(&m); | 475 | spi_message_init(&m); |
497 | 476 | ||
@@ -611,16 +590,16 @@ static int dataflash_write_user_otp(struct mtd_info *mtd, | |||
611 | 590 | ||
612 | static char *otp_setup(struct mtd_info *device, char revision) | 591 | static char *otp_setup(struct mtd_info *device, char revision) |
613 | { | 592 | { |
614 | device->get_fact_prot_info = dataflash_get_otp_info; | 593 | device->_get_fact_prot_info = dataflash_get_otp_info; |
615 | device->read_fact_prot_reg = dataflash_read_fact_otp; | 594 | device->_read_fact_prot_reg = dataflash_read_fact_otp; |
616 | device->get_user_prot_info = dataflash_get_otp_info; | 595 | device->_get_user_prot_info = dataflash_get_otp_info; |
617 | device->read_user_prot_reg = dataflash_read_user_otp; | 596 | device->_read_user_prot_reg = dataflash_read_user_otp; |
618 | 597 | ||
619 | /* rev c parts (at45db321c and at45db1281 only!) use a | 598 | /* rev c parts (at45db321c and at45db1281 only!) use a |
620 | * different write procedure; not (yet?) implemented. | 599 | * different write procedure; not (yet?) implemented. |
621 | */ | 600 | */ |
622 | if (revision > 'c') | 601 | if (revision > 'c') |
623 | device->write_user_prot_reg = dataflash_write_user_otp; | 602 | device->_write_user_prot_reg = dataflash_write_user_otp; |
624 | 603 | ||
625 | return ", OTP"; | 604 | return ", OTP"; |
626 | } | 605 | } |
@@ -672,9 +651,9 @@ add_dataflash_otp(struct spi_device *spi, char *name, | |||
672 | device->owner = THIS_MODULE; | 651 | device->owner = THIS_MODULE; |
673 | device->type = MTD_DATAFLASH; | 652 | device->type = MTD_DATAFLASH; |
674 | device->flags = MTD_WRITEABLE; | 653 | device->flags = MTD_WRITEABLE; |
675 | device->erase = dataflash_erase; | 654 | device->_erase = dataflash_erase; |
676 | device->read = dataflash_read; | 655 | device->_read = dataflash_read; |
677 | device->write = dataflash_write; | 656 | device->_write = dataflash_write; |
678 | device->priv = priv; | 657 | device->priv = priv; |
679 | 658 | ||
680 | device->dev.parent = &spi->dev; | 659 | device->dev.parent = &spi->dev; |
@@ -946,18 +925,7 @@ static struct spi_driver dataflash_driver = { | |||
946 | /* FIXME: investigate suspend and resume... */ | 925 | /* FIXME: investigate suspend and resume... */ |
947 | }; | 926 | }; |
948 | 927 | ||
949 | static int __init dataflash_init(void) | 928 | module_spi_driver(dataflash_driver); |
950 | { | ||
951 | return spi_register_driver(&dataflash_driver); | ||
952 | } | ||
953 | module_init(dataflash_init); | ||
954 | |||
955 | static void __exit dataflash_exit(void) | ||
956 | { | ||
957 | spi_unregister_driver(&dataflash_driver); | ||
958 | } | ||
959 | module_exit(dataflash_exit); | ||
960 | |||
961 | 929 | ||
962 | MODULE_LICENSE("GPL"); | 930 | MODULE_LICENSE("GPL"); |
963 | MODULE_AUTHOR("Andrew Victor, David Brownell"); | 931 | MODULE_AUTHOR("Andrew Victor, David Brownell"); |
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 2562689ba6b4..ec59d65897fb 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c | |||
@@ -34,34 +34,23 @@ static struct mtd_info *mtd_info; | |||
34 | 34 | ||
35 | static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) | 35 | static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) |
36 | { | 36 | { |
37 | if (instr->addr + instr->len > mtd->size) | ||
38 | return -EINVAL; | ||
39 | |||
40 | memset((char *)mtd->priv + instr->addr, 0xff, instr->len); | 37 | memset((char *)mtd->priv + instr->addr, 0xff, instr->len); |
41 | |||
42 | instr->state = MTD_ERASE_DONE; | 38 | instr->state = MTD_ERASE_DONE; |
43 | mtd_erase_callback(instr); | 39 | mtd_erase_callback(instr); |
44 | |||
45 | return 0; | 40 | return 0; |
46 | } | 41 | } |
47 | 42 | ||
48 | static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, | 43 | static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, |
49 | size_t *retlen, void **virt, resource_size_t *phys) | 44 | size_t *retlen, void **virt, resource_size_t *phys) |
50 | { | 45 | { |
51 | if (from + len > mtd->size) | ||
52 | return -EINVAL; | ||
53 | |||
54 | /* can we return a physical address with this driver? */ | ||
55 | if (phys) | ||
56 | return -EINVAL; | ||
57 | |||
58 | *virt = mtd->priv + from; | 46 | *virt = mtd->priv + from; |
59 | *retlen = len; | 47 | *retlen = len; |
60 | return 0; | 48 | return 0; |
61 | } | 49 | } |
62 | 50 | ||
63 | static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | 51 | static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) |
64 | { | 52 | { |
53 | return 0; | ||
65 | } | 54 | } |
66 | 55 | ||
67 | /* | 56 | /* |
@@ -80,11 +69,7 @@ static unsigned long ram_get_unmapped_area(struct mtd_info *mtd, | |||
80 | static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, | 69 | static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, |
81 | size_t *retlen, u_char *buf) | 70 | size_t *retlen, u_char *buf) |
82 | { | 71 | { |
83 | if (from + len > mtd->size) | ||
84 | return -EINVAL; | ||
85 | |||
86 | memcpy(buf, mtd->priv + from, len); | 72 | memcpy(buf, mtd->priv + from, len); |
87 | |||
88 | *retlen = len; | 73 | *retlen = len; |
89 | return 0; | 74 | return 0; |
90 | } | 75 | } |
@@ -92,11 +77,7 @@ static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
92 | static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, | 77 | static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, |
93 | size_t *retlen, const u_char *buf) | 78 | size_t *retlen, const u_char *buf) |
94 | { | 79 | { |
95 | if (to + len > mtd->size) | ||
96 | return -EINVAL; | ||
97 | |||
98 | memcpy((char *)mtd->priv + to, buf, len); | 80 | memcpy((char *)mtd->priv + to, buf, len); |
99 | |||
100 | *retlen = len; | 81 | *retlen = len; |
101 | return 0; | 82 | return 0; |
102 | } | 83 | } |
@@ -126,12 +107,12 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, | |||
126 | mtd->priv = mapped_address; | 107 | mtd->priv = mapped_address; |
127 | 108 | ||
128 | mtd->owner = THIS_MODULE; | 109 | mtd->owner = THIS_MODULE; |
129 | mtd->erase = ram_erase; | 110 | mtd->_erase = ram_erase; |
130 | mtd->point = ram_point; | 111 | mtd->_point = ram_point; |
131 | mtd->unpoint = ram_unpoint; | 112 | mtd->_unpoint = ram_unpoint; |
132 | mtd->get_unmapped_area = ram_get_unmapped_area; | 113 | mtd->_get_unmapped_area = ram_get_unmapped_area; |
133 | mtd->read = ram_read; | 114 | mtd->_read = ram_read; |
134 | mtd->write = ram_write; | 115 | mtd->_write = ram_write; |
135 | 116 | ||
136 | if (mtd_device_register(mtd, NULL, 0)) | 117 | if (mtd_device_register(mtd, NULL, 0)) |
137 | return -EIO; | 118 | return -EIO; |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 23423bd00b06..67823de68db6 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -33,45 +33,33 @@ struct phram_mtd_list { | |||
33 | 33 | ||
34 | static LIST_HEAD(phram_list); | 34 | static LIST_HEAD(phram_list); |
35 | 35 | ||
36 | |||
37 | static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) | 36 | static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) |
38 | { | 37 | { |
39 | u_char *start = mtd->priv; | 38 | u_char *start = mtd->priv; |
40 | 39 | ||
41 | if (instr->addr + instr->len > mtd->size) | ||
42 | return -EINVAL; | ||
43 | |||
44 | memset(start + instr->addr, 0xff, instr->len); | 40 | memset(start + instr->addr, 0xff, instr->len); |
45 | 41 | ||
46 | /* This'll catch a few races. Free the thing before returning :) | 42 | /* |
43 | * This'll catch a few races. Free the thing before returning :) | ||
47 | * I don't feel at all ashamed. This kind of thing is possible anyway | 44 | * I don't feel at all ashamed. This kind of thing is possible anyway |
48 | * with flash, but unlikely. | 45 | * with flash, but unlikely. |
49 | */ | 46 | */ |
50 | |||
51 | instr->state = MTD_ERASE_DONE; | 47 | instr->state = MTD_ERASE_DONE; |
52 | |||
53 | mtd_erase_callback(instr); | 48 | mtd_erase_callback(instr); |
54 | |||
55 | return 0; | 49 | return 0; |
56 | } | 50 | } |
57 | 51 | ||
58 | static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, | 52 | static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, |
59 | size_t *retlen, void **virt, resource_size_t *phys) | 53 | size_t *retlen, void **virt, resource_size_t *phys) |
60 | { | 54 | { |
61 | if (from + len > mtd->size) | ||
62 | return -EINVAL; | ||
63 | |||
64 | /* can we return a physical address with this driver? */ | ||
65 | if (phys) | ||
66 | return -EINVAL; | ||
67 | |||
68 | *virt = mtd->priv + from; | 55 | *virt = mtd->priv + from; |
69 | *retlen = len; | 56 | *retlen = len; |
70 | return 0; | 57 | return 0; |
71 | } | 58 | } |
72 | 59 | ||
73 | static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | 60 | static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) |
74 | { | 61 | { |
62 | return 0; | ||
75 | } | 63 | } |
76 | 64 | ||
77 | static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, | 65 | static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, |
@@ -79,14 +67,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
79 | { | 67 | { |
80 | u_char *start = mtd->priv; | 68 | u_char *start = mtd->priv; |
81 | 69 | ||
82 | if (from >= mtd->size) | ||
83 | return -EINVAL; | ||
84 | |||
85 | if (len > mtd->size - from) | ||
86 | len = mtd->size - from; | ||
87 | |||
88 | memcpy(buf, start + from, len); | 70 | memcpy(buf, start + from, len); |
89 | |||
90 | *retlen = len; | 71 | *retlen = len; |
91 | return 0; | 72 | return 0; |
92 | } | 73 | } |
@@ -96,20 +77,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
96 | { | 77 | { |
97 | u_char *start = mtd->priv; | 78 | u_char *start = mtd->priv; |
98 | 79 | ||
99 | if (to >= mtd->size) | ||
100 | return -EINVAL; | ||
101 | |||
102 | if (len > mtd->size - to) | ||
103 | len = mtd->size - to; | ||
104 | |||
105 | memcpy(start + to, buf, len); | 80 | memcpy(start + to, buf, len); |
106 | |||
107 | *retlen = len; | 81 | *retlen = len; |
108 | return 0; | 82 | return 0; |
109 | } | 83 | } |
110 | 84 | ||
111 | |||
112 | |||
113 | static void unregister_devices(void) | 85 | static void unregister_devices(void) |
114 | { | 86 | { |
115 | struct phram_mtd_list *this, *safe; | 87 | struct phram_mtd_list *this, *safe; |
@@ -142,11 +114,11 @@ static int register_device(char *name, unsigned long start, unsigned long len) | |||
142 | new->mtd.name = name; | 114 | new->mtd.name = name; |
143 | new->mtd.size = len; | 115 | new->mtd.size = len; |
144 | new->mtd.flags = MTD_CAP_RAM; | 116 | new->mtd.flags = MTD_CAP_RAM; |
145 | new->mtd.erase = phram_erase; | 117 | new->mtd._erase = phram_erase; |
146 | new->mtd.point = phram_point; | 118 | new->mtd._point = phram_point; |
147 | new->mtd.unpoint = phram_unpoint; | 119 | new->mtd._unpoint = phram_unpoint; |
148 | new->mtd.read = phram_read; | 120 | new->mtd._read = phram_read; |
149 | new->mtd.write = phram_write; | 121 | new->mtd._write = phram_write; |
150 | new->mtd.owner = THIS_MODULE; | 122 | new->mtd.owner = THIS_MODULE; |
151 | new->mtd.type = MTD_RAM; | 123 | new->mtd.type = MTD_RAM; |
152 | new->mtd.erasesize = PAGE_SIZE; | 124 | new->mtd.erasesize = PAGE_SIZE; |
@@ -233,7 +205,17 @@ static inline void kill_final_newline(char *str) | |||
233 | return 1; \ | 205 | return 1; \ |
234 | } while (0) | 206 | } while (0) |
235 | 207 | ||
236 | static int phram_setup(const char *val, struct kernel_param *kp) | 208 | /* |
209 | * This shall contain the module parameter if any. It is of the form: | ||
210 | * - phram=<device>,<address>,<size> for module case | ||
211 | * - phram.phram=<device>,<address>,<size> for built-in case | ||
212 | * We leave 64 bytes for the device name, 12 for the address and 12 for the | ||
213 | * size. | ||
214 | * Example: phram.phram=rootfs,0xa0000000,512Mi | ||
215 | */ | ||
216 | static __initdata char phram_paramline[64+12+12]; | ||
217 | |||
218 | static int __init phram_setup(const char *val) | ||
237 | { | 219 | { |
238 | char buf[64+12+12], *str = buf; | 220 | char buf[64+12+12], *str = buf; |
239 | char *token[3]; | 221 | char *token[3]; |
@@ -282,12 +264,28 @@ static int phram_setup(const char *val, struct kernel_param *kp) | |||
282 | return ret; | 264 | return ret; |
283 | } | 265 | } |
284 | 266 | ||
285 | module_param_call(phram, phram_setup, NULL, NULL, 000); | 267 | static int __init phram_param_call(const char *val, struct kernel_param *kp) |
268 | { | ||
269 | /* | ||
270 | * This function is always called before 'init_phram()', whether | ||
271 | * built-in or module. | ||
272 | */ | ||
273 | if (strlen(val) >= sizeof(phram_paramline)) | ||
274 | return -ENOSPC; | ||
275 | strcpy(phram_paramline, val); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | module_param_call(phram, phram_param_call, NULL, NULL, 000); | ||
286 | MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\""); | 281 | MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\""); |
287 | 282 | ||
288 | 283 | ||
289 | static int __init init_phram(void) | 284 | static int __init init_phram(void) |
290 | { | 285 | { |
286 | if (phram_paramline[0]) | ||
287 | return phram_setup(phram_paramline); | ||
288 | |||
291 | return 0; | 289 | return 0; |
292 | } | 290 | } |
293 | 291 | ||
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 5d53c5760a6c..0c51b988e1f8 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c | |||
@@ -94,12 +94,48 @@ | |||
94 | #include <linux/ioctl.h> | 94 | #include <linux/ioctl.h> |
95 | #include <asm/io.h> | 95 | #include <asm/io.h> |
96 | #include <linux/pci.h> | 96 | #include <linux/pci.h> |
97 | |||
98 | #include <linux/mtd/mtd.h> | 97 | #include <linux/mtd/mtd.h> |
99 | #include <linux/mtd/pmc551.h> | 98 | |
99 | #define PMC551_VERSION \ | ||
100 | "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" | ||
101 | |||
102 | #define PCI_VENDOR_ID_V3_SEMI 0x11b0 | ||
103 | #define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 | ||
104 | |||
105 | #define PMC551_PCI_MEM_MAP0 0x50 | ||
106 | #define PMC551_PCI_MEM_MAP1 0x54 | ||
107 | #define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000 | ||
108 | #define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0 | ||
109 | #define PMC551_PCI_MEM_MAP_REG_EN 0x00000002 | ||
110 | #define PMC551_PCI_MEM_MAP_ENABLE 0x00000001 | ||
111 | |||
112 | #define PMC551_SDRAM_MA 0x60 | ||
113 | #define PMC551_SDRAM_CMD 0x62 | ||
114 | #define PMC551_DRAM_CFG 0x64 | ||
115 | #define PMC551_SYS_CTRL_REG 0x78 | ||
116 | |||
117 | #define PMC551_DRAM_BLK0 0x68 | ||
118 | #define PMC551_DRAM_BLK1 0x6c | ||
119 | #define PMC551_DRAM_BLK2 0x70 | ||
120 | #define PMC551_DRAM_BLK3 0x74 | ||
121 | #define PMC551_DRAM_BLK_GET_SIZE(x) (524288 << ((x >> 4) & 0x0f)) | ||
122 | #define PMC551_DRAM_BLK_SET_COL_MUX(x, v) (((x) & ~0x00007000) | (((v) & 0x7) << 12)) | ||
123 | #define PMC551_DRAM_BLK_SET_ROW_MUX(x, v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8)) | ||
124 | |||
125 | struct mypriv { | ||
126 | struct pci_dev *dev; | ||
127 | u_char *start; | ||
128 | u32 base_map0; | ||
129 | u32 curr_map0; | ||
130 | u32 asize; | ||
131 | struct mtd_info *nextpmc551; | ||
132 | }; | ||
100 | 133 | ||
101 | static struct mtd_info *pmc551list; | 134 | static struct mtd_info *pmc551list; |
102 | 135 | ||
136 | static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, | ||
137 | size_t *retlen, void **virt, resource_size_t *phys); | ||
138 | |||
103 | static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) | 139 | static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) |
104 | { | 140 | { |
105 | struct mypriv *priv = mtd->priv; | 141 | struct mypriv *priv = mtd->priv; |
@@ -115,16 +151,6 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
115 | #endif | 151 | #endif |
116 | 152 | ||
117 | end = instr->addr + instr->len - 1; | 153 | end = instr->addr + instr->len - 1; |
118 | |||
119 | /* Is it past the end? */ | ||
120 | if (end > mtd->size) { | ||
121 | #ifdef CONFIG_MTD_PMC551_DEBUG | ||
122 | printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n", | ||
123 | (long)end, (long)mtd->size); | ||
124 | #endif | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | eoff_hi = end & ~(priv->asize - 1); | 154 | eoff_hi = end & ~(priv->asize - 1); |
129 | soff_hi = instr->addr & ~(priv->asize - 1); | 155 | soff_hi = instr->addr & ~(priv->asize - 1); |
130 | eoff_lo = end & (priv->asize - 1); | 156 | eoff_lo = end & (priv->asize - 1); |
@@ -178,18 +204,6 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, | |||
178 | printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len); | 204 | printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len); |
179 | #endif | 205 | #endif |
180 | 206 | ||
181 | if (from + len > mtd->size) { | ||
182 | #ifdef CONFIG_MTD_PMC551_DEBUG | ||
183 | printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n", | ||
184 | (long)from + len, (long)mtd->size); | ||
185 | #endif | ||
186 | return -EINVAL; | ||
187 | } | ||
188 | |||
189 | /* can we return a physical address with this driver? */ | ||
190 | if (phys) | ||
191 | return -EINVAL; | ||
192 | |||
193 | soff_hi = from & ~(priv->asize - 1); | 207 | soff_hi = from & ~(priv->asize - 1); |
194 | soff_lo = from & (priv->asize - 1); | 208 | soff_lo = from & (priv->asize - 1); |
195 | 209 | ||
@@ -205,11 +219,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, | |||
205 | return 0; | 219 | return 0; |
206 | } | 220 | } |
207 | 221 | ||
208 | static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | 222 | static int pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len) |
209 | { | 223 | { |
210 | #ifdef CONFIG_MTD_PMC551_DEBUG | 224 | #ifdef CONFIG_MTD_PMC551_DEBUG |
211 | printk(KERN_DEBUG "pmc551_unpoint()\n"); | 225 | printk(KERN_DEBUG "pmc551_unpoint()\n"); |
212 | #endif | 226 | #endif |
227 | return 0; | ||
213 | } | 228 | } |
214 | 229 | ||
215 | static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, | 230 | static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, |
@@ -228,16 +243,6 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
228 | #endif | 243 | #endif |
229 | 244 | ||
230 | end = from + len - 1; | 245 | end = from + len - 1; |
231 | |||
232 | /* Is it past the end? */ | ||
233 | if (end > mtd->size) { | ||
234 | #ifdef CONFIG_MTD_PMC551_DEBUG | ||
235 | printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n", | ||
236 | (long)end, (long)mtd->size); | ||
237 | #endif | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | soff_hi = from & ~(priv->asize - 1); | 246 | soff_hi = from & ~(priv->asize - 1); |
242 | eoff_hi = end & ~(priv->asize - 1); | 247 | eoff_hi = end & ~(priv->asize - 1); |
243 | soff_lo = from & (priv->asize - 1); | 248 | soff_lo = from & (priv->asize - 1); |
@@ -295,16 +300,6 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
295 | #endif | 300 | #endif |
296 | 301 | ||
297 | end = to + len - 1; | 302 | end = to + len - 1; |
298 | /* Is it past the end? or did the u32 wrap? */ | ||
299 | if (end > mtd->size) { | ||
300 | #ifdef CONFIG_MTD_PMC551_DEBUG | ||
301 | printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, " | ||
302 | "size: %ld, to: %ld)\n", (long)end, (long)mtd->size, | ||
303 | (long)to); | ||
304 | #endif | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | soff_hi = to & ~(priv->asize - 1); | 303 | soff_hi = to & ~(priv->asize - 1); |
309 | eoff_hi = end & ~(priv->asize - 1); | 304 | eoff_hi = end & ~(priv->asize - 1); |
310 | soff_lo = to & (priv->asize - 1); | 305 | soff_lo = to & (priv->asize - 1); |
@@ -358,7 +353,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
358 | * mechanism | 353 | * mechanism |
359 | * returns the size of the memory region found. | 354 | * returns the size of the memory region found. |
360 | */ | 355 | */ |
361 | static u32 fixup_pmc551(struct pci_dev *dev) | 356 | static int fixup_pmc551(struct pci_dev *dev) |
362 | { | 357 | { |
363 | #ifdef CONFIG_MTD_PMC551_BUGFIX | 358 | #ifdef CONFIG_MTD_PMC551_BUGFIX |
364 | u32 dram_data; | 359 | u32 dram_data; |
@@ -668,7 +663,7 @@ static int __init init_pmc551(void) | |||
668 | struct mypriv *priv; | 663 | struct mypriv *priv; |
669 | int found = 0; | 664 | int found = 0; |
670 | struct mtd_info *mtd; | 665 | struct mtd_info *mtd; |
671 | u32 length = 0; | 666 | int length = 0; |
672 | 667 | ||
673 | if (msize) { | 668 | if (msize) { |
674 | msize = (1 << (ffs(msize) - 1)) << 20; | 669 | msize = (1 << (ffs(msize) - 1)) << 20; |
@@ -786,11 +781,11 @@ static int __init init_pmc551(void) | |||
786 | 781 | ||
787 | mtd->size = msize; | 782 | mtd->size = msize; |
788 | mtd->flags = MTD_CAP_RAM; | 783 | mtd->flags = MTD_CAP_RAM; |
789 | mtd->erase = pmc551_erase; | 784 | mtd->_erase = pmc551_erase; |
790 | mtd->read = pmc551_read; | 785 | mtd->_read = pmc551_read; |
791 | mtd->write = pmc551_write; | 786 | mtd->_write = pmc551_write; |
792 | mtd->point = pmc551_point; | 787 | mtd->_point = pmc551_point; |
793 | mtd->unpoint = pmc551_unpoint; | 788 | mtd->_unpoint = pmc551_unpoint; |
794 | mtd->type = MTD_RAM; | 789 | mtd->type = MTD_RAM; |
795 | mtd->name = "PMC551 RAM board"; | 790 | mtd->name = "PMC551 RAM board"; |
796 | mtd->erasesize = 0x10000; | 791 | mtd->erasesize = 0x10000; |
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 288594163c22..8f52fc858e48 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c | |||
@@ -75,7 +75,7 @@ static slram_mtd_list_t *slram_mtdlist = NULL; | |||
75 | static int slram_erase(struct mtd_info *, struct erase_info *); | 75 | static int slram_erase(struct mtd_info *, struct erase_info *); |
76 | static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **, | 76 | static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **, |
77 | resource_size_t *); | 77 | resource_size_t *); |
78 | static void slram_unpoint(struct mtd_info *, loff_t, size_t); | 78 | static int slram_unpoint(struct mtd_info *, loff_t, size_t); |
79 | static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 79 | static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
80 | static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 80 | static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
81 | 81 | ||
@@ -83,21 +83,13 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
83 | { | 83 | { |
84 | slram_priv_t *priv = mtd->priv; | 84 | slram_priv_t *priv = mtd->priv; |
85 | 85 | ||
86 | if (instr->addr + instr->len > mtd->size) { | ||
87 | return(-EINVAL); | ||
88 | } | ||
89 | |||
90 | memset(priv->start + instr->addr, 0xff, instr->len); | 86 | memset(priv->start + instr->addr, 0xff, instr->len); |
91 | |||
92 | /* This'll catch a few races. Free the thing before returning :) | 87 | /* This'll catch a few races. Free the thing before returning :) |
93 | * I don't feel at all ashamed. This kind of thing is possible anyway | 88 | * I don't feel at all ashamed. This kind of thing is possible anyway |
94 | * with flash, but unlikely. | 89 | * with flash, but unlikely. |
95 | */ | 90 | */ |
96 | |||
97 | instr->state = MTD_ERASE_DONE; | 91 | instr->state = MTD_ERASE_DONE; |
98 | |||
99 | mtd_erase_callback(instr); | 92 | mtd_erase_callback(instr); |
100 | |||
101 | return(0); | 93 | return(0); |
102 | } | 94 | } |
103 | 95 | ||
@@ -106,20 +98,14 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len, | |||
106 | { | 98 | { |
107 | slram_priv_t *priv = mtd->priv; | 99 | slram_priv_t *priv = mtd->priv; |
108 | 100 | ||
109 | /* can we return a physical address with this driver? */ | ||
110 | if (phys) | ||
111 | return -EINVAL; | ||
112 | |||
113 | if (from + len > mtd->size) | ||
114 | return -EINVAL; | ||
115 | |||
116 | *virt = priv->start + from; | 101 | *virt = priv->start + from; |
117 | *retlen = len; | 102 | *retlen = len; |
118 | return(0); | 103 | return(0); |
119 | } | 104 | } |
120 | 105 | ||
121 | static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | 106 | static int slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) |
122 | { | 107 | { |
108 | return 0; | ||
123 | } | 109 | } |
124 | 110 | ||
125 | static int slram_read(struct mtd_info *mtd, loff_t from, size_t len, | 111 | static int slram_read(struct mtd_info *mtd, loff_t from, size_t len, |
@@ -127,14 +113,7 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
127 | { | 113 | { |
128 | slram_priv_t *priv = mtd->priv; | 114 | slram_priv_t *priv = mtd->priv; |
129 | 115 | ||
130 | if (from > mtd->size) | ||
131 | return -EINVAL; | ||
132 | |||
133 | if (from + len > mtd->size) | ||
134 | len = mtd->size - from; | ||
135 | |||
136 | memcpy(buf, priv->start + from, len); | 116 | memcpy(buf, priv->start + from, len); |
137 | |||
138 | *retlen = len; | 117 | *retlen = len; |
139 | return(0); | 118 | return(0); |
140 | } | 119 | } |
@@ -144,11 +123,7 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
144 | { | 123 | { |
145 | slram_priv_t *priv = mtd->priv; | 124 | slram_priv_t *priv = mtd->priv; |
146 | 125 | ||
147 | if (to + len > mtd->size) | ||
148 | return -EINVAL; | ||
149 | |||
150 | memcpy(priv->start + to, buf, len); | 126 | memcpy(priv->start + to, buf, len); |
151 | |||
152 | *retlen = len; | 127 | *retlen = len; |
153 | return(0); | 128 | return(0); |
154 | } | 129 | } |
@@ -199,11 +174,11 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
199 | (*curmtd)->mtdinfo->name = name; | 174 | (*curmtd)->mtdinfo->name = name; |
200 | (*curmtd)->mtdinfo->size = length; | 175 | (*curmtd)->mtdinfo->size = length; |
201 | (*curmtd)->mtdinfo->flags = MTD_CAP_RAM; | 176 | (*curmtd)->mtdinfo->flags = MTD_CAP_RAM; |
202 | (*curmtd)->mtdinfo->erase = slram_erase; | 177 | (*curmtd)->mtdinfo->_erase = slram_erase; |
203 | (*curmtd)->mtdinfo->point = slram_point; | 178 | (*curmtd)->mtdinfo->_point = slram_point; |
204 | (*curmtd)->mtdinfo->unpoint = slram_unpoint; | 179 | (*curmtd)->mtdinfo->_unpoint = slram_unpoint; |
205 | (*curmtd)->mtdinfo->read = slram_read; | 180 | (*curmtd)->mtdinfo->_read = slram_read; |
206 | (*curmtd)->mtdinfo->write = slram_write; | 181 | (*curmtd)->mtdinfo->_write = slram_write; |
207 | (*curmtd)->mtdinfo->owner = THIS_MODULE; | 182 | (*curmtd)->mtdinfo->owner = THIS_MODULE; |
208 | (*curmtd)->mtdinfo->type = MTD_RAM; | 183 | (*curmtd)->mtdinfo->type = MTD_RAM; |
209 | (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; | 184 | (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; |
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c new file mode 100644 index 000000000000..797d43cd3550 --- /dev/null +++ b/drivers/mtd/devices/spear_smi.c | |||
@@ -0,0 +1,1147 @@ | |||
1 | /* | ||
2 | * SMI (Serial Memory Controller) device driver for Serial NOR Flash on | ||
3 | * SPEAr platform | ||
4 | * The serial nor interface is largely based on drivers/mtd/m25p80.c, | ||
5 | * however the SPI interface has been replaced by SMI. | ||
6 | * | ||
7 | * Copyright © 2010 STMicroelectronics. | ||
8 | * Ashish Priyadarshi | ||
9 | * Shiraz Hashim <shiraz.hashim@st.com> | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public | ||
12 | * License version 2. This program is licensed "as is" without any | ||
13 | * warranty of any kind, whether express or implied. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/param.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/mtd/mtd.h> | ||
30 | #include <linux/mtd/partitions.h> | ||
31 | #include <linux/mtd/spear_smi.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/sched.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <linux/of.h> | ||
37 | #include <linux/of_address.h> | ||
38 | |||
39 | /* SMI clock rate */ | ||
40 | #define SMI_MAX_CLOCK_FREQ 50000000 /* 50 MHz */ | ||
41 | |||
42 | /* MAX time out to safely come out of a erase or write busy conditions */ | ||
43 | #define SMI_PROBE_TIMEOUT (HZ / 10) | ||
44 | #define SMI_MAX_TIME_OUT (3 * HZ) | ||
45 | |||
46 | /* timeout for command completion */ | ||
47 | #define SMI_CMD_TIMEOUT (HZ / 10) | ||
48 | |||
49 | /* registers of smi */ | ||
50 | #define SMI_CR1 0x0 /* SMI control register 1 */ | ||
51 | #define SMI_CR2 0x4 /* SMI control register 2 */ | ||
52 | #define SMI_SR 0x8 /* SMI status register */ | ||
53 | #define SMI_TR 0xC /* SMI transmit register */ | ||
54 | #define SMI_RR 0x10 /* SMI receive register */ | ||
55 | |||
56 | /* defines for control_reg 1 */ | ||
57 | #define BANK_EN (0xF << 0) /* enables all banks */ | ||
58 | #define DSEL_TIME (0x6 << 4) /* Deselect time 6 + 1 SMI_CK periods */ | ||
59 | #define SW_MODE (0x1 << 28) /* enables SW Mode */ | ||
60 | #define WB_MODE (0x1 << 29) /* Write Burst Mode */ | ||
61 | #define FAST_MODE (0x1 << 15) /* Fast Mode */ | ||
62 | #define HOLD1 (0x1 << 16) /* Clock Hold period selection */ | ||
63 | |||
64 | /* defines for control_reg 2 */ | ||
65 | #define SEND (0x1 << 7) /* Send data */ | ||
66 | #define TFIE (0x1 << 8) /* Transmission Flag Interrupt Enable */ | ||
67 | #define WCIE (0x1 << 9) /* Write Complete Interrupt Enable */ | ||
68 | #define RD_STATUS_REG (0x1 << 10) /* reads status reg */ | ||
69 | #define WE (0x1 << 11) /* Write Enable */ | ||
70 | |||
71 | #define TX_LEN_SHIFT 0 | ||
72 | #define RX_LEN_SHIFT 4 | ||
73 | #define BANK_SHIFT 12 | ||
74 | |||
75 | /* defines for status register */ | ||
76 | #define SR_WIP 0x1 /* Write in progress */ | ||
77 | #define SR_WEL 0x2 /* Write enable latch */ | ||
78 | #define SR_BP0 0x4 /* Block protect 0 */ | ||
79 | #define SR_BP1 0x8 /* Block protect 1 */ | ||
80 | #define SR_BP2 0x10 /* Block protect 2 */ | ||
81 | #define SR_SRWD 0x80 /* SR write protect */ | ||
82 | #define TFF 0x100 /* Transfer Finished Flag */ | ||
83 | #define WCF 0x200 /* Transfer Finished Flag */ | ||
84 | #define ERF1 0x400 /* Forbidden Write Request */ | ||
85 | #define ERF2 0x800 /* Forbidden Access */ | ||
86 | |||
87 | #define WM_SHIFT 12 | ||
88 | |||
89 | /* flash opcodes */ | ||
90 | #define OPCODE_RDID 0x9f /* Read JEDEC ID */ | ||
91 | |||
92 | /* Flash Device Ids maintenance section */ | ||
93 | |||
94 | /* data structure to maintain flash ids from different vendors */ | ||
95 | struct flash_device { | ||
96 | char *name; | ||
97 | u8 erase_cmd; | ||
98 | u32 device_id; | ||
99 | u32 pagesize; | ||
100 | unsigned long sectorsize; | ||
101 | unsigned long size_in_bytes; | ||
102 | }; | ||
103 | |||
104 | #define FLASH_ID(n, es, id, psize, ssize, size) \ | ||
105 | { \ | ||
106 | .name = n, \ | ||
107 | .erase_cmd = es, \ | ||
108 | .device_id = id, \ | ||
109 | .pagesize = psize, \ | ||
110 | .sectorsize = ssize, \ | ||
111 | .size_in_bytes = size \ | ||
112 | } | ||
113 | |||
114 | static struct flash_device flash_devices[] = { | ||
115 | FLASH_ID("st m25p16" , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000), | ||
116 | FLASH_ID("st m25p32" , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000), | ||
117 | FLASH_ID("st m25p64" , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000), | ||
118 | FLASH_ID("st m25p128" , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000), | ||
119 | FLASH_ID("st m25p05" , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000), | ||
120 | FLASH_ID("st m25p10" , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000), | ||
121 | FLASH_ID("st m25p20" , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000), | ||
122 | FLASH_ID("st m25p40" , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000), | ||
123 | FLASH_ID("st m25p80" , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000), | ||
124 | FLASH_ID("st m45pe10" , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), | ||
125 | FLASH_ID("st m45pe20" , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), | ||
126 | FLASH_ID("st m45pe40" , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), | ||
127 | FLASH_ID("st m45pe80" , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), | ||
128 | FLASH_ID("sp s25fl004" , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000), | ||
129 | FLASH_ID("sp s25fl008" , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000), | ||
130 | FLASH_ID("sp s25fl016" , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000), | ||
131 | FLASH_ID("sp s25fl032" , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000), | ||
132 | FLASH_ID("sp s25fl064" , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000), | ||
133 | FLASH_ID("atmel 25f512" , 0x52, 0x0065001F, 0x80 , 0x8000 , 0x10000), | ||
134 | FLASH_ID("atmel 25f1024" , 0x52, 0x0060001F, 0x100, 0x8000 , 0x20000), | ||
135 | FLASH_ID("atmel 25f2048" , 0x52, 0x0063001F, 0x100, 0x10000, 0x40000), | ||
136 | FLASH_ID("atmel 25f4096" , 0x52, 0x0064001F, 0x100, 0x10000, 0x80000), | ||
137 | FLASH_ID("atmel 25fs040" , 0xd7, 0x0004661F, 0x100, 0x10000, 0x80000), | ||
138 | FLASH_ID("mac 25l512" , 0xd8, 0x001020C2, 0x010, 0x10000, 0x10000), | ||
139 | FLASH_ID("mac 25l1005" , 0xd8, 0x001120C2, 0x010, 0x10000, 0x20000), | ||
140 | FLASH_ID("mac 25l2005" , 0xd8, 0x001220C2, 0x010, 0x10000, 0x40000), | ||
141 | FLASH_ID("mac 25l4005" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000), | ||
142 | FLASH_ID("mac 25l4005a" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000), | ||
143 | FLASH_ID("mac 25l8005" , 0xd8, 0x001420C2, 0x010, 0x10000, 0x100000), | ||
144 | FLASH_ID("mac 25l1605" , 0xd8, 0x001520C2, 0x100, 0x10000, 0x200000), | ||
145 | FLASH_ID("mac 25l1605a" , 0xd8, 0x001520C2, 0x010, 0x10000, 0x200000), | ||
146 | FLASH_ID("mac 25l3205" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000), | ||
147 | FLASH_ID("mac 25l3205a" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000), | ||
148 | FLASH_ID("mac 25l6405" , 0xd8, 0x001720C2, 0x100, 0x10000, 0x800000), | ||
149 | }; | ||
150 | |||
151 | /* Define spear specific structures */ | ||
152 | |||
153 | struct spear_snor_flash; | ||
154 | |||
155 | /** | ||
156 | * struct spear_smi - Structure for SMI Device | ||
157 | * | ||
158 | * @clk: functional clock | ||
159 | * @status: current status register of SMI. | ||
160 | * @clk_rate: functional clock rate of SMI (default: SMI_MAX_CLOCK_FREQ) | ||
161 | * @lock: lock to prevent parallel access of SMI. | ||
162 | * @io_base: base address for registers of SMI. | ||
163 | * @pdev: platform device | ||
164 | * @cmd_complete: queue to wait for command completion of NOR-flash. | ||
165 | * @num_flashes: number of flashes actually present on board. | ||
166 | * @flash: separate structure for each Serial NOR-flash attached to SMI. | ||
167 | */ | ||
168 | struct spear_smi { | ||
169 | struct clk *clk; | ||
170 | u32 status; | ||
171 | unsigned long clk_rate; | ||
172 | struct mutex lock; | ||
173 | void __iomem *io_base; | ||
174 | struct platform_device *pdev; | ||
175 | wait_queue_head_t cmd_complete; | ||
176 | u32 num_flashes; | ||
177 | struct spear_snor_flash *flash[MAX_NUM_FLASH_CHIP]; | ||
178 | }; | ||
179 | |||
180 | /** | ||
181 | * struct spear_snor_flash - Structure for Serial NOR Flash | ||
182 | * | ||
183 | * @bank: Bank number(0, 1, 2, 3) for each NOR-flash. | ||
184 | * @dev_id: Device ID of NOR-flash. | ||
185 | * @lock: lock to manage flash read, write and erase operations | ||
186 | * @mtd: MTD info for each NOR-flash. | ||
187 | * @num_parts: Total number of partition in each bank of NOR-flash. | ||
188 | * @parts: Partition info for each bank of NOR-flash. | ||
189 | * @page_size: Page size of NOR-flash. | ||
190 | * @base_addr: Base address of NOR-flash. | ||
191 | * @erase_cmd: erase command may vary on different flash types | ||
192 | * @fast_mode: flash supports read in fast mode | ||
193 | */ | ||
194 | struct spear_snor_flash { | ||
195 | u32 bank; | ||
196 | u32 dev_id; | ||
197 | struct mutex lock; | ||
198 | struct mtd_info mtd; | ||
199 | u32 num_parts; | ||
200 | struct mtd_partition *parts; | ||
201 | u32 page_size; | ||
202 | void __iomem *base_addr; | ||
203 | u8 erase_cmd; | ||
204 | u8 fast_mode; | ||
205 | }; | ||
206 | |||
207 | static inline struct spear_snor_flash *get_flash_data(struct mtd_info *mtd) | ||
208 | { | ||
209 | return container_of(mtd, struct spear_snor_flash, mtd); | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * spear_smi_read_sr - Read status register of flash through SMI | ||
214 | * @dev: structure of SMI information. | ||
215 | * @bank: bank to which flash is connected | ||
216 | * | ||
217 | * This routine will return the status register of the flash chip present at the | ||
218 | * given bank. | ||
219 | */ | ||
220 | static int spear_smi_read_sr(struct spear_smi *dev, u32 bank) | ||
221 | { | ||
222 | int ret; | ||
223 | u32 ctrlreg1; | ||
224 | |||
225 | mutex_lock(&dev->lock); | ||
226 | dev->status = 0; /* Will be set in interrupt handler */ | ||
227 | |||
228 | ctrlreg1 = readl(dev->io_base + SMI_CR1); | ||
229 | /* program smi in hw mode */ | ||
230 | writel(ctrlreg1 & ~(SW_MODE | WB_MODE), dev->io_base + SMI_CR1); | ||
231 | |||
232 | /* performing a rsr instruction in hw mode */ | ||
233 | writel((bank << BANK_SHIFT) | RD_STATUS_REG | TFIE, | ||
234 | dev->io_base + SMI_CR2); | ||
235 | |||
236 | /* wait for tff */ | ||
237 | ret = wait_event_interruptible_timeout(dev->cmd_complete, | ||
238 | dev->status & TFF, SMI_CMD_TIMEOUT); | ||
239 | |||
240 | /* copy dev->status (lower 16 bits) in order to release lock */ | ||
241 | if (ret > 0) | ||
242 | ret = dev->status & 0xffff; | ||
243 | else | ||
244 | ret = -EIO; | ||
245 | |||
246 | /* restore the ctrl regs state */ | ||
247 | writel(ctrlreg1, dev->io_base + SMI_CR1); | ||
248 | writel(0, dev->io_base + SMI_CR2); | ||
249 | mutex_unlock(&dev->lock); | ||
250 | |||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * spear_smi_wait_till_ready - wait till flash is ready | ||
256 | * @dev: structure of SMI information. | ||
257 | * @bank: flash corresponding to this bank | ||
258 | * @timeout: timeout for busy wait condition | ||
259 | * | ||
260 | * This routine checks for WIP (write in progress) bit in Status register | ||
261 | * If successful the routine returns 0 else -EBUSY | ||
262 | */ | ||
263 | static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank, | ||
264 | unsigned long timeout) | ||
265 | { | ||
266 | unsigned long finish; | ||
267 | int status; | ||
268 | |||
269 | finish = jiffies + timeout; | ||
270 | do { | ||
271 | status = spear_smi_read_sr(dev, bank); | ||
272 | if (status < 0) | ||
273 | continue; /* try till timeout */ | ||
274 | else if (!(status & SR_WIP)) | ||
275 | return 0; | ||
276 | |||
277 | cond_resched(); | ||
278 | } while (!time_after_eq(jiffies, finish)); | ||
279 | |||
280 | dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n"); | ||
281 | return status; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * spear_smi_int_handler - SMI Interrupt Handler. | ||
286 | * @irq: irq number | ||
287 | * @dev_id: structure of SMI device, embedded in dev_id. | ||
288 | * | ||
289 | * The handler clears all interrupt conditions and records the status in | ||
290 | * dev->status which is used by the driver later. | ||
291 | */ | ||
292 | static irqreturn_t spear_smi_int_handler(int irq, void *dev_id) | ||
293 | { | ||
294 | u32 status = 0; | ||
295 | struct spear_smi *dev = dev_id; | ||
296 | |||
297 | status = readl(dev->io_base + SMI_SR); | ||
298 | |||
299 | if (unlikely(!status)) | ||
300 | return IRQ_NONE; | ||
301 | |||
302 | /* clear all interrupt conditions */ | ||
303 | writel(0, dev->io_base + SMI_SR); | ||
304 | |||
305 | /* copy the status register in dev->status */ | ||
306 | dev->status |= status; | ||
307 | |||
308 | /* send the completion */ | ||
309 | wake_up_interruptible(&dev->cmd_complete); | ||
310 | |||
311 | return IRQ_HANDLED; | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * spear_smi_hw_init - initializes the smi controller. | ||
316 | * @dev: structure of smi device | ||
317 | * | ||
318 | * this routine initializes the smi controller wit the default values | ||
319 | */ | ||
320 | static void spear_smi_hw_init(struct spear_smi *dev) | ||
321 | { | ||
322 | unsigned long rate = 0; | ||
323 | u32 prescale = 0; | ||
324 | u32 val; | ||
325 | |||
326 | rate = clk_get_rate(dev->clk); | ||
327 | |||
328 | /* functional clock of smi */ | ||
329 | prescale = DIV_ROUND_UP(rate, dev->clk_rate); | ||
330 | |||
331 | /* | ||
332 | * setting the standard values, fast mode, prescaler for | ||
333 | * SMI_MAX_CLOCK_FREQ (50MHz) operation and bank enable | ||
334 | */ | ||
335 | val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8); | ||
336 | |||
337 | mutex_lock(&dev->lock); | ||
338 | writel(val, dev->io_base + SMI_CR1); | ||
339 | mutex_unlock(&dev->lock); | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * get_flash_index - match chip id from a flash list. | ||
344 | * @flash_id: a valid nor flash chip id obtained from board. | ||
345 | * | ||
346 | * try to validate the chip id by matching from a list, if not found then simply | ||
347 | * returns negative. In case of success returns index in to the flash devices | ||
348 | * array. | ||
349 | */ | ||
350 | static int get_flash_index(u32 flash_id) | ||
351 | { | ||
352 | int index; | ||
353 | |||
354 | /* Matches chip-id to entire list of 'serial-nor flash' ids */ | ||
355 | for (index = 0; index < ARRAY_SIZE(flash_devices); index++) { | ||
356 | if (flash_devices[index].device_id == flash_id) | ||
357 | return index; | ||
358 | } | ||
359 | |||
360 | /* Memory chip is not listed and not supported */ | ||
361 | return -ENODEV; | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * spear_smi_write_enable - Enable the flash to do write operation | ||
366 | * @dev: structure of SMI device | ||
367 | * @bank: enable write for flash connected to this bank | ||
368 | * | ||
369 | * Set write enable latch with Write Enable command. | ||
370 | * Returns 0 on success. | ||
371 | */ | ||
372 | static int spear_smi_write_enable(struct spear_smi *dev, u32 bank) | ||
373 | { | ||
374 | int ret; | ||
375 | u32 ctrlreg1; | ||
376 | |||
377 | mutex_lock(&dev->lock); | ||
378 | dev->status = 0; /* Will be set in interrupt handler */ | ||
379 | |||
380 | ctrlreg1 = readl(dev->io_base + SMI_CR1); | ||
381 | /* program smi in h/w mode */ | ||
382 | writel(ctrlreg1 & ~SW_MODE, dev->io_base + SMI_CR1); | ||
383 | |||
384 | /* give the flash, write enable command */ | ||
385 | writel((bank << BANK_SHIFT) | WE | TFIE, dev->io_base + SMI_CR2); | ||
386 | |||
387 | ret = wait_event_interruptible_timeout(dev->cmd_complete, | ||
388 | dev->status & TFF, SMI_CMD_TIMEOUT); | ||
389 | |||
390 | /* restore the ctrl regs state */ | ||
391 | writel(ctrlreg1, dev->io_base + SMI_CR1); | ||
392 | writel(0, dev->io_base + SMI_CR2); | ||
393 | |||
394 | if (ret <= 0) { | ||
395 | ret = -EIO; | ||
396 | dev_err(&dev->pdev->dev, | ||
397 | "smi controller failed on write enable\n"); | ||
398 | } else { | ||
399 | /* check whether write mode status is set for required bank */ | ||
400 | if (dev->status & (1 << (bank + WM_SHIFT))) | ||
401 | ret = 0; | ||
402 | else { | ||
403 | dev_err(&dev->pdev->dev, "couldn't enable write\n"); | ||
404 | ret = -EIO; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | mutex_unlock(&dev->lock); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static inline u32 | ||
413 | get_sector_erase_cmd(struct spear_snor_flash *flash, u32 offset) | ||
414 | { | ||
415 | u32 cmd; | ||
416 | u8 *x = (u8 *)&cmd; | ||
417 | |||
418 | x[0] = flash->erase_cmd; | ||
419 | x[1] = offset >> 16; | ||
420 | x[2] = offset >> 8; | ||
421 | x[3] = offset; | ||
422 | |||
423 | return cmd; | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * spear_smi_erase_sector - erase one sector of flash | ||
428 | * @dev: structure of SMI information | ||
429 | * @command: erase command to be send | ||
430 | * @bank: bank to which this command needs to be send | ||
431 | * @bytes: size of command | ||
432 | * | ||
433 | * Erase one sector of flash memory at offset ``offset'' which is any | ||
434 | * address within the sector which should be erased. | ||
435 | * Returns 0 if successful, non-zero otherwise. | ||
436 | */ | ||
437 | static int spear_smi_erase_sector(struct spear_smi *dev, | ||
438 | u32 bank, u32 command, u32 bytes) | ||
439 | { | ||
440 | u32 ctrlreg1 = 0; | ||
441 | int ret; | ||
442 | |||
443 | ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT); | ||
444 | if (ret) | ||
445 | return ret; | ||
446 | |||
447 | ret = spear_smi_write_enable(dev, bank); | ||
448 | if (ret) | ||
449 | return ret; | ||
450 | |||
451 | mutex_lock(&dev->lock); | ||
452 | |||
453 | ctrlreg1 = readl(dev->io_base + SMI_CR1); | ||
454 | writel((ctrlreg1 | SW_MODE) & ~WB_MODE, dev->io_base + SMI_CR1); | ||
455 | |||
456 | /* send command in sw mode */ | ||
457 | writel(command, dev->io_base + SMI_TR); | ||
458 | |||
459 | writel((bank << BANK_SHIFT) | SEND | TFIE | (bytes << TX_LEN_SHIFT), | ||
460 | dev->io_base + SMI_CR2); | ||
461 | |||
462 | ret = wait_event_interruptible_timeout(dev->cmd_complete, | ||
463 | dev->status & TFF, SMI_CMD_TIMEOUT); | ||
464 | |||
465 | if (ret <= 0) { | ||
466 | ret = -EIO; | ||
467 | dev_err(&dev->pdev->dev, "sector erase failed\n"); | ||
468 | } else | ||
469 | ret = 0; /* success */ | ||
470 | |||
471 | /* restore ctrl regs */ | ||
472 | writel(ctrlreg1, dev->io_base + SMI_CR1); | ||
473 | writel(0, dev->io_base + SMI_CR2); | ||
474 | |||
475 | mutex_unlock(&dev->lock); | ||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * spear_mtd_erase - perform flash erase operation as requested by user | ||
481 | * @mtd: Provides the memory characteristics | ||
482 | * @e_info: Provides the erase information | ||
483 | * | ||
484 | * Erase an address range on the flash chip. The address range may extend | ||
485 | * one or more erase sectors. Return an error is there is a problem erasing. | ||
486 | */ | ||
487 | static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info) | ||
488 | { | ||
489 | struct spear_snor_flash *flash = get_flash_data(mtd); | ||
490 | struct spear_smi *dev = mtd->priv; | ||
491 | u32 addr, command, bank; | ||
492 | int len, ret; | ||
493 | |||
494 | if (!flash || !dev) | ||
495 | return -ENODEV; | ||
496 | |||
497 | bank = flash->bank; | ||
498 | if (bank > dev->num_flashes - 1) { | ||
499 | dev_err(&dev->pdev->dev, "Invalid Bank Num"); | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | addr = e_info->addr; | ||
504 | len = e_info->len; | ||
505 | |||
506 | mutex_lock(&flash->lock); | ||
507 | |||
508 | /* now erase sectors in loop */ | ||
509 | while (len) { | ||
510 | command = get_sector_erase_cmd(flash, addr); | ||
511 | /* preparing the command for flash */ | ||
512 | ret = spear_smi_erase_sector(dev, bank, command, 4); | ||
513 | if (ret) { | ||
514 | e_info->state = MTD_ERASE_FAILED; | ||
515 | mutex_unlock(&flash->lock); | ||
516 | return ret; | ||
517 | } | ||
518 | addr += mtd->erasesize; | ||
519 | len -= mtd->erasesize; | ||
520 | } | ||
521 | |||
522 | mutex_unlock(&flash->lock); | ||
523 | e_info->state = MTD_ERASE_DONE; | ||
524 | mtd_erase_callback(e_info); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * spear_mtd_read - performs flash read operation as requested by the user | ||
531 | * @mtd: MTD information of the memory bank | ||
532 | * @from: Address from which to start read | ||
533 | * @len: Number of bytes to be read | ||
534 | * @retlen: Fills the Number of bytes actually read | ||
535 | * @buf: Fills this after reading | ||
536 | * | ||
537 | * Read an address range from the flash chip. The address range | ||
538 | * may be any size provided it is within the physical boundaries. | ||
539 | * Returns 0 on success, non zero otherwise | ||
540 | */ | ||
541 | static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
542 | size_t *retlen, u8 *buf) | ||
543 | { | ||
544 | struct spear_snor_flash *flash = get_flash_data(mtd); | ||
545 | struct spear_smi *dev = mtd->priv; | ||
546 | void *src; | ||
547 | u32 ctrlreg1, val; | ||
548 | int ret; | ||
549 | |||
550 | if (!flash || !dev) | ||
551 | return -ENODEV; | ||
552 | |||
553 | if (flash->bank > dev->num_flashes - 1) { | ||
554 | dev_err(&dev->pdev->dev, "Invalid Bank Num"); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | /* select address as per bank number */ | ||
559 | src = flash->base_addr + from; | ||
560 | |||
561 | mutex_lock(&flash->lock); | ||
562 | |||
563 | /* wait till previous write/erase is done. */ | ||
564 | ret = spear_smi_wait_till_ready(dev, flash->bank, SMI_MAX_TIME_OUT); | ||
565 | if (ret) { | ||
566 | mutex_unlock(&flash->lock); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | mutex_lock(&dev->lock); | ||
571 | /* put smi in hw mode not wbt mode */ | ||
572 | ctrlreg1 = val = readl(dev->io_base + SMI_CR1); | ||
573 | val &= ~(SW_MODE | WB_MODE); | ||
574 | if (flash->fast_mode) | ||
575 | val |= FAST_MODE; | ||
576 | |||
577 | writel(val, dev->io_base + SMI_CR1); | ||
578 | |||
579 | memcpy_fromio(buf, (u8 *)src, len); | ||
580 | |||
581 | /* restore ctrl reg1 */ | ||
582 | writel(ctrlreg1, dev->io_base + SMI_CR1); | ||
583 | mutex_unlock(&dev->lock); | ||
584 | |||
585 | *retlen = len; | ||
586 | mutex_unlock(&flash->lock); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank, | ||
592 | void *dest, const void *src, size_t len) | ||
593 | { | ||
594 | int ret; | ||
595 | u32 ctrlreg1; | ||
596 | |||
597 | /* wait until finished previous write command. */ | ||
598 | ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT); | ||
599 | if (ret) | ||
600 | return ret; | ||
601 | |||
602 | /* put smi in write enable */ | ||
603 | ret = spear_smi_write_enable(dev, bank); | ||
604 | if (ret) | ||
605 | return ret; | ||
606 | |||
607 | /* put smi in hw, write burst mode */ | ||
608 | mutex_lock(&dev->lock); | ||
609 | |||
610 | ctrlreg1 = readl(dev->io_base + SMI_CR1); | ||
611 | writel((ctrlreg1 | WB_MODE) & ~SW_MODE, dev->io_base + SMI_CR1); | ||
612 | |||
613 | memcpy_toio(dest, src, len); | ||
614 | |||
615 | writel(ctrlreg1, dev->io_base + SMI_CR1); | ||
616 | |||
617 | mutex_unlock(&dev->lock); | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * spear_mtd_write - performs write operation as requested by the user. | ||
623 | * @mtd: MTD information of the memory bank. | ||
624 | * @to: Address to write. | ||
625 | * @len: Number of bytes to be written. | ||
626 | * @retlen: Number of bytes actually wrote. | ||
627 | * @buf: Buffer from which the data to be taken. | ||
628 | * | ||
629 | * Write an address range to the flash chip. Data must be written in | ||
630 | * flash_page_size chunks. The address range may be any size provided | ||
631 | * it is within the physical boundaries. | ||
632 | * Returns 0 on success, non zero otherwise | ||
633 | */ | ||
634 | static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
635 | size_t *retlen, const u8 *buf) | ||
636 | { | ||
637 | struct spear_snor_flash *flash = get_flash_data(mtd); | ||
638 | struct spear_smi *dev = mtd->priv; | ||
639 | void *dest; | ||
640 | u32 page_offset, page_size; | ||
641 | int ret; | ||
642 | |||
643 | if (!flash || !dev) | ||
644 | return -ENODEV; | ||
645 | |||
646 | if (flash->bank > dev->num_flashes - 1) { | ||
647 | dev_err(&dev->pdev->dev, "Invalid Bank Num"); | ||
648 | return -EINVAL; | ||
649 | } | ||
650 | |||
651 | /* select address as per bank number */ | ||
652 | dest = flash->base_addr + to; | ||
653 | mutex_lock(&flash->lock); | ||
654 | |||
655 | page_offset = (u32)to % flash->page_size; | ||
656 | |||
657 | /* do if all the bytes fit onto one page */ | ||
658 | if (page_offset + len <= flash->page_size) { | ||
659 | ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf, len); | ||
660 | if (!ret) | ||
661 | *retlen += len; | ||
662 | } else { | ||
663 | u32 i; | ||
664 | |||
665 | /* the size of data remaining on the first page */ | ||
666 | page_size = flash->page_size - page_offset; | ||
667 | |||
668 | ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf, | ||
669 | page_size); | ||
670 | if (ret) | ||
671 | goto err_write; | ||
672 | else | ||
673 | *retlen += page_size; | ||
674 | |||
675 | /* write everything in pagesize chunks */ | ||
676 | for (i = page_size; i < len; i += page_size) { | ||
677 | page_size = len - i; | ||
678 | if (page_size > flash->page_size) | ||
679 | page_size = flash->page_size; | ||
680 | |||
681 | ret = spear_smi_cpy_toio(dev, flash->bank, dest + i, | ||
682 | buf + i, page_size); | ||
683 | if (ret) | ||
684 | break; | ||
685 | else | ||
686 | *retlen += page_size; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | err_write: | ||
691 | mutex_unlock(&flash->lock); | ||
692 | |||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | /** | ||
697 | * spear_smi_probe_flash - Detects the NOR Flash chip. | ||
698 | * @dev: structure of SMI information. | ||
699 | * @bank: bank on which flash must be probed | ||
700 | * | ||
701 | * This routine will check whether there exists a flash chip on a given memory | ||
702 | * bank ID. | ||
703 | * Return index of the probed flash in flash devices structure | ||
704 | */ | ||
705 | static int spear_smi_probe_flash(struct spear_smi *dev, u32 bank) | ||
706 | { | ||
707 | int ret; | ||
708 | u32 val = 0; | ||
709 | |||
710 | ret = spear_smi_wait_till_ready(dev, bank, SMI_PROBE_TIMEOUT); | ||
711 | if (ret) | ||
712 | return ret; | ||
713 | |||
714 | mutex_lock(&dev->lock); | ||
715 | |||
716 | dev->status = 0; /* Will be set in interrupt handler */ | ||
717 | /* put smi in sw mode */ | ||
718 | val = readl(dev->io_base + SMI_CR1); | ||
719 | writel(val | SW_MODE, dev->io_base + SMI_CR1); | ||
720 | |||
721 | /* send readid command in sw mode */ | ||
722 | writel(OPCODE_RDID, dev->io_base + SMI_TR); | ||
723 | |||
724 | val = (bank << BANK_SHIFT) | SEND | (1 << TX_LEN_SHIFT) | | ||
725 | (3 << RX_LEN_SHIFT) | TFIE; | ||
726 | writel(val, dev->io_base + SMI_CR2); | ||
727 | |||
728 | /* wait for TFF */ | ||
729 | ret = wait_event_interruptible_timeout(dev->cmd_complete, | ||
730 | dev->status & TFF, SMI_CMD_TIMEOUT); | ||
731 | if (ret <= 0) { | ||
732 | ret = -ENODEV; | ||
733 | goto err_probe; | ||
734 | } | ||
735 | |||
736 | /* get memory chip id */ | ||
737 | val = readl(dev->io_base + SMI_RR); | ||
738 | val &= 0x00ffffff; | ||
739 | ret = get_flash_index(val); | ||
740 | |||
741 | err_probe: | ||
742 | /* clear sw mode */ | ||
743 | val = readl(dev->io_base + SMI_CR1); | ||
744 | writel(val & ~SW_MODE, dev->io_base + SMI_CR1); | ||
745 | |||
746 | mutex_unlock(&dev->lock); | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | |||
751 | #ifdef CONFIG_OF | ||
752 | static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev, | ||
753 | struct device_node *np) | ||
754 | { | ||
755 | struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev); | ||
756 | struct device_node *pp = NULL; | ||
757 | const __be32 *addr; | ||
758 | u32 val; | ||
759 | int len; | ||
760 | int i = 0; | ||
761 | |||
762 | if (!np) | ||
763 | return -ENODEV; | ||
764 | |||
765 | of_property_read_u32(np, "clock-rate", &val); | ||
766 | pdata->clk_rate = val; | ||
767 | |||
768 | pdata->board_flash_info = devm_kzalloc(&pdev->dev, | ||
769 | sizeof(*pdata->board_flash_info), | ||
770 | GFP_KERNEL); | ||
771 | |||
772 | /* Fill structs for each subnode (flash device) */ | ||
773 | while ((pp = of_get_next_child(np, pp))) { | ||
774 | struct spear_smi_flash_info *flash_info; | ||
775 | |||
776 | flash_info = &pdata->board_flash_info[i]; | ||
777 | pdata->np[i] = pp; | ||
778 | |||
779 | /* Read base-addr and size from DT */ | ||
780 | addr = of_get_property(pp, "reg", &len); | ||
781 | pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]); | ||
782 | pdata->board_flash_info->size = be32_to_cpup(&addr[1]); | ||
783 | |||
784 | if (of_get_property(pp, "st,smi-fast-mode", NULL)) | ||
785 | pdata->board_flash_info->fast_mode = 1; | ||
786 | |||
787 | i++; | ||
788 | } | ||
789 | |||
790 | pdata->num_flashes = i; | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | #else | ||
795 | static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev, | ||
796 | struct device_node *np) | ||
797 | { | ||
798 | return -ENOSYS; | ||
799 | } | ||
800 | #endif | ||
801 | |||
802 | static int spear_smi_setup_banks(struct platform_device *pdev, | ||
803 | u32 bank, struct device_node *np) | ||
804 | { | ||
805 | struct spear_smi *dev = platform_get_drvdata(pdev); | ||
806 | struct mtd_part_parser_data ppdata = {}; | ||
807 | struct spear_smi_flash_info *flash_info; | ||
808 | struct spear_smi_plat_data *pdata; | ||
809 | struct spear_snor_flash *flash; | ||
810 | struct mtd_partition *parts = NULL; | ||
811 | int count = 0; | ||
812 | int flash_index; | ||
813 | int ret = 0; | ||
814 | |||
815 | pdata = dev_get_platdata(&pdev->dev); | ||
816 | if (bank > pdata->num_flashes - 1) | ||
817 | return -EINVAL; | ||
818 | |||
819 | flash_info = &pdata->board_flash_info[bank]; | ||
820 | if (!flash_info) | ||
821 | return -ENODEV; | ||
822 | |||
823 | flash = kzalloc(sizeof(*flash), GFP_ATOMIC); | ||
824 | if (!flash) | ||
825 | return -ENOMEM; | ||
826 | flash->bank = bank; | ||
827 | flash->fast_mode = flash_info->fast_mode ? 1 : 0; | ||
828 | mutex_init(&flash->lock); | ||
829 | |||
830 | /* verify whether nor flash is really present on board */ | ||
831 | flash_index = spear_smi_probe_flash(dev, bank); | ||
832 | if (flash_index < 0) { | ||
833 | dev_info(&dev->pdev->dev, "smi-nor%d not found\n", bank); | ||
834 | ret = flash_index; | ||
835 | goto err_probe; | ||
836 | } | ||
837 | /* map the memory for nor flash chip */ | ||
838 | flash->base_addr = ioremap(flash_info->mem_base, flash_info->size); | ||
839 | if (!flash->base_addr) { | ||
840 | ret = -EIO; | ||
841 | goto err_probe; | ||
842 | } | ||
843 | |||
844 | dev->flash[bank] = flash; | ||
845 | flash->mtd.priv = dev; | ||
846 | |||
847 | if (flash_info->name) | ||
848 | flash->mtd.name = flash_info->name; | ||
849 | else | ||
850 | flash->mtd.name = flash_devices[flash_index].name; | ||
851 | |||
852 | flash->mtd.type = MTD_NORFLASH; | ||
853 | flash->mtd.writesize = 1; | ||
854 | flash->mtd.flags = MTD_CAP_NORFLASH; | ||
855 | flash->mtd.size = flash_info->size; | ||
856 | flash->mtd.erasesize = flash_devices[flash_index].sectorsize; | ||
857 | flash->page_size = flash_devices[flash_index].pagesize; | ||
858 | flash->mtd.writebufsize = flash->page_size; | ||
859 | flash->erase_cmd = flash_devices[flash_index].erase_cmd; | ||
860 | flash->mtd._erase = spear_mtd_erase; | ||
861 | flash->mtd._read = spear_mtd_read; | ||
862 | flash->mtd._write = spear_mtd_write; | ||
863 | flash->dev_id = flash_devices[flash_index].device_id; | ||
864 | |||
865 | dev_info(&dev->pdev->dev, "mtd .name=%s .size=%llx(%lluM)\n", | ||
866 | flash->mtd.name, flash->mtd.size, | ||
867 | flash->mtd.size / (1024 * 1024)); | ||
868 | |||
869 | dev_info(&dev->pdev->dev, ".erasesize = 0x%x(%uK)\n", | ||
870 | flash->mtd.erasesize, flash->mtd.erasesize / 1024); | ||
871 | |||
872 | #ifndef CONFIG_OF | ||
873 | if (flash_info->partitions) { | ||
874 | parts = flash_info->partitions; | ||
875 | count = flash_info->nr_partitions; | ||
876 | } | ||
877 | #endif | ||
878 | ppdata.of_node = np; | ||
879 | |||
880 | ret = mtd_device_parse_register(&flash->mtd, NULL, &ppdata, parts, | ||
881 | count); | ||
882 | if (ret) { | ||
883 | dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret); | ||
884 | goto err_map; | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | |||
889 | err_map: | ||
890 | iounmap(flash->base_addr); | ||
891 | |||
892 | err_probe: | ||
893 | kfree(flash); | ||
894 | return ret; | ||
895 | } | ||
896 | |||
897 | /** | ||
898 | * spear_smi_probe - Entry routine | ||
899 | * @pdev: platform device structure | ||
900 | * | ||
901 | * This is the first routine which gets invoked during booting and does all | ||
902 | * initialization/allocation work. The routine looks for available memory banks, | ||
903 | * and do proper init for any found one. | ||
904 | * Returns 0 on success, non zero otherwise | ||
905 | */ | ||
906 | static int __devinit spear_smi_probe(struct platform_device *pdev) | ||
907 | { | ||
908 | struct device_node *np = pdev->dev.of_node; | ||
909 | struct spear_smi_plat_data *pdata = NULL; | ||
910 | struct spear_smi *dev; | ||
911 | struct resource *smi_base; | ||
912 | int irq, ret = 0; | ||
913 | int i; | ||
914 | |||
915 | if (np) { | ||
916 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
917 | if (!pdata) { | ||
918 | pr_err("%s: ERROR: no memory", __func__); | ||
919 | ret = -ENOMEM; | ||
920 | goto err; | ||
921 | } | ||
922 | pdev->dev.platform_data = pdata; | ||
923 | ret = spear_smi_probe_config_dt(pdev, np); | ||
924 | if (ret) { | ||
925 | ret = -ENODEV; | ||
926 | dev_err(&pdev->dev, "no platform data\n"); | ||
927 | goto err; | ||
928 | } | ||
929 | } else { | ||
930 | pdata = dev_get_platdata(&pdev->dev); | ||
931 | if (pdata < 0) { | ||
932 | ret = -ENODEV; | ||
933 | dev_err(&pdev->dev, "no platform data\n"); | ||
934 | goto err; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
939 | if (!smi_base) { | ||
940 | ret = -ENODEV; | ||
941 | dev_err(&pdev->dev, "invalid smi base address\n"); | ||
942 | goto err; | ||
943 | } | ||
944 | |||
945 | irq = platform_get_irq(pdev, 0); | ||
946 | if (irq < 0) { | ||
947 | ret = -ENODEV; | ||
948 | dev_err(&pdev->dev, "invalid smi irq\n"); | ||
949 | goto err; | ||
950 | } | ||
951 | |||
952 | dev = kzalloc(sizeof(*dev), GFP_ATOMIC); | ||
953 | if (!dev) { | ||
954 | ret = -ENOMEM; | ||
955 | dev_err(&pdev->dev, "mem alloc fail\n"); | ||
956 | goto err; | ||
957 | } | ||
958 | |||
959 | smi_base = request_mem_region(smi_base->start, resource_size(smi_base), | ||
960 | pdev->name); | ||
961 | if (!smi_base) { | ||
962 | ret = -EBUSY; | ||
963 | dev_err(&pdev->dev, "request mem region fail\n"); | ||
964 | goto err_mem; | ||
965 | } | ||
966 | |||
967 | dev->io_base = ioremap(smi_base->start, resource_size(smi_base)); | ||
968 | if (!dev->io_base) { | ||
969 | ret = -EIO; | ||
970 | dev_err(&pdev->dev, "ioremap fail\n"); | ||
971 | goto err_ioremap; | ||
972 | } | ||
973 | |||
974 | dev->pdev = pdev; | ||
975 | dev->clk_rate = pdata->clk_rate; | ||
976 | |||
977 | if (dev->clk_rate < 0 || dev->clk_rate > SMI_MAX_CLOCK_FREQ) | ||
978 | dev->clk_rate = SMI_MAX_CLOCK_FREQ; | ||
979 | |||
980 | dev->num_flashes = pdata->num_flashes; | ||
981 | |||
982 | if (dev->num_flashes > MAX_NUM_FLASH_CHIP) { | ||
983 | dev_err(&pdev->dev, "exceeding max number of flashes\n"); | ||
984 | dev->num_flashes = MAX_NUM_FLASH_CHIP; | ||
985 | } | ||
986 | |||
987 | dev->clk = clk_get(&pdev->dev, NULL); | ||
988 | if (IS_ERR(dev->clk)) { | ||
989 | ret = PTR_ERR(dev->clk); | ||
990 | goto err_clk; | ||
991 | } | ||
992 | |||
993 | ret = clk_enable(dev->clk); | ||
994 | if (ret) | ||
995 | goto err_clk_enable; | ||
996 | |||
997 | ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev); | ||
998 | if (ret) { | ||
999 | dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n"); | ||
1000 | goto err_irq; | ||
1001 | } | ||
1002 | |||
1003 | mutex_init(&dev->lock); | ||
1004 | init_waitqueue_head(&dev->cmd_complete); | ||
1005 | spear_smi_hw_init(dev); | ||
1006 | platform_set_drvdata(pdev, dev); | ||
1007 | |||
1008 | /* loop for each serial nor-flash which is connected to smi */ | ||
1009 | for (i = 0; i < dev->num_flashes; i++) { | ||
1010 | ret = spear_smi_setup_banks(pdev, i, pdata->np[i]); | ||
1011 | if (ret) { | ||
1012 | dev_err(&dev->pdev->dev, "bank setup failed\n"); | ||
1013 | goto err_bank_setup; | ||
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | |||
1019 | err_bank_setup: | ||
1020 | free_irq(irq, dev); | ||
1021 | platform_set_drvdata(pdev, NULL); | ||
1022 | err_irq: | ||
1023 | clk_disable(dev->clk); | ||
1024 | err_clk_enable: | ||
1025 | clk_put(dev->clk); | ||
1026 | err_clk: | ||
1027 | iounmap(dev->io_base); | ||
1028 | err_ioremap: | ||
1029 | release_mem_region(smi_base->start, resource_size(smi_base)); | ||
1030 | err_mem: | ||
1031 | kfree(dev); | ||
1032 | err: | ||
1033 | return ret; | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * spear_smi_remove - Exit routine | ||
1038 | * @pdev: platform device structure | ||
1039 | * | ||
1040 | * free all allocations and delete the partitions. | ||
1041 | */ | ||
1042 | static int __devexit spear_smi_remove(struct platform_device *pdev) | ||
1043 | { | ||
1044 | struct spear_smi *dev; | ||
1045 | struct spear_smi_plat_data *pdata; | ||
1046 | struct spear_snor_flash *flash; | ||
1047 | struct resource *smi_base; | ||
1048 | int ret; | ||
1049 | int i, irq; | ||
1050 | |||
1051 | dev = platform_get_drvdata(pdev); | ||
1052 | if (!dev) { | ||
1053 | dev_err(&pdev->dev, "dev is null\n"); | ||
1054 | return -ENODEV; | ||
1055 | } | ||
1056 | |||
1057 | pdata = dev_get_platdata(&pdev->dev); | ||
1058 | |||
1059 | /* clean up for all nor flash */ | ||
1060 | for (i = 0; i < dev->num_flashes; i++) { | ||
1061 | flash = dev->flash[i]; | ||
1062 | if (!flash) | ||
1063 | continue; | ||
1064 | |||
1065 | /* clean up mtd stuff */ | ||
1066 | ret = mtd_device_unregister(&flash->mtd); | ||
1067 | if (ret) | ||
1068 | dev_err(&pdev->dev, "error removing mtd\n"); | ||
1069 | |||
1070 | iounmap(flash->base_addr); | ||
1071 | kfree(flash); | ||
1072 | } | ||
1073 | |||
1074 | irq = platform_get_irq(pdev, 0); | ||
1075 | free_irq(irq, dev); | ||
1076 | |||
1077 | clk_disable(dev->clk); | ||
1078 | clk_put(dev->clk); | ||
1079 | iounmap(dev->io_base); | ||
1080 | kfree(dev); | ||
1081 | |||
1082 | smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1083 | release_mem_region(smi_base->start, resource_size(smi_base)); | ||
1084 | platform_set_drvdata(pdev, NULL); | ||
1085 | |||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | int spear_smi_suspend(struct platform_device *pdev, pm_message_t state) | ||
1090 | { | ||
1091 | struct spear_smi *dev = platform_get_drvdata(pdev); | ||
1092 | |||
1093 | if (dev && dev->clk) | ||
1094 | clk_disable(dev->clk); | ||
1095 | |||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | int spear_smi_resume(struct platform_device *pdev) | ||
1100 | { | ||
1101 | struct spear_smi *dev = platform_get_drvdata(pdev); | ||
1102 | int ret = -EPERM; | ||
1103 | |||
1104 | if (dev && dev->clk) | ||
1105 | ret = clk_enable(dev->clk); | ||
1106 | |||
1107 | if (!ret) | ||
1108 | spear_smi_hw_init(dev); | ||
1109 | return ret; | ||
1110 | } | ||
1111 | |||
1112 | #ifdef CONFIG_OF | ||
1113 | static const struct of_device_id spear_smi_id_table[] = { | ||
1114 | { .compatible = "st,spear600-smi" }, | ||
1115 | {} | ||
1116 | }; | ||
1117 | MODULE_DEVICE_TABLE(of, spear_smi_id_table); | ||
1118 | #endif | ||
1119 | |||
1120 | static struct platform_driver spear_smi_driver = { | ||
1121 | .driver = { | ||
1122 | .name = "smi", | ||
1123 | .bus = &platform_bus_type, | ||
1124 | .owner = THIS_MODULE, | ||
1125 | .of_match_table = of_match_ptr(spear_smi_id_table), | ||
1126 | }, | ||
1127 | .probe = spear_smi_probe, | ||
1128 | .remove = __devexit_p(spear_smi_remove), | ||
1129 | .suspend = spear_smi_suspend, | ||
1130 | .resume = spear_smi_resume, | ||
1131 | }; | ||
1132 | |||
1133 | static int spear_smi_init(void) | ||
1134 | { | ||
1135 | return platform_driver_register(&spear_smi_driver); | ||
1136 | } | ||
1137 | module_init(spear_smi_init); | ||
1138 | |||
1139 | static void spear_smi_exit(void) | ||
1140 | { | ||
1141 | platform_driver_unregister(&spear_smi_driver); | ||
1142 | } | ||
1143 | module_exit(spear_smi_exit); | ||
1144 | |||
1145 | MODULE_LICENSE("GPL"); | ||
1146 | MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.hashim@st.com>"); | ||
1147 | MODULE_DESCRIPTION("MTD SMI driver for serial nor flash chips"); | ||
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 5fc198350b94..ab8a2f4c8d60 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c | |||
@@ -175,9 +175,6 @@ static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
175 | int err; | 175 | int err; |
176 | 176 | ||
177 | /* Sanity checks */ | 177 | /* Sanity checks */ |
178 | if (instr->addr + instr->len > flash->mtd.size) | ||
179 | return -EINVAL; | ||
180 | |||
181 | if ((uint32_t)instr->len % mtd->erasesize) | 178 | if ((uint32_t)instr->len % mtd->erasesize) |
182 | return -EINVAL; | 179 | return -EINVAL; |
183 | 180 | ||
@@ -223,16 +220,6 @@ static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
223 | unsigned char command[4]; | 220 | unsigned char command[4]; |
224 | int ret; | 221 | int ret; |
225 | 222 | ||
226 | /* Sanity checking */ | ||
227 | if (len == 0) | ||
228 | return 0; | ||
229 | |||
230 | if (from + len > flash->mtd.size) | ||
231 | return -EINVAL; | ||
232 | |||
233 | if (retlen) | ||
234 | *retlen = 0; | ||
235 | |||
236 | spi_message_init(&message); | 223 | spi_message_init(&message); |
237 | memset(&transfer, 0, sizeof(transfer)); | 224 | memset(&transfer, 0, sizeof(transfer)); |
238 | 225 | ||
@@ -274,13 +261,6 @@ static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
274 | int i, j, ret, bytes, copied = 0; | 261 | int i, j, ret, bytes, copied = 0; |
275 | unsigned char command[5]; | 262 | unsigned char command[5]; |
276 | 263 | ||
277 | /* Sanity checks */ | ||
278 | if (!len) | ||
279 | return 0; | ||
280 | |||
281 | if (to + len > flash->mtd.size) | ||
282 | return -EINVAL; | ||
283 | |||
284 | if ((uint32_t)to % mtd->writesize) | 264 | if ((uint32_t)to % mtd->writesize) |
285 | return -EINVAL; | 265 | return -EINVAL; |
286 | 266 | ||
@@ -402,10 +382,11 @@ static int __devinit sst25l_probe(struct spi_device *spi) | |||
402 | flash->mtd.flags = MTD_CAP_NORFLASH; | 382 | flash->mtd.flags = MTD_CAP_NORFLASH; |
403 | flash->mtd.erasesize = flash_info->erase_size; | 383 | flash->mtd.erasesize = flash_info->erase_size; |
404 | flash->mtd.writesize = flash_info->page_size; | 384 | flash->mtd.writesize = flash_info->page_size; |
385 | flash->mtd.writebufsize = flash_info->page_size; | ||
405 | flash->mtd.size = flash_info->page_size * flash_info->nr_pages; | 386 | flash->mtd.size = flash_info->page_size * flash_info->nr_pages; |
406 | flash->mtd.erase = sst25l_erase; | 387 | flash->mtd._erase = sst25l_erase; |
407 | flash->mtd.read = sst25l_read; | 388 | flash->mtd._read = sst25l_read; |
408 | flash->mtd.write = sst25l_write; | 389 | flash->mtd._write = sst25l_write; |
409 | 390 | ||
410 | dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, | 391 | dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, |
411 | (long long)flash->mtd.size >> 10); | 392 | (long long)flash->mtd.size >> 10); |
@@ -418,9 +399,9 @@ static int __devinit sst25l_probe(struct spi_device *spi) | |||
418 | flash->mtd.numeraseregions); | 399 | flash->mtd.numeraseregions); |
419 | 400 | ||
420 | 401 | ||
421 | ret = mtd_device_parse_register(&flash->mtd, NULL, 0, | 402 | ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, |
422 | data ? data->parts : NULL, | 403 | data ? data->parts : NULL, |
423 | data ? data->nr_parts : 0); | 404 | data ? data->nr_parts : 0); |
424 | if (ret) { | 405 | if (ret) { |
425 | kfree(flash); | 406 | kfree(flash); |
426 | dev_set_drvdata(&spi->dev, NULL); | 407 | dev_set_drvdata(&spi->dev, NULL); |
@@ -450,18 +431,7 @@ static struct spi_driver sst25l_driver = { | |||
450 | .remove = __devexit_p(sst25l_remove), | 431 | .remove = __devexit_p(sst25l_remove), |
451 | }; | 432 | }; |
452 | 433 | ||
453 | static int __init sst25l_init(void) | 434 | module_spi_driver(sst25l_driver); |
454 | { | ||
455 | return spi_register_driver(&sst25l_driver); | ||
456 | } | ||
457 | |||
458 | static void __exit sst25l_exit(void) | ||
459 | { | ||
460 | spi_unregister_driver(&sst25l_driver); | ||
461 | } | ||
462 | |||
463 | module_init(sst25l_init); | ||
464 | module_exit(sst25l_exit); | ||
465 | 435 | ||
466 | MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips"); | 436 | MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips"); |
467 | MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, " | 437 | MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, " |