From b2b5637e3fd641b263ede4cd0bc22a810bdcdacc Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 31 Aug 2008 19:32:13 +0300 Subject: [PATCH] --- yaml --- r: 116033 b: refs/heads/master c: 7d200e88cbdff5334d23d3af8d444eb9cc041962 h: refs/heads/master i: 116031: e602b8ed9891f7a3e1672e83a407e41995f84dff v: v3 --- [refs] | 2 +- trunk/Documentation/mtd/nand_ecc.txt | 714 ----------- .../arm/mach-pxa/include/mach/pxa3xx_nand.h | 44 +- .../arch/arm/plat-mxc/include/mach/mxc_nand.h | 27 - .../arch/arm/plat-omap/include/mach/onenand.h | 6 +- trunk/arch/x86/pci/i386.c | 78 ++ trunk/drivers/mtd/Kconfig | 5 - trunk/drivers/mtd/chips/Kconfig | 4 +- trunk/drivers/mtd/chips/cfi_cmdset_0001.c | 71 +- trunk/drivers/mtd/chips/cfi_probe.c | 58 +- trunk/drivers/mtd/chips/cfi_util.c | 66 +- trunk/drivers/mtd/chips/gen_probe.c | 2 +- trunk/drivers/mtd/devices/Kconfig | 21 - trunk/drivers/mtd/devices/m25p80.c | 140 +-- trunk/drivers/mtd/devices/mtd_dataflash.c | 214 +--- trunk/drivers/mtd/inftlcore.c | 5 +- trunk/drivers/mtd/maps/Kconfig | 33 +- trunk/drivers/mtd/maps/Makefile | 4 + trunk/drivers/mtd/maps/ebony.c | 163 +++ trunk/drivers/mtd/maps/ocotea.c | 154 +++ trunk/drivers/mtd/maps/omap-toto-flash.c | 133 ++ trunk/drivers/mtd/maps/pci.c | 18 +- trunk/drivers/mtd/maps/physmap_of.c | 3 +- trunk/drivers/mtd/maps/walnut.c | 122 ++ trunk/drivers/mtd/mtdchar.c | 4 +- trunk/drivers/mtd/mtdconcat.c | 4 +- trunk/drivers/mtd/mtdpart.c | 4 +- trunk/drivers/mtd/nand/Kconfig | 36 +- trunk/drivers/mtd/nand/Makefile | 3 +- trunk/drivers/mtd/nand/atmel_nand.c | 58 +- trunk/drivers/mtd/nand/fsl_elbc_nand.c | 3 +- trunk/drivers/mtd/nand/fsl_upm.c | 68 +- trunk/drivers/mtd/nand/mxc_nand.c | 1077 ----------------- trunk/drivers/mtd/nand/nand_base.c | 16 +- trunk/drivers/mtd/nand/nand_ecc.c | 554 ++------- trunk/drivers/mtd/nand/nandsim.c | 1 + trunk/drivers/mtd/nand/pxa3xx_nand.c | 147 ++- trunk/drivers/mtd/nand/sh_flctl.c | 301 ----- trunk/drivers/mtd/nand/toto.c | 206 ++++ trunk/drivers/mtd/ofpart.c | 1 + trunk/drivers/mtd/onenand/Kconfig | 8 - trunk/drivers/mtd/onenand/Makefile | 1 - trunk/drivers/mtd/onenand/omap2.c | 802 ------------ trunk/drivers/mtd/onenand/onenand_base.c | 2 +- trunk/drivers/mtd/ssfdc.c | 3 +- trunk/drivers/mtd/ubi/cdev.c | 6 +- trunk/drivers/pci/rom.c | 6 +- trunk/fs/Kconfig | 190 ++- trunk/fs/jffs2/Kconfig | 188 --- trunk/fs/jffs2/compr.c | 4 +- trunk/fs/jffs2/dir.c | 2 +- trunk/fs/jffs2/erase.c | 4 +- trunk/fs/jffs2/fs.c | 6 +- trunk/include/linux/ioport.h | 1 - trunk/include/linux/mtd/cfi.h | 9 +- trunk/include/linux/mtd/flashchip.h | 4 - trunk/include/linux/mtd/mtd.h | 4 +- trunk/include/linux/mtd/nand.h | 1 - trunk/include/linux/mtd/onenand_regs.h | 2 - trunk/include/linux/mtd/partitions.h | 1 + trunk/include/linux/mtd/sh_flctl.h | 125 -- trunk/include/linux/pci.h | 2 - trunk/kernel/resource.c | 88 +- trunk/kernel/softlockup.c | 4 - trunk/sound/pci/hda/patch_realtek.c | 1 + trunk/sound/pci/oxygen/hifier.c | 4 - trunk/sound/pci/oxygen/oxygen.c | 4 - 67 files changed, 1578 insertions(+), 4464 deletions(-) delete mode 100644 trunk/Documentation/mtd/nand_ecc.txt delete mode 100644 trunk/arch/arm/plat-mxc/include/mach/mxc_nand.h create mode 100644 trunk/drivers/mtd/maps/ebony.c create mode 100644 trunk/drivers/mtd/maps/ocotea.c create mode 100644 trunk/drivers/mtd/maps/omap-toto-flash.c create mode 100644 trunk/drivers/mtd/maps/walnut.c delete mode 100644 trunk/drivers/mtd/nand/mxc_nand.c delete mode 100644 trunk/drivers/mtd/nand/sh_flctl.c create mode 100644 trunk/drivers/mtd/nand/toto.c delete mode 100644 trunk/drivers/mtd/onenand/omap2.c delete mode 100644 trunk/fs/jffs2/Kconfig delete mode 100644 trunk/include/linux/mtd/sh_flctl.h diff --git a/[refs] b/[refs] index 6563a2db74a9..cf881ca41555 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: faa5c2a15e14b6a4e59fcae65dec5258e723ea9f +refs/heads/master: 7d200e88cbdff5334d23d3af8d444eb9cc041962 diff --git a/trunk/Documentation/mtd/nand_ecc.txt b/trunk/Documentation/mtd/nand_ecc.txt deleted file mode 100644 index bdf93b7f0f24..000000000000 --- a/trunk/Documentation/mtd/nand_ecc.txt +++ /dev/null @@ -1,714 +0,0 @@ -Introduction -============ - -Having looked at the linux mtd/nand driver and more specific at nand_ecc.c -I felt there was room for optimisation. I bashed the code for a few hours -performing tricks like table lookup removing superfluous code etc. -After that the speed was increased by 35-40%. -Still I was not too happy as I felt there was additional room for improvement. - -Bad! I was hooked. -I decided to annotate my steps in this file. Perhaps it is useful to someone -or someone learns something from it. - - -The problem -=========== - -NAND flash (at least SLC one) typically has sectors of 256 bytes. -However NAND flash is not extremely reliable so some error detection -(and sometimes correction) is needed. - -This is done by means of a Hamming code. I'll try to explain it in -laymans terms (and apologies to all the pro's in the field in case I do -not use the right terminology, my coding theory class was almost 30 -years ago, and I must admit it was not one of my favourites). - -As I said before the ecc calculation is performed on sectors of 256 -bytes. This is done by calculating several parity bits over the rows and -columns. The parity used is even parity which means that the parity bit = 1 -if the data over which the parity is calculated is 1 and the parity bit = 0 -if the data over which the parity is calculated is 0. So the total -number of bits over the data over which the parity is calculated + the -parity bit is even. (see wikipedia if you can't follow this). -Parity is often calculated by means of an exclusive or operation, -sometimes also referred to as xor. In C the operator for xor is ^ - -Back to ecc. -Let's give a small figure: - -byte 0: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp2 rp4 ... rp14 -byte 1: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp2 rp4 ... rp14 -byte 2: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp3 rp4 ... rp14 -byte 3: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp3 rp4 ... rp14 -byte 4: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp2 rp5 ... rp14 -.... -byte 254: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp3 rp5 ... rp15 -byte 255: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp3 rp5 ... rp15 - cp1 cp0 cp1 cp0 cp1 cp0 cp1 cp0 - cp3 cp3 cp2 cp2 cp3 cp3 cp2 cp2 - cp5 cp5 cp5 cp5 cp4 cp4 cp4 cp4 - -This figure represents a sector of 256 bytes. -cp is my abbreviaton for column parity, rp for row parity. - -Let's start to explain column parity. -cp0 is the parity that belongs to all bit0, bit2, bit4, bit6. -so the sum of all bit0, bit2, bit4 and bit6 values + cp0 itself is even. -Similarly cp1 is the sum of all bit1, bit3, bit5 and bit7. -cp2 is the parity over bit0, bit1, bit4 and bit5 -cp3 is the parity over bit2, bit3, bit6 and bit7. -cp4 is the parity over bit0, bit1, bit2 and bit3. -cp5 is the parity over bit4, bit5, bit6 and bit7. -Note that each of cp0 .. cp5 is exactly one bit. - -Row parity actually works almost the same. -rp0 is the parity of all even bytes (0, 2, 4, 6, ... 252, 254) -rp1 is the parity of all odd bytes (1, 3, 5, 7, ..., 253, 255) -rp2 is the parity of all bytes 0, 1, 4, 5, 8, 9, ... -(so handle two bytes, then skip 2 bytes). -rp3 is covers the half rp2 does not cover (bytes 2, 3, 6, 7, 10, 11, ...) -for rp4 the rule is cover 4 bytes, skip 4 bytes, cover 4 bytes, skip 4 etc. -so rp4 calculates parity over bytes 0, 1, 2, 3, 8, 9, 10, 11, 16, ...) -and rp5 covers the other half, so bytes 4, 5, 6, 7, 12, 13, 14, 15, 20, .. -The story now becomes quite boring. I guess you get the idea. -rp6 covers 8 bytes then skips 8 etc -rp7 skips 8 bytes then covers 8 etc -rp8 covers 16 bytes then skips 16 etc -rp9 skips 16 bytes then covers 16 etc -rp10 covers 32 bytes then skips 32 etc -rp11 skips 32 bytes then covers 32 etc -rp12 covers 64 bytes then skips 64 etc -rp13 skips 64 bytes then covers 64 etc -rp14 covers 128 bytes then skips 128 -rp15 skips 128 bytes then covers 128 - -In the end the parity bits are grouped together in three bytes as -follows: -ECC Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 -ECC 0 rp07 rp06 rp05 rp04 rp03 rp02 rp01 rp00 -ECC 1 rp15 rp14 rp13 rp12 rp11 rp10 rp09 rp08 -ECC 2 cp5 cp4 cp3 cp2 cp1 cp0 1 1 - -I detected after writing this that ST application note AN1823 -(http://www.st.com/stonline/books/pdf/docs/10123.pdf) gives a much -nicer picture.(but they use line parity as term where I use row parity) -Oh well, I'm graphically challenged, so suffer with me for a moment :-) -And I could not reuse the ST picture anyway for copyright reasons. - - -Attempt 0 -========= - -Implementing the parity calculation is pretty simple. -In C pseudocode: -for (i = 0; i < 256; i++) -{ - if (i & 0x01) - rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1; - else - rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1; - if (i & 0x02) - rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3; - else - rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp2; - if (i & 0x04) - rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp5; - else - rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp4; - if (i & 0x08) - rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp7; - else - rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp6; - if (i & 0x10) - rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp9; - else - rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp8; - if (i & 0x20) - rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11; - else - rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10; - if (i & 0x40) - rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13; - else - rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp12; - if (i & 0x80) - rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp15; - else - rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp14; - cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0; - cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1; - cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2; - cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3 - cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4 - cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5 -} - - -Analysis 0 -========== - -C does have bitwise operators but not really operators to do the above -efficiently (and most hardware has no such instructions either). -Therefore without implementing this it was clear that the code above was -not going to bring me a Nobel prize :-) - -Fortunately the exclusive or operation is commutative, so we can combine -the values in any order. So instead of calculating all the bits -individually, let us try to rearrange things. -For the column parity this is easy. We can just xor the bytes and in the -end filter out the relevant bits. This is pretty nice as it will bring -all cp calculation out of the if loop. - -Similarly we can first xor the bytes for the various rows. -This leads to: - - -Attempt 1 -========= - -const char parity[256] = { - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 -}; - -void ecc1(const unsigned char *buf, unsigned char *code) -{ - int i; - const unsigned char *bp = buf; - unsigned char cur; - unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; - unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15; - unsigned char par; - - par = 0; - rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0; - rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0; - rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0; - rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0; - - for (i = 0; i < 256; i++) - { - cur = *bp++; - par ^= cur; - if (i & 0x01) rp1 ^= cur; else rp0 ^= cur; - if (i & 0x02) rp3 ^= cur; else rp2 ^= cur; - if (i & 0x04) rp5 ^= cur; else rp4 ^= cur; - if (i & 0x08) rp7 ^= cur; else rp6 ^= cur; - if (i & 0x10) rp9 ^= cur; else rp8 ^= cur; - if (i & 0x20) rp11 ^= cur; else rp10 ^= cur; - if (i & 0x40) rp13 ^= cur; else rp12 ^= cur; - if (i & 0x80) rp15 ^= cur; else rp14 ^= cur; - } - code[0] = - (parity[rp7] << 7) | - (parity[rp6] << 6) | - (parity[rp5] << 5) | - (parity[rp4] << 4) | - (parity[rp3] << 3) | - (parity[rp2] << 2) | - (parity[rp1] << 1) | - (parity[rp0]); - code[1] = - (parity[rp15] << 7) | - (parity[rp14] << 6) | - (parity[rp13] << 5) | - (parity[rp12] << 4) | - (parity[rp11] << 3) | - (parity[rp10] << 2) | - (parity[rp9] << 1) | - (parity[rp8]); - code[2] = - (parity[par & 0xf0] << 7) | - (parity[par & 0x0f] << 6) | - (parity[par & 0xcc] << 5) | - (parity[par & 0x33] << 4) | - (parity[par & 0xaa] << 3) | - (parity[par & 0x55] << 2); - code[0] = ~code[0]; - code[1] = ~code[1]; - code[2] = ~code[2]; -} - -Still pretty straightforward. The last three invert statements are there to -give a checksum of 0xff 0xff 0xff for an empty flash. In an empty flash -all data is 0xff, so the checksum then matches. - -I also introduced the parity lookup. I expected this to be the fastest -way to calculate the parity, but I will investigate alternatives later -on. - - -Analysis 1 -========== - -The code works, but is not terribly efficient. On my system it took -almost 4 times as much time as the linux driver code. But hey, if it was -*that* easy this would have been done long before. -No pain. no gain. - -Fortunately there is plenty of room for improvement. - -In step 1 we moved from bit-wise calculation to byte-wise calculation. -However in C we can also use the unsigned long data type and virtually -every modern microprocessor supports 32 bit operations, so why not try -to write our code in such a way that we process data in 32 bit chunks. - -Of course this means some modification as the row parity is byte by -byte. A quick analysis: -for the column parity we use the par variable. When extending to 32 bits -we can in the end easily calculate p0 and p1 from it. -(because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0 -respectively) -also rp2 and rp3 can be easily retrieved from par as rp3 covers the -first two bytes and rp2 the last two bytes. - -Note that of course now the loop is executed only 64 times (256/4). -And note that care must taken wrt byte ordering. The way bytes are -ordered in a long is machine dependent, and might affect us. -Anyway, if there is an issue: this code is developed on x86 (to be -precise: a DELL PC with a D920 Intel CPU) - -And of course the performance might depend on alignment, but I expect -that the I/O buffers in the nand driver are aligned properly (and -otherwise that should be fixed to get maximum performance). - -Let's give it a try... - - -Attempt 2 -========= - -extern const char parity[256]; - -void ecc2(const unsigned char *buf, unsigned char *code) -{ - int i; - const unsigned long *bp = (unsigned long *)buf; - unsigned long cur; - unsigned long rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; - unsigned long rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15; - unsigned long par; - - par = 0; - rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0; - rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0; - rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0; - rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0; - - for (i = 0; i < 64; i++) - { - cur = *bp++; - par ^= cur; - if (i & 0x01) rp5 ^= cur; else rp4 ^= cur; - if (i & 0x02) rp7 ^= cur; else rp6 ^= cur; - if (i & 0x04) rp9 ^= cur; else rp8 ^= cur; - if (i & 0x08) rp11 ^= cur; else rp10 ^= cur; - if (i & 0x10) rp13 ^= cur; else rp12 ^= cur; - if (i & 0x20) rp15 ^= cur; else rp14 ^= cur; - } - /* - we need to adapt the code generation for the fact that rp vars are now - long; also the column parity calculation needs to be changed. - we'll bring rp4 to 15 back to single byte entities by shifting and - xoring - */ - rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); rp4 &= 0xff; - rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); rp5 &= 0xff; - rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); rp6 &= 0xff; - rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); rp7 &= 0xff; - rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); rp8 &= 0xff; - rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); rp9 &= 0xff; - rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8); rp10 &= 0xff; - rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8); rp11 &= 0xff; - rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8); rp12 &= 0xff; - rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8); rp13 &= 0xff; - rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8); rp14 &= 0xff; - rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8); rp15 &= 0xff; - rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp3 &= 0xff; - rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); rp2 &= 0xff; - par ^= (par >> 16); - rp1 = (par >> 8); rp1 &= 0xff; - rp0 = (par & 0xff); - par ^= (par >> 8); par &= 0xff; - - code[0] = - (parity[rp7] << 7) | - (parity[rp6] << 6) | - (parity[rp5] << 5) | - (parity[rp4] << 4) | - (parity[rp3] << 3) | - (parity[rp2] << 2) | - (parity[rp1] << 1) | - (parity[rp0]); - code[1] = - (parity[rp15] << 7) | - (parity[rp14] << 6) | - (parity[rp13] << 5) | - (parity[rp12] << 4) | - (parity[rp11] << 3) | - (parity[rp10] << 2) | - (parity[rp9] << 1) | - (parity[rp8]); - code[2] = - (parity[par & 0xf0] << 7) | - (parity[par & 0x0f] << 6) | - (parity[par & 0xcc] << 5) | - (parity[par & 0x33] << 4) | - (parity[par & 0xaa] << 3) | - (parity[par & 0x55] << 2); - code[0] = ~code[0]; - code[1] = ~code[1]; - code[2] = ~code[2]; -} - -The parity array is not shown any more. Note also that for these -examples I kinda deviated from my regular programming style by allowing -multiple statements on a line, not using { } in then and else blocks -with only a single statement and by using operators like ^= - - -Analysis 2 -========== - -The code (of course) works, and hurray: we are a little bit faster than -the linux driver code (about 15%). But wait, don't cheer too quickly. -THere is more to be gained. -If we look at e.g. rp14 and rp15 we see that we either xor our data with -rp14 or with rp15. However we also have par which goes over all data. -This means there is no need to calculate rp14 as it can be calculated from -rp15 through rp14 = par ^ rp15; -(or if desired we can avoid calculating rp15 and calculate it from -rp14). That is why some places refer to inverse parity. -Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13. -Effectively this means we can eliminate the else clause from the if -statements. Also we can optimise the calculation in the end a little bit -by going from long to byte first. Actually we can even avoid the table -lookups - -Attempt 3 -========= - -Odd replaced: - if (i & 0x01) rp5 ^= cur; else rp4 ^= cur; - if (i & 0x02) rp7 ^= cur; else rp6 ^= cur; - if (i & 0x04) rp9 ^= cur; else rp8 ^= cur; - if (i & 0x08) rp11 ^= cur; else rp10 ^= cur; - if (i & 0x10) rp13 ^= cur; else rp12 ^= cur; - if (i & 0x20) rp15 ^= cur; else rp14 ^= cur; -with - if (i & 0x01) rp5 ^= cur; - if (i & 0x02) rp7 ^= cur; - if (i & 0x04) rp9 ^= cur; - if (i & 0x08) rp11 ^= cur; - if (i & 0x10) rp13 ^= cur; - if (i & 0x20) rp15 ^= cur; - - and outside the loop added: - rp4 = par ^ rp5; - rp6 = par ^ rp7; - rp8 = par ^ rp9; - rp10 = par ^ rp11; - rp12 = par ^ rp13; - rp14 = par ^ rp15; - -And after that the code takes about 30% more time, although the number of -statements is reduced. This is also reflected in the assembly code. - - -Analysis 3 -========== - -Very weird. Guess it has to do with caching or instruction parallellism -or so. I also tried on an eeePC (Celeron, clocked at 900 Mhz). Interesting -observation was that this one is only 30% slower (according to time) -executing the code as my 3Ghz D920 processor. - -Well, it was expected not to be easy so maybe instead move to a -different track: let's move back to the code from attempt2 and do some -loop unrolling. This will eliminate a few if statements. I'll try -different amounts of unrolling to see what works best. - - -Attempt 4 -========= - -Unrolled the loop 1, 2, 3 and 4 times. -For 4 the code starts with: - - for (i = 0; i < 4; i++) - { - cur = *bp++; - par ^= cur; - rp4 ^= cur; - rp6 ^= cur; - rp8 ^= cur; - rp10 ^= cur; - if (i & 0x1) rp13 ^= cur; else rp12 ^= cur; - if (i & 0x2) rp15 ^= cur; else rp14 ^= cur; - cur = *bp++; - par ^= cur; - rp5 ^= cur; - rp6 ^= cur; - ... - - -Analysis 4 -========== - -Unrolling once gains about 15% -Unrolling twice keeps the gain at about 15% -Unrolling three times gives a gain of 30% compared to attempt 2. -Unrolling four times gives a marginal improvement compared to unrolling -three times. - -I decided to proceed with a four time unrolled loop anyway. It was my gut -feeling that in the next steps I would obtain additional gain from it. - -The next step was triggered by the fact that par contains the xor of all -bytes and rp4 and rp5 each contain the xor of half of the bytes. -So in effect par = rp4 ^ rp5. But as xor is commutative we can also say -that rp5 = par ^ rp4. So no need to keep both rp4 and rp5 around. We can -eliminate rp5 (or rp4, but I already foresaw another optimisation). -The same holds for rp6/7, rp8/9, rp10/11 rp12/13 and rp14/15. - - -Attempt 5 -========= - -Effectively so all odd digit rp assignments in the loop were removed. -This included the else clause of the if statements. -Of course after the loop we need to correct things by adding code like: - rp5 = par ^ rp4; -Also the initial assignments (rp5 = 0; etc) could be removed. -Along the line I also removed the initialisation of rp0/1/2/3. - - -Analysis 5 -========== - -Measurements showed this was a good move. The run-time roughly halved -compared with attempt 4 with 4 times unrolled, and we only require 1/3rd -of the processor time compared to the current code in the linux kernel. - -However, still I thought there was more. I didn't like all the if -statements. Why not keep a running parity and only keep the last if -statement. Time for yet another version! - - -Attempt 6 -========= - -THe code within the for loop was changed to: - - for (i = 0; i < 4; i++) - { - cur = *bp++; tmppar = cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= tmppar; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp8 ^= tmppar; - - cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp10 ^= tmppar; - - cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur; - cur = *bp++; tmppar ^= cur; rp8 ^= cur; - - cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; - - par ^= tmppar; - if ((i & 0x1) == 0) rp12 ^= tmppar; - if ((i & 0x2) == 0) rp14 ^= tmppar; - } - -As you can see tmppar is used to accumulate the parity within a for -iteration. In the last 3 statements is is added to par and, if needed, -to rp12 and rp14. - -While making the changes I also found that I could exploit that tmppar -contains the running parity for this iteration. So instead of having: -rp4 ^= cur; rp6 = cur; -I removed the rp6 = cur; statement and did rp6 ^= tmppar; on next -statement. A similar change was done for rp8 and rp10 - - -Analysis 6 -========== - -Measuring this code again showed big gain. When executing the original -linux code 1 million times, this took about 1 second on my system. -(using time to measure the performance). After this iteration I was back -to 0.075 sec. Actually I had to decide to start measuring over 10 -million interations in order not to loose too much accuracy. This one -definitely seemed to be the jackpot! - -There is a little bit more room for improvement though. There are three -places with statements: -rp4 ^= cur; rp6 ^= cur; -It seems more efficient to also maintain a variable rp4_6 in the while -loop; This eliminates 3 statements per loop. Of course after the loop we -need to correct by adding: - rp4 ^= rp4_6; - rp6 ^= rp4_6 -Furthermore there are 4 sequential assingments to rp8. This can be -encoded slightly more efficient by saving tmppar before those 4 lines -and later do rp8 = rp8 ^ tmppar ^ notrp8; -(where notrp8 is the value of rp8 before those 4 lines). -Again a use of the commutative property of xor. -Time for a new test! - - -Attempt 7 -========= - -The new code now looks like: - - for (i = 0; i < 4; i++) - { - cur = *bp++; tmppar = cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= tmppar; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp8 ^= tmppar; - - cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; rp10 ^= tmppar; - - notrp8 = tmppar; - cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; - rp8 = rp8 ^ tmppar ^ notrp8; - - cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; - cur = *bp++; tmppar ^= cur; rp6 ^= cur; - cur = *bp++; tmppar ^= cur; rp4 ^= cur; - cur = *bp++; tmppar ^= cur; - - par ^= tmppar; - if ((i & 0x1) == 0) rp12 ^= tmppar; - if ((i & 0x2) == 0) rp14 ^= tmppar; - } - rp4 ^= rp4_6; - rp6 ^= rp4_6; - - -Not a big change, but every penny counts :-) - - -Analysis 7 -========== - -Acutally this made things worse. Not very much, but I don't want to move -into the wrong direction. Maybe something to investigate later. Could -have to do with caching again. - -Guess that is what there is to win within the loop. Maybe unrolling one -more time will help. I'll keep the optimisations from 7 for now. - - -Attempt 8 -========= - -Unrolled the loop one more time. - - -Analysis 8 -========== - -This makes things worse. Let's stick with attempt 6 and continue from there. -Although it seems that the code within the loop cannot be optimised -further there is still room to optimize the generation of the ecc codes. -We can simply calcualate the total parity. If this is 0 then rp4 = rp5 -etc. If the parity is 1, then rp4 = !rp5; -But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits -in the result byte and then do something like - code[0] |= (code[0] << 1); -Lets test this. - - -Attempt 9 -========= - -Changed the code but again this slightly degrades performance. Tried all -kind of other things, like having dedicated parity arrays to avoid the -shift after parity[rp7] << 7; No gain. -Change the lookup using the parity array by using shift operators (e.g. -replace parity[rp7] << 7 with: -rp7 ^= (rp7 << 4); -rp7 ^= (rp7 << 2); -rp7 ^= (rp7 << 1); -rp7 &= 0x80; -No gain. - -The only marginal change was inverting the parity bits, so we can remove -the last three invert statements. - -Ah well, pity this does not deliver more. Then again 10 million -iterations using the linux driver code takes between 13 and 13.5 -seconds, whereas my code now takes about 0.73 seconds for those 10 -million iterations. So basically I've improved the performance by a -factor 18 on my system. Not that bad. Of course on different hardware -you will get different results. No warranties! - -But of course there is no such thing as a free lunch. The codesize almost -tripled (from 562 bytes to 1434 bytes). Then again, it is not that much. - - -Correcting errors -================= - -For correcting errors I again used the ST application note as a starter, -but I also peeked at the existing code. -The algorithm itself is pretty straightforward. Just xor the given and -the calculated ecc. If all bytes are 0 there is no problem. If 11 bits -are 1 we have one correctable bit error. If there is 1 bit 1, we have an -error in the given ecc code. -It proved to be fastest to do some table lookups. Performance gain -introduced by this is about a factor 2 on my system when a repair had to -be done, and 1% or so if no repair had to be done. -Code size increased from 330 bytes to 686 bytes for this function. -(gcc 4.2, -O3) - - -Conclusion -========== - -The gain when calculating the ecc is tremendous. Om my development hardware -a speedup of a factor of 18 for ecc calculation was achieved. On a test on an -embedded system with a MIPS core a factor 7 was obtained. -On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor -5 (big endian mode, gcc 4.1.2, -O3) -For correction not much gain could be obtained (as bitflips are rare). Then -again there are also much less cycles spent there. - -It seems there is not much more gain possible in this, at least when -programmed in C. Of course it might be possible to squeeze something more -out of it with an assembler program, but due to pipeline behaviour etc -this is very tricky (at least for intel hw). - -Author: Frans Meulenbroeks -Copyright (C) 2008 Koninklijke Philips Electronics NV. diff --git a/trunk/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h b/trunk/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h index eb35fca9aea5..eb4b190b6657 100644 --- a/trunk/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h +++ b/trunk/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h @@ -4,43 +4,6 @@ #include #include -struct pxa3xx_nand_timing { - unsigned int tCH; /* Enable signal hold time */ - unsigned int tCS; /* Enable signal setup time */ - unsigned int tWH; /* ND_nWE high duration */ - unsigned int tWP; /* ND_nWE pulse time */ - unsigned int tRH; /* ND_nRE high duration */ - unsigned int tRP; /* ND_nRE pulse width */ - unsigned int tR; /* ND_nWE high to ND_nRE low for read */ - unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ - unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ -}; - -struct pxa3xx_nand_cmdset { - uint16_t read1; - uint16_t read2; - uint16_t program; - uint16_t read_status; - uint16_t read_id; - uint16_t erase; - uint16_t reset; - uint16_t lock; - uint16_t unlock; - uint16_t lock_status; -}; - -struct pxa3xx_nand_flash { - const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ - const struct pxa3xx_nand_cmdset *cmdset; - - uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ - uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ - uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ - uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ - uint32_t num_blocks; /* Number of physical blocks in Flash */ - uint32_t chip_id; -}; - struct pxa3xx_nand_platform_data { /* the data flash bus is shared between the Static Memory @@ -49,11 +12,8 @@ struct pxa3xx_nand_platform_data { */ int enable_arbiter; - const struct mtd_partition *parts; - unsigned int nr_parts; - - const struct pxa3xx_nand_flash * flash; - size_t num_flash; + struct mtd_partition *parts; + unsigned int nr_parts; }; extern void pxa3xx_set_nand_info(struct pxa3xx_nand_platform_data *info); diff --git a/trunk/arch/arm/plat-mxc/include/mach/mxc_nand.h b/trunk/arch/arm/plat-mxc/include/mach/mxc_nand.h deleted file mode 100644 index 2b972df22d12..000000000000 --- a/trunk/arch/arm/plat-mxc/include/mach/mxc_nand.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Sascha Hauer, kernel@pengutronix.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#ifndef __ASM_ARCH_NAND_H -#define __ASM_ARCH_NAND_H - -struct mxc_nand_platform_data { - int width; /* data bus width in bytes */ - int hw_ecc; /* 0 if supress hardware ECC */ -}; -#endif /* __ASM_ARCH_NAND_H */ diff --git a/trunk/arch/arm/plat-omap/include/mach/onenand.h b/trunk/arch/arm/plat-omap/include/mach/onenand.h index 4649d302c263..d57f20226b28 100644 --- a/trunk/arch/arm/plat-omap/include/mach/onenand.h +++ b/trunk/arch/arm/plat-omap/include/mach/onenand.h @@ -16,10 +16,6 @@ struct omap_onenand_platform_data { int gpio_irq; struct mtd_partition *parts; int nr_parts; - int (*onenand_setup)(void __iomem *, int freq); + int (*onenand_setup)(void __iomem *); int dma_channel; }; - -int omap2_onenand_rephase(void); - -#define ONENAND_MAX_PARTITIONS 8 diff --git a/trunk/arch/x86/pci/i386.c b/trunk/arch/x86/pci/i386.c index 5807d1bc73f7..d765da913842 100644 --- a/trunk/arch/x86/pci/i386.c +++ b/trunk/arch/x86/pci/i386.c @@ -31,8 +31,11 @@ #include #include #include +#include #include +#include +#include #include "pci.h" @@ -77,6 +80,77 @@ pcibios_align_resource(void *data, struct resource *res, } EXPORT_SYMBOL(pcibios_align_resource); +static int check_res_with_valid(struct pci_dev *dev, struct resource *res) +{ + unsigned long base; + unsigned long size; + int i; + + base = res->start; + size = (res->start == 0 && res->end == res->start) ? 0 : + (res->end - res->start + 1); + + if (!base || !size) + return 0; + +#ifdef CONFIG_HPET_TIMER + /* for hpet */ + if (base == hpet_address && (res->flags & IORESOURCE_MEM)) { + dev_info(&dev->dev, "BAR has HPET at %08lx-%08lx\n", + base, base + size - 1); + return 1; + } +#endif + +#ifdef CONFIG_X86_IO_APIC + for (i = 0; i < nr_ioapics; i++) { + unsigned long ioapic_phys = mp_ioapics[i].mp_apicaddr; + + if (base == ioapic_phys && (res->flags & IORESOURCE_MEM)) { + dev_info(&dev->dev, "BAR has ioapic at %08lx-%08lx\n", + base, base + size - 1); + return 1; + } + } +#endif + +#ifdef CONFIG_PCI_MMCONFIG + for (i = 0; i < pci_mmcfg_config_num; i++) { + unsigned long addr; + + addr = pci_mmcfg_config[i].address; + if (base == addr && (res->flags & IORESOURCE_MEM)) { + dev_info(&dev->dev, "BAR has MMCONFIG at %08lx-%08lx\n", + base, base + size - 1); + return 1; + } + } +#endif + + return 0; +} + +static int check_platform(struct pci_dev *dev, struct resource *res) +{ + struct resource *root = NULL; + + /* + * forcibly insert it into the + * resource tree + */ + if (res->flags & IORESOURCE_MEM) + root = &iomem_resource; + else if (res->flags & IORESOURCE_IO) + root = &ioport_resource; + + if (root && check_res_with_valid(dev, res)) { + insert_resource(root, res); + + return 1; + } + + return 0; +} /* * Handle resources of PCI devices. If the world were perfect, we could * just allocate all the resource regions and do nothing more. It isn't. @@ -128,6 +202,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) pr = pci_find_parent_resource(dev, r); if (!r->start || !pr || request_resource(pr, r) < 0) { + if (check_platform(dev, r)) + continue; dev_err(&dev->dev, "BAR %d: can't " "allocate resource\n", idx); /* @@ -171,6 +247,8 @@ static void __init pcibios_allocate_resources(int pass) r->flags, disabled, pass); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { + if (check_platform(dev, r)) + continue; dev_err(&dev->dev, "BAR %d: can't " "allocate resource\n", idx); /* We'll assign a new address later */ diff --git a/trunk/drivers/mtd/Kconfig b/trunk/drivers/mtd/Kconfig index a90d50c2c3e5..14f11f8b9e5f 100644 --- a/trunk/drivers/mtd/Kconfig +++ b/trunk/drivers/mtd/Kconfig @@ -172,11 +172,6 @@ config MTD_CHAR memory chips, and also use ioctl() to obtain information about the device, or to erase parts of it. -config HAVE_MTD_OTP - bool - help - Enable access to OTP regions using MTD_CHAR. - config MTD_BLKDEVS tristate "Common interface to block layer for MTD 'translation layers'" depends on BLOCK diff --git a/trunk/drivers/mtd/chips/Kconfig b/trunk/drivers/mtd/chips/Kconfig index 9408099eec48..479d32b57a1e 100644 --- a/trunk/drivers/mtd/chips/Kconfig +++ b/trunk/drivers/mtd/chips/Kconfig @@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers" config MTD_CFI tristate "Detect flash chips by Common Flash Interface (CFI) probe" select MTD_GEN_PROBE - select MTD_CFI_UTIL help The Common Flash Interface specification was developed by Intel, AMD and other flash manufactures that provides a universal method @@ -155,7 +154,6 @@ config MTD_CFI_I8 config MTD_OTP bool "Protection Registers aka one-time programmable (OTP) bits" depends on MTD_CFI_ADV_OPTIONS - select HAVE_MTD_OTP default n help This enables support for reading, writing and locking so called @@ -189,7 +187,7 @@ config MTD_CFI_INTELEXT StrataFlash and other parts. config MTD_CFI_AMDSTD - tristate "Support for AMD/Fujitsu/Spansion flash chips" + tristate "Support for AMD/Fujitsu flash chips" depends on MTD_GEN_PROBE select MTD_CFI_UTIL help diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c index c93a8be5d5f1..5f1b472137a0 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c @@ -478,28 +478,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) else cfi->chips[i].erase_time = 2000000; - if (cfi->cfiq->WordWriteTimeoutTyp && - cfi->cfiq->WordWriteTimeoutMax) - cfi->chips[i].word_write_time_max = - 1<<(cfi->cfiq->WordWriteTimeoutTyp + - cfi->cfiq->WordWriteTimeoutMax); - else - cfi->chips[i].word_write_time_max = 50000 * 8; - - if (cfi->cfiq->BufWriteTimeoutTyp && - cfi->cfiq->BufWriteTimeoutMax) - cfi->chips[i].buffer_write_time_max = - 1<<(cfi->cfiq->BufWriteTimeoutTyp + - cfi->cfiq->BufWriteTimeoutMax); - - if (cfi->cfiq->BlockEraseTimeoutTyp && - cfi->cfiq->BlockEraseTimeoutMax) - cfi->chips[i].erase_time_max = - 1000<<(cfi->cfiq->BlockEraseTimeoutTyp + - cfi->cfiq->BlockEraseTimeoutMax); - else - cfi->chips[i].erase_time_max = 2000000 * 8; - cfi->chips[i].ref_point_counter = 0; init_waitqueue_head(&(cfi->chips[i].wq)); } @@ -725,10 +703,6 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long struct cfi_pri_intelext *cfip = cfi->cmdset_priv; unsigned long timeo = jiffies + HZ; - /* Prevent setting state FL_SYNCING for chip in suspended state. */ - if (mode == FL_SYNCING && chip->oldstate != FL_READY) - goto sleep; - switch (chip->state) { case FL_STATUS: @@ -834,9 +808,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr DECLARE_WAITQUEUE(wait, current); retry: - if (chip->priv && - (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE - || mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING + || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { /* * OK. We have possibility for contention on the write/erase * operations which are global to the real chip and not per @@ -886,14 +859,6 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr return ret; } spin_lock(&shared->lock); - - /* We should not own chip if it is already - * in FL_SYNCING state. Put contender and retry. */ - if (chip->state == FL_SYNCING) { - put_chip(map, contender, contender->start); - spin_unlock(contender->mutex); - goto retry; - } spin_unlock(contender->mutex); } @@ -1047,7 +1012,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, static int __xipram xip_wait_for_operation( struct map_info *map, struct flchip *chip, - unsigned long adr, unsigned int chip_op_time_max) + unsigned long adr, unsigned int chip_op_time ) { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *cfip = cfi->cmdset_priv; @@ -1056,7 +1021,7 @@ static int __xipram xip_wait_for_operation( flstate_t oldstate, newstate; start = xip_currtime(); - usec = chip_op_time_max; + usec = chip_op_time * 8; if (usec == 0) usec = 500000; done = 0; @@ -1166,8 +1131,8 @@ static int __xipram xip_wait_for_operation( #define XIP_INVAL_CACHED_RANGE(map, from, size) \ INVALIDATE_CACHED_RANGE(map, from, size) -#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec, usec_max) \ - xip_wait_for_operation(map, chip, cmd_adr, usec_max) +#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \ + xip_wait_for_operation(map, chip, cmd_adr, usec) #else @@ -1179,7 +1144,7 @@ static int __xipram xip_wait_for_operation( static int inval_cache_and_wait_for_operation( struct map_info *map, struct flchip *chip, unsigned long cmd_adr, unsigned long inval_adr, int inval_len, - unsigned int chip_op_time, unsigned int chip_op_time_max) + unsigned int chip_op_time) { struct cfi_private *cfi = map->fldrv_priv; map_word status, status_OK = CMD(0x80); @@ -1191,7 +1156,8 @@ static int inval_cache_and_wait_for_operation( INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len); spin_lock(chip->mutex); - timeo = chip_op_time_max; + /* set our timeout to 8 times the expected delay */ + timeo = chip_op_time * 8; if (!timeo) timeo = 500000; reset_timeo = timeo; @@ -1251,8 +1217,8 @@ static int inval_cache_and_wait_for_operation( #endif -#define WAIT_TIMEOUT(map, chip, adr, udelay, udelay_max) \ - INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay, udelay_max); +#define WAIT_TIMEOUT(map, chip, adr, udelay) \ + INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay); static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) @@ -1486,8 +1452,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, map_bankwidth(map), - chip->word_write_time, - chip->word_write_time_max); + chip->word_write_time); if (ret) { xip_enable(map, chip, adr); printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); @@ -1658,7 +1623,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, chip->state = FL_WRITING_TO_BUFFER; map_write(map, write_cmd, cmd_adr); - ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0); + ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0); if (ret) { /* Argh. Not ready for write to buffer */ map_word Xstatus = map_read(map, cmd_adr); @@ -1675,7 +1640,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, /* Figure out the number of words to write */ word_gap = (-adr & (map_bankwidth(map)-1)); - words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map)); + words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); if (!word_gap) { words--; } else { @@ -1727,8 +1692,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, initial_adr, initial_len, - chip->buffer_write_time, - chip->buffer_write_time_max); + chip->buffer_write_time); if (ret) { map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; @@ -1863,8 +1827,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, - chip->erase_time, - chip->erase_time_max); + chip->erase_time); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; @@ -2043,7 +2006,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip */ udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; - ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100); + ret = WAIT_TIMEOUT(map, chip, adr, udelay); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; diff --git a/trunk/drivers/mtd/chips/cfi_probe.c b/trunk/drivers/mtd/chips/cfi_probe.c index e63e6749429a..c418e92e1d92 100644 --- a/trunk/drivers/mtd/chips/cfi_probe.c +++ b/trunk/drivers/mtd/chips/cfi_probe.c @@ -44,14 +44,17 @@ do { \ #define xip_enable(base, map, cfi) \ do { \ - cfi_qry_mode_off(base, map, cfi); \ + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ xip_allowed(base, map); \ } while (0) #define xip_disable_qry(base, map, cfi) \ do { \ xip_disable(); \ - cfi_qry_mode_on(base, map, cfi); \ + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \ } while (0) #else @@ -67,6 +70,32 @@ do { \ in: interleave,type,mode ret: table index, <0 for error */ +static int __xipram qry_present(struct map_info *map, __u32 base, + struct cfi_private *cfi) +{ + int osf = cfi->interleave * cfi->device_type; // scale factor + map_word val[3]; + map_word qry[3]; + + qry[0] = cfi_build_cmd('Q', map, cfi); + qry[1] = cfi_build_cmd('R', map, cfi); + qry[2] = cfi_build_cmd('Y', map, cfi); + + val[0] = map_read(map, base + osf*0x10); + val[1] = map_read(map, base + osf*0x11); + val[2] = map_read(map, base + osf*0x12); + + if (!map_word_equal(map, qry[0], val[0])) + return 0; + + if (!map_word_equal(map, qry[1], val[1])) + return 0; + + if (!map_word_equal(map, qry[2], val[2])) + return 0; + + return 1; // "QRY" found +} static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, unsigned long *chip_map, struct cfi_private *cfi) @@ -87,7 +116,11 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, } xip_disable(); - if (!cfi_qry_mode_on(base, map, cfi)) { + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); + + if (!qry_present(map,base,cfi)) { xip_enable(base, map, cfi); return 0; } @@ -108,13 +141,14 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, start = i << cfi->chipshift; /* This chip should be in read mode if it's one we've already touched. */ - if (cfi_qry_present(map, start, cfi)) { + if (qry_present(map, start, cfi)) { /* Eep. This chip also had the QRY marker. * Is it an alias for the new one? */ - cfi_qry_mode_off(start, map, cfi); + cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); /* If the QRY marker goes away, it's an alias */ - if (!cfi_qry_present(map, start, cfi)) { + if (!qry_present(map, start, cfi)) { xip_allowed(base, map); printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, start); @@ -124,9 +158,10 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, * unfortunate. Stick the new chip in read mode * too and if it's the same, assume it's an alias. */ /* FIXME: Use other modes to do a proper check */ - cfi_qry_mode_off(base, map, cfi); + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); - if (cfi_qry_present(map, base, cfi)) { + if (qry_present(map, base, cfi)) { xip_allowed(base, map); printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, start); @@ -141,7 +176,8 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, cfi->numchips++; /* Put it back into Read Mode */ - cfi_qry_mode_off(base, map, cfi); + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); xip_allowed(base, map); printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", @@ -201,7 +237,9 @@ static int __xipram cfi_chip_setup(struct map_info *map, cfi_read_query(map, base + 0xf * ofs_factor); /* Put it back into Read Mode */ - cfi_qry_mode_off(base, map, cfi); + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + /* ... even if it's an Intel chip */ + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); xip_allowed(base, map); /* Do any necessary byteswapping */ diff --git a/trunk/drivers/mtd/chips/cfi_util.c b/trunk/drivers/mtd/chips/cfi_util.c index 34d40e25d312..0ee457018016 100644 --- a/trunk/drivers/mtd/chips/cfi_util.c +++ b/trunk/drivers/mtd/chips/cfi_util.c @@ -24,66 +24,6 @@ #include #include -int __xipram cfi_qry_present(struct map_info *map, __u32 base, - struct cfi_private *cfi) -{ - int osf = cfi->interleave * cfi->device_type; /* scale factor */ - map_word val[3]; - map_word qry[3]; - - qry[0] = cfi_build_cmd('Q', map, cfi); - qry[1] = cfi_build_cmd('R', map, cfi); - qry[2] = cfi_build_cmd('Y', map, cfi); - - val[0] = map_read(map, base + osf*0x10); - val[1] = map_read(map, base + osf*0x11); - val[2] = map_read(map, base + osf*0x12); - - if (!map_word_equal(map, qry[0], val[0])) - return 0; - - if (!map_word_equal(map, qry[1], val[1])) - return 0; - - if (!map_word_equal(map, qry[2], val[2])) - return 0; - - return 1; /* "QRY" found */ -} -EXPORT_SYMBOL_GPL(cfi_qry_present); - -int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, - struct cfi_private *cfi) -{ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - if (cfi_qry_present(map, base, cfi)) - return 1; - /* QRY not found probably we deal with some odd CFI chips */ - /* Some revisions of some old Intel chips? */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - if (cfi_qry_present(map, base, cfi)) - return 1; - /* ST M29DW chips */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); - if (cfi_qry_present(map, base, cfi)) - return 1; - /* QRY not found */ - return 0; -} -EXPORT_SYMBOL_GPL(cfi_qry_mode_on); - -void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, - struct cfi_private *cfi) -{ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); -} -EXPORT_SYMBOL_GPL(cfi_qry_mode_off); - struct cfi_extquery * __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) { @@ -108,7 +48,8 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n #endif /* Switch it into Query Mode */ - cfi_qry_mode_on(base, map, cfi); + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); + /* Read in the Extended Query Table */ for (i=0; idevice_type, NULL); + cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL); #ifdef CONFIG_MTD_XIP (void) map_read(map, base); diff --git a/trunk/drivers/mtd/chips/gen_probe.c b/trunk/drivers/mtd/chips/gen_probe.c index e2dc96441e05..f061885b2812 100644 --- a/trunk/drivers/mtd/chips/gen_probe.c +++ b/trunk/drivers/mtd/chips/gen_probe.c @@ -111,7 +111,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi max_chips = 1; } - mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); + mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG ); chip_map = kzalloc(mapsize, GFP_KERNEL); if (!chip_map) { printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); diff --git a/trunk/drivers/mtd/devices/Kconfig b/trunk/drivers/mtd/devices/Kconfig index 6fde0a2e3567..9c613f06623c 100644 --- a/trunk/drivers/mtd/devices/Kconfig +++ b/trunk/drivers/mtd/devices/Kconfig @@ -59,27 +59,6 @@ config MTD_DATAFLASH Sometimes DataFlash chips are packaged inside MMC-format cards; at this writing, the MMC stack won't handle those. -config MTD_DATAFLASH_WRITE_VERIFY - bool "Verify DataFlash page writes" - depends on MTD_DATAFLASH - help - This adds an extra check when data is written to the flash. - It may help if you are verifying chip setup (timings etc) on - your board. There is a rare possibility that even though the - device thinks the write was successful, a bit could have been - flipped accidentally due to device wear or something else. - -config MTD_DATAFLASH_OTP - bool "DataFlash OTP support (Security Register)" - depends on MTD_DATAFLASH - select HAVE_MTD_OTP - help - Newer DataFlash chips (revisions C and D) support 128 bytes of - one-time-programmable (OTP) data. The first half may be written - (once) with up to 64 bytes of data, such as a serial number or - other key product data. The second half is programmed with a - unique-to-each-chip bit pattern at the factory. - config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" depends on SPI_MASTER && EXPERIMENTAL diff --git a/trunk/drivers/mtd/devices/m25p80.c b/trunk/drivers/mtd/devices/m25p80.c index 697a3a217837..b35c3333e210 100644 --- a/trunk/drivers/mtd/devices/m25p80.c +++ b/trunk/drivers/mtd/devices/m25p80.c @@ -39,7 +39,6 @@ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ -#define OPCODE_BE 0xc7 /* Erase whole flash block */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ @@ -134,7 +133,7 @@ static inline int write_enable(struct m25p *flash) { u8 code = OPCODE_WREN; - return spi_write(flash->spi, &code, 1); + return spi_write_then_read(flash->spi, &code, 1, NULL, 0); } @@ -162,31 +161,6 @@ static int wait_till_ready(struct m25p *flash) return 1; } -/* - * Erase the whole flash memory - * - * Returns 0 if successful, non-zero otherwise. - */ -static int erase_block(struct m25p *flash) -{ - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n", - flash->spi->dev.bus_id, __func__, - flash->mtd.size / 1024); - - /* Wait until finished previous write command. */ - if (wait_till_ready(flash)) - return 1; - - /* Send write enable, then erase commands. */ - write_enable(flash); - - /* Set up command buffer. */ - flash->command[0] = OPCODE_BE; - - spi_write(flash->spi, flash->command, 1); - - return 0; -} /* * Erase one sector of flash memory at offset ``offset'' which is any @@ -255,21 +229,15 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) */ /* now erase those sectors */ - if (len == flash->mtd.size && erase_block(flash)) { - instr->state = MTD_ERASE_FAILED; - mutex_unlock(&flash->lock); - return -EIO; - } else { - while (len) { - if (erase_sector(flash, addr)) { - instr->state = MTD_ERASE_FAILED; - mutex_unlock(&flash->lock); - return -EIO; - } - - addr += mtd->erasesize; - len -= mtd->erasesize; + while (len) { + if (erase_sector(flash, addr)) { + instr->state = MTD_ERASE_FAILED; + mutex_unlock(&flash->lock); + return -EIO; } + + addr += mtd->erasesize; + len -= mtd->erasesize; } mutex_unlock(&flash->lock); @@ -469,7 +437,6 @@ struct flash_info { * then a two byte device id. */ u32 jedec_id; - u16 ext_id; /* The size listed here is what works with OPCODE_SE, which isn't * necessarily called a "sector" by the vendor. @@ -489,75 +456,72 @@ struct flash_info { static struct flash_info __devinitdata m25p_data [] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K, }, - { "at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K, }, + { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, + { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, - { "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K, }, - { "at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K, }, + { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, + { "at25df641", 0x1f4800, 64 * 1024, 128, SECT_4K, }, - { "at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K, }, - { "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K, }, - { "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, }, - { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, }, + { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, + { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, + { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, + { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ - { "s25sl004a", 0x010212, 0, 64 * 1024, 8, }, - { "s25sl008a", 0x010213, 0, 64 * 1024, 16, }, - { "s25sl016a", 0x010214, 0, 64 * 1024, 32, }, - { "s25sl032a", 0x010215, 0, 64 * 1024, 64, }, - { "s25sl064a", 0x010216, 0, 64 * 1024, 128, }, - { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, }, - { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, }, + { "s25sl004a", 0x010212, 64 * 1024, 8, }, + { "s25sl008a", 0x010213, 64 * 1024, 16, }, + { "s25sl016a", 0x010214, 64 * 1024, 32, }, + { "s25sl032a", 0x010215, 64 * 1024, 64, }, + { "s25sl064a", 0x010216, 64 * 1024, 128, }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, }, - { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, }, - { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, }, - { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, }, + { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, + { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, + { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, + { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, /* ST Microelectronics -- newer production may have feature updates */ - { "m25p05", 0x202010, 0, 32 * 1024, 2, }, - { "m25p10", 0x202011, 0, 32 * 1024, 4, }, - { "m25p20", 0x202012, 0, 64 * 1024, 4, }, - { "m25p40", 0x202013, 0, 64 * 1024, 8, }, - { "m25p80", 0, 0, 64 * 1024, 16, }, - { "m25p16", 0x202015, 0, 64 * 1024, 32, }, - { "m25p32", 0x202016, 0, 64 * 1024, 64, }, - { "m25p64", 0x202017, 0, 64 * 1024, 128, }, - { "m25p128", 0x202018, 0, 256 * 1024, 64, }, - - { "m45pe80", 0x204014, 0, 64 * 1024, 16, }, - { "m45pe16", 0x204015, 0, 64 * 1024, 32, }, - - { "m25pe80", 0x208014, 0, 64 * 1024, 16, }, - { "m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K, }, + { "m25p05", 0x202010, 32 * 1024, 2, }, + { "m25p10", 0x202011, 32 * 1024, 4, }, + { "m25p20", 0x202012, 64 * 1024, 4, }, + { "m25p40", 0x202013, 64 * 1024, 8, }, + { "m25p80", 0, 64 * 1024, 16, }, + { "m25p16", 0x202015, 64 * 1024, 32, }, + { "m25p32", 0x202016, 64 * 1024, 64, }, + { "m25p64", 0x202017, 64 * 1024, 128, }, + { "m25p128", 0x202018, 256 * 1024, 64, }, + + { "m45pe80", 0x204014, 64 * 1024, 16, }, + { "m45pe16", 0x204015, 64 * 1024, 32, }, + + { "m25pe80", 0x208014, 64 * 1024, 16, }, + { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { "w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K, }, - { "w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K, }, - { "w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K, }, - { "w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K, }, - { "w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K, }, - { "w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K, }, - { "w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K, }, + { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, + { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, + { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, + { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, + { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, + { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, + { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, }; static struct flash_info *__devinit jedec_probe(struct spi_device *spi) { int tmp; u8 code = OPCODE_RDID; - u8 id[5]; + u8 id[3]; u32 jedec; - u16 ext_jedec; struct flash_info *info; /* JEDEC also defines an optional "extended device information" * string for after vendor-specific data, after the three bytes * we use here. Supporting some chips might require using it. */ - tmp = spi_write_then_read(spi, &code, 1, id, 5); + tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", spi->dev.bus_id, tmp); @@ -569,14 +533,10 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) jedec = jedec << 8; jedec |= id[2]; - ext_jedec = id[3] << 8 | id[4]; - for (tmp = 0, info = m25p_data; tmp < ARRAY_SIZE(m25p_data); tmp++, info++) { if (info->jedec_id == jedec) - if (ext_jedec != 0 && info->ext_id != ext_jedec) - continue; return info; } dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); diff --git a/trunk/drivers/mtd/devices/mtd_dataflash.c b/trunk/drivers/mtd/devices/mtd_dataflash.c index 6dd9aff8bb2d..8bd0dea6885f 100644 --- a/trunk/drivers/mtd/devices/mtd_dataflash.c +++ b/trunk/drivers/mtd/devices/mtd_dataflash.c @@ -30,10 +30,12 @@ * doesn't (yet) use these for any kind of i/o overlap or prefetching. * * Sometimes DataFlash is packaged in MMC-format cards, although the - * MMC stack can't (yet?) distinguish between MMC and DataFlash + * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash * protocols during enumeration. */ +#define CONFIG_DATAFLASH_WRITE_VERIFY + /* reads can bypass the buffers */ #define OP_READ_CONTINUOUS 0xE8 #define OP_READ_PAGE 0xD2 @@ -78,8 +80,7 @@ */ #define OP_READ_ID 0x9F #define OP_READ_SECURITY 0x77 -#define OP_WRITE_SECURITY_REVC 0x9A -#define OP_WRITE_SECURITY 0x9B /* revision D */ +#define OP_WRITE_SECURITY 0x9A /* OTP bits */ struct dataflash { @@ -401,7 +402,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, (void) dataflash_waitready(priv->spi); -#ifdef CONFIG_MTD_DATAFLASH_VERIFY_WRITE +#ifdef CONFIG_DATAFLASH_WRITE_VERIFY /* (3) Compare to Buffer1 */ addr = pageaddr << priv->page_offset; @@ -430,7 +431,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, } else status = 0; -#endif /* CONFIG_MTD_DATAFLASH_VERIFY_WRITE */ +#endif /* CONFIG_DATAFLASH_WRITE_VERIFY */ remaining = remaining - writelen; pageaddr++; @@ -450,192 +451,16 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, /* ......................................................................... */ -#ifdef CONFIG_MTD_DATAFLASH_OTP - -static int dataflash_get_otp_info(struct mtd_info *mtd, - struct otp_info *info, size_t len) -{ - /* Report both blocks as identical: bytes 0..64, locked. - * Unless the user block changed from all-ones, we can't - * tell whether it's still writable; so we assume it isn't. - */ - info->start = 0; - info->length = 64; - info->locked = 1; - return sizeof(*info); -} - -static ssize_t otp_read(struct spi_device *spi, unsigned base, - uint8_t *buf, loff_t off, size_t len) -{ - struct spi_message m; - size_t l; - uint8_t *scratch; - struct spi_transfer t; - int status; - - if (off > 64) - return -EINVAL; - - if ((off + len) > 64) - len = 64 - off; - if (len == 0) - return len; - - spi_message_init(&m); - - l = 4 + base + off + len; - scratch = kzalloc(l, GFP_KERNEL); - if (!scratch) - return -ENOMEM; - - /* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes - * IN: ignore 4 bytes, data bytes 0..N (max 127) - */ - scratch[0] = OP_READ_SECURITY; - - memset(&t, 0, sizeof t); - t.tx_buf = scratch; - t.rx_buf = scratch; - t.len = l; - spi_message_add_tail(&t, &m); - - dataflash_waitready(spi); - - status = spi_sync(spi, &m); - if (status >= 0) { - memcpy(buf, scratch + 4 + base + off, len); - status = len; - } - - kfree(scratch); - return status; -} - -static int dataflash_read_fact_otp(struct mtd_info *mtd, - loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct dataflash *priv = (struct dataflash *)mtd->priv; - int status; - - /* 64 bytes, from 0..63 ... start at 64 on-chip */ - mutex_lock(&priv->lock); - status = otp_read(priv->spi, 64, buf, from, len); - mutex_unlock(&priv->lock); - - if (status < 0) - return status; - *retlen = status; - return 0; -} - -static int dataflash_read_user_otp(struct mtd_info *mtd, - loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct dataflash *priv = (struct dataflash *)mtd->priv; - int status; - - /* 64 bytes, from 0..63 ... start at 0 on-chip */ - mutex_lock(&priv->lock); - status = otp_read(priv->spi, 0, buf, from, len); - mutex_unlock(&priv->lock); - - if (status < 0) - return status; - *retlen = status; - return 0; -} - -static int dataflash_write_user_otp(struct mtd_info *mtd, - loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct spi_message m; - const size_t l = 4 + 64; - uint8_t *scratch; - struct spi_transfer t; - struct dataflash *priv = (struct dataflash *)mtd->priv; - int status; - - if (len > 64) - return -EINVAL; - - /* Strictly speaking, we *could* truncate the write ... but - * let's not do that for the only write that's ever possible. - */ - if ((from + len) > 64) - return -EINVAL; - - /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes - * IN: ignore all - */ - scratch = kzalloc(l, GFP_KERNEL); - if (!scratch) - return -ENOMEM; - scratch[0] = OP_WRITE_SECURITY; - memcpy(scratch + 4 + from, buf, len); - - spi_message_init(&m); - - memset(&t, 0, sizeof t); - t.tx_buf = scratch; - t.len = l; - spi_message_add_tail(&t, &m); - - /* Write the OTP bits, if they've not yet been written. - * This modifies SRAM buffer1. - */ - mutex_lock(&priv->lock); - dataflash_waitready(priv->spi); - status = spi_sync(priv->spi, &m); - mutex_unlock(&priv->lock); - - kfree(scratch); - - if (status >= 0) { - status = 0; - *retlen = len; - } - return status; -} - -static char *otp_setup(struct mtd_info *device, char revision) -{ - device->get_fact_prot_info = dataflash_get_otp_info; - device->read_fact_prot_reg = dataflash_read_fact_otp; - device->get_user_prot_info = dataflash_get_otp_info; - device->read_user_prot_reg = dataflash_read_user_otp; - - /* rev c parts (at45db321c and at45db1281 only!) use a - * different write procedure; not (yet?) implemented. - */ - if (revision > 'c') - device->write_user_prot_reg = dataflash_write_user_otp; - - return ", OTP"; -} - -#else - -static char *otp_setup(struct mtd_info *device, char revision) -{ - return " (OTP)"; -} - -#endif - -/* ......................................................................... */ - /* * Register DataFlash device with MTD subsystem. */ static int __devinit -add_dataflash_otp(struct spi_device *spi, char *name, - int nr_pages, int pagesize, int pageoffset, char revision) +add_dataflash(struct spi_device *spi, char *name, + int nr_pages, int pagesize, int pageoffset) { struct dataflash *priv; struct mtd_info *device; struct flash_platform_data *pdata = spi->dev.platform_data; - char *otp_tag = ""; priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) @@ -664,12 +489,8 @@ add_dataflash_otp(struct spi_device *spi, char *name, device->write = dataflash_write; device->priv = priv; - if (revision >= 'c') - otp_tag = otp_setup(device, revision); - - dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", - name, DIV_ROUND_UP(device->size, 1024), - pagesize, otp_tag); + dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", + name, DIV_ROUND_UP(device->size, 1024), pagesize); dev_set_drvdata(&spi->dev, priv); if (mtd_has_partitions()) { @@ -698,14 +519,6 @@ add_dataflash_otp(struct spi_device *spi, char *name, return add_mtd_device(device) == 1 ? -ENODEV : 0; } -static inline int __devinit -add_dataflash(struct spi_device *spi, char *name, - int nr_pages, int pagesize, int pageoffset) -{ - return add_dataflash_otp(spi, name, nr_pages, pagesize, - pageoffset, 0); -} - struct flash_info { char *name; @@ -851,16 +664,13 @@ static int __devinit dataflash_probe(struct spi_device *spi) * Try to detect dataflash by JEDEC ID. * If it succeeds we know we have either a C or D part. * D will support power of 2 pagesize option. - * Both support the security register, though with different - * write procedures. */ info = jedec_probe(spi); if (IS_ERR(info)) return PTR_ERR(info); if (info != NULL) - return add_dataflash_otp(spi, info->name, info->nr_pages, - info->pagesize, info->pageoffset, - (info->flags & SUP_POW2PS) ? 'd' : 'c'); + return add_dataflash(spi, info->name, info->nr_pages, + info->pagesize, info->pageoffset); /* * Older chips support only legacy commands, identifing diff --git a/trunk/drivers/mtd/inftlcore.c b/trunk/drivers/mtd/inftlcore.c index 50ce13887f63..c4f9d3378b24 100644 --- a/trunk/drivers/mtd/inftlcore.c +++ b/trunk/drivers/mtd/inftlcore.c @@ -388,10 +388,6 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned if (thisEUN == targetEUN) break; - /* Unlink the last block from the chain. */ - inftl->PUtable[prevEUN] = BLOCK_NIL; - - /* Now try to erase it. */ if (INFTL_formatblock(inftl, thisEUN) < 0) { /* * Could not erase : mark block as reserved. @@ -400,6 +396,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned } else { /* Correctly erased : mark it as free */ inftl->PUtable[thisEUN] = BLOCK_FREE; + inftl->PUtable[prevEUN] = BLOCK_NIL; inftl->numfreeEUNs++; } } diff --git a/trunk/drivers/mtd/maps/Kconfig b/trunk/drivers/mtd/maps/Kconfig index 5ea169362164..df8e00bba07b 100644 --- a/trunk/drivers/mtd/maps/Kconfig +++ b/trunk/drivers/mtd/maps/Kconfig @@ -332,6 +332,30 @@ config MTD_CFI_FLAGADM Mapping for the Flaga digital module. If you don't have one, ignore this setting. +config MTD_WALNUT + tristate "Flash device mapped on IBM 405GP Walnut" + depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE + help + This enables access routines for the flash chips on the IBM 405GP + Walnut board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + +config MTD_EBONY + tristate "Flash devices mapped on IBM 440GP Ebony" + depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE + help + This enables access routines for the flash chips on the IBM 440GP + Ebony board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + +config MTD_OCOTEA + tristate "Flash devices mapped on IBM 440GX Ocotea" + depends on MTD_CFI && OCOTEA && !PPC_MERGE + help + This enables access routines for the flash chips on the IBM 440GX + Ocotea board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + config MTD_REDWOOD tristate "CFI Flash devices mapped on IBM Redwood" depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) @@ -434,6 +458,13 @@ config MTD_CEIVA PhotoMax Digital Picture Frame. If you have such a device, say 'Y'. +config MTD_NOR_TOTO + tristate "NOR Flash device on TOTO board" + depends on ARCH_OMAP && OMAP_TOTO + help + This enables access to the NOR flash on the Texas Instruments + TOTO board. + config MTD_H720X tristate "Hynix evaluation board mappings" depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) @@ -491,7 +522,7 @@ config MTD_BFIN_ASYNC config MTD_UCLINUX tristate "Generic uClinux RAM/ROM filesystem support" - depends on MTD_PARTITIONS && MTD_RAM && !MMU + depends on MTD_PARTITIONS && !MMU help Map driver to support image based filesystems for uClinux. diff --git a/trunk/drivers/mtd/maps/Makefile b/trunk/drivers/mtd/maps/Makefile index 6d9ba35caf11..6cda6df973e5 100644 --- a/trunk/drivers/mtd/maps/Makefile +++ b/trunk/drivers/mtd/maps/Makefile @@ -50,8 +50,12 @@ obj-$(CONFIG_MTD_REDWOOD) += redwood.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o +obj-$(CONFIG_MTD_EBONY) += ebony.o +obj-$(CONFIG_MTD_OCOTEA) += ocotea.o +obj-$(CONFIG_MTD_WALNUT) += walnut.o obj-$(CONFIG_MTD_H720X) += h720x-flash.o obj-$(CONFIG_MTD_SBC8240) += sbc8240.o +obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o diff --git a/trunk/drivers/mtd/maps/ebony.c b/trunk/drivers/mtd/maps/ebony.c new file mode 100644 index 000000000000..d92b7c70d3ed --- /dev/null +++ b/trunk/drivers/mtd/maps/ebony.c @@ -0,0 +1,163 @@ +/* + * Mapping for Ebony user flash + * + * Matt Porter + * + * Copyright 2002-2004 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mtd_info *flash; + +static struct map_info ebony_small_map = { + .name = "Ebony small flash", + .size = EBONY_SMALL_FLASH_SIZE, + .bankwidth = 1, +}; + +static struct map_info ebony_large_map = { + .name = "Ebony large flash", + .size = EBONY_LARGE_FLASH_SIZE, + .bankwidth = 1, +}; + +static struct mtd_partition ebony_small_partitions[] = { + { + .name = "OpenBIOS", + .offset = 0x0, + .size = 0x80000, + } +}; + +static struct mtd_partition ebony_large_partitions[] = { + { + .name = "fs", + .offset = 0, + .size = 0x380000, + }, + { + .name = "firmware", + .offset = 0x380000, + .size = 0x80000, + } +}; + +int __init init_ebony(void) +{ + u8 fpga0_reg; + u8 __iomem *fpga0_adr; + unsigned long long small_flash_base, large_flash_base; + + fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16); + if (!fpga0_adr) + return -ENOMEM; + + fpga0_reg = readb(fpga0_adr); + iounmap(fpga0_adr); + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH2; + else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH1; + else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_LOW2; + else + small_flash_base = EBONY_SMALL_FLASH_LOW1; + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_ONBRD_FLASH_EN(fpga0_reg)) + large_flash_base = EBONY_LARGE_FLASH_LOW; + else + large_flash_base = EBONY_LARGE_FLASH_HIGH; + + ebony_small_map.phys = small_flash_base; + ebony_small_map.virt = ioremap64(small_flash_base, + ebony_small_map.size); + + if (!ebony_small_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ebony_small_map); + + flash = do_map_probe("jedec_probe", &ebony_small_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_small_partitions, + ARRAY_SIZE(ebony_small_partitions)); + } else { + printk("map probe failed for flash\n"); + iounmap(ebony_small_map.virt); + return -ENXIO; + } + + ebony_large_map.phys = large_flash_base; + ebony_large_map.virt = ioremap64(large_flash_base, + ebony_large_map.size); + + if (!ebony_large_map.virt) { + printk("Failed to ioremap flash\n"); + iounmap(ebony_small_map.virt); + return -EIO; + } + + simple_map_init(&ebony_large_map); + + flash = do_map_probe("jedec_probe", &ebony_large_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_large_partitions, + ARRAY_SIZE(ebony_large_partitions)); + } else { + printk("map probe failed for flash\n"); + iounmap(ebony_small_map.virt); + iounmap(ebony_large_map.virt); + return -ENXIO; + } + + return 0; +} + +static void __exit cleanup_ebony(void) +{ + if (flash) { + del_mtd_partitions(flash); + map_destroy(flash); + } + + if (ebony_small_map.virt) { + iounmap(ebony_small_map.virt); + ebony_small_map.virt = NULL; + } + + if (ebony_large_map.virt) { + iounmap(ebony_large_map.virt); + ebony_large_map.virt = NULL; + } +} + +module_init(init_ebony); +module_exit(cleanup_ebony); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matt Porter "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards"); diff --git a/trunk/drivers/mtd/maps/ocotea.c b/trunk/drivers/mtd/maps/ocotea.c new file mode 100644 index 000000000000..5522eac8c980 --- /dev/null +++ b/trunk/drivers/mtd/maps/ocotea.c @@ -0,0 +1,154 @@ +/* + * Mapping for Ocotea user flash + * + * Matt Porter + * + * Copyright 2002-2004 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mtd_info *flash; + +static struct map_info ocotea_small_map = { + .name = "Ocotea small flash", + .size = OCOTEA_SMALL_FLASH_SIZE, + .buswidth = 1, +}; + +static struct map_info ocotea_large_map = { + .name = "Ocotea large flash", + .size = OCOTEA_LARGE_FLASH_SIZE, + .buswidth = 1, +}; + +static struct mtd_partition ocotea_small_partitions[] = { + { + .name = "pibs", + .offset = 0x0, + .size = 0x100000, + } +}; + +static struct mtd_partition ocotea_large_partitions[] = { + { + .name = "fs", + .offset = 0, + .size = 0x300000, + }, + { + .name = "firmware", + .offset = 0x300000, + .size = 0x100000, + } +}; + +int __init init_ocotea(void) +{ + u8 fpga0_reg; + u8 *fpga0_adr; + unsigned long long small_flash_base, large_flash_base; + + fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16); + if (!fpga0_adr) + return -ENOMEM; + + fpga0_reg = readb((unsigned long)fpga0_adr); + iounmap(fpga0_adr); + + if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) { + small_flash_base = OCOTEA_SMALL_FLASH_HIGH; + large_flash_base = OCOTEA_LARGE_FLASH_LOW; + } + else { + small_flash_base = OCOTEA_SMALL_FLASH_LOW; + large_flash_base = OCOTEA_LARGE_FLASH_HIGH; + } + + ocotea_small_map.phys = small_flash_base; + ocotea_small_map.virt = ioremap64(small_flash_base, + ocotea_small_map.size); + + if (!ocotea_small_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ocotea_small_map); + + flash = do_map_probe("map_rom", &ocotea_small_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ocotea_small_partitions, + ARRAY_SIZE(ocotea_small_partitions)); + } else { + printk("map probe failed for flash\n"); + iounmap(ocotea_small_map.virt); + return -ENXIO; + } + + ocotea_large_map.phys = large_flash_base; + ocotea_large_map.virt = ioremap64(large_flash_base, + ocotea_large_map.size); + + if (!ocotea_large_map.virt) { + printk("Failed to ioremap flash\n"); + iounmap(ocotea_small_map.virt); + return -EIO; + } + + simple_map_init(&ocotea_large_map); + + flash = do_map_probe("cfi_probe", &ocotea_large_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ocotea_large_partitions, + ARRAY_SIZE(ocotea_large_partitions)); + } else { + printk("map probe failed for flash\n"); + iounmap(ocotea_small_map.virt); + iounmap(ocotea_large_map.virt); + return -ENXIO; + } + + return 0; +} + +static void __exit cleanup_ocotea(void) +{ + if (flash) { + del_mtd_partitions(flash); + map_destroy(flash); + } + + if (ocotea_small_map.virt) { + iounmap((void *)ocotea_small_map.virt); + ocotea_small_map.virt = 0; + } + + if (ocotea_large_map.virt) { + iounmap((void *)ocotea_large_map.virt); + ocotea_large_map.virt = 0; + } +} + +module_init(init_ocotea); +module_exit(cleanup_ocotea); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matt Porter "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards"); diff --git a/trunk/drivers/mtd/maps/omap-toto-flash.c b/trunk/drivers/mtd/maps/omap-toto-flash.c new file mode 100644 index 000000000000..0a60ebbc2175 --- /dev/null +++ b/trunk/drivers/mtd/maps/omap-toto-flash.c @@ -0,0 +1,133 @@ +/* + * NOR Flash memory access on TI Toto board + * + * jzhang@ti.com (C) 2003 Texas Instruments. + * + * (C) 2002 MontVista Software, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#ifndef CONFIG_ARCH_OMAP +#error This is for OMAP architecture only +#endif + +//these lines need be moved to a hardware header file +#define OMAP_TOTO_FLASH_BASE 0xd8000000 +#define OMAP_TOTO_FLASH_SIZE 0x80000 + +static struct map_info omap_toto_map_flash = { + .name = "OMAP Toto flash", + .bankwidth = 2, + .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, +}; + + +static struct mtd_partition toto_flash_partitions[] = { + { + .name = "BootLoader", + .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/ + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "ReservedSpace", + .size = 0x00030000, + .offset = MTDPART_OFS_APPEND, + //mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + .name = "EnvArea", /* bottom 64KiB for env vars */ + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; + +static struct mtd_partition *parsed_parts; + +static struct mtd_info *flash_mtd; + +static int __init init_flash (void) +{ + + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + const char *part_type; + + /* + * Static partition definition selection + */ + part_type = "static"; + + parts = toto_flash_partitions; + nb_parts = ARRAY_SIZE(toto_flash_partitions); + omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE; + omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE); + + simple_map_init(&omap_toto_map_flash); + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n", + omap_toto_map_flash.bankwidth*8); + flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); + if (!flash_mtd) + return -ENXIO; + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } + + if (nb_parts == 0) { + printk(KERN_NOTICE "OMAP toto flash: no partition info available," + "registering whole flash at once\n"); + if (add_mtd_device(flash_mtd)){ + return -ENXIO; + } + } else { + printk(KERN_NOTICE "Using %s partition definition\n", + part_type); + return add_mtd_partitions(flash_mtd, parts, nb_parts); + } + return 0; +} + +int __init omap_toto_mtd_init(void) +{ + int status; + + if (status = init_flash()) { + printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n"); + } + return status; +} + +static void __exit omap_toto_mtd_cleanup(void) +{ + if (flash_mtd) { + del_mtd_partitions(flash_mtd); + map_destroy(flash_mtd); + kfree(parsed_parts); + } +} + +module_init(omap_toto_mtd_init); +module_exit(omap_toto_mtd_cleanup); + +MODULE_AUTHOR("Jian Zhang"); +MODULE_DESCRIPTION("OMAP Toto board map driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/maps/pci.c b/trunk/drivers/mtd/maps/pci.c index 48f4cf5cb9d1..5c6a25c90380 100644 --- a/trunk/drivers/mtd/maps/pci.c +++ b/trunk/drivers/mtd/maps/pci.c @@ -203,8 +203,15 @@ intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) * not enabled, should we be allocating a new resource for it * or simply enabling it? */ - pci_enable_rom(dev); - printk("%s: enabling expansion ROM\n", pci_name(dev)); + if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) & + IORESOURCE_ROM_ENABLE)) { + u32 val; + pci_resource_flags(dev, PCI_ROM_RESOURCE) |= IORESOURCE_ROM_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); + printk("%s: enabling expansion ROM\n", pci_name(dev)); + } } if (!len || !base) @@ -225,13 +232,18 @@ intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) static void intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) { + u32 val; + if (map->base) iounmap(map->base); /* * We need to undo the PCI BAR2/PCI ROM BAR address alteration. */ - pci_disable_rom(dev); + pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~IORESOURCE_ROM_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); } static unsigned long diff --git a/trunk/drivers/mtd/maps/physmap_of.c b/trunk/drivers/mtd/maps/physmap_of.c index 5fcfec034a94..49acd4171893 100644 --- a/trunk/drivers/mtd/maps/physmap_of.c +++ b/trunk/drivers/mtd/maps/physmap_of.c @@ -230,7 +230,8 @@ static int __devinit of_flash_probe(struct of_device *dev, #ifdef CONFIG_MTD_OF_PARTS if (err == 0) { - err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts); + err = of_mtd_parse_partitions(&dev->dev, info->mtd, + dp, &info->parts); if (err < 0) return err; } diff --git a/trunk/drivers/mtd/maps/walnut.c b/trunk/drivers/mtd/maps/walnut.c new file mode 100644 index 000000000000..e243476c8171 --- /dev/null +++ b/trunk/drivers/mtd/maps/walnut.c @@ -0,0 +1,122 @@ +/* + * Mapping for Walnut flash + * (used ebony.c as a "framework") + * + * Heikki Lindholm + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* these should be in platforms/4xx/walnut.h ? */ +#define WALNUT_FLASH_ONBD_N(x) (x & 0x02) +#define WALNUT_FLASH_SRAM_SEL(x) (x & 0x01) +#define WALNUT_FLASH_LOW 0xFFF00000 +#define WALNUT_FLASH_HIGH 0xFFF80000 +#define WALNUT_FLASH_SIZE 0x80000 + +static struct mtd_info *flash; + +static struct map_info walnut_map = { + .name = "Walnut flash", + .size = WALNUT_FLASH_SIZE, + .bankwidth = 1, +}; + +/* Actually, OpenBIOS is the last 128 KiB of the flash - better + * partitioning could be made */ +static struct mtd_partition walnut_partitions[] = { + { + .name = "OpenBIOS", + .offset = 0x0, + .size = WALNUT_FLASH_SIZE, + /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ + } +}; + +int __init init_walnut(void) +{ + u8 fpga_brds1; + void *fpga_brds1_adr; + void *fpga_status_adr; + unsigned long flash_base; + + /* this should already be mapped (platform/4xx/walnut.c) */ + fpga_status_adr = ioremap(WALNUT_FPGA_BASE, 8); + if (!fpga_status_adr) + return -ENOMEM; + + fpga_brds1_adr = fpga_status_adr+5; + fpga_brds1 = readb(fpga_brds1_adr); + /* iounmap(fpga_status_adr); */ + + if (WALNUT_FLASH_ONBD_N(fpga_brds1)) { + printk("The on-board flash is disabled (U79 sw 5)!"); + iounmap(fpga_status_adr); + return -EIO; + } + if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) + flash_base = WALNUT_FLASH_LOW; + else + flash_base = WALNUT_FLASH_HIGH; + + walnut_map.phys = flash_base; + walnut_map.virt = + (void __iomem *)ioremap(flash_base, walnut_map.size); + + if (!walnut_map.virt) { + printk("Failed to ioremap flash.\n"); + iounmap(fpga_status_adr); + return -EIO; + } + + simple_map_init(&walnut_map); + + flash = do_map_probe("jedec_probe", &walnut_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, walnut_partitions, + ARRAY_SIZE(walnut_partitions)); + } else { + printk("map probe failed for flash\n"); + iounmap(fpga_status_adr); + return -ENXIO; + } + + iounmap(fpga_status_adr); + return 0; +} + +static void __exit cleanup_walnut(void) +{ + if (flash) { + del_mtd_partitions(flash); + map_destroy(flash); + } + + if (walnut_map.virt) { + iounmap((void *)walnut_map.virt); + walnut_map.virt = 0; + } +} + +module_init(init_walnut); +module_exit(cleanup_walnut); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Heikki Lindholm "); +MODULE_DESCRIPTION("MTD map and partitions for IBM 405GP Walnut boards"); diff --git a/trunk/drivers/mtd/mtdchar.c b/trunk/drivers/mtd/mtdchar.c index 13cc67ad272a..d2f331876e4c 100644 --- a/trunk/drivers/mtd/mtdchar.c +++ b/trunk/drivers/mtd/mtdchar.c @@ -350,7 +350,7 @@ static void mtdchar_erase_callback (struct erase_info *instr) wake_up((wait_queue_head_t *)instr->priv); } -#ifdef CONFIG_HAVE_MTD_OTP +#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) static int otp_select_filemode(struct mtd_file_info *mfi, int mode) { struct mtd_info *mtd = mfi->mtd; @@ -663,7 +663,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, break; } -#ifdef CONFIG_HAVE_MTD_OTP +#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) case OTPSELECT: { int mode; diff --git a/trunk/drivers/mtd/mtdconcat.c b/trunk/drivers/mtd/mtdconcat.c index 789842d0e6f2..2972a5edb73d 100644 --- a/trunk/drivers/mtd/mtdconcat.c +++ b/trunk/drivers/mtd/mtdconcat.c @@ -444,7 +444,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + instr->fail_addr = 0xffffffff; /* make a local copy of instr to avoid modifying the caller's struct */ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); @@ -493,7 +493,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) /* sanity check: should never happen since * block alignment has been checked above */ BUG_ON(err == -EINVAL); - if (erase->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + if (erase->fail_addr != 0xffffffff) instr->fail_addr = erase->fail_addr + offset; break; } diff --git a/trunk/drivers/mtd/mtdpart.c b/trunk/drivers/mtd/mtdpart.c index 8e77e36e75ee..edb90b58a9b1 100644 --- a/trunk/drivers/mtd/mtdpart.c +++ b/trunk/drivers/mtd/mtdpart.c @@ -214,7 +214,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) instr->addr += part->offset; ret = part->master->erase(part->master, instr); if (ret) { - if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + if (instr->fail_addr != 0xffffffff) instr->fail_addr -= part->offset; instr->addr -= part->offset; } @@ -226,7 +226,7 @@ void mtd_erase_callback(struct erase_info *instr) if (instr->mtd->erase == part_erase) { struct mtd_part *part = PART(instr->mtd); - if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + if (instr->fail_addr != 0xffffffff) instr->fail_addr -= part->offset; instr->addr -= part->offset; } diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index 89b4d39386ab..41f361c49b32 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -68,6 +68,12 @@ config MTD_NAND_AMS_DELTA help Support for NAND flash on Amstrad E3 (Delta). +config MTD_NAND_TOTO + tristate "NAND Flash device on TOTO board" + depends on ARCH_OMAP && BROKEN + help + Support for NAND flash on Texas Instruments Toto platform. + config MTD_NAND_TS7250 tristate "NAND Flash device on TS-7250 board" depends on MACH_TS72XX @@ -157,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC incorrect ECC generation, and if using these, the default of software ECC is preferable. +config MTD_NAND_NDFC + tristate "NDFC NanD Flash Controller" + depends on 4xx && !PPC_MERGE + select MTD_NAND_ECC_SMC + help + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs + config MTD_NAND_S3C2410_CLKSTOP bool "S3C2410 NAND IDLE clock stop" depends on MTD_NAND_S3C2410 @@ -327,13 +340,6 @@ config MTD_NAND_PXA3xx This enables the driver for the NAND flash device found on PXA3xx processors -config MTD_NAND_PXA3xx_BUILTIN - bool "Use builtin definitions for some NAND chips (deprecated)" - depends on MTD_NAND_PXA3xx - help - This enables builtin definitions for some NAND chips. This - is deprecated in favor of platform specific data. - config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MTD_NAND && MACH_ARMCORE @@ -394,24 +400,10 @@ config MTD_NAND_FSL_ELBC config MTD_NAND_FSL_UPM tristate "Support for NAND on Freescale UPM" - depends on MTD_NAND && (PPC_83xx || PPC_85xx) + depends on MTD_NAND && OF_GPIO && (PPC_83xx || PPC_85xx) select FSL_LBC help Enables support for NAND Flash chips wired onto Freescale PowerPC processor localbus with User-Programmable Machine support. -config MTD_NAND_MXC - tristate "MXC NAND support" - depends on ARCH_MX2 - help - This enables the driver for the NAND flash controller on the - MXC processors. - -config MTD_NAND_SH_FLCTL - tristate "Support for NAND on Renesas SuperH FLCTL" - depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 - help - Several Renesas SuperH CPU has FLCTL. This option enables support - for NAND Flash using FLCTL. This driver support SH7723. - endif # MTD_NAND diff --git a/trunk/drivers/mtd/nand/Makefile b/trunk/drivers/mtd/nand/Makefile index 9bfeca324b32..b786c5da82da 100644 --- a/trunk/drivers/mtd/nand/Makefile +++ b/trunk/drivers/mtd/nand/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o +obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o @@ -33,7 +34,5 @@ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o -obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o -obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o nand-objs := nand_base.o nand_bbt.o diff --git a/trunk/drivers/mtd/nand/atmel_nand.c b/trunk/drivers/mtd/nand/atmel_nand.c index c98c1570a40b..3387e0d5076b 100644 --- a/trunk/drivers/mtd/nand/atmel_nand.c +++ b/trunk/drivers/mtd/nand/atmel_nand.c @@ -173,6 +173,48 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); } +/* + * write oob for small pages + */ +static int atmel_nand_write_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsize = chip->ecc.size, length = mtd->oobsize; + int len, pos, status = 0; + const uint8_t *bufpoi = chip->oob_poi; + + pos = eccsize + chunk; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + len = min_t(int, length, chunk); + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; + +} + +/* + * read oob for small pages + */ +static int atmel_nand_read_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + /* * Calculate HW ECC * @@ -193,14 +235,14 @@ static int atmel_nand_calculate(struct mtd_info *mtd, /* get the first 2 ECC bytes */ ecc_value = ecc_readl(host->ecc, PR); - ecc_code[0] = ecc_value & 0xFF; - ecc_code[1] = (ecc_value >> 8) & 0xFF; + ecc_code[eccpos[0]] = ecc_value & 0xFF; + ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; /* get the last 2 ECC bytes */ ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; - ecc_code[2] = ecc_value & 0xFF; - ecc_code[3] = (ecc_value >> 8) & 0xFF; + ecc_code[eccpos[2]] = ecc_value & 0xFF; + ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; return 0; } @@ -434,12 +476,14 @@ static int __init atmel_nand_probe(struct platform_device *pdev) res = -EIO; goto err_ecc_ioremap; } - nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; nand_chip->ecc.calculate = atmel_nand_calculate; nand_chip->ecc.correct = atmel_nand_correct; nand_chip->ecc.hwctl = atmel_nand_hwctl; nand_chip->ecc.read_page = atmel_nand_read_page; nand_chip->ecc.bytes = 4; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.postpad = 0; } nand_chip->chip_delay = 20; /* 20us command delay time */ @@ -470,7 +514,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_scan_ident; } - if (nand_chip->ecc.mode == NAND_ECC_HW) { + if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { /* ECC is calculated for the whole page (1 step) */ nand_chip->ecc.size = mtd->writesize; @@ -478,6 +522,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) switch (mtd->writesize) { case 512: nand_chip->ecc.layout = &atmel_oobinfo_small; + nand_chip->ecc.read_oob = atmel_nand_read_oob_512; + nand_chip->ecc.write_oob = atmel_nand_write_oob_512; ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); break; case 1024: diff --git a/trunk/drivers/mtd/nand/fsl_elbc_nand.c b/trunk/drivers/mtd/nand/fsl_elbc_nand.c index 4aa5bd6158da..98ad3cefcaf4 100644 --- a/trunk/drivers/mtd/nand/fsl_elbc_nand.c +++ b/trunk/drivers/mtd/nand/fsl_elbc_nand.c @@ -918,7 +918,8 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, #ifdef CONFIG_MTD_OF_PARTS if (ret == 0) { - ret = of_mtd_parse_partitions(priv->dev, node, &parts); + ret = of_mtd_parse_partitions(priv->dev, &priv->mtd, + node, &parts); if (ret < 0) goto err; } diff --git a/trunk/drivers/mtd/nand/fsl_upm.c b/trunk/drivers/mtd/nand/fsl_upm.c index 024e3fffd4bb..1ebfd87f00b4 100644 --- a/trunk/drivers/mtd/nand/fsl_upm.c +++ b/trunk/drivers/mtd/nand/fsl_upm.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -37,6 +36,8 @@ struct fsl_upm_nand { uint8_t upm_cmd_offset; void __iomem *io_base; int rnb_gpio; + const uint32_t *wait_pattern; + const uint32_t *wait_write; int chip_delay; }; @@ -60,11 +61,10 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun) if (fun->rnb_gpio >= 0) { while (--cnt && !fun_chip_ready(&fun->mtd)) cpu_relax(); - if (!cnt) - dev_err(fun->dev, "tired waiting for RNB\n"); - } else { - ndelay(100); } + + if (!cnt) + dev_err(fun->dev, "tired waiting for RNB\n"); } static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) @@ -89,7 +89,8 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); - fun_wait_rnb(fun); + if (fun->wait_pattern) + fun_wait_rnb(fun); } static uint8_t fun_read_byte(struct mtd_info *mtd) @@ -115,16 +116,14 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) for (i = 0; i < len; i++) { out_8(fun->chip.IO_ADDR_W, buf[i]); - fun_wait_rnb(fun); + if (fun->wait_write) + fun_wait_rnb(fun); } } -static int __devinit fun_chip_init(struct fsl_upm_nand *fun, - const struct device_node *upm_np, - const struct resource *io_res) +static int __devinit fun_chip_init(struct fsl_upm_nand *fun) { int ret; - struct device_node *flash_np; #ifdef CONFIG_MTD_PARTITIONS static const char *part_types[] = { "cmdlinepart", NULL, }; #endif @@ -144,37 +143,18 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, fun->mtd.priv = &fun->chip; fun->mtd.owner = THIS_MODULE; - flash_np = of_get_next_child(upm_np, NULL); - if (!flash_np) - return -ENODEV; - - fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, - flash_np->name); - if (!fun->mtd.name) { - ret = -ENOMEM; - goto err; - } - ret = nand_scan(&fun->mtd, 1); if (ret) - goto err; + return ret; + + fun->mtd.name = fun->dev->bus_id; #ifdef CONFIG_MTD_PARTITIONS ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); - -#ifdef CONFIG_MTD_OF_PARTS - if (ret == 0) - ret = of_mtd_parse_partitions(fun->dev, &fun->mtd, - flash_np, &fun->parts); -#endif if (ret > 0) - ret = add_mtd_partitions(&fun->mtd, fun->parts, ret); - else + return add_mtd_partitions(&fun->mtd, fun->parts, ret); #endif - ret = add_mtd_device(&fun->mtd); -err: - of_node_put(flash_np); - return ret; + return add_mtd_device(&fun->mtd); } static int __devinit fun_probe(struct of_device *ofdev, @@ -231,12 +211,6 @@ static int __devinit fun_probe(struct of_device *ofdev, goto err2; } - prop = of_get_property(ofdev->node, "chip-delay", NULL); - if (prop) - fun->chip_delay = *prop; - else - fun->chip_delay = 50; - fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, io_res.end - io_res.start + 1); if (!fun->io_base) { @@ -246,8 +220,17 @@ static int __devinit fun_probe(struct of_device *ofdev, fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; + fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern", + NULL); + fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL); + + prop = of_get_property(ofdev->node, "chip-delay", NULL); + if (prop) + fun->chip_delay = *prop; + else + fun->chip_delay = 50; - ret = fun_chip_init(fun, ofdev->node, &io_res); + ret = fun_chip_init(fun); if (ret) goto err2; @@ -268,7 +251,6 @@ static int __devexit fun_remove(struct of_device *ofdev) struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); nand_release(&fun->mtd); - kfree(fun->mtd.name); if (fun->rnb_gpio >= 0) gpio_free(fun->rnb_gpio); diff --git a/trunk/drivers/mtd/nand/mxc_nand.c b/trunk/drivers/mtd/nand/mxc_nand.c deleted file mode 100644 index 21fd4f1c4806..000000000000 --- a/trunk/drivers/mtd/nand/mxc_nand.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Sascha Hauer, kernel@pengutronix.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRIVER_NAME "mxc_nand" - -/* Addresses for NFC registers */ -#define NFC_BUF_SIZE 0xE00 -#define NFC_BUF_ADDR 0xE04 -#define NFC_FLASH_ADDR 0xE06 -#define NFC_FLASH_CMD 0xE08 -#define NFC_CONFIG 0xE0A -#define NFC_ECC_STATUS_RESULT 0xE0C -#define NFC_RSLTMAIN_AREA 0xE0E -#define NFC_RSLTSPARE_AREA 0xE10 -#define NFC_WRPROT 0xE12 -#define NFC_UNLOCKSTART_BLKADDR 0xE14 -#define NFC_UNLOCKEND_BLKADDR 0xE16 -#define NFC_NF_WRPRST 0xE18 -#define NFC_CONFIG1 0xE1A -#define NFC_CONFIG2 0xE1C - -/* Addresses for NFC RAM BUFFER Main area 0 */ -#define MAIN_AREA0 0x000 -#define MAIN_AREA1 0x200 -#define MAIN_AREA2 0x400 -#define MAIN_AREA3 0x600 - -/* Addresses for NFC SPARE BUFFER Spare area 0 */ -#define SPARE_AREA0 0x800 -#define SPARE_AREA1 0x810 -#define SPARE_AREA2 0x820 -#define SPARE_AREA3 0x830 - -/* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register - * for Command operation */ -#define NFC_CMD 0x1 - -/* Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register - * for Address operation */ -#define NFC_ADDR 0x2 - -/* Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register - * for Input operation */ -#define NFC_INPUT 0x4 - -/* Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register - * for Data Output operation */ -#define NFC_OUTPUT 0x8 - -/* Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register - * for Read ID operation */ -#define NFC_ID 0x10 - -/* Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register - * for Read Status operation */ -#define NFC_STATUS 0x20 - -/* Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read - * Status operation */ -#define NFC_INT 0x8000 - -#define NFC_SP_EN (1 << 2) -#define NFC_ECC_EN (1 << 3) -#define NFC_INT_MSK (1 << 4) -#define NFC_BIG (1 << 5) -#define NFC_RST (1 << 6) -#define NFC_CE (1 << 7) -#define NFC_ONE_CYCLE (1 << 8) - -struct mxc_nand_host { - struct mtd_info mtd; - struct nand_chip nand; - struct mtd_partition *parts; - struct device *dev; - - void __iomem *regs; - int spare_only; - int status_request; - int pagesize_2k; - uint16_t col_addr; - struct clk *clk; - int clk_act; - int irq; - - wait_queue_head_t irq_waitq; -}; - -/* Define delays in microsec for NAND device operations */ -#define TROP_US_DELAY 2000 -/* Macros to get byte and bit positions of ECC */ -#define COLPOS(x) ((x) >> 3) -#define BITPOS(x) ((x) & 0xf) - -/* Define single bit Error positions in Main & Spare area */ -#define MAIN_SINGLEBIT_ERROR 0x4 -#define SPARE_SINGLEBIT_ERROR 0x1 - -/* OOB placement block for use with hardware ecc generation */ -static struct nand_ecclayout nand_hw_eccoob_8 = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 5}, {11, 5}, } -}; - -static struct nand_ecclayout nand_hw_eccoob_16 = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 6}, {12, 4}, } -}; - -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; -#endif - -static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) -{ - struct mxc_nand_host *host = dev_id; - - uint16_t tmp; - - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; /* Disable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); - - wake_up(&host->irq_waitq); - - return IRQ_HANDLED; -} - -/* This function polls the NANDFC to wait for the basic operation to - * complete by checking the INT bit of config2 register. - */ -static void wait_op_done(struct mxc_nand_host *host, int max_retries, - uint16_t param, int useirq) -{ - uint32_t tmp; - - if (useirq) { - if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { - - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_INT_MSK; /* Enable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); - - wait_event(host->irq_waitq, - readw(host->regs + NFC_CONFIG2) & NFC_INT); - - tmp = readw(host->regs + NFC_CONFIG2); - tmp &= ~NFC_INT; - writew(tmp, host->regs + NFC_CONFIG2); - } - } else { - while (max_retries-- > 0) { - if (readw(host->regs + NFC_CONFIG2) & NFC_INT) { - tmp = readw(host->regs + NFC_CONFIG2); - tmp &= ~NFC_INT; - writew(tmp, host->regs + NFC_CONFIG2); - break; - } - udelay(1); - } - if (max_retries <= 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", - __func__, param); - } -} - -/* This function issues the specified command to the NAND device and - * waits for completion. */ -static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) -{ - DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); - - writew(cmd, host->regs + NFC_FLASH_CMD); - writew(NFC_CMD, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, cmd, useirq); -} - -/* This function sends an address (or partial address) to the - * NAND device. The address is used to select the source/destination for - * a NAND command. */ -static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) -{ - DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); - - writew(addr, host->regs + NFC_FLASH_ADDR); - writew(NFC_ADDR, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, addr, islast); -} - -/* This function requests the NANDFC to initate the transfer - * of data currently in the NANDFC RAM buffer to the NAND device. */ -static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only); - - /* NANDFC buffer 0 is used for page read/write */ - writew(buf_id, host->regs + NFC_BUF_ADDR); - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint16_t config1 = readw(host->regs + NFC_CONFIG1); - if (spare_only) - config1 |= NFC_SP_EN; - else - config1 &= ~(NFC_SP_EN); - writew(config1, host->regs + NFC_CONFIG1); - } - - writew(NFC_INPUT, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only, true); -} - -/* Requests NANDFC to initated the transfer of data from the - * NAND device into in the NANDFC ram buffer. */ -static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); - - /* NANDFC buffer 0 is used for page read/write */ - writew(buf_id, host->regs + NFC_BUF_ADDR); - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint32_t config1 = readw(host->regs + NFC_CONFIG1); - if (spare_only) - config1 |= NFC_SP_EN; - else - config1 &= ~NFC_SP_EN; - writew(config1, host->regs + NFC_CONFIG1); - } - - writew(NFC_OUTPUT, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only, true); -} - -/* Request the NANDFC to perform a read of the NAND device ID. */ -static void send_read_id(struct mxc_nand_host *host) -{ - struct nand_chip *this = &host->nand; - uint16_t tmp; - - /* NANDFC buffer 0 is used for device ID output */ - writew(0x0, host->regs + NFC_BUF_ADDR); - - /* Read ID into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); - - writew(NFC_ID, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0, true); - - if (this->options & NAND_BUSWIDTH_16) { - void __iomem *main_buf = host->regs + MAIN_AREA0; - /* compress the ID info */ - writeb(readb(main_buf + 2), main_buf + 1); - writeb(readb(main_buf + 4), main_buf + 2); - writeb(readb(main_buf + 6), main_buf + 3); - writeb(readb(main_buf + 8), main_buf + 4); - writeb(readb(main_buf + 10), main_buf + 5); - } -} - -/* This function requests the NANDFC to perform a read of the - * NAND device status and returns the current status. */ -static uint16_t get_dev_status(struct mxc_nand_host *host) -{ - void __iomem *main_buf = host->regs + MAIN_AREA1; - uint32_t store; - uint16_t ret, tmp; - /* Issue status request to NAND device */ - - /* store the main area1 first word, later do recovery */ - store = readl(main_buf); - /* NANDFC buffer 1 is used for device status to prevent - * corruption of read/write buffer on status requests. */ - writew(1, host->regs + NFC_BUF_ADDR); - - /* Read status into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); - - writew(NFC_STATUS, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0, true); - - /* Status is placed in first word of main buffer */ - /* get status, then recovery area 1 data */ - ret = readw(main_buf); - writel(store, main_buf); - - return ret; -} - -/* This functions is used by upper layer to checks if device is ready */ -static int mxc_nand_dev_ready(struct mtd_info *mtd) -{ - /* - * NFC handles R/B internally. Therefore, this function - * always returns status as ready. - */ - return 1; -} - -static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - /* - * 1-Bit errors are automatically corrected in HW. No need for - * additional correction. 2-Bit errors cannot be corrected by - * HW ECC, so we need to return failure - */ - uint16_t ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT); - - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -1; - } - - return 0; -} - -static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - return 0; -} - -static u_char mxc_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint8_t ret = 0; - uint16_t col, rd_word; - uint16_t __iomem *main_buf = host->regs + MAIN_AREA0; - uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0; - - /* Check for status request */ - if (host->status_request) - return get_dev_status(host) & 0xFF; - - /* Get column for 16-bit access */ - col = host->col_addr >> 1; - - /* If we are accessing the spare region */ - if (host->spare_only) - rd_word = readw(&spare_buf[col]); - else - rd_word = readw(&main_buf[col]); - - /* Pick upper/lower byte of word from RAM buffer */ - if (host->col_addr & 0x1) - ret = (rd_word >> 8) & 0xFF; - else - ret = rd_word & 0xFF; - - /* Update saved column address */ - host->col_addr++; - - return ret; -} - -static uint16_t mxc_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint16_t col, rd_word, ret; - uint16_t __iomem *p; - - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_word(col = %d)\n", host->col_addr); - - col = host->col_addr; - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - if (col < mtd->writesize) - p = (host->regs + MAIN_AREA0) + (col >> 1); - else - p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1); - - if (col & 1) { - rd_word = readw(p); - ret = (rd_word >> 8) & 0xff; - rd_word = readw(&p[1]); - ret |= (rd_word << 8) & 0xff00; - - } else - ret = readw(p); - - /* Update saved column address */ - host->col_addr = col + 2; - - return ret; -} - -/* Write data of length len to buffer buf. The data to be - * written on NAND Flash is first copied to RAMbuffer. After the Data Input - * Operation by the NFC, the data is written to NAND Flash */ -static void mxc_nand_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - int n, col, i = 0; - - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, - len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - DEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); - - while (n) { - void __iomem *p; - - if (col < mtd->writesize) - p = host->regs + MAIN_AREA0 + (col & ~3); - else - p = host->regs + SPARE_AREA0 - - mtd->writesize + (col & ~3); - - DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, - __LINE__, p); - - if (((col | (int)&buf[i]) & 3) || n < 16) { - uint32_t data = 0; - - if (col & 3 || n < 4) - data = readl(p); - - switch (col & 3) { - case 0: - if (n) { - data = (data & 0xffffff00) | - (buf[i++] << 0); - n--; - col++; - } - case 1: - if (n) { - data = (data & 0xffff00ff) | - (buf[i++] << 8); - n--; - col++; - } - case 2: - if (n) { - data = (data & 0xff00ffff) | - (buf[i++] << 16); - n--; - col++; - } - case 3: - if (n) { - data = (data & 0x00ffffff) | - (buf[i++] << 24); - n--; - col++; - } - } - - writel(data, p); - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - - DEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: n = %d, m = %d, i = %d, col = %d\n", - __func__, __LINE__, n, m, i, col); - - memcpy(p, &buf[i], m); - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; -} - -/* Read the data buffer from the NAND Flash. To read the data from NAND - * Flash first the data output cycle is initiated by the NFC, which copies - * the data to RAMbuffer. This data of length len is then copied to buffer buf. - */ -static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - int n, col, i = 0; - - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - while (n) { - void __iomem *p; - - if (col < mtd->writesize) - p = host->regs + MAIN_AREA0 + (col & ~3); - else - p = host->regs + SPARE_AREA0 - - mtd->writesize + (col & ~3); - - if (((col | (int)&buf[i]) & 3) || n < 16) { - uint32_t data; - - data = readl(p); - switch (col & 3) { - case 0: - if (n) { - buf[i++] = (uint8_t) (data); - n--; - col++; - } - case 1: - if (n) { - buf[i++] = (uint8_t) (data >> 8); - n--; - col++; - } - case 2: - if (n) { - buf[i++] = (uint8_t) (data >> 16); - n--; - col++; - } - case 3: - if (n) { - buf[i++] = (uint8_t) (data >> 24); - n--; - col++; - } - } - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - memcpy(&buf[i], p, m); - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; - -} - -/* Used by the upper layer to verify the data in NAND Flash - * with the data in the buf. */ -static int mxc_nand_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - return -EFAULT; -} - -/* This function is used by upper layer for select and - * deselect of the NAND chip */ -static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - -#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE - if (chip > 0) { - DEBUG(MTD_DEBUG_LEVEL0, - "ERROR: Illegal chip select (chip = %d)\n", chip); - return; - } - - if (chip == -1) { - writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE, - host->regs + NFC_CONFIG1); - return; - } - - writew(readw(host->regs + NFC_CONFIG1) | NFC_CE, - host->regs + NFC_CONFIG1); -#endif - - switch (chip) { - case -1: - /* Disable the NFC clock */ - if (host->clk_act) { - clk_disable(host->clk); - host->clk_act = 0; - } - break; - case 0: - /* Enable the NFC clock */ - if (!host->clk_act) { - clk_enable(host->clk); - host->clk_act = 1; - } - break; - - default: - break; - } -} - -/* Used by the upper layer to write command to NAND Flash for - * different operations to be carried out on NAND Flash */ -static void mxc_nand_command(struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - int useirq = true; - - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", - command, column, page_addr); - - /* Reset command state information */ - host->status_request = false; - - /* Command pre-processing step */ - switch (command) { - - case NAND_CMD_STATUS: - host->col_addr = 0; - host->status_request = true; - break; - - case NAND_CMD_READ0: - host->col_addr = column; - host->spare_only = false; - useirq = false; - break; - - case NAND_CMD_READOOB: - host->col_addr = column; - host->spare_only = true; - useirq = false; - if (host->pagesize_2k) - command = NAND_CMD_READ0; /* only READ0 is valid */ - break; - - case NAND_CMD_SEQIN: - if (column >= mtd->writesize) { - /* - * FIXME: before send SEQIN command for write OOB, - * We must read one page out. - * For K9F1GXX has no READ1 command to set current HW - * pointer to spare area, we must write the whole page - * including OOB together. - */ - if (host->pagesize_2k) - /* call ourself to read a page */ - mxc_nand_command(mtd, NAND_CMD_READ0, 0, - page_addr); - - host->col_addr = column - mtd->writesize; - host->spare_only = true; - - /* Set program pointer to spare region */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READOOB, false); - } else { - host->spare_only = false; - host->col_addr = column; - - /* Set program pointer to page start */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READ0, false); - } - useirq = false; - break; - - case NAND_CMD_PAGEPROG: - send_prog_page(host, 0, host->spare_only); - - if (host->pagesize_2k) { - /* data in 4 areas datas */ - send_prog_page(host, 1, host->spare_only); - send_prog_page(host, 2, host->spare_only); - send_prog_page(host, 3, host->spare_only); - } - - break; - - case NAND_CMD_ERASE1: - useirq = false; - break; - } - - /* Write out the command to the device. */ - send_cmd(host, command, useirq); - - /* Write out column address, if necessary */ - if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * layers perform a read/write buf operation, - * we will used the saved column adress to index into - * the full page. - */ - send_addr(host, 0, page_addr == -1); - if (host->pagesize_2k) - /* another col addr cycle for 2k page */ - send_addr(host, 0, false); - } - - /* Write out page address, if necessary */ - if (page_addr != -1) { - /* paddr_0 - p_addr_7 */ - send_addr(host, (page_addr & 0xff), false); - - if (host->pagesize_2k) { - send_addr(host, (page_addr >> 8) & 0xFF, false); - if (mtd->size >= 0x40000000) - send_addr(host, (page_addr >> 16) & 0xff, true); - } else { - /* One more address cycle for higher density devices */ - if (mtd->size >= 0x4000000) { - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff, false); - send_addr(host, (page_addr >> 16) & 0xff, true); - } else - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff, true); - } - } - - /* Command post-processing step */ - switch (command) { - - case NAND_CMD_RESET: - break; - - case NAND_CMD_READOOB: - case NAND_CMD_READ0: - if (host->pagesize_2k) { - /* send read confirm command */ - send_cmd(host, NAND_CMD_READSTART, true); - /* read for each AREA */ - send_read_page(host, 0, host->spare_only); - send_read_page(host, 1, host->spare_only); - send_read_page(host, 2, host->spare_only); - send_read_page(host, 3, host->spare_only); - } else - send_read_page(host, 0, host->spare_only); - break; - - case NAND_CMD_READID: - send_read_id(host); - break; - - case NAND_CMD_PAGEPROG: - break; - - case NAND_CMD_STATUS: - break; - - case NAND_CMD_ERASE2: - break; - } -} - -static int __init mxcnd_probe(struct platform_device *pdev) -{ - struct nand_chip *this; - struct mtd_info *mtd; - struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; - struct mxc_nand_host *host; - struct resource *res; - uint16_t tmp; - int err = 0, nr_parts = 0; - - /* Allocate memory for MTD device structure and private data */ - host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL); - if (!host) - return -ENOMEM; - - host->dev = &pdev->dev; - /* structures must be linked */ - this = &host->nand; - mtd = &host->mtd; - mtd->priv = this; - mtd->owner = THIS_MODULE; - - /* 50 us command delay time */ - this->chip_delay = 5; - - this->priv = host; - this->dev_ready = mxc_nand_dev_ready; - this->cmdfunc = mxc_nand_command; - this->select_chip = mxc_nand_select_chip; - this->read_byte = mxc_nand_read_byte; - this->read_word = mxc_nand_read_word; - this->write_buf = mxc_nand_write_buf; - this->read_buf = mxc_nand_read_buf; - this->verify_buf = mxc_nand_verify_buf; - - host->clk = clk_get(&pdev->dev, "nfc_clk"); - if (IS_ERR(host->clk)) - goto eclk; - - clk_enable(host->clk); - host->clk_act = 1; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err = -ENODEV; - goto eres; - } - - host->regs = ioremap(res->start, res->end - res->start + 1); - if (!host->regs) { - err = -EIO; - goto eres; - } - - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; - writew(tmp, host->regs + NFC_CONFIG1); - - init_waitqueue_head(&host->irq_waitq); - - host->irq = platform_get_irq(pdev, 0); - - err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host); - if (err) - goto eirq; - - if (pdata->hw_ecc) { - this->ecc.calculate = mxc_nand_calculate_ecc; - this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = mxc_nand_correct_data; - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = 512; - this->ecc.bytes = 3; - this->ecc.layout = &nand_hw_eccoob_8; - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } else { - this->ecc.size = 512; - this->ecc.bytes = 3; - this->ecc.layout = &nand_hw_eccoob_8; - this->ecc.mode = NAND_ECC_SOFT; - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } - - /* Reset NAND */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* preset operation */ - /* Unlock the internal RAM Buffer */ - writew(0x2, host->regs + NFC_CONFIG); - - /* Blocks to be unlocked */ - writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); - writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); - - /* Unlock Block Command for given address range */ - writew(0x4, host->regs + NFC_WRPROT); - - /* NAND bus width determines access funtions used by upper layer */ - if (pdata->width == 2) { - this->options |= NAND_BUSWIDTH_16; - this->ecc.layout = &nand_hw_eccoob_16; - } - - host->pagesize_2k = 0; - - /* Scan to find existence of the device */ - if (nand_scan(mtd, 1)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_ND: Unable to find any NAND device.\n"); - err = -ENXIO; - goto escan; - } - - /* Register the partitions */ -#ifdef CONFIG_MTD_PARTITIONS - nr_parts = - parse_mtd_partitions(mtd, part_probes, &host->parts, 0); - if (nr_parts > 0) - add_mtd_partitions(mtd, host->parts, nr_parts); - else -#endif - { - pr_info("Registering %s as whole device\n", mtd->name); - add_mtd_device(mtd); - } - - platform_set_drvdata(pdev, host); - - return 0; - -escan: - free_irq(host->irq, NULL); -eirq: - iounmap(host->regs); -eres: - clk_put(host->clk); -eclk: - kfree(host); - - return err; -} - -static int __devexit mxcnd_remove(struct platform_device *pdev) -{ - struct mxc_nand_host *host = platform_get_drvdata(pdev); - - clk_put(host->clk); - - platform_set_drvdata(pdev, NULL); - - nand_release(&host->mtd); - free_irq(host->irq, NULL); - iounmap(host->regs); - kfree(host); - - return 0; -} - -#ifdef CONFIG_PM -static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mtd_info *info = platform_get_drvdata(pdev); - int ret = 0; - - DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n"); - if (info) - ret = info->suspend(info); - - /* Disable the NFC clock */ - clk_disable(nfc_clk); /* FIXME */ - - return ret; -} - -static int mxcnd_resume(struct platform_device *pdev) -{ - struct mtd_info *info = platform_get_drvdata(pdev); - int ret = 0; - - DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n"); - /* Enable the NFC clock */ - clk_enable(nfc_clk); /* FIXME */ - - if (info) - info->resume(info); - - return ret; -} - -#else -# define mxcnd_suspend NULL -# define mxcnd_resume NULL -#endif /* CONFIG_PM */ - -static struct platform_driver mxcnd_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .remove = __exit_p(mxcnd_remove), - .suspend = mxcnd_suspend, - .resume = mxcnd_resume, -}; - -static int __init mxc_nd_init(void) -{ - /* Register the device driver structure. */ - pr_info("MXC MTD nand Driver\n"); - if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) { - printk(KERN_ERR "Driver register failed for mxcnd_driver\n"); - return -ENODEV; - } - return 0; -} - -static void __exit mxc_nd_cleanup(void) -{ - /* Unregister the device structure */ - platform_driver_unregister(&mxcnd_driver); -} - -module_init(mxc_nd_init); -module_exit(mxc_nd_cleanup); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MXC NAND MTD driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index 0a9c9cd33f96..d1129bae6c27 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -801,9 +801,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function * @mtd: mtd info structure * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data + * @dataofs offset of requested data within the page + * @readlen data length + * @buf: buffer to store read data */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) { @@ -2042,7 +2042,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, return -EINVAL; } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + instr->fail_addr = 0xffffffff; /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_ERASING); @@ -2318,12 +2318,6 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* Select the device */ chip->select_chip(mtd, 0); - /* - * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up - */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); @@ -2494,8 +2488,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) /* Check for a chip array */ for (i = 1; i < maxchips; i++) { chip->select_chip(mtd, i); - /* See comment in nand_get_flash_type for reset */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ diff --git a/trunk/drivers/mtd/nand/nand_ecc.c b/trunk/drivers/mtd/nand/nand_ecc.c index 868147acce2c..918a806a8471 100644 --- a/trunk/drivers/mtd/nand/nand_ecc.c +++ b/trunk/drivers/mtd/nand/nand_ecc.c @@ -1,18 +1,13 @@ /* - * This file contains an ECC algorithm that detects and corrects 1 bit - * errors in a 256 byte block of data. + * This file contains an ECC algorithm from Toshiba that detects and + * corrects 1 bit errors in a 256 byte block of data. * * drivers/mtd/nand/nand_ecc.c * - * Copyright © 2008 Koninklijke Philips Electronics NV. - * Author: Frans Meulenbroeks + * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) + * Toshiba America Electronics Components, Inc. * - * Completely replaces the previous ECC implementation which was written by: - * Steven J. Hill (sjhill@realitydiluted.com) - * Thomas Gleixner (tglx@linutronix.de) - * - * Information on how this algorithm works and how it was developed - * can be found in Documentation/mtd/nand_ecc.txt + * Copyright (C) 2006 Thomas Gleixner * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -28,475 +23,174 @@ * with this file; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from these files, or you compile these + * files and link them with other works to produce a work based on these + * files, these files do not by themselves cause the resulting work to be + * covered by the GNU General Public License. However the source code for + * these files must still be made available in accordance with section (3) + * of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. */ -/* - * The STANDALONE macro is useful when running the code outside the kernel - * e.g. when running the code in a testbed or a benchmark program. - * When STANDALONE is used, the module related macros are commented out - * as well as the linux include files. - * Instead a private definition of mtd_info is given to satisfy the compiler - * (the code does not use mtd_info, so the code does not care) - */ -#ifndef STANDALONE #include #include #include -#include -#include #include -#include -#else -#include -struct mtd_info; -#define EXPORT_SYMBOL(x) /* x */ - -#define MODULE_LICENSE(x) /* x */ -#define MODULE_AUTHOR(x) /* x */ -#define MODULE_DESCRIPTION(x) /* x */ - -#define printk printf -#define KERN_ERR "" -#endif - -/* - * invparity is a 256 byte table that contains the odd parity - * for each byte. So if the number of bits in a byte is even, - * the array element is 1, and when the number of bits is odd - * the array eleemnt is 0. - */ -static const char invparity[256] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 -}; - -/* - * bitsperbyte contains the number of bits per byte - * this is only used for testing and repairing parity - * (a precalculated value slightly improves performance) - */ -static const char bitsperbyte[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; /* - * addressbits is a lookup table to filter out the bits from the xor-ed - * ecc data that identify the faulty location. - * this is only used for repairing parity - * see the comments in nand_correct_data for more details + * Pre-calculated 256-way 1 byte column parity */ -static const char addressbits[256] = { - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, - 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, - 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, - 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, - 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, - 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, - 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, - 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, - 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, - 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, - 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, - 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, - 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, - 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, - 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, - 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, - 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, - 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, - 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, - 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, - 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, - 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, - 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, - 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, - 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, - 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, - 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; /** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte - * block + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block * @mtd: MTD block structure - * @buf: input buffer with raw data - * @code: output buffer with ECC + * @dat: raw data + * @ecc_code: buffer for ECC */ -int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, - unsigned char *code) +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) { + uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; int i; - const uint32_t *bp = (uint32_t *)buf; - /* 256 or 512 bytes/ecc */ - const uint32_t eccsize_mult = - (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; - uint32_t cur; /* current value in buffer */ - /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ - uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; - uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; - uint32_t uninitialized_var(rp17); /* to make compiler happy */ - uint32_t par; /* the cumulative parity for all data */ - uint32_t tmppar; /* the cumulative parity for this iteration; - for rp12, rp14 and rp16 at the end of the - loop */ - - par = 0; - rp4 = 0; - rp6 = 0; - rp8 = 0; - rp10 = 0; - rp12 = 0; - rp14 = 0; - rp16 = 0; - - /* - * The loop is unrolled a number of times; - * This avoids if statements to decide on which rp value to update - * Also we process the data by longwords. - * Note: passing unaligned data might give a performance penalty. - * It is assumed that the buffers are aligned. - * tmppar is the cumulative sum of this iteration. - * needed for calculating rp12, rp14, rp16 and par - * also used as a performance improvement for rp6, rp8 and rp10 - */ - for (i = 0; i < eccsize_mult << 2; i++) { - cur = *bp++; - tmppar = cur; - rp4 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp6 ^= tmppar; - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp8 ^= tmppar; - - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - rp6 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp6 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp10 ^= tmppar; - - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - rp6 ^= cur; - rp8 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp6 ^= cur; - rp8 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - rp8 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp8 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - rp6 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp6 ^= cur; - cur = *bp++; - tmppar ^= cur; - rp4 ^= cur; - cur = *bp++; - tmppar ^= cur; + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; - par ^= tmppar; - if ((i & 0x1) == 0) - rp12 ^= tmppar; - if ((i & 0x2) == 0) - rp14 ^= tmppar; - if (eccsize_mult == 2 && (i & 0x4) == 0) - rp16 ^= tmppar; - } + /* Build up column parity */ + for(i = 0; i < 256; i++) { + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[*dat++]; + reg1 ^= (idx & 0x3f); - /* - * handle the fact that we use longword operations - * we'll bring rp4..rp14..rp16 back to single byte entities by - * shifting and xoring first fold the upper and lower 16 bits, - * then the upper and lower 8 bits. - */ - rp4 ^= (rp4 >> 16); - rp4 ^= (rp4 >> 8); - rp4 &= 0xff; - rp6 ^= (rp6 >> 16); - rp6 ^= (rp6 >> 8); - rp6 &= 0xff; - rp8 ^= (rp8 >> 16); - rp8 ^= (rp8 >> 8); - rp8 &= 0xff; - rp10 ^= (rp10 >> 16); - rp10 ^= (rp10 >> 8); - rp10 &= 0xff; - rp12 ^= (rp12 >> 16); - rp12 ^= (rp12 >> 8); - rp12 &= 0xff; - rp14 ^= (rp14 >> 16); - rp14 ^= (rp14 >> 8); - rp14 &= 0xff; - if (eccsize_mult == 2) { - rp16 ^= (rp16 >> 16); - rp16 ^= (rp16 >> 8); - rp16 &= 0xff; + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (uint8_t) i; + reg2 ^= ~((uint8_t) i); + } } - /* - * we also need to calculate the row parity for rp0..rp3 - * This is present in par, because par is now - * rp3 rp3 rp2 rp2 in little endian and - * rp2 rp2 rp3 rp3 in big endian - * as well as - * rp1 rp0 rp1 rp0 in little endian and - * rp0 rp1 rp0 rp1 in big endian - * First calculate rp2 and rp3 - */ -#ifdef __BIG_ENDIAN - rp2 = (par >> 16); - rp2 ^= (rp2 >> 8); - rp2 &= 0xff; - rp3 = par & 0xffff; - rp3 ^= (rp3 >> 8); - rp3 &= 0xff; -#else - rp3 = (par >> 16); - rp3 ^= (rp3 >> 8); - rp3 &= 0xff; - rp2 = par & 0xffff; - rp2 ^= (rp2 >> 8); - rp2 &= 0xff; -#endif - - /* reduce par to 16 bits then calculate rp1 and rp0 */ - par ^= (par >> 16); -#ifdef __BIG_ENDIAN - rp0 = (par >> 8) & 0xff; - rp1 = (par & 0xff); -#else - rp1 = (par >> 8) & 0xff; - rp0 = (par & 0xff); -#endif - - /* finally reduce par to 8 bits */ - par ^= (par >> 8); - par &= 0xff; - - /* - * and calculate rp5..rp15..rp17 - * note that par = rp4 ^ rp5 and due to the commutative property - * of the ^ operator we can say: - * rp5 = (par ^ rp4); - * The & 0xff seems superfluous, but benchmarking learned that - * leaving it out gives slightly worse results. No idea why, probably - * it has to do with the way the pipeline in pentium is organized. - */ - rp5 = (par ^ rp4) & 0xff; - rp7 = (par ^ rp6) & 0xff; - rp9 = (par ^ rp8) & 0xff; - rp11 = (par ^ rp10) & 0xff; - rp13 = (par ^ rp12) & 0xff; - rp15 = (par ^ rp14) & 0xff; - if (eccsize_mult == 2) - rp17 = (par ^ rp16) & 0xff; - - /* - * Finally calculate the ecc bits. - * Again here it might seem that there are performance optimisations - * possible, but benchmarks showed that on the system this is developed - * the code below is the fastest - */ + /* Create non-inverted ECC code from line parity */ + tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ + tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ + tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ + tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ + tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ + tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ + tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ + tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ + + tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ + tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ + tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ + tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ + tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ + tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ + tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ + tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + + /* Calculate final ECC code */ #ifdef CONFIG_MTD_NAND_ECC_SMC - code[0] = - (invparity[rp7] << 7) | - (invparity[rp6] << 6) | - (invparity[rp5] << 5) | - (invparity[rp4] << 4) | - (invparity[rp3] << 3) | - (invparity[rp2] << 2) | - (invparity[rp1] << 1) | - (invparity[rp0]); - code[1] = - (invparity[rp15] << 7) | - (invparity[rp14] << 6) | - (invparity[rp13] << 5) | - (invparity[rp12] << 4) | - (invparity[rp11] << 3) | - (invparity[rp10] << 2) | - (invparity[rp9] << 1) | - (invparity[rp8]); + ecc_code[0] = ~tmp2; + ecc_code[1] = ~tmp1; #else - code[1] = - (invparity[rp7] << 7) | - (invparity[rp6] << 6) | - (invparity[rp5] << 5) | - (invparity[rp4] << 4) | - (invparity[rp3] << 3) | - (invparity[rp2] << 2) | - (invparity[rp1] << 1) | - (invparity[rp0]); - code[0] = - (invparity[rp15] << 7) | - (invparity[rp14] << 6) | - (invparity[rp13] << 5) | - (invparity[rp12] << 4) | - (invparity[rp11] << 3) | - (invparity[rp10] << 2) | - (invparity[rp9] << 1) | - (invparity[rp8]); + ecc_code[0] = ~tmp1; + ecc_code[1] = ~tmp2; #endif - if (eccsize_mult == 1) - code[2] = - (invparity[par & 0xf0] << 7) | - (invparity[par & 0x0f] << 6) | - (invparity[par & 0xcc] << 5) | - (invparity[par & 0x33] << 4) | - (invparity[par & 0xaa] << 3) | - (invparity[par & 0x55] << 2) | - 3; - else - code[2] = - (invparity[par & 0xf0] << 7) | - (invparity[par & 0x0f] << 6) | - (invparity[par & 0xcc] << 5) | - (invparity[par & 0x33] << 4) | - (invparity[par & 0xaa] << 3) | - (invparity[par & 0x55] << 2) | - (invparity[rp17] << 1) | - (invparity[rp16] << 0); + ecc_code[2] = ((~reg1) << 2) | 0x03; + return 0; } EXPORT_SYMBOL(nand_calculate_ecc); +static inline int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + /** * nand_correct_data - [NAND Interface] Detect and correct bit error(s) * @mtd: MTD block structure - * @buf: raw data read from the chip + * @dat: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * - * Detect and correct a 1 bit error for 256/512 byte block + * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, - unsigned char *read_ecc, unsigned char *calc_ecc) +int nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) { - unsigned char b0, b1, b2; - unsigned char byte_addr, bit_addr; - /* 256 or 512 bytes/ecc */ - const uint32_t eccsize_mult = - (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; + uint8_t s0, s1, s2; - /* - * b0 to b2 indicate which bit is faulty (if any) - * we might need the xor result more than once, - * so keep them in a local var - */ #ifdef CONFIG_MTD_NAND_ECC_SMC - b0 = read_ecc[0] ^ calc_ecc[0]; - b1 = read_ecc[1] ^ calc_ecc[1]; + s0 = calc_ecc[0] ^ read_ecc[0]; + s1 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; #else - b0 = read_ecc[1] ^ calc_ecc[1]; - b1 = read_ecc[0] ^ calc_ecc[0]; + s1 = calc_ecc[0] ^ read_ecc[0]; + s0 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; #endif - b2 = read_ecc[2] ^ calc_ecc[2]; + if ((s0 | s1 | s2) == 0) + return 0; - /* check if there are any bitfaults */ + /* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - /* repeated if statements are slightly more efficient than switch ... */ - /* ordered in order of likelihood */ + uint32_t byteoffs, bitnum; - if ((b0 | b1 | b2) == 0) - return 0; /* no error */ + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; - if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && - (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && - ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) || - (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) { - /* single bit error */ - /* - * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty - * byte, cp 5/3/1 indicate the faulty bit. - * A lookup table (called addressbits) is used to filter - * the bits from the byte they are in. - * A marginal optimisation is possible by having three - * different lookup tables. - * One as we have now (for b0), one for b2 - * (that would avoid the >> 1), and one for b1 (with all values - * << 4). However it was felt that introducing two more tables - * hardly justify the gain. - * - * The b2 shift is there to get rid of the lowest two bits. - * We could also do addressbits[b2] >> 1 but for the - * performace it does not make any difference - */ - if (eccsize_mult == 1) - byte_addr = (addressbits[b1] << 4) + addressbits[b0]; - else - byte_addr = (addressbits[b2 & 0x3] << 8) + - (addressbits[b1] << 4) + addressbits[b0]; - bit_addr = addressbits[b2 >> 2]; - /* flip the bit */ - buf[byte_addr] ^= (1 << bit_addr); - return 1; + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; } - /* count nr of bits; use table lookup, faster than calculating it */ - if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) - return 1; /* error in ecc data; no action needed */ - printk(KERN_ERR "uncorrectable error : "); - return -1; + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -EBADMSG; } EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Frans Meulenbroeks "); +MODULE_AUTHOR("Steven J. Hill "); MODULE_DESCRIPTION("Generic NAND ECC support"); diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index ae7c57781a68..556e8131ecdc 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -38,6 +38,7 @@ #include #include #include +#include /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ diff --git a/trunk/drivers/mtd/nand/pxa3xx_nand.c b/trunk/drivers/mtd/nand/pxa3xx_nand.c index c0fa9c9edf08..a64ad15b8fdd 100644 --- a/trunk/drivers/mtd/nand/pxa3xx_nand.c +++ b/trunk/drivers/mtd/nand/pxa3xx_nand.c @@ -115,11 +115,55 @@ enum { STATE_PIO_WRITING, }; +struct pxa3xx_nand_timing { + unsigned int tCH; /* Enable signal hold time */ + unsigned int tCS; /* Enable signal setup time */ + unsigned int tWH; /* ND_nWE high duration */ + unsigned int tWP; /* ND_nWE pulse time */ + unsigned int tRH; /* ND_nRE high duration */ + unsigned int tRP; /* ND_nRE pulse width */ + unsigned int tR; /* ND_nWE high to ND_nRE low for read */ + unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ + unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ +}; + +struct pxa3xx_nand_cmdset { + uint16_t read1; + uint16_t read2; + uint16_t program; + uint16_t read_status; + uint16_t read_id; + uint16_t erase; + uint16_t reset; + uint16_t lock; + uint16_t unlock; + uint16_t lock_status; +}; + +struct pxa3xx_nand_flash { + struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ + struct pxa3xx_nand_cmdset *cmdset; + + uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ + uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ + uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ + uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ + uint32_t num_blocks; /* Number of physical blocks in Flash */ + uint32_t chip_id; + + /* NOTE: these are automatically calculated, do not define */ + size_t oob_size; + size_t read_id_bytes; + + unsigned int col_addr_cycles; + unsigned int row_addr_cycles; +}; + struct pxa3xx_nand_info { struct nand_chip nand_chip; struct platform_device *pdev; - const struct pxa3xx_nand_flash *flash_info; + struct pxa3xx_nand_flash *flash_info; struct clk *clk; void __iomem *mmio_base; @@ -158,20 +202,12 @@ struct pxa3xx_nand_info { uint32_t ndcb0; uint32_t ndcb1; uint32_t ndcb2; - - /* calculated from pxa3xx_nand_flash data */ - size_t oob_size; - size_t read_id_bytes; - - unsigned int col_addr_cycles; - unsigned int row_addr_cycles; }; static int use_dma = 1; module_param(use_dma, bool, 0444); MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN static struct pxa3xx_nand_cmdset smallpage_cmdset = { .read1 = 0x0000, .read2 = 0x0050, @@ -255,35 +291,11 @@ static struct pxa3xx_nand_flash micron1GbX16 = { .chip_id = 0xb12c, }; -static struct pxa3xx_nand_timing stm2GbX16_timing = { - .tCH = 10, - .tCS = 35, - .tWH = 15, - .tWP = 25, - .tRH = 15, - .tRP = 25, - .tR = 25000, - .tWHR = 60, - .tAR = 10, -}; - -static struct pxa3xx_nand_flash stm2GbX16 = { - .timing = &stm2GbX16_timing, - .page_per_block = 64, - .page_size = 2048, - .flash_width = 16, - .dfc_width = 16, - .num_blocks = 2048, - .chip_id = 0xba20, -}; - static struct pxa3xx_nand_flash *builtin_flash_types[] = { &samsung512MbX16, µn1GbX8, µn1GbX16, - &stm2GbX16, }; -#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */ #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -300,7 +312,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, - const struct pxa3xx_nand_timing *t) + struct pxa3xx_nand_timing *t) { unsigned long nand_clk = clk_get_rate(info->clk); uint32_t ndtr0, ndtr1; @@ -342,8 +354,8 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, uint16_t cmd, int column, int page_addr) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + struct pxa3xx_nand_flash *f = info->flash_info; + struct pxa3xx_nand_cmdset *cmdset = f->cmdset; /* calculate data size */ switch (f->page_size) { @@ -361,14 +373,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); info->ndcb1 = 0; info->ndcb2 = 0; - info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); + info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles); - if (info->col_addr_cycles == 2) { + if (f->col_addr_cycles == 2) { /* large block, 2 cycles for column address * row address starts from 3rd cycle */ info->ndcb1 |= (page_addr << 16) | (column & 0xffff); - if (info->row_addr_cycles == 3) + if (f->row_addr_cycles == 3) info->ndcb2 = (page_addr >> 16) & 0xff; } else /* small block, 1 cycles for column address @@ -394,7 +406,7 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info, static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) { - const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; + struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); info->ndcb1 = 0; @@ -629,8 +641,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { struct pxa3xx_nand_info *info = mtd->priv; - const struct pxa3xx_nand_flash *flash_info = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; + struct pxa3xx_nand_flash *flash_info = info->flash_info; + struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; int ret; info->use_dma = (use_dma) ? 1 : 0; @@ -708,7 +720,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->use_dma = 0; /* force PIO read */ info->buf_start = 0; info->buf_count = (command == NAND_CMD_READID) ? - info->read_id_bytes : 1; + flash_info->read_id_bytes : 1; if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? cmdset->read_id : cmdset->read_status)) @@ -849,8 +861,8 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) { - const struct pxa3xx_nand_flash *f = info->flash_info; - const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; + struct pxa3xx_nand_flash *f = info->flash_info; + struct pxa3xx_nand_cmdset *cmdset = f->cmdset; uint32_t ndcr; uint8_t id_buff[8]; @@ -879,7 +891,7 @@ static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) } static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, - const struct pxa3xx_nand_flash *f) + struct pxa3xx_nand_flash *f) { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; @@ -892,25 +904,25 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, return -EINVAL; /* calculate flash information */ - info->oob_size = (f->page_size == 2048) ? 64 : 16; - info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; + f->oob_size = (f->page_size == 2048) ? 64 : 16; + f->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ - info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; + f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; if (f->num_blocks * f->page_per_block > 65536) - info->row_addr_cycles = 3; + f->row_addr_cycles = 3; else - info->row_addr_cycles = 2; + f->row_addr_cycles = 2; ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; + ndcr |= (f->col_addr_cycles == 2) ? NDCR_RA_START : 0; ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); + ndcr |= NDCR_RD_ID_CNT(f->read_id_bytes); ndcr |= NDCR_SPARE_EN; /* enable spare by default */ info->reg_ndcr = ndcr; @@ -920,27 +932,12 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, return 0; } -static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, - const struct pxa3xx_nand_platform_data *pdata) +static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f; - uint32_t id = -1; + struct pxa3xx_nand_flash *f; + uint32_t id; int i; - for (i = 0; inum_flash; ++i) { - f = pdata->flash + i; - - if (pxa3xx_nand_config_flash(info, f)) - continue; - - if (__readid(info, &id)) - continue; - - if (id == f->chip_id) - return 0; - } - -#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { f = builtin_flash_types[i]; @@ -954,11 +951,7 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, if (id == f->chip_id) return 0; } -#endif - dev_warn(&info->pdev->dev, - "failed to detect configured nand flash; found %04x instead of\n", - id); return -ENODEV; } @@ -1021,7 +1014,7 @@ static struct nand_ecclayout hw_largepage_ecclayout = { static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, struct pxa3xx_nand_info *info) { - const struct pxa3xx_nand_flash *f = info->flash_info; + struct pxa3xx_nand_flash *f = info->flash_info; struct nand_chip *this = &info->nand_chip; this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; @@ -1142,7 +1135,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) goto fail_free_buf; } - ret = pxa3xx_nand_detect_flash(info, pdata); + ret = pxa3xx_nand_detect_flash(info); if (ret) { dev_err(&pdev->dev, "failed to detect flash\n"); ret = -ENODEV; diff --git a/trunk/drivers/mtd/nand/sh_flctl.c b/trunk/drivers/mtd/nand/sh_flctl.c deleted file mode 100644 index 600a76f5580e..000000000000 --- a/trunk/drivers/mtd/nand/sh_flctl.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * SuperH FLCTL nand controller - * - * Copyright © 2008 Renesas Solutions Corp. - * Copyright © 2008 Atom Create Engineering Co., Ltd. - * - * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static struct nand_ecclayout flctl_4secc_oob_16 = { - .eccbytes = 10, - .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - .oobfree = { - {.offset = 12, - . length = 4} }, -}; - -static struct nand_ecclayout flctl_4secc_oob_64 = { - .eccbytes = 10, - .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57}, - .oobfree = { - {.offset = 60, - . length = 4} }, -}; - -static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; - -static struct nand_bbt_descr flctl_4secc_smallpage = { - .options = NAND_BBT_SCAN2NDPAGE, - .offs = 11, - .len = 1, - .pattern = scan_ff_pattern, -}; - -static struct nand_bbt_descr flctl_4secc_largepage = { - .options = 0, - .offs = 58, - .len = 2, - .pattern = scan_ff_pattern, -}; - -static void empty_fifo(struct sh_flctl *flctl) -{ - writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */ - writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */ -} - -static void start_translation(struct sh_flctl *flctl) -{ - writeb(TRSTRT, FLTRCR(flctl)); -} - -static void wait_completion(struct sh_flctl *flctl) -{ - uint32_t timeout = LOOP_TIMEOUT_MAX; - - while (timeout--) { - if (readb(FLTRCR(flctl)) & TREND) { - writeb(0x0, FLTRCR(flctl)); - return; - } - udelay(1); - } - - printk(KERN_ERR "wait_completion(): Timeout occured \n"); - writeb(0x0, FLTRCR(flctl)); -} - -static void set_addr(struct mtd_info *mtd, int column, int page_addr) -{ - struct sh_flctl *flctl = mtd_to_flctl(mtd); - uint32_t addr = 0; - - if (column == -1) { - addr = page_addr; /* ERASE1 */ - } else if (page_addr != -1) { - /* SEQIN, READ0, etc.. */ - if (flctl->page_size) { - addr = column & 0x0FFF; - addr |= (page_addr & 0xff) << 16; - addr |= ((page_addr >> 8) & 0xff) << 24; - /* big than 128MB */ - if (flctl->rw_ADRCNT == ADRCNT2_E) { - uint32_t addr2; - addr2 = (page_addr >> 16) & 0xff; - writel(addr2, FLADR2(flctl)); - } - } else { - addr = column; - addr |= (page_addr & 0xff) << 8; - addr |= ((page_addr >> 8) & 0xff) << 16; - addr |= ((page_addr >> 16) & 0xff) << 24; - } - } - writel(addr, FLADR(flctl)); -} - -static void wait_rfifo_ready(struct sh_flctl *flctl) -{ - uint32_t timeout = LOOP_TIMEOUT_MAX; - - while (timeout--) { - uint32_t val; - /* check FIFO */ - val = readl(FLDTCNTR(flctl)) >> 16; - if (val & 0xFF) - return; - udelay(1); - } - printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n"); -} - -static void wait_wfifo_ready(struct sh_flctl *flctl) -{ - uint32_t len, timeout = LOOP_TIMEOUT_MAX; - - while (timeout--) { - /* check FIFO */ - len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF; - if (len >= 4) - return; - udelay(1); - } - printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n"); -} - -static int wait_recfifo_ready(struct sh_flctl *flctl) -{ - uint32_t timeout = LOOP_TIMEOUT_MAX; - int checked[4]; - void __iomem *ecc_reg[4]; - int i; - uint32_t data, size; - - memset(checked, 0, sizeof(checked)); - - while (timeout--) { - size = readl(FLDTCNTR(flctl)) >> 24; - if (size & 0xFF) - return 0; /* success */ - - if (readl(FL4ECCCR(flctl)) & _4ECCFA) - return 1; /* can't correct */ - - udelay(1); - if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) - continue; - - /* start error correction */ - ecc_reg[0] = FL4ECCRESULT0(flctl); - ecc_reg[1] = FL4ECCRESULT1(flctl); - ecc_reg[2] = FL4ECCRESULT2(flctl); - ecc_reg[3] = FL4ECCRESULT3(flctl); - - for (i = 0; i < 3; i++) { - data = readl(ecc_reg[i]); - if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) { - uint8_t org; - int index; - - index = data >> 16; - org = flctl->done_buff[index]; - flctl->done_buff[index] = org ^ (data & 0xFF); - checked[i] = 1; - } - } - - writel(0, FL4ECCCR(flctl)); - } - - printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n"); - return 1; /* timeout */ -} - -static void wait_wecfifo_ready(struct sh_flctl *flctl) -{ - uint32_t timeout = LOOP_TIMEOUT_MAX; - uint32_t len; - - while (timeout--) { - /* check FLECFIFO */ - len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF; - if (len >= 4) - return; - udelay(1); - } - printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n"); -} - -static void read_datareg(struct sh_flctl *flctl, int offset) -{ - unsigned long data; - unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; - - wait_completion(flctl); - - data = readl(FLDATAR(flctl)); - *buf = le32_to_cpu(data); -} - -static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) -{ - int i, len_4align; - unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; - void *fifo_addr = (void *)FLDTFIFO(flctl); - - len_4align = (rlen + 3) / 4; - - for (i = 0; i < len_4align; i++) { - wait_rfifo_ready(flctl); - buf[i] = readl(fifo_addr); - buf[i] = be32_to_cpu(buf[i]); - } -} - -static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff) -{ - int i; - unsigned long *ecc_buf = (unsigned long *)buff; - void *fifo_addr = (void *)FLECFIFO(flctl); - - for (i = 0; i < 4; i++) { - if (wait_recfifo_ready(flctl)) - return 1; - ecc_buf[i] = readl(fifo_addr); - ecc_buf[i] = be32_to_cpu(ecc_buf[i]); - } - - return 0; -} - -static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) -{ - int i, len_4align; - unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; - void *fifo_addr = (void *)FLDTFIFO(flctl); - - len_4align = (rlen + 3) / 4; - for (i = 0; i < len_4align; i++) { - wait_wfifo_ready(flctl); - writel(cpu_to_be32(data[i]), fifo_addr); - } -} - -static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) -{ - struct sh_flctl *flctl = mtd_to_flctl(mtd); - uint32_t flcmncr_val = readl(FLCMNCR(flctl)); - uint32_t flcmdcr_val, addr_len_bytes = 0; - - /* Set SNAND bit if page size is 2048byte */ - if (flctl->page_size) - flcmncr_val |= SNAND_E; - else - flcmncr_val &= ~SNAND_E; - - /* default FLCMDCR val */ - flcmdcr_val = DOCMD1_E | DOADR_E; - - /* Set for FLCMDCR */ - switch (cmd) { - case NAND_CMD_ERASE1: - addr_len_bytes = flctl->erase_ADRCNT; - flcmdcr_val |= DOCMD2_E; - break; - case NAND_CMD_READ0: - case NAND_CMD_READOOB: - addr_len_bytes = flctl->rw_ADRCNT; - flcmdcr_val |= CDSRC_E; - break; - case NAND_CMD_SEQIN: - /* This case is that cmd is READ0 or READ1 or READ00 */ - flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */ - break; - case NAND_CMD_PAGEPROG: - addr_len_bytes = flctl->rw_ADRCNT; diff --git a/trunk/drivers/mtd/nand/toto.c b/trunk/drivers/mtd/nand/toto.c new file mode 100644 index 000000000000..bbf492e6830d --- /dev/null +++ b/trunk/drivers/mtd/nand/toto.c @@ -0,0 +1,206 @@ +/* + * drivers/mtd/nand/toto.c + * + * Copyright (c) 2003 Texas Instruments + * + * Derived from drivers/mtd/autcpu12.c + * + * Copyright (c) 2002 Thomas Gleixner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * TI fido board. It supports 32MiB and 64MiB cards + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_NAND_WORKAROUND 1 + +/* + * MTD structure for TOTO board + */ +static struct mtd_info *toto_mtd = NULL; + +static unsigned long toto_io_base = OMAP_FLASH_1_BASE; + +/* + * Define partitions for flash devices + */ + +static struct mtd_partition partition_info64M[] = { + { .name = "toto kernel partition 1", + .offset = 0, + .size = 2 * SZ_1M }, + { .name = "toto file sys partition 2", + .offset = 2 * SZ_1M, + .size = 14 * SZ_1M }, + { .name = "toto user partition 3", + .offset = 16 * SZ_1M, + .size = 16 * SZ_1M }, + { .name = "toto devboard extra partition 4", + .offset = 32 * SZ_1M, + .size = 32 * SZ_1M }, +}; + +static struct mtd_partition partition_info32M[] = { + { .name = "toto kernel partition 1", + .offset = 0, + .size = 2 * SZ_1M }, + { .name = "toto file sys partition 2", + .offset = 2 * SZ_1M, + .size = 14 * SZ_1M }, + { .name = "toto user partition 3", + .offset = 16 * SZ_1M, + .size = 16 * SZ_1M }, +}; + +#define NUM_PARTITIONS32M 3 +#define NUM_PARTITIONS64M 4 + +/* + * hardware specific access to control-lines + * + * ctrl: + * NAND_NCE: bit 0 -> bit 14 (0x4000) + * NAND_CLE: bit 1 -> bit 12 (0x1000) + * NAND_ALE: bit 2 -> bit 1 (0x0002) + */ +static void toto_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + unsigned long bits; + + /* hopefully enough time for tc make proceding write to clear */ + udelay(1); + + bits = (~ctrl & NAND_NCE) << 14; + bits |= (ctrl & NAND_CLE) << 12; + bits |= (ctrl & NAND_ALE) >> 1; + +#warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx + gpiosetout(0x5002, bits); + +#ifdef CONFIG_NAND_WORKAROUND + /* "some" dev boards busted, blue wired to rts2 :( */ + rts2setout(2, (ctrl & NAND_CLE) << 1); +#endif + /* allow time to ensure gpio state to over take memory write */ + udelay(1); + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + +/* + * Main initialization routine + */ +static int __init toto_init(void) +{ + struct nand_chip *this; + int err = 0; + + /* Allocate memory for MTD device structure and private data */ + toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!toto_mtd) { + printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); + err = -ENOMEM; + goto out; + } + + /* Get pointer to private data */ + this = (struct nand_chip *)(&toto_mtd[1]); + + /* Initialize structures */ + memset(toto_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + toto_mtd->priv = this; + toto_mtd->owner = THIS_MODULE; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = toto_io_base; + this->IO_ADDR_W = toto_io_base; + this->cmd_ctrl = toto_hwcontrol; + this->dev_ready = NULL; + /* 25 us command delay time */ + this->chip_delay = 30; + this->ecc.mode = NAND_ECC_SOFT; + + /* Scan to find existance of the device */ + if (nand_scan(toto_mtd, 1)) { + err = -ENXIO; + goto out_mtd; + } + + /* Register the partitions */ + switch (toto_mtd->size) { + case SZ_64M: + add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); + break; + case SZ_32M: + add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); + break; + default:{ + printk(KERN_WARNING "Unsupported Nand device\n"); + err = -ENXIO; + goto out_buf; + } + } + + gpioreserve(NAND_MASK); /* claim our gpios */ + archflashwp(0, 0); /* open up flash for writing */ + + goto out; + + out_mtd: + kfree(toto_mtd); + out: + return err; +} + +module_init(toto_init); + +/* + * Clean up routine + */ +static void __exit toto_cleanup(void) +{ + /* Release resources, unregister device */ + nand_release(toto_mtd); + + /* Free the MTD device structure */ + kfree(toto_mtd); + + /* stop flash writes */ + archflashwp(0, 1); + + /* release gpios to system */ + gpiorelease(NAND_MASK); +} + +module_exit(toto_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Richard Woodruff "); +MODULE_DESCRIPTION("Glue layer for NAND flash on toto board"); diff --git a/trunk/drivers/mtd/ofpart.c b/trunk/drivers/mtd/ofpart.c index 9e45b3f39c0e..4f80c2fd89af 100644 --- a/trunk/drivers/mtd/ofpart.c +++ b/trunk/drivers/mtd/ofpart.c @@ -20,6 +20,7 @@ #include int __devinit of_mtd_parse_partitions(struct device *dev, + struct mtd_info *mtd, struct device_node *node, struct mtd_partition **pparts) { diff --git a/trunk/drivers/mtd/onenand/Kconfig b/trunk/drivers/mtd/onenand/Kconfig index 79fa79e8f8de..cb41cbca64f7 100644 --- a/trunk/drivers/mtd/onenand/Kconfig +++ b/trunk/drivers/mtd/onenand/Kconfig @@ -27,16 +27,8 @@ config MTD_ONENAND_GENERIC help Support for OneNAND flash via platform device driver. -config MTD_ONENAND_OMAP2 - tristate "OneNAND on OMAP2/OMAP3 support" - depends on MTD_ONENAND && (ARCH_OMAP2 || ARCH_OMAP3) - help - Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU - via the GPMC memory controller. - config MTD_ONENAND_OTP bool "OneNAND OTP Support" - select HAVE_MTD_OTP help One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. diff --git a/trunk/drivers/mtd/onenand/Makefile b/trunk/drivers/mtd/onenand/Makefile index 64b6cc61a520..4d2eacfd7e11 100644 --- a/trunk/drivers/mtd/onenand/Makefile +++ b/trunk/drivers/mtd/onenand/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o # Board specific. obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o -obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o # Simulator obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o diff --git a/trunk/drivers/mtd/onenand/omap2.c b/trunk/drivers/mtd/onenand/omap2.c deleted file mode 100644 index 8387e05daae2..000000000000 --- a/trunk/drivers/mtd/onenand/omap2.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - * linux/drivers/mtd/onenand/omap2.c - * - * OneNAND driver for OMAP2 / OMAP3 - * - * Copyright © 2005-2006 Nokia Corporation - * - * Author: Jarkko Lavinen and Juha Yrjölä - * IRQ and DMA support written by Timo Teras - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define DRIVER_NAME "omap2-onenand" - -#define ONENAND_IO_SIZE SZ_128K -#define ONENAND_BUFRAM_SIZE (1024 * 5) - -struct omap2_onenand { - struct platform_device *pdev; - int gpmc_cs; - unsigned long phys_base; - int gpio_irq; - struct mtd_info mtd; - struct mtd_partition *parts; - struct onenand_chip onenand; - struct completion irq_done; - struct completion dma_done; - int dma_channel; - int freq; - int (*setup)(void __iomem *base, int freq); -}; - -static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) -{ - struct omap2_onenand *c = data; - - complete(&c->dma_done); -} - -static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id) -{ - struct omap2_onenand *c = dev_id; - - complete(&c->irq_done); - - return IRQ_HANDLED; -} - -static inline unsigned short read_reg(struct omap2_onenand *c, int reg) -{ - return readw(c->onenand.base + reg); -} - -static inline void write_reg(struct omap2_onenand *c, unsigned short value, - int reg) -{ - writew(value, c->onenand.base + reg); -} - -static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr) -{ - printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n", - msg, state, ctrl, intr); -} - -static void wait_warn(char *msg, int state, unsigned int ctrl, - unsigned int intr) -{ - printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x " - "intr 0x%04x\n", msg, state, ctrl, intr); -} - -static int omap2_onenand_wait(struct mtd_info *mtd, int state) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - unsigned int intr = 0; - unsigned int ctrl; - unsigned long timeout; - u32 syscfg; - - if (state == FL_RESETING) { - int i; - - for (i = 0; i < 20; i++) { - udelay(1); - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if (intr & ONENAND_INT_MASTER) - break; - } - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ERROR) { - wait_err("controller error", state, ctrl, intr); - return -EIO; - } - if (!(intr & ONENAND_INT_RESET)) { - wait_err("timeout", state, ctrl, intr); - return -EIO; - } - return 0; - } - - if (state != FL_READING) { - int result; - - /* Turn interrupts on */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { - syscfg |= ONENAND_SYS_CFG1_IOBE; - write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - if (cpu_is_omap34xx()) - /* Add a delay to let GPIO settle */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - } - - INIT_COMPLETION(c->irq_done); - if (c->gpio_irq) { - result = omap_get_gpio_datain(c->gpio_irq); - if (result == -1) { - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - intr = read_reg(c, ONENAND_REG_INTERRUPT); - wait_err("gpio error", state, ctrl, intr); - return -EIO; - } - } else - result = 0; - if (result == 0) { - int retry_cnt = 0; -retry: - result = wait_for_completion_timeout(&c->irq_done, - msecs_to_jiffies(20)); - if (result == 0) { - /* Timeout after 20ms */ - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO) { - /* - * The operation seems to be still going - * so give it some more time. - */ - retry_cnt += 1; - if (retry_cnt < 3) - goto retry; - intr = read_reg(c, - ONENAND_REG_INTERRUPT); - wait_err("timeout", state, ctrl, intr); - return -EIO; - } - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if ((intr & ONENAND_INT_MASTER) == 0) - wait_warn("timeout", state, ctrl, intr); - } - } - } else { - int retry_cnt = 0; - - /* Turn interrupts off */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - syscfg &= ~ONENAND_SYS_CFG1_IOBE; - write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - - timeout = jiffies + msecs_to_jiffies(20); - while (1) { - if (time_before(jiffies, timeout)) { - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if (intr & ONENAND_INT_MASTER) - break; - } else { - /* Timeout after 20ms */ - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO) { - /* - * The operation seems to be still going - * so give it some more time. - */ - retry_cnt += 1; - if (retry_cnt < 3) { - timeout = jiffies + - msecs_to_jiffies(20); - continue; - } - } - break; - } - } - } - - intr = read_reg(c, ONENAND_REG_INTERRUPT); - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - - if (intr & ONENAND_INT_READ) { - int ecc = read_reg(c, ONENAND_REG_ECC_STATUS); - - if (ecc) { - unsigned int addr1, addr8; - - addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1); - addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8); - if (ecc & ONENAND_ECC_2BIT_ALL) { - printk(KERN_ERR "onenand_wait: ECC error = " - "0x%04x, addr1 %#x, addr8 %#x\n", - ecc, addr1, addr8); - mtd->ecc_stats.failed++; - return -EBADMSG; - } else if (ecc & ONENAND_ECC_1BIT_ALL) { - printk(KERN_NOTICE "onenand_wait: correctable " - "ECC error = 0x%04x, addr1 %#x, " - "addr8 %#x\n", ecc, addr1, addr8); - mtd->ecc_stats.corrected++; - } - } - } else if (state == FL_READING) { - wait_err("timeout", state, ctrl, intr); - return -EIO; - } - - if (ctrl & ONENAND_CTRL_ERROR) { - wait_err("controller error", state, ctrl, intr); - if (ctrl & ONENAND_CTRL_LOCK) - printk(KERN_ERR "onenand_wait: " - "Device is write protected!!!\n"); - return -EIO; - } - - if (ctrl & 0xFE9F) - wait_warn("unexpected controller status", state, ctrl, intr); - - return 0; -} - -static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area) -{ - struct onenand_chip *this = mtd->priv; - - if (ONENAND_CURRENT_BUFFERRAM(this)) { - if (area == ONENAND_DATARAM) - return mtd->writesize; - if (area == ONENAND_SPARERAM) - return mtd->oobsize; - } - - return 0; -} - -#if defined(CONFIG_ARCH_OMAP3) || defined(MULTI_OMAP2) - -static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - dma_addr_t dma_src, dma_dst; - int bram_offset; - unsigned long timeout; - void *buf = (void *)buffer; - size_t xtra; - volatile unsigned *done; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - if (bram_offset & 3 || (size_t)buf & 3 || count < 384) - goto out_copy; - - if (buf >= high_memory) { - struct page *p1; - - if (((size_t)buf & PAGE_MASK) != - ((size_t)(buf + count - 1) & PAGE_MASK)) - goto out_copy; - p1 = vmalloc_to_page(buf); - if (!p1) - goto out_copy; - buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); - } - - xtra = count & 3; - if (xtra) { - count -= xtra; - memcpy(buf + count, this->base + bram_offset + count, xtra); - } - - dma_src = c->phys_base + bram_offset; - dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE); - if (dma_mapping_error(&c->pdev->dev, dma_dst)) { - dev_err(&c->pdev->dev, - "Couldn't DMA map a %d byte buffer\n", - count); - goto out_copy; - } - - omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, - count >> 2, 1, 0, 0, 0); - omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_src, 0, 0); - omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_dst, 0, 0); - - INIT_COMPLETION(c->dma_done); - omap_start_dma(c->dma_channel); - - timeout = jiffies + msecs_to_jiffies(20); - done = &c->dma_done.done; - while (time_before(jiffies, timeout)) - if (*done) - break; - - dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); - - if (!*done) { - dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); - goto out_copy; - } - - return 0; - -out_copy: - memcpy(buf, this->base + bram_offset, count); - return 0; -} - -static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - dma_addr_t dma_src, dma_dst; - int bram_offset; - unsigned long timeout; - void *buf = (void *)buffer; - volatile unsigned *done; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - if (bram_offset & 3 || (size_t)buf & 3 || count < 384) - goto out_copy; - - /* panic_write() may be in an interrupt context */ - if (in_interrupt()) - goto out_copy; - - if (buf >= high_memory) { - struct page *p1; - - if (((size_t)buf & PAGE_MASK) != - ((size_t)(buf + count - 1) & PAGE_MASK)) - goto out_copy; - p1 = vmalloc_to_page(buf); - if (!p1) - goto out_copy; - buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); - } - - dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE); - dma_dst = c->phys_base + bram_offset; - if (dma_mapping_error(&c->pdev->dev, dma_dst)) { - dev_err(&c->pdev->dev, - "Couldn't DMA map a %d byte buffer\n", - count); - return -1; - } - - omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, - count >> 2, 1, 0, 0, 0); - omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_src, 0, 0); - omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_dst, 0, 0); - - INIT_COMPLETION(c->dma_done); - omap_start_dma(c->dma_channel); - - timeout = jiffies + msecs_to_jiffies(20); - done = &c->dma_done.done; - while (time_before(jiffies, timeout)) - if (*done) - break; - - dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); - - if (!*done) { - dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); - goto out_copy; - } - - return 0; - -out_copy: - memcpy(this->base + bram_offset, buf, count); - return 0; -} - -#else - -int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count); - -int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count); - -#endif - -#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2) - -static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - dma_addr_t dma_src, dma_dst; - int bram_offset; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - /* DMA is not used. Revisit PM requirements before enabling it. */ - if (1 || (c->dma_channel < 0) || - ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || - (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { - memcpy(buffer, (__force void *)(this->base + bram_offset), - count); - return 0; - } - - dma_src = c->phys_base + bram_offset; - dma_dst = dma_map_single(&c->pdev->dev, buffer, count, - DMA_FROM_DEVICE); - if (dma_mapping_error(&c->pdev->dev, dma_dst)) { - dev_err(&c->pdev->dev, - "Couldn't DMA map a %d byte buffer\n", - count); - return -1; - } - - omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, - count / 4, 1, 0, 0, 0); - omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_src, 0, 0); - omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_dst, 0, 0); - - INIT_COMPLETION(c->dma_done); - omap_start_dma(c->dma_channel); - wait_for_completion(&c->dma_done); - - dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); - - return 0; -} - -static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - dma_addr_t dma_src, dma_dst; - int bram_offset; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - /* DMA is not used. Revisit PM requirements before enabling it. */ - if (1 || (c->dma_channel < 0) || - ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || - (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { - memcpy((__force void *)(this->base + bram_offset), buffer, - count); - return 0; - } - - dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count, - DMA_TO_DEVICE); - dma_dst = c->phys_base + bram_offset; - if (dma_mapping_error(&c->pdev->dev, dma_dst)) { - dev_err(&c->pdev->dev, - "Couldn't DMA map a %d byte buffer\n", - count); - return -1; - } - - omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16, - count / 2, 1, 0, 0, 0); - omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_src, 0, 0); - omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, - dma_dst, 0, 0); - - INIT_COMPLETION(c->dma_done); - omap_start_dma(c->dma_channel); - wait_for_completion(&c->dma_done); - - dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); - - return 0; -} - -#else - -int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count); - -int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count); - -#endif - -static struct platform_driver omap2_onenand_driver; - -static int __adjust_timing(struct device *dev, void *data) -{ - int ret = 0; - struct omap2_onenand *c; - - c = dev_get_drvdata(dev); - - BUG_ON(c->setup == NULL); - - /* DMA is not in use so this is all that is needed */ - /* Revisit for OMAP3! */ - ret = c->setup(c->onenand.base, c->freq); - - return ret; -} - -int omap2_onenand_rephase(void) -{ - return driver_for_each_device(&omap2_onenand_driver.driver, NULL, - NULL, __adjust_timing); -} - -static void __devexit omap2_onenand_shutdown(struct platform_device *pdev) -{ - struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); - - /* With certain content in the buffer RAM, the OMAP boot ROM code - * can recognize the flash chip incorrectly. Zero it out before - * soft reset. - */ - memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); -} - -static int __devinit omap2_onenand_probe(struct platform_device *pdev) -{ - struct omap_onenand_platform_data *pdata; - struct omap2_onenand *c; - int r; - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data missing\n"); - return -ENODEV; - } - - c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL); - if (!c) - return -ENOMEM; - - init_completion(&c->irq_done); - init_completion(&c->dma_done); - c->gpmc_cs = pdata->cs; - c->gpio_irq = pdata->gpio_irq; - c->dma_channel = pdata->dma_channel; - if (c->dma_channel < 0) { - /* if -1, don't use DMA */ - c->gpio_irq = 0; - } - - r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base); - if (r < 0) { - dev_err(&pdev->dev, "Cannot request GPMC CS\n"); - goto err_kfree; - } - - if (request_mem_region(c->phys_base, ONENAND_IO_SIZE, - pdev->dev.driver->name) == NULL) { - dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, " - "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE); - r = -EBUSY; - goto err_free_cs; - } - c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE); - if (c->onenand.base == NULL) { - r = -ENOMEM; - goto err_release_mem_region; - } - - if (pdata->onenand_setup != NULL) { - r = pdata->onenand_setup(c->onenand.base, c->freq); - if (r < 0) { - dev_err(&pdev->dev, "Onenand platform setup failed: " - "%d\n", r); - goto err_iounmap; - } - c->setup = pdata->onenand_setup; - } - - if (c->gpio_irq) { - if ((r = omap_request_gpio(c->gpio_irq)) < 0) { - dev_err(&pdev->dev, "Failed to request GPIO%d for " - "OneNAND\n", c->gpio_irq); - goto err_iounmap; - } - omap_set_gpio_direction(c->gpio_irq, 1); - - if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq), - omap2_onenand_interrupt, IRQF_TRIGGER_RISING, - pdev->dev.driver->name, c)) < 0) - goto err_release_gpio; - } - - if (c->dma_channel >= 0) { - r = omap_request_dma(0, pdev->dev.driver->name, - omap2_onenand_dma_cb, (void *) c, - &c->dma_channel); - if (r == 0) { - omap_set_dma_write_mode(c->dma_channel, - OMAP_DMA_WRITE_NON_POSTED); - omap_set_dma_src_data_pack(c->dma_channel, 1); - omap_set_dma_src_burst_mode(c->dma_channel, - OMAP_DMA_DATA_BURST_8); - omap_set_dma_dest_data_pack(c->dma_channel, 1); - omap_set_dma_dest_burst_mode(c->dma_channel, - OMAP_DMA_DATA_BURST_8); - } else { - dev_info(&pdev->dev, - "failed to allocate DMA for OneNAND, " - "using PIO instead\n"); - c->dma_channel = -1; - } - } - - dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual " - "base %p\n", c->gpmc_cs, c->phys_base, - c->onenand.base); - - c->pdev = pdev; - c->mtd.name = pdev->dev.bus_id; - c->mtd.priv = &c->onenand; - c->mtd.owner = THIS_MODULE; - - if (c->dma_channel >= 0) { - struct onenand_chip *this = &c->onenand; - - this->wait = omap2_onenand_wait; - if (cpu_is_omap34xx()) { - this->read_bufferram = omap3_onenand_read_bufferram; - this->write_bufferram = omap3_onenand_write_bufferram; - } else { - this->read_bufferram = omap2_onenand_read_bufferram; - this->write_bufferram = omap2_onenand_write_bufferram; - } - } - - if ((r = onenand_scan(&c->mtd, 1)) < 0) - goto err_release_dma; - - switch ((c->onenand.version_id >> 4) & 0xf) { - case 0: - c->freq = 40; - break; - case 1: - c->freq = 54; - break; - case 2: - c->freq = 66; - break; - case 3: - c->freq = 83; - break; - } - -#ifdef CONFIG_MTD_PARTITIONS - if (pdata->parts != NULL) - r = add_mtd_partitions(&c->mtd, pdata->parts, - pdata->nr_parts); - else -#endif - r = add_mtd_device(&c->mtd); - if (r < 0) - goto err_release_onenand; - - platform_set_drvdata(pdev, c); - - return 0; - -err_release_onenand: - onenand_release(&c->mtd); -err_release_dma: - if (c->dma_channel != -1) - omap_free_dma(c->dma_channel); - if (c->gpio_irq) - free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c); -err_release_gpio: - if (c->gpio_irq) - omap_free_gpio(c->gpio_irq); -err_iounmap: - iounmap(c->onenand.base); -err_release_mem_region: - release_mem_region(c->phys_base, ONENAND_IO_SIZE); -err_free_cs: - gpmc_cs_free(c->gpmc_cs); -err_kfree: - kfree(c); - - return r; -} - -static int __devexit omap2_onenand_remove(struct platform_device *pdev) -{ - struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); - - BUG_ON(c == NULL); - -#ifdef CONFIG_MTD_PARTITIONS - if (c->parts) - del_mtd_partitions(&c->mtd); - else - del_mtd_device(&c->mtd); -#else - del_mtd_device(&c->mtd); -#endif - - onenand_release(&c->mtd); - if (c->dma_channel != -1) - omap_free_dma(c->dma_channel); - omap2_onenand_shutdown(pdev); - platform_set_drvdata(pdev, NULL); - if (c->gpio_irq) { - free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c); - omap_free_gpio(c->gpio_irq); - } - iounmap(c->onenand.base); - release_mem_region(c->phys_base, ONENAND_IO_SIZE); - kfree(c); - - return 0; -} - -static struct platform_driver omap2_onenand_driver = { - .probe = omap2_onenand_probe, - .remove = omap2_onenand_remove, - .shutdown = omap2_onenand_shutdown, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init omap2_onenand_init(void) -{ - printk(KERN_INFO "OneNAND driver initializing\n"); - return platform_driver_register(&omap2_onenand_driver); -} - -static void __exit omap2_onenand_exit(void) -{ - platform_driver_unregister(&omap2_onenand_driver); -} - -module_init(omap2_onenand_init); -module_exit(omap2_onenand_exit); - -MODULE_ALIAS(DRIVER_NAME); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarkko Lavinen "); -MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3"); diff --git a/trunk/drivers/mtd/onenand/onenand_base.c b/trunk/drivers/mtd/onenand/onenand_base.c index 90ed319f26e6..926cf3a4135d 100644 --- a/trunk/drivers/mtd/onenand/onenand_base.c +++ b/trunk/drivers/mtd/onenand/onenand_base.c @@ -1794,7 +1794,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + instr->fail_addr = 0xffffffff; /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_ERASING); diff --git a/trunk/drivers/mtd/ssfdc.c b/trunk/drivers/mtd/ssfdc.c index 33a5d6ed6f18..a5f3d60047d4 100644 --- a/trunk/drivers/mtd/ssfdc.c +++ b/trunk/drivers/mtd/ssfdc.c @@ -321,7 +321,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, - DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); + (ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) / + MAX_PHYS_BLK_PER_ZONE); /* Set geometry */ ssfdc->heads = 16; diff --git a/trunk/drivers/mtd/ubi/cdev.c b/trunk/drivers/mtd/ubi/cdev.c index 03c759b4eeb5..b30a0b83d7f1 100644 --- a/trunk/drivers/mtd/ubi/cdev.c +++ b/trunk/drivers/mtd/ubi/cdev.c @@ -104,12 +104,9 @@ static int vol_cdev_open(struct inode *inode, struct file *file) struct ubi_volume_desc *desc; int vol_id = iminor(inode) - 1, mode, ubi_num; - lock_kernel(); ubi_num = ubi_major2num(imajor(inode)); - if (ubi_num < 0) { - unlock_kernel(); + if (ubi_num < 0) return ubi_num; - } if (file->f_mode & FMODE_WRITE) mode = UBI_READWRITE; @@ -119,7 +116,6 @@ static int vol_cdev_open(struct inode *inode, struct file *file) dbg_gen("open volume %d, mode %d", vol_id, mode); desc = ubi_open_volume(ubi_num, vol_id, mode); - unlock_kernel(); if (IS_ERR(desc)) return PTR_ERR(desc); diff --git a/trunk/drivers/pci/rom.c b/trunk/drivers/pci/rom.c index 1f5f6143f35c..bd5c0e031398 100644 --- a/trunk/drivers/pci/rom.c +++ b/trunk/drivers/pci/rom.c @@ -21,7 +21,7 @@ * between the ROM and other resources, so enabling it may disable access * to MMIO registers or other card memory. */ -int pci_enable_rom(struct pci_dev *pdev) +static int pci_enable_rom(struct pci_dev *pdev) { struct resource *res = pdev->resource + PCI_ROM_RESOURCE; struct pci_bus_region region; @@ -45,7 +45,7 @@ int pci_enable_rom(struct pci_dev *pdev) * Disable ROM decoding on a PCI device by turning off the last bit in the * ROM BAR. */ -void pci_disable_rom(struct pci_dev *pdev) +static void pci_disable_rom(struct pci_dev *pdev) { u32 rom_addr; pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); @@ -260,5 +260,3 @@ void pci_cleanup_rom(struct pci_dev *pdev) EXPORT_SYMBOL(pci_map_rom); EXPORT_SYMBOL(pci_unmap_rom); -EXPORT_SYMBOL_GPL(pci_enable_rom); -EXPORT_SYMBOL_GPL(pci_disable_rom); diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index b7c88e1f0161..abccb5dab9a8 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -1136,7 +1136,195 @@ config EFS_FS To compile the EFS file system support as a module, choose M here: the module will be called efs. -source "fs/jffs2/Kconfig" +config JFFS2_FS + tristate "Journalling Flash File System v2 (JFFS2) support" + select CRC32 + depends on MTD + help + JFFS2 is the second generation of the Journalling Flash File System + for use on diskless embedded devices. It provides improved wear + levelling, compression and support for hard links. You cannot use + this on normal block devices, only on 'MTD' devices. + + Further information on the design and implementation of JFFS2 is + available at . + +config JFFS2_FS_DEBUG + int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" + depends on JFFS2_FS + default "0" + help + This controls the amount of debugging messages produced by the JFFS2 + code. Set it to zero for use in production systems. For evaluation, + testing and debugging, it's advisable to set it to one. This will + enable a few assertions and will print debugging messages at the + KERN_DEBUG loglevel, where they won't normally be visible. Level 2 + is unlikely to be useful - it enables extra debugging in certain + areas which at one point needed debugging, but when the bugs were + located and fixed, the detailed messages were relegated to level 2. + + If reporting bugs, please try to have available a full dump of the + messages at debug level 1 while the misbehaviour was occurring. + +config JFFS2_FS_WRITEBUFFER + bool "JFFS2 write-buffering support" + depends on JFFS2_FS + default y + help + This enables the write-buffering support in JFFS2. + + This functionality is required to support JFFS2 on the following + types of flash devices: + - NAND flash + - NOR flash with transparent ECC + - DataFlash + +config JFFS2_FS_WBUF_VERIFY + bool "Verify JFFS2 write-buffer reads" + depends on JFFS2_FS_WRITEBUFFER + default n + help + This causes JFFS2 to read back every page written through the + write-buffer, and check for errors. + +config JFFS2_SUMMARY + bool "JFFS2 summary support (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + This feature makes it possible to use summary information + for faster filesystem mount. + + The summary information can be inserted into a filesystem image + by the utility 'sumtool'. + + If unsure, say 'N'. + +config JFFS2_FS_XATTR + bool "JFFS2 XATTR support (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + +config JFFS2_FS_POSIX_ACL + bool "JFFS2 POSIX Access Control Lists" + depends on JFFS2_FS_XATTR + default y + select FS_POSIX_ACL + help + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + +config JFFS2_FS_SECURITY + bool "JFFS2 Security Labels" + depends on JFFS2_FS_XATTR + default y + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the jffs2 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + +config JFFS2_COMPRESSION_OPTIONS + bool "Advanced compression options for JFFS2" + depends on JFFS2_FS + default n + help + Enabling this option allows you to explicitly choose which + compression modules, if any, are enabled in JFFS2. Removing + compressors can mean you cannot read existing file systems, + and enabling experimental compressors can mean that you + write a file system which cannot be read by a standard kernel. + + If unsure, you should _definitely_ say 'N'. + +config JFFS2_ZLIB + bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS + select ZLIB_INFLATE + select ZLIB_DEFLATE + depends on JFFS2_FS + default y + help + Zlib is designed to be a free, general-purpose, legally unencumbered, + lossless data-compression library for use on virtually any computer + hardware and operating system. See for + further information. + + Say 'Y' if unsure. + +config JFFS2_LZO + bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS + select LZO_COMPRESS + select LZO_DECOMPRESS + depends on JFFS2_FS + default n + help + minilzo-based compression. Generally works better than Zlib. + + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + +config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS + default y + help + Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. + +config JFFS2_RUBIN + bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS + default n + help + RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. + +choice + prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS + default JFFS2_CMODE_PRIORITY + depends on JFFS2_FS + help + You can set here the default compression mode of JFFS2 from + the available compression modes. Don't touch if unsure. + +config JFFS2_CMODE_NONE + bool "no compression" + help + Uses no compression. + +config JFFS2_CMODE_PRIORITY + bool "priority" + help + Tries the compressors in a predefined order and chooses the first + successful one. + +config JFFS2_CMODE_SIZE + bool "size (EXPERIMENTAL)" + help + Tries all compressors and chooses the one which has the smallest + result. + +config JFFS2_CMODE_FAVOURLZO + bool "Favour LZO" + help + Tries all compressors and chooses the one which has the smallest + result but gives some preference to LZO (which has faster + decompression) at the expense of size. + +endchoice + # UBIFS File system configuration source "fs/ubifs/Kconfig" diff --git a/trunk/fs/jffs2/Kconfig b/trunk/fs/jffs2/Kconfig deleted file mode 100644 index 6ae169cd8faa..000000000000 --- a/trunk/fs/jffs2/Kconfig +++ /dev/null @@ -1,188 +0,0 @@ -config JFFS2_FS - tristate "Journalling Flash File System v2 (JFFS2) support" - select CRC32 - depends on MTD - help - JFFS2 is the second generation of the Journalling Flash File System - for use on diskless embedded devices. It provides improved wear - levelling, compression and support for hard links. You cannot use - this on normal block devices, only on 'MTD' devices. - - Further information on the design and implementation of JFFS2 is - available at . - -config JFFS2_FS_DEBUG - int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" - depends on JFFS2_FS - default "0" - help - This controls the amount of debugging messages produced by the JFFS2 - code. Set it to zero for use in production systems. For evaluation, - testing and debugging, it's advisable to set it to one. This will - enable a few assertions and will print debugging messages at the - KERN_DEBUG loglevel, where they won't normally be visible. Level 2 - is unlikely to be useful - it enables extra debugging in certain - areas which at one point needed debugging, but when the bugs were - located and fixed, the detailed messages were relegated to level 2. - - If reporting bugs, please try to have available a full dump of the - messages at debug level 1 while the misbehaviour was occurring. - -config JFFS2_FS_WRITEBUFFER - bool "JFFS2 write-buffering support" - depends on JFFS2_FS - default y - help - This enables the write-buffering support in JFFS2. - - This functionality is required to support JFFS2 on the following - types of flash devices: - - NAND flash - - NOR flash with transparent ECC - - DataFlash - -config JFFS2_FS_WBUF_VERIFY - bool "Verify JFFS2 write-buffer reads" - depends on JFFS2_FS_WRITEBUFFER - default n - help - This causes JFFS2 to read back every page written through the - write-buffer, and check for errors. - -config JFFS2_SUMMARY - bool "JFFS2 summary support (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This feature makes it possible to use summary information - for faster filesystem mount. - - The summary information can be inserted into a filesystem image - by the utility 'sumtool'. - - If unsure, say 'N'. - -config JFFS2_FS_XATTR - bool "JFFS2 XATTR support (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - -config JFFS2_FS_POSIX_ACL - bool "JFFS2 POSIX Access Control Lists" - depends on JFFS2_FS_XATTR - default y - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config JFFS2_FS_SECURITY - bool "JFFS2 Security Labels" - depends on JFFS2_FS_XATTR - default y - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the jffs2 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. - -config JFFS2_COMPRESSION_OPTIONS - bool "Advanced compression options for JFFS2" - depends on JFFS2_FS - default n - help - Enabling this option allows you to explicitly choose which - compression modules, if any, are enabled in JFFS2. Removing - compressors can mean you cannot read existing file systems, - and enabling experimental compressors can mean that you - write a file system which cannot be read by a standard kernel. - - If unsure, you should _definitely_ say 'N'. - -config JFFS2_ZLIB - bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS - select ZLIB_INFLATE - select ZLIB_DEFLATE - depends on JFFS2_FS - default y - help - Zlib is designed to be a free, general-purpose, legally unencumbered, - lossless data-compression library for use on virtually any computer - hardware and operating system. See for - further information. - - Say 'Y' if unsure. - -config JFFS2_LZO - bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS - select LZO_COMPRESS - select LZO_DECOMPRESS - depends on JFFS2_FS - default n - help - minilzo-based compression. Generally works better than Zlib. - - This feature was added in July, 2007. Say 'N' if you need - compatibility with older bootloaders or kernels. - -config JFFS2_RTIME - bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS - depends on JFFS2_FS - default y - help - Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. - -config JFFS2_RUBIN - bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS - depends on JFFS2_FS - default n - help - RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. - -choice - prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS - default JFFS2_CMODE_PRIORITY - depends on JFFS2_FS - help - You can set here the default compression mode of JFFS2 from - the available compression modes. Don't touch if unsure. - -config JFFS2_CMODE_NONE - bool "no compression" - help - Uses no compression. - -config JFFS2_CMODE_PRIORITY - bool "priority" - help - Tries the compressors in a predefined order and chooses the first - successful one. - -config JFFS2_CMODE_SIZE - bool "size (EXPERIMENTAL)" - help - Tries all compressors and chooses the one which has the smallest - result. - -config JFFS2_CMODE_FAVOURLZO - bool "Favour LZO" - help - Tries all compressors and chooses the one which has the smallest - result but gives some preference to LZO (which has faster - decompression) at the expense of size. - -endchoice diff --git a/trunk/fs/jffs2/compr.c b/trunk/fs/jffs2/compr.c index f25e70c1b51c..86739ee53b37 100644 --- a/trunk/fs/jffs2/compr.c +++ b/trunk/fs/jffs2/compr.c @@ -53,8 +53,8 @@ static int jffs2_is_best_compression(struct jffs2_compressor *this, } /* jffs2_compress: - * @data_in: Pointer to uncompressed data - * @cpage_out: Pointer to returned pointer to buffer for compressed data + * @data: Pointer to uncompressed data + * @cdata: Pointer to returned pointer to buffer for compressed data * @datalen: On entry, holds the amount of data available for compression. * On exit, expected to hold the amount of data actually compressed. * @cdatalen: On entry, holds the amount of space available for compressed diff --git a/trunk/fs/jffs2/dir.c b/trunk/fs/jffs2/dir.c index b1aaae823a52..cd219ef55254 100644 --- a/trunk/fs/jffs2/dir.c +++ b/trunk/fs/jffs2/dir.c @@ -311,7 +311,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ if (targetlen > 254) - return -ENAMETOOLONG; + return -EINVAL; ri = jffs2_alloc_raw_inode(); diff --git a/trunk/fs/jffs2/erase.c b/trunk/fs/jffs2/erase.c index 259461b910af..dddb2a6c9e2c 100644 --- a/trunk/fs/jffs2/erase.c +++ b/trunk/fs/jffs2/erase.c @@ -68,7 +68,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, instr->len = c->sector_size; instr->callback = jffs2_erase_callback; instr->priv = (unsigned long)(&instr[1]); - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + instr->fail_addr = 0xffffffff; ((struct erase_priv_struct *)instr->priv)->jeb = jeb; ((struct erase_priv_struct *)instr->priv)->c = c; @@ -175,7 +175,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock { /* For NAND, if the failure did not occur at the device level for a specific physical page, don't bother updating the bad block table. */ - if (jffs2_cleanmarker_oob(c) && (bad_offset != MTD_FAIL_ADDR_UNKNOWN)) { + if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) { /* We had a device-level failure to erase. Let's see if we've failed too many times. */ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { diff --git a/trunk/fs/jffs2/fs.c b/trunk/fs/jffs2/fs.c index 249305d65d5b..086c43830221 100644 --- a/trunk/fs/jffs2/fs.c +++ b/trunk/fs/jffs2/fs.c @@ -207,8 +207,6 @@ int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_files = 0; buf->f_ffree = 0; buf->f_namelen = JFFS2_MAX_NAME_LEN; - buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; - buf->f_fsid.val[1] = c->mtd->index; spin_lock(&c->erase_completion_lock); avail = c->dirty_size + c->free_size; @@ -442,14 +440,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i memset(ri, 0, sizeof(*ri)); /* Set OS-specific defaults for new inodes */ - ri->uid = cpu_to_je16(current_fsuid()); + ri->uid = cpu_to_je16(current->fsuid); if (dir_i->i_mode & S_ISGID) { ri->gid = cpu_to_je16(dir_i->i_gid); if (S_ISDIR(mode)) mode |= S_ISGID; } else { - ri->gid = cpu_to_je16(current_fsgid()); + ri->gid = cpu_to_je16(current->fsgid); } /* POSIX ACLs have to be processed now, at least partly. diff --git a/trunk/include/linux/ioport.h b/trunk/include/linux/ioport.h index 8d3b7a9afd17..22d2115458c6 100644 --- a/trunk/include/linux/ioport.h +++ b/trunk/include/linux/ioport.h @@ -109,7 +109,6 @@ extern struct resource iomem_resource; extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new); -extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); extern int allocate_resource(struct resource *root, struct resource *new, resource_size_t size, resource_size_t min, resource_size_t max, resource_size_t align, diff --git a/trunk/include/linux/mtd/cfi.h b/trunk/include/linux/mtd/cfi.h index ee5124ec319e..d6fb115f5a07 100644 --- a/trunk/include/linux/mtd/cfi.h +++ b/trunk/include/linux/mtd/cfi.h @@ -12,7 +12,6 @@ #include #include #include -#include #ifdef CONFIG_MTD_CFI_I1 #define cfi_interleave(cfi) 1 @@ -431,6 +430,7 @@ static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t { map_word val; uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); + val = cfi_build_cmd(cmd, map, cfi); if (prev_val) @@ -483,13 +483,6 @@ static inline void cfi_udelay(int us) } } -int __xipram cfi_qry_present(struct map_info *map, __u32 base, - struct cfi_private *cfi); -int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, - struct cfi_private *cfi); -void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, - struct cfi_private *cfi); - struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, const char* name); struct cfi_fixup { diff --git a/trunk/include/linux/mtd/flashchip.h b/trunk/include/linux/mtd/flashchip.h index d4f38c5fd44e..08dd131301c1 100644 --- a/trunk/include/linux/mtd/flashchip.h +++ b/trunk/include/linux/mtd/flashchip.h @@ -73,10 +73,6 @@ struct flchip { int buffer_write_time; int erase_time; - int word_write_time_max; - int buffer_write_time_max; - int erase_time_max; - void *priv; }; diff --git a/trunk/include/linux/mtd/mtd.h b/trunk/include/linux/mtd/mtd.h index eae26bb6430a..922636548558 100644 --- a/trunk/include/linux/mtd/mtd.h +++ b/trunk/include/linux/mtd/mtd.h @@ -25,10 +25,8 @@ #define MTD_ERASE_DONE 0x08 #define MTD_ERASE_FAILED 0x10 -#define MTD_FAIL_ADDR_UNKNOWN 0xffffffff - /* If the erase fails, fail_addr might indicate exactly which block failed. If - fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level or was not + fail_addr = 0xffffffff, the failure was not at the device level or was not specific to any particular block. */ struct erase_info { struct mtd_info *mtd; diff --git a/trunk/include/linux/mtd/nand.h b/trunk/include/linux/mtd/nand.h index 733d3f3b4eb8..81774e5facf4 100644 --- a/trunk/include/linux/mtd/nand.h +++ b/trunk/include/linux/mtd/nand.h @@ -248,7 +248,6 @@ struct nand_hw_control { * @read_page_raw: function to read a raw page without ECC * @write_page_raw: function to write a raw page without ECC * @read_page: function to read a page according to the ecc generator requirements - * @read_subpage: function to read parts of the page covered by ECC. * @write_page: function to write a page according to the ecc generator requirements * @read_oob: function to read chip OOB data * @write_oob: function to write chip OOB data diff --git a/trunk/include/linux/mtd/onenand_regs.h b/trunk/include/linux/mtd/onenand_regs.h index 0c6bbe28f38c..d1b310c92eb4 100644 --- a/trunk/include/linux/mtd/onenand_regs.h +++ b/trunk/include/linux/mtd/onenand_regs.h @@ -152,8 +152,6 @@ #define ONENAND_SYS_CFG1_INT (1 << 6) #define ONENAND_SYS_CFG1_IOBE (1 << 5) #define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) -#define ONENAND_SYS_CFG1_HF (1 << 2) -#define ONENAND_SYS_CFG1_SYNC_WRITE (1 << 1) /* * Controller Status Register F240h (R) diff --git a/trunk/include/linux/mtd/partitions.h b/trunk/include/linux/mtd/partitions.h index c92b4d439609..5014f7a9f5df 100644 --- a/trunk/include/linux/mtd/partitions.h +++ b/trunk/include/linux/mtd/partitions.h @@ -73,6 +73,7 @@ struct device; struct device_node; int __devinit of_mtd_parse_partitions(struct device *dev, + struct mtd_info *mtd, struct device_node *node, struct mtd_partition **pparts); diff --git a/trunk/include/linux/mtd/sh_flctl.h b/trunk/include/linux/mtd/sh_flctl.h deleted file mode 100644 index e77c1cea404d..000000000000 --- a/trunk/include/linux/mtd/sh_flctl.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * SuperH FLCTL nand controller - * - * Copyright © 2008 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __SH_FLCTL_H__ -#define __SH_FLCTL_H__ - -#include -#include -#include - -/* FLCTL registers */ -#define FLCMNCR(f) (f->reg + 0x0) -#define FLCMDCR(f) (f->reg + 0x4) -#define FLCMCDR(f) (f->reg + 0x8) -#define FLADR(f) (f->reg + 0xC) -#define FLADR2(f) (f->reg + 0x3C) -#define FLDATAR(f) (f->reg + 0x10) -#define FLDTCNTR(f) (f->reg + 0x14) -#define FLINTDMACR(f) (f->reg + 0x18) -#define FLBSYTMR(f) (f->reg + 0x1C) -#define FLBSYCNT(f) (f->reg + 0x20) -#define FLDTFIFO(f) (f->reg + 0x24) -#define FLECFIFO(f) (f->reg + 0x28) -#define FLTRCR(f) (f->reg + 0x2C) -#define FL4ECCRESULT0(f) (f->reg + 0x80) -#define FL4ECCRESULT1(f) (f->reg + 0x84) -#define FL4ECCRESULT2(f) (f->reg + 0x88) -#define FL4ECCRESULT3(f) (f->reg + 0x8C) -#define FL4ECCCR(f) (f->reg + 0x90) -#define FL4ECCCNT(f) (f->reg + 0x94) -#define FLERRADR(f) (f->reg + 0x98) - -/* FLCMNCR control bits */ -#define ECCPOS2 (0x1 << 25) -#define _4ECCCNTEN (0x1 << 24) -#define _4ECCEN (0x1 << 23) -#define _4ECCCORRECT (0x1 << 22) -#define SNAND_E (0x1 << 18) /* SNAND (0=512 1=2048)*/ -#define QTSEL_E (0x1 << 17) -#define ENDIAN (0x1 << 16) /* 1 = little endian */ -#define FCKSEL_E (0x1 << 15) -#define ECCPOS_00 (0x00 << 12) -#define ECCPOS_01 (0x01 << 12) -#define ECCPOS_02 (0x02 << 12) -#define ACM_SACCES_MODE (0x01 << 10) -#define NANWF_E (0x1 << 9) -#define SE_D (0x1 << 8) /* Spare area disable */ -#define CE1_ENABLE (0x1 << 4) /* Chip Enable 1 */ -#define CE0_ENABLE (0x1 << 3) /* Chip Enable 0 */ -#define TYPESEL_SET (0x1 << 0) - -/* FLCMDCR control bits */ -#define ADRCNT2_E (0x1 << 31) /* 5byte address enable */ -#define ADRMD_E (0x1 << 26) /* Sector address access */ -#define CDSRC_E (0x1 << 25) /* Data buffer selection */ -#define DOSR_E (0x1 << 24) /* Status read check */ -#define SELRW (0x1 << 21) /* 0:read 1:write */ -#define DOADR_E (0x1 << 20) /* Address stage execute */ -#define ADRCNT_1 (0x00 << 18) /* Address data bytes: 1byte */ -#define ADRCNT_2 (0x01 << 18) /* Address data bytes: 2byte */ -#define ADRCNT_3 (0x02 << 18) /* Address data bytes: 3byte */ -#define ADRCNT_4 (0x03 << 18) /* Address data bytes: 4byte */ -#define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */ -#define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */ - -/* FLTRCR control bits */ -#define TRSTRT (0x1 << 0) /* translation start */ -#define TREND (0x1 << 1) /* translation end */ - -/* FL4ECCCR control bits */ -#define _4ECCFA (0x1 << 2) /* 4 symbols correct fault */ -#define _4ECCEND (0x1 << 1) /* 4 symbols end */ -#define _4ECCEXST (0x1 << 0) /* 4 symbols exist */ - -#define INIT_FL4ECCRESULT_VAL 0x03FF03FF -#define LOOP_TIMEOUT_MAX 0x00010000 - -#define mtd_to_flctl(mtd) container_of(mtd, struct sh_flctl, mtd) - -struct sh_flctl { - struct mtd_info mtd; - struct nand_chip chip; - void __iomem *reg; - - uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ - int read_bytes; - int index; - int seqin_column; /* column in SEQIN cmd */ - int seqin_page_addr; /* page_addr in SEQIN cmd */ - uint32_t seqin_read_cmd; /* read cmd in SEQIN cmd */ - int erase1_page_addr; /* page_addr in ERASE1 cmd */ - uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */ - uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */ - - int hwecc_cant_correct[4]; - - unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */ - unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */ -}; - -struct sh_flctl_platform_data { - struct mtd_partition *parts; - int nr_parts; - unsigned long flcmncr_val; - - unsigned has_hwecc:1; -}; - -#endif /* __SH_FLCTL_H__ */ diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 7a4cee00c1d6..c0e14008a3c2 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -631,8 +631,6 @@ int __must_check pci_assign_resource(struct pci_dev *dev, int i); int pci_select_bars(struct pci_dev *dev, unsigned long flags); /* ROM control related routines */ -int pci_enable_rom(struct pci_dev *pdev); -void pci_disable_rom(struct pci_dev *pdev); void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); size_t pci_get_rom_size(void __iomem *rom, size_t size); diff --git a/trunk/kernel/resource.c b/trunk/kernel/resource.c index cf0a178c7513..f5b518eabefe 100644 --- a/trunk/kernel/resource.c +++ b/trunk/kernel/resource.c @@ -362,21 +362,35 @@ int allocate_resource(struct resource *root, struct resource *new, EXPORT_SYMBOL(allocate_resource); -/* - * Insert a resource into the resource tree. If successful, return NULL, - * otherwise return the conflicting resource (compare to __request_resource()) +/** + * insert_resource - Inserts a resource in the resource tree + * @parent: parent of the new resource + * @new: new resource to insert + * + * Returns 0 on success, -EBUSY if the resource can't be inserted. + * + * This function is equivalent to request_resource when no conflict + * happens. If a conflict happens, and the conflicting resources + * entirely fit within the range of the new resource, then the new + * resource is inserted and the conflicting resources become children of + * the new resource. */ -static struct resource * __insert_resource(struct resource *parent, struct resource *new) +int insert_resource(struct resource *parent, struct resource *new) { + int result; struct resource *first, *next; + write_lock(&resource_lock); + for (;; parent = first) { + result = 0; first = __request_resource(parent, new); if (!first) - return first; + goto out; + result = -EBUSY; if (first == parent) - return first; + goto out; if ((first->start > new->start) || (first->end < new->end)) break; @@ -387,13 +401,15 @@ static struct resource * __insert_resource(struct resource *parent, struct resou for (next = first; ; next = next->sibling) { /* Partial overlap? Bad, and unfixable */ if (next->start < new->start || next->end > new->end) - return next; + goto out; if (!next->sibling) break; if (next->sibling->start > new->end) break; } + result = 0; + new->parent = parent; new->sibling = next->sibling; new->child = first; @@ -410,64 +426,10 @@ static struct resource * __insert_resource(struct resource *parent, struct resou next = next->sibling; next->sibling = new; } - return NULL; -} -/** - * insert_resource - Inserts a resource in the resource tree - * @parent: parent of the new resource - * @new: new resource to insert - * - * Returns 0 on success, -EBUSY if the resource can't be inserted. - * - * This function is equivalent to request_resource when no conflict - * happens. If a conflict happens, and the conflicting resources - * entirely fit within the range of the new resource, then the new - * resource is inserted and the conflicting resources become children of - * the new resource. - */ -int insert_resource(struct resource *parent, struct resource *new) -{ - struct resource *conflict; - - write_lock(&resource_lock); - conflict = __insert_resource(parent, new); - write_unlock(&resource_lock); - return conflict ? -EBUSY : 0; -} - -/** - * insert_resource_expand_to_fit - Insert a resource into the resource tree - * @parent: parent of the new resource - * @new: new resource to insert - * - * Insert a resource into the resource tree, possibly expanding it in order - * to make it encompass any conflicting resources. - */ -void insert_resource_expand_to_fit(struct resource *root, struct resource *new) -{ - if (new->parent) - return; - - write_lock(&resource_lock); - for (;;) { - struct resource *conflict; - - conflict = __insert_resource(root, new); - if (!conflict) - break; - if (conflict == root) - break; - - /* Ok, expand resource to cover the conflict, then try again .. */ - if (conflict->start < new->start) - new->start = conflict->start; - if (conflict->end > new->end) - new->end = conflict->end; - - printk("Expanded resource %s due to conflict with %s\n", new->name, conflict->name); - } + out: write_unlock(&resource_lock); + return result; } /** diff --git a/trunk/kernel/softlockup.c b/trunk/kernel/softlockup.c index 1a07f8ca4b92..b75b492fbfcf 100644 --- a/trunk/kernel/softlockup.c +++ b/trunk/kernel/softlockup.c @@ -180,10 +180,6 @@ static void check_hung_task(struct task_struct *t, unsigned long now) if (t->flags & PF_FROZEN) return; - /* Don't check for tasks waiting on network file systems like NFS */ - if (t->state & TASK_KILLABLE) - return; - if (switch_count != t->last_switch_count || !t->last_switch_timestamp) { t->last_switch_count = switch_count; t->last_switch_timestamp = now; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index d6ec9eef2910..909f1c101c95 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -6197,6 +6197,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), diff --git a/trunk/sound/pci/oxygen/hifier.c b/trunk/sound/pci/oxygen/hifier.c index dad393ae040a..7442460583dd 100644 --- a/trunk/sound/pci/oxygen/hifier.c +++ b/trunk/sound/pci/oxygen/hifier.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -108,9 +107,6 @@ static void set_ak4396_params(struct oxygen *chip, else value |= AK4396_DFS_QUAD; data->ak4396_ctl2 = value; - - msleep(1); /* wait for the new MCLK to become stable */ - ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); ak4396_write(chip, AK4396_CONTROL_2, value); ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index c5829d30ef86..7c8ae31eb468 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -28,7 +28,6 @@ * GPIO 1 -> DFS1 of AK5385 */ -#include #include #include #include @@ -214,9 +213,6 @@ static void set_ak4396_params(struct oxygen *chip, else value |= AK4396_DFS_QUAD; data->ak4396_ctl2 = value; - - msleep(1); /* wait for the new MCLK to become stable */ - for (i = 0; i < 4; ++i) { ak4396_write(chip, i, AK4396_CONTROL_1, AK4396_DIF_24_MSB);