diff options
Diffstat (limited to 'drivers/mtd')
127 files changed, 6042 insertions, 2527 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 027054dea032..f6b775e63ac8 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $ | 1 | # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ |
2 | 2 | ||
3 | menu "Memory Technology Devices (MTD)" | 3 | menu "Memory Technology Devices (MTD)" |
4 | 4 | ||
@@ -10,7 +10,7 @@ config MTD | |||
10 | will provide the generic support for MTD drivers to register | 10 | will provide the generic support for MTD drivers to register |
11 | themselves with the kernel and for potential users of MTD devices | 11 | themselves with the kernel and for potential users of MTD devices |
12 | to enumerate the devices which are present and obtain a handle on | 12 | to enumerate the devices which are present and obtain a handle on |
13 | them. It will also allow you to select individual drivers for | 13 | them. It will also allow you to select individual drivers for |
14 | particular hardware and users of MTD devices. If unsure, say N. | 14 | particular hardware and users of MTD devices. If unsure, say N. |
15 | 15 | ||
16 | config MTD_DEBUG | 16 | config MTD_DEBUG |
@@ -61,11 +61,11 @@ config MTD_REDBOOT_PARTS | |||
61 | 61 | ||
62 | If you need code which can detect and parse this table, and register | 62 | If you need code which can detect and parse this table, and register |
63 | MTD 'partitions' corresponding to each image in the table, enable | 63 | MTD 'partitions' corresponding to each image in the table, enable |
64 | this option. | 64 | this option. |
65 | 65 | ||
66 | You will still need the parsing functions to be called by the driver | 66 | You will still need the parsing functions to be called by the driver |
67 | for your particular device. It won't happen automatically. The | 67 | for your particular device. It won't happen automatically. The |
68 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for | 68 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for |
69 | example. | 69 | example. |
70 | 70 | ||
71 | config MTD_REDBOOT_DIRECTORY_BLOCK | 71 | config MTD_REDBOOT_DIRECTORY_BLOCK |
@@ -81,10 +81,10 @@ config MTD_REDBOOT_DIRECTORY_BLOCK | |||
81 | partition table. A zero or positive value gives an absolete | 81 | partition table. A zero or positive value gives an absolete |
82 | erase block number. A negative value specifies a number of | 82 | erase block number. A negative value specifies a number of |
83 | sectors before the end of the device. | 83 | sectors before the end of the device. |
84 | 84 | ||
85 | For example "2" means block number 2, "-1" means the last | 85 | For example "2" means block number 2, "-1" means the last |
86 | block and "-2" means the penultimate block. | 86 | block and "-2" means the penultimate block. |
87 | 87 | ||
88 | config MTD_REDBOOT_PARTS_UNALLOCATED | 88 | config MTD_REDBOOT_PARTS_UNALLOCATED |
89 | bool " Include unallocated flash regions" | 89 | bool " Include unallocated flash regions" |
90 | depends on MTD_REDBOOT_PARTS | 90 | depends on MTD_REDBOOT_PARTS |
@@ -105,11 +105,11 @@ config MTD_CMDLINE_PARTS | |||
105 | ---help--- | 105 | ---help--- |
106 | Allow generic configuration of the MTD paritition tables via the kernel | 106 | Allow generic configuration of the MTD paritition tables via the kernel |
107 | command line. Multiple flash resources are supported for hardware where | 107 | command line. Multiple flash resources are supported for hardware where |
108 | different kinds of flash memory are available. | 108 | different kinds of flash memory are available. |
109 | 109 | ||
110 | You will still need the parsing functions to be called by the driver | 110 | You will still need the parsing functions to be called by the driver |
111 | for your particular device. It won't happen automatically. The | 111 | for your particular device. It won't happen automatically. The |
112 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for | 112 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for |
113 | example. | 113 | example. |
114 | 114 | ||
115 | The format for the command line is as follows: | 115 | The format for the command line is as follows: |
@@ -118,12 +118,12 @@ config MTD_CMDLINE_PARTS | |||
118 | <mtddef> := <mtd-id>:<partdef>[,<partdef>] | 118 | <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
119 | <partdef> := <size>[@offset][<name>][ro] | 119 | <partdef> := <size>[@offset][<name>][ro] |
120 | <mtd-id> := unique id used in mapping driver/device | 120 | <mtd-id> := unique id used in mapping driver/device |
121 | <size> := standard linux memsize OR "-" to denote all | 121 | <size> := standard linux memsize OR "-" to denote all |
122 | remaining space | 122 | remaining space |
123 | <name> := (NAME) | 123 | <name> := (NAME) |
124 | 124 | ||
125 | Due to the way Linux handles the command line, no spaces are | 125 | Due to the way Linux handles the command line, no spaces are |
126 | allowed in the partition definition, including mtd id's and partition | 126 | allowed in the partition definition, including mtd id's and partition |
127 | names. | 127 | names. |
128 | 128 | ||
129 | Examples: | 129 | Examples: |
@@ -240,7 +240,7 @@ config INFTL | |||
240 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" | 240 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" |
241 | depends on MTD | 241 | depends on MTD |
242 | ---help--- | 242 | ---help--- |
243 | This provides support for the Inverse NAND Flash Translation | 243 | This provides support for the Inverse NAND Flash Translation |
244 | Layer which is used on M-Systems' newer DiskOnChip devices. It | 244 | Layer which is used on M-Systems' newer DiskOnChip devices. It |
245 | uses a kind of pseudo-file system on a flash device to emulate | 245 | uses a kind of pseudo-file system on a flash device to emulate |
246 | a block device with 512-byte sectors, on top of which you put | 246 | a block device with 512-byte sectors, on top of which you put |
@@ -253,6 +253,16 @@ config INFTL | |||
253 | permitted to copy, modify and distribute the code as you wish. Just | 253 | permitted to copy, modify and distribute the code as you wish. Just |
254 | not use it. | 254 | not use it. |
255 | 255 | ||
256 | config RFD_FTL | ||
257 | tristate "Resident Flash Disk (Flash Translation Layer) support" | ||
258 | depends on MTD | ||
259 | ---help--- | ||
260 | This provides support for the flash translation layer known | ||
261 | as the Resident Flash Disk (RFD), as used by the Embedded BIOS | ||
262 | of General Software. There is a blurb at: | ||
263 | |||
264 | http://www.gensw.com/pages/prod/bios/rfd.htm | ||
265 | |||
256 | source "drivers/mtd/chips/Kconfig" | 266 | source "drivers/mtd/chips/Kconfig" |
257 | 267 | ||
258 | source "drivers/mtd/maps/Kconfig" | 268 | source "drivers/mtd/maps/Kconfig" |
@@ -261,5 +271,7 @@ source "drivers/mtd/devices/Kconfig" | |||
261 | 271 | ||
262 | source "drivers/mtd/nand/Kconfig" | 272 | source "drivers/mtd/nand/Kconfig" |
263 | 273 | ||
274 | source "drivers/mtd/onenand/Kconfig" | ||
275 | |||
264 | endmenu | 276 | endmenu |
265 | 277 | ||
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index e4ad588327f7..fc9374407c2b 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the memory technology device drivers. | 2 | # Makefile for the memory technology device drivers. |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.5 2004/08/10 20:51:49 dwmw2 Exp $ | 4 | # $Id: Makefile.common,v 1.7 2005/07/11 10:39:27 gleixner Exp $ |
5 | 5 | ||
6 | # Core functionality. | 6 | # Core functionality. |
7 | mtd-y := mtdcore.o | 7 | mtd-y := mtdcore.o |
@@ -20,8 +20,9 @@ obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o | |||
20 | obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o | 20 | obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o |
21 | obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o | 21 | obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o |
22 | obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o | 22 | obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o |
23 | obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o | ||
23 | 24 | ||
24 | nftl-objs := nftlcore.o nftlmount.o | 25 | nftl-objs := nftlcore.o nftlmount.o |
25 | inftl-objs := inftlcore.o inftlmount.o | 26 | inftl-objs := inftlcore.o inftlmount.o |
26 | 27 | ||
27 | obj-y += chips/ maps/ devices/ nand/ | 28 | obj-y += chips/ maps/ devices/ nand/ onenand/ |
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 7363e101eb0f..6a45be04564b 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c | |||
@@ -1,27 +1,27 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | drivers/mtd/afs.c: ARM Flash Layout/Partitioning | 3 | drivers/mtd/afs.c: ARM Flash Layout/Partitioning |
4 | 4 | ||
5 | Copyright (C) 2000 ARM Limited | 5 | Copyright (C) 2000 ARM Limited |
6 | 6 | ||
7 | This program is free software; you can redistribute it and/or modify | 7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | 8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or | 9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | 10 | (at your option) any later version. |
11 | 11 | ||
12 | This program is distributed in the hope that it will be useful, | 12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. |
16 | 16 | ||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License |
18 | along with this program; if not, write to the Free Software | 18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | 20 | ||
21 | This is access code for flashes using ARM's flash partitioning | 21 | This is access code for flashes using ARM's flash partitioning |
22 | standards. | 22 | standards. |
23 | 23 | ||
24 | $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $ | 24 | $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $ |
25 | 25 | ||
26 | ======================================================================*/ | 26 | ======================================================================*/ |
27 | 27 | ||
@@ -163,7 +163,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) | |||
163 | return ret; | 163 | return ret; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int parse_afs_partitions(struct mtd_info *mtd, | 166 | static int parse_afs_partitions(struct mtd_info *mtd, |
167 | struct mtd_partition **pparts, | 167 | struct mtd_partition **pparts, |
168 | unsigned long origin) | 168 | unsigned long origin) |
169 | { | 169 | { |
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index df95d2158b16..eafa23f5cbd6 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/chips/Kconfig | 1 | # drivers/mtd/chips/Kconfig |
2 | # $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $ | 2 | # $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $ |
3 | 3 | ||
4 | menu "RAM/ROM/Flash chip drivers" | 4 | menu "RAM/ROM/Flash chip drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -39,7 +39,7 @@ config MTD_CFI_ADV_OPTIONS | |||
39 | If you need to specify a specific endianness for access to flash | 39 | If you need to specify a specific endianness for access to flash |
40 | chips, or if you wish to reduce the size of the kernel by including | 40 | chips, or if you wish to reduce the size of the kernel by including |
41 | support for only specific arrangements of flash chips, say 'Y'. This | 41 | support for only specific arrangements of flash chips, say 'Y'. This |
42 | option does not directly affect the code, but will enable other | 42 | option does not directly affect the code, but will enable other |
43 | configuration options which allow you to do so. | 43 | configuration options which allow you to do so. |
44 | 44 | ||
45 | If unsure, say 'N'. | 45 | If unsure, say 'N'. |
@@ -56,7 +56,7 @@ config MTD_CFI_NOSWAP | |||
56 | data bits when writing the 'magic' commands to the chips. Saying | 56 | data bits when writing the 'magic' commands to the chips. Saying |
57 | 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't | 57 | 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't |
58 | enabled, means that the CPU will not do any swapping; the chips | 58 | enabled, means that the CPU will not do any swapping; the chips |
59 | are expected to be wired to the CPU in 'host-endian' form. | 59 | are expected to be wired to the CPU in 'host-endian' form. |
60 | Specific arrangements are possible with the BIG_ENDIAN_BYTE and | 60 | Specific arrangements are possible with the BIG_ENDIAN_BYTE and |
61 | LITTLE_ENDIAN_BYTE, if the bytes are reversed. | 61 | LITTLE_ENDIAN_BYTE, if the bytes are reversed. |
62 | 62 | ||
@@ -79,10 +79,10 @@ config MTD_CFI_GEOMETRY | |||
79 | bool "Specific CFI Flash geometry selection" | 79 | bool "Specific CFI Flash geometry selection" |
80 | depends on MTD_CFI_ADV_OPTIONS | 80 | depends on MTD_CFI_ADV_OPTIONS |
81 | help | 81 | help |
82 | This option does not affect the code directly, but will enable | 82 | This option does not affect the code directly, but will enable |
83 | some other configuration options which would allow you to reduce | 83 | some other configuration options which would allow you to reduce |
84 | the size of the kernel by including support for only certain | 84 | the size of the kernel by including support for only certain |
85 | arrangements of CFI chips. If unsure, say 'N' and all options | 85 | arrangements of CFI chips. If unsure, say 'N' and all options |
86 | which are supported by the current code will be enabled. | 86 | which are supported by the current code will be enabled. |
87 | 87 | ||
88 | config MTD_MAP_BANK_WIDTH_1 | 88 | config MTD_MAP_BANK_WIDTH_1 |
@@ -197,7 +197,7 @@ config MTD_CFI_AMDSTD | |||
197 | help | 197 | help |
198 | The Common Flash Interface defines a number of different command | 198 | The Common Flash Interface defines a number of different command |
199 | sets which a CFI-compliant chip may claim to implement. This code | 199 | sets which a CFI-compliant chip may claim to implement. This code |
200 | provides support for one of those command sets, used on chips | 200 | provides support for one of those command sets, used on chips |
201 | including the AMD Am29LV320. | 201 | including the AMD Am29LV320. |
202 | 202 | ||
203 | config MTD_CFI_AMDSTD_RETRY | 203 | config MTD_CFI_AMDSTD_RETRY |
@@ -237,14 +237,14 @@ config MTD_RAM | |||
237 | tristate "Support for RAM chips in bus mapping" | 237 | tristate "Support for RAM chips in bus mapping" |
238 | depends on MTD | 238 | depends on MTD |
239 | help | 239 | help |
240 | This option enables basic support for RAM chips accessed through | 240 | This option enables basic support for RAM chips accessed through |
241 | a bus mapping driver. | 241 | a bus mapping driver. |
242 | 242 | ||
243 | config MTD_ROM | 243 | config MTD_ROM |
244 | tristate "Support for ROM chips in bus mapping" | 244 | tristate "Support for ROM chips in bus mapping" |
245 | depends on MTD | 245 | depends on MTD |
246 | help | 246 | help |
247 | This option enables basic support for ROM chips accessed through | 247 | This option enables basic support for ROM chips accessed through |
248 | a bus mapping driver. | 248 | a bus mapping driver. |
249 | 249 | ||
250 | config MTD_ABSENT | 250 | config MTD_ABSENT |
@@ -275,7 +275,7 @@ config MTD_AMDSTD | |||
275 | depends on MTD && MTD_OBSOLETE_CHIPS | 275 | depends on MTD && MTD_OBSOLETE_CHIPS |
276 | help | 276 | help |
277 | This option enables support for flash chips using AMD-compatible | 277 | This option enables support for flash chips using AMD-compatible |
278 | commands, including some which are not CFI-compatible and hence | 278 | commands, including some which are not CFI-compatible and hence |
279 | cannot be used with the CONFIG_MTD_CFI_AMDSTD option. | 279 | cannot be used with the CONFIG_MTD_CFI_AMDSTD option. |
280 | 280 | ||
281 | It also works on AMD compatible chips that do conform to CFI. | 281 | It also works on AMD compatible chips that do conform to CFI. |
@@ -285,7 +285,7 @@ config MTD_SHARP | |||
285 | depends on MTD && MTD_OBSOLETE_CHIPS | 285 | depends on MTD && MTD_OBSOLETE_CHIPS |
286 | help | 286 | help |
287 | This option enables support for flash chips using Sharp-compatible | 287 | This option enables support for flash chips using Sharp-compatible |
288 | commands, including some which are not CFI-compatible and hence | 288 | commands, including some which are not CFI-compatible and hence |
289 | cannot be used with the CONFIG_MTD_CFI_INTELxxx options. | 289 | cannot be used with the CONFIG_MTD_CFI_INTELxxx options. |
290 | 290 | ||
291 | config MTD_JEDEC | 291 | config MTD_JEDEC |
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile index 6830489828c6..8afe3092c4e3 100644 --- a/drivers/mtd/chips/Makefile +++ b/drivers/mtd/chips/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # linux/drivers/chips/Makefile | 2 | # linux/drivers/chips/Makefile |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $ | 4 | # $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $ |
5 | 5 | ||
6 | # *** BIG UGLY NOTE *** | 6 | # *** BIG UGLY NOTE *** |
7 | # | 7 | # |
@@ -11,7 +11,7 @@ | |||
11 | # the CFI command set drivers are linked before gen_probe.o | 11 | # the CFI command set drivers are linked before gen_probe.o |
12 | 12 | ||
13 | obj-$(CONFIG_MTD) += chipreg.o | 13 | obj-$(CONFIG_MTD) += chipreg.o |
14 | obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o | 14 | obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o |
15 | obj-$(CONFIG_MTD_CFI) += cfi_probe.o | 15 | obj-$(CONFIG_MTD_CFI) += cfi_probe.o |
16 | obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o | 16 | obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o |
17 | obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o | 17 | obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o |
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 2dafeba3f3d5..fdb91b6f1d97 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Jonas Holmberg <jonas.holmberg@axis.com> | 4 | * Author: Jonas Holmberg <jonas.holmberg@axis.com> |
5 | * | 5 | * |
6 | * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $ | 6 | * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $ |
7 | * | 7 | * |
8 | * Copyright (c) 2001 Axis Communications AB | 8 | * Copyright (c) 2001 Axis Communications AB |
9 | * | 9 | * |
@@ -93,9 +93,9 @@ | |||
93 | #define D6_MASK 0x40 | 93 | #define D6_MASK 0x40 |
94 | 94 | ||
95 | struct amd_flash_private { | 95 | struct amd_flash_private { |
96 | int device_type; | 96 | int device_type; |
97 | int interleave; | 97 | int interleave; |
98 | int numchips; | 98 | int numchips; |
99 | unsigned long chipshift; | 99 | unsigned long chipshift; |
100 | // const char *im_name; | 100 | // const char *im_name; |
101 | struct flchip chips[0]; | 101 | struct flchip chips[0]; |
@@ -253,7 +253,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
253 | int i; | 253 | int i; |
254 | int retval = 0; | 254 | int retval = 0; |
255 | int lock_status; | 255 | int lock_status; |
256 | 256 | ||
257 | map = mtd->priv; | 257 | map = mtd->priv; |
258 | 258 | ||
259 | /* Pass the whole chip through sector by sector and check for each | 259 | /* Pass the whole chip through sector by sector and check for each |
@@ -273,7 +273,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
273 | unlock_sector(map, eraseoffset, is_unlock); | 273 | unlock_sector(map, eraseoffset, is_unlock); |
274 | 274 | ||
275 | lock_status = is_sector_locked(map, eraseoffset); | 275 | lock_status = is_sector_locked(map, eraseoffset); |
276 | 276 | ||
277 | if (is_unlock && lock_status) { | 277 | if (is_unlock && lock_status) { |
278 | printk("Cannot unlock sector at address %x length %xx\n", | 278 | printk("Cannot unlock sector at address %x length %xx\n", |
279 | eraseoffset, merip->erasesize); | 279 | eraseoffset, merip->erasesize); |
@@ -305,7 +305,7 @@ static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
305 | /* | 305 | /* |
306 | * Reads JEDEC manufacturer ID and device ID and returns the index of the first | 306 | * Reads JEDEC manufacturer ID and device ID and returns the index of the first |
307 | * matching table entry (-1 if not found or alias for already found chip). | 307 | * matching table entry (-1 if not found or alias for already found chip). |
308 | */ | 308 | */ |
309 | static int probe_new_chip(struct mtd_info *mtd, __u32 base, | 309 | static int probe_new_chip(struct mtd_info *mtd, __u32 base, |
310 | struct flchip *chips, | 310 | struct flchip *chips, |
311 | struct amd_flash_private *private, | 311 | struct amd_flash_private *private, |
@@ -636,7 +636,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
636 | { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, | 636 | { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, |
637 | { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } | 637 | { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } |
638 | } | 638 | } |
639 | } | 639 | } |
640 | }; | 640 | }; |
641 | 641 | ||
642 | struct mtd_info *mtd; | 642 | struct mtd_info *mtd; |
@@ -701,7 +701,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
701 | 701 | ||
702 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * | 702 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * |
703 | mtd->numeraseregions, GFP_KERNEL); | 703 | mtd->numeraseregions, GFP_KERNEL); |
704 | if (!mtd->eraseregions) { | 704 | if (!mtd->eraseregions) { |
705 | printk(KERN_WARNING "%s: Failed to allocate " | 705 | printk(KERN_WARNING "%s: Failed to allocate " |
706 | "memory for MTD erase region info\n", map->name); | 706 | "memory for MTD erase region info\n", map->name); |
707 | kfree(mtd); | 707 | kfree(mtd); |
@@ -739,12 +739,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
739 | mtd->type = MTD_NORFLASH; | 739 | mtd->type = MTD_NORFLASH; |
740 | mtd->flags = MTD_CAP_NORFLASH; | 740 | mtd->flags = MTD_CAP_NORFLASH; |
741 | mtd->name = map->name; | 741 | mtd->name = map->name; |
742 | mtd->erase = amd_flash_erase; | 742 | mtd->erase = amd_flash_erase; |
743 | mtd->read = amd_flash_read; | 743 | mtd->read = amd_flash_read; |
744 | mtd->write = amd_flash_write; | 744 | mtd->write = amd_flash_write; |
745 | mtd->sync = amd_flash_sync; | 745 | mtd->sync = amd_flash_sync; |
746 | mtd->suspend = amd_flash_suspend; | 746 | mtd->suspend = amd_flash_suspend; |
747 | mtd->resume = amd_flash_resume; | 747 | mtd->resume = amd_flash_resume; |
748 | mtd->lock = amd_flash_lock; | 748 | mtd->lock = amd_flash_lock; |
749 | mtd->unlock = amd_flash_unlock; | 749 | mtd->unlock = amd_flash_unlock; |
750 | 750 | ||
@@ -789,7 +789,7 @@ retry: | |||
789 | map->name, chip->state); | 789 | map->name, chip->state); |
790 | set_current_state(TASK_UNINTERRUPTIBLE); | 790 | set_current_state(TASK_UNINTERRUPTIBLE); |
791 | add_wait_queue(&chip->wq, &wait); | 791 | add_wait_queue(&chip->wq, &wait); |
792 | 792 | ||
793 | spin_unlock_bh(chip->mutex); | 793 | spin_unlock_bh(chip->mutex); |
794 | 794 | ||
795 | schedule(); | 795 | schedule(); |
@@ -802,7 +802,7 @@ retry: | |||
802 | timeo = jiffies + HZ; | 802 | timeo = jiffies + HZ; |
803 | 803 | ||
804 | goto retry; | 804 | goto retry; |
805 | } | 805 | } |
806 | 806 | ||
807 | adr += chip->start; | 807 | adr += chip->start; |
808 | 808 | ||
@@ -889,7 +889,7 @@ retry: | |||
889 | map->name, chip->state); | 889 | map->name, chip->state); |
890 | set_current_state(TASK_UNINTERRUPTIBLE); | 890 | set_current_state(TASK_UNINTERRUPTIBLE); |
891 | add_wait_queue(&chip->wq, &wait); | 891 | add_wait_queue(&chip->wq, &wait); |
892 | 892 | ||
893 | spin_unlock_bh(chip->mutex); | 893 | spin_unlock_bh(chip->mutex); |
894 | 894 | ||
895 | schedule(); | 895 | schedule(); |
@@ -901,7 +901,7 @@ retry: | |||
901 | timeo = jiffies + HZ; | 901 | timeo = jiffies + HZ; |
902 | 902 | ||
903 | goto retry; | 903 | goto retry; |
904 | } | 904 | } |
905 | 905 | ||
906 | chip->state = FL_WRITING; | 906 | chip->state = FL_WRITING; |
907 | 907 | ||
@@ -911,7 +911,7 @@ retry: | |||
911 | wide_write(map, datum, adr); | 911 | wide_write(map, datum, adr); |
912 | 912 | ||
913 | times_left = 500000; | 913 | times_left = 500000; |
914 | while (times_left-- && flash_is_busy(map, adr, private->interleave)) { | 914 | while (times_left-- && flash_is_busy(map, adr, private->interleave)) { |
915 | if (need_resched()) { | 915 | if (need_resched()) { |
916 | spin_unlock_bh(chip->mutex); | 916 | spin_unlock_bh(chip->mutex); |
917 | schedule(); | 917 | schedule(); |
@@ -989,7 +989,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
989 | if (ret) { | 989 | if (ret) { |
990 | return ret; | 990 | return ret; |
991 | } | 991 | } |
992 | 992 | ||
993 | ofs += n; | 993 | ofs += n; |
994 | buf += n; | 994 | buf += n; |
995 | (*retlen) += n; | 995 | (*retlen) += n; |
@@ -1002,7 +1002,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
1002 | } | 1002 | } |
1003 | } | 1003 | } |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | /* We are now aligned, write as much as possible. */ | 1006 | /* We are now aligned, write as much as possible. */ |
1007 | while(len >= map->buswidth) { | 1007 | while(len >= map->buswidth) { |
1008 | __u32 datum; | 1008 | __u32 datum; |
@@ -1063,7 +1063,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
1063 | if (ret) { | 1063 | if (ret) { |
1064 | return ret; | 1064 | return ret; |
1065 | } | 1065 | } |
1066 | 1066 | ||
1067 | (*retlen) += n; | 1067 | (*retlen) += n; |
1068 | } | 1068 | } |
1069 | 1069 | ||
@@ -1085,7 +1085,7 @@ retry: | |||
1085 | if (chip->state != FL_READY){ | 1085 | if (chip->state != FL_READY){ |
1086 | set_current_state(TASK_UNINTERRUPTIBLE); | 1086 | set_current_state(TASK_UNINTERRUPTIBLE); |
1087 | add_wait_queue(&chip->wq, &wait); | 1087 | add_wait_queue(&chip->wq, &wait); |
1088 | 1088 | ||
1089 | spin_unlock_bh(chip->mutex); | 1089 | spin_unlock_bh(chip->mutex); |
1090 | 1090 | ||
1091 | schedule(); | 1091 | schedule(); |
@@ -1098,7 +1098,7 @@ retry: | |||
1098 | timeo = jiffies + HZ; | 1098 | timeo = jiffies + HZ; |
1099 | 1099 | ||
1100 | goto retry; | 1100 | goto retry; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | chip->state = FL_ERASING; | 1103 | chip->state = FL_ERASING; |
1104 | 1104 | ||
@@ -1106,30 +1106,30 @@ retry: | |||
1106 | ENABLE_VPP(map); | 1106 | ENABLE_VPP(map); |
1107 | send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); | 1107 | send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); |
1108 | send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); | 1108 | send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); |
1109 | 1109 | ||
1110 | timeo = jiffies + (HZ * 20); | 1110 | timeo = jiffies + (HZ * 20); |
1111 | 1111 | ||
1112 | spin_unlock_bh(chip->mutex); | 1112 | spin_unlock_bh(chip->mutex); |
1113 | msleep(1000); | 1113 | msleep(1000); |
1114 | spin_lock_bh(chip->mutex); | 1114 | spin_lock_bh(chip->mutex); |
1115 | 1115 | ||
1116 | while (flash_is_busy(map, adr, private->interleave)) { | 1116 | while (flash_is_busy(map, adr, private->interleave)) { |
1117 | 1117 | ||
1118 | if (chip->state != FL_ERASING) { | 1118 | if (chip->state != FL_ERASING) { |
1119 | /* Someone's suspended the erase. Sleep */ | 1119 | /* Someone's suspended the erase. Sleep */ |
1120 | set_current_state(TASK_UNINTERRUPTIBLE); | 1120 | set_current_state(TASK_UNINTERRUPTIBLE); |
1121 | add_wait_queue(&chip->wq, &wait); | 1121 | add_wait_queue(&chip->wq, &wait); |
1122 | 1122 | ||
1123 | spin_unlock_bh(chip->mutex); | 1123 | spin_unlock_bh(chip->mutex); |
1124 | printk(KERN_INFO "%s: erase suspended. Sleeping\n", | 1124 | printk(KERN_INFO "%s: erase suspended. Sleeping\n", |
1125 | map->name); | 1125 | map->name); |
1126 | schedule(); | 1126 | schedule(); |
1127 | remove_wait_queue(&chip->wq, &wait); | 1127 | remove_wait_queue(&chip->wq, &wait); |
1128 | 1128 | ||
1129 | if (signal_pending(current)) { | 1129 | if (signal_pending(current)) { |
1130 | return -EINTR; | 1130 | return -EINTR; |
1131 | } | 1131 | } |
1132 | 1132 | ||
1133 | timeo = jiffies + (HZ*2); /* FIXME */ | 1133 | timeo = jiffies + (HZ*2); /* FIXME */ |
1134 | spin_lock_bh(chip->mutex); | 1134 | spin_lock_bh(chip->mutex); |
1135 | continue; | 1135 | continue; |
@@ -1145,7 +1145,7 @@ retry: | |||
1145 | 1145 | ||
1146 | return -EIO; | 1146 | return -EIO; |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | /* Latency issues. Drop the lock, wait a while and retry */ | 1149 | /* Latency issues. Drop the lock, wait a while and retry */ |
1150 | spin_unlock_bh(chip->mutex); | 1150 | spin_unlock_bh(chip->mutex); |
1151 | 1151 | ||
@@ -1153,7 +1153,7 @@ retry: | |||
1153 | schedule(); | 1153 | schedule(); |
1154 | else | 1154 | else |
1155 | udelay(1); | 1155 | udelay(1); |
1156 | 1156 | ||
1157 | spin_lock_bh(chip->mutex); | 1157 | spin_lock_bh(chip->mutex); |
1158 | } | 1158 | } |
1159 | 1159 | ||
@@ -1180,7 +1180,7 @@ retry: | |||
1180 | return -EIO; | 1180 | return -EIO; |
1181 | } | 1181 | } |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | DISABLE_VPP(map); | 1184 | DISABLE_VPP(map); |
1185 | chip->state = FL_READY; | 1185 | chip->state = FL_READY; |
1186 | wake_up(&chip->wq); | 1186 | wake_up(&chip->wq); |
@@ -1246,7 +1246,7 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1246 | * with the erase region at that address. | 1246 | * with the erase region at that address. |
1247 | */ | 1247 | */ |
1248 | 1248 | ||
1249 | while ((i < mtd->numeraseregions) && | 1249 | while ((i < mtd->numeraseregions) && |
1250 | ((instr->addr + instr->len) >= regions[i].offset)) { | 1250 | ((instr->addr + instr->len) >= regions[i].offset)) { |
1251 | i++; | 1251 | i++; |
1252 | } | 1252 | } |
@@ -1293,10 +1293,10 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1293 | } | 1293 | } |
1294 | } | 1294 | } |
1295 | } | 1295 | } |
1296 | 1296 | ||
1297 | instr->state = MTD_ERASE_DONE; | 1297 | instr->state = MTD_ERASE_DONE; |
1298 | mtd_erase_callback(instr); | 1298 | mtd_erase_callback(instr); |
1299 | 1299 | ||
1300 | return 0; | 1300 | return 0; |
1301 | } | 1301 | } |
1302 | 1302 | ||
@@ -1324,7 +1324,7 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1324 | case FL_JEDEC_QUERY: | 1324 | case FL_JEDEC_QUERY: |
1325 | chip->oldstate = chip->state; | 1325 | chip->oldstate = chip->state; |
1326 | chip->state = FL_SYNCING; | 1326 | chip->state = FL_SYNCING; |
1327 | /* No need to wake_up() on this state change - | 1327 | /* No need to wake_up() on this state change - |
1328 | * as the whole point is that nobody can do anything | 1328 | * as the whole point is that nobody can do anything |
1329 | * with the chip now anyway. | 1329 | * with the chip now anyway. |
1330 | */ | 1330 | */ |
@@ -1335,13 +1335,13 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1335 | default: | 1335 | default: |
1336 | /* Not an idle state */ | 1336 | /* Not an idle state */ |
1337 | add_wait_queue(&chip->wq, &wait); | 1337 | add_wait_queue(&chip->wq, &wait); |
1338 | 1338 | ||
1339 | spin_unlock_bh(chip->mutex); | 1339 | spin_unlock_bh(chip->mutex); |
1340 | 1340 | ||
1341 | schedule(); | 1341 | schedule(); |
1342 | 1342 | ||
1343 | remove_wait_queue(&chip->wq, &wait); | 1343 | remove_wait_queue(&chip->wq, &wait); |
1344 | 1344 | ||
1345 | goto retry; | 1345 | goto retry; |
1346 | } | 1346 | } |
1347 | } | 1347 | } |
@@ -1351,7 +1351,7 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1351 | chip = &private->chips[i]; | 1351 | chip = &private->chips[i]; |
1352 | 1352 | ||
1353 | spin_lock_bh(chip->mutex); | 1353 | spin_lock_bh(chip->mutex); |
1354 | 1354 | ||
1355 | if (chip->state == FL_SYNCING) { | 1355 | if (chip->state == FL_SYNCING) { |
1356 | chip->state = chip->oldstate; | 1356 | chip->state = chip->oldstate; |
1357 | wake_up(&chip->wq); | 1357 | wake_up(&chip->wq); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c3fc9b2f21fb..143f01a4c170 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -4,9 +4,9 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $ | 7 | * $Id: cfi_cmdset_0001.c,v 1.185 2005/11/07 11:14:22 gleixner Exp $ |
8 | * | ||
8 | * | 9 | * |
9 | * | ||
10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
11 | * - completely revamped method functions so they are aware and | 11 | * - completely revamped method functions so they are aware and |
12 | * independent of the flash geometry (buswidth, interleave, etc.) | 12 | * independent of the flash geometry (buswidth, interleave, etc.) |
@@ -51,6 +51,7 @@ | |||
51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
54 | static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); | ||
54 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); | 55 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); |
55 | static void cfi_intelext_sync (struct mtd_info *); | 56 | static void cfi_intelext_sync (struct mtd_info *); |
56 | static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); | 57 | static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); |
@@ -105,6 +106,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = { | |||
105 | static void cfi_tell_features(struct cfi_pri_intelext *extp) | 106 | static void cfi_tell_features(struct cfi_pri_intelext *extp) |
106 | { | 107 | { |
107 | int i; | 108 | int i; |
109 | printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion); | ||
108 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); | 110 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); |
109 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); | 111 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); |
110 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); | 112 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); |
@@ -116,36 +118,43 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
116 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); | 118 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); |
117 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); | 119 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); |
118 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); | 120 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); |
119 | for (i=10; i<32; i++) { | 121 | printk(" - Extended Flash Array: %s\n", extp->FeatureSupport&1024?"supported":"unsupported"); |
120 | if (extp->FeatureSupport & (1<<i)) | 122 | for (i=11; i<32; i++) { |
123 | if (extp->FeatureSupport & (1<<i)) | ||
121 | printk(" - Unknown Bit %X: supported\n", i); | 124 | printk(" - Unknown Bit %X: supported\n", i); |
122 | } | 125 | } |
123 | 126 | ||
124 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); | 127 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); |
125 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); | 128 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); |
126 | for (i=1; i<8; i++) { | 129 | for (i=1; i<8; i++) { |
127 | if (extp->SuspendCmdSupport & (1<<i)) | 130 | if (extp->SuspendCmdSupport & (1<<i)) |
128 | printk(" - Unknown Bit %X: supported\n", i); | 131 | printk(" - Unknown Bit %X: supported\n", i); |
129 | } | 132 | } |
130 | 133 | ||
131 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); | 134 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); |
132 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); | 135 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); |
133 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); | 136 | printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); |
134 | for (i=2; i<16; i++) { | 137 | for (i=2; i<3; i++) { |
135 | if (extp->BlkStatusRegMask & (1<<i)) | 138 | if (extp->BlkStatusRegMask & (1<<i)) |
136 | printk(" - Unknown Bit %X Active: yes\n",i); | 139 | printk(" - Unknown Bit %X Active: yes\n",i); |
137 | } | 140 | } |
138 | 141 | printk(" - EFA Lock Bit: %s\n", extp->BlkStatusRegMask&16?"yes":"no"); | |
139 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | 142 | printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no"); |
143 | for (i=6; i<16; i++) { | ||
144 | if (extp->BlkStatusRegMask & (1<<i)) | ||
145 | printk(" - Unknown Bit %X Active: yes\n",i); | ||
146 | } | ||
147 | |||
148 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | ||
140 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); | 149 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); |
141 | if (extp->VppOptimal) | 150 | if (extp->VppOptimal) |
142 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", | 151 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", |
143 | extp->VppOptimal >> 4, extp->VppOptimal & 0xf); | 152 | extp->VppOptimal >> 4, extp->VppOptimal & 0xf); |
144 | } | 153 | } |
145 | #endif | 154 | #endif |
146 | 155 | ||
147 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 156 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
148 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ | 157 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ |
149 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | 158 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) |
150 | { | 159 | { |
151 | struct map_info *map = mtd->priv; | 160 | struct map_info *map = mtd->priv; |
@@ -176,7 +185,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) | |||
176 | { | 185 | { |
177 | struct map_info *map = mtd->priv; | 186 | struct map_info *map = mtd->priv; |
178 | struct cfi_private *cfi = map->fldrv_priv; | 187 | struct cfi_private *cfi = map->fldrv_priv; |
179 | 188 | ||
180 | cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ | 189 | cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ |
181 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ | 190 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ |
182 | } | 191 | } |
@@ -185,7 +194,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) | |||
185 | { | 194 | { |
186 | struct map_info *map = mtd->priv; | 195 | struct map_info *map = mtd->priv; |
187 | struct cfi_private *cfi = map->fldrv_priv; | 196 | struct cfi_private *cfi = map->fldrv_priv; |
188 | 197 | ||
189 | /* Note this is done after the region info is endian swapped */ | 198 | /* Note this is done after the region info is endian swapped */ |
190 | cfi->cfiq->EraseRegionInfo[1] = | 199 | cfi->cfiq->EraseRegionInfo[1] = |
191 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; | 200 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; |
@@ -207,12 +216,13 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
207 | if (cfi->cfiq->BufWriteTimeoutTyp) { | 216 | if (cfi->cfiq->BufWriteTimeoutTyp) { |
208 | printk(KERN_INFO "Using buffer write method\n" ); | 217 | printk(KERN_INFO "Using buffer write method\n" ); |
209 | mtd->write = cfi_intelext_write_buffers; | 218 | mtd->write = cfi_intelext_write_buffers; |
219 | mtd->writev = cfi_intelext_writev; | ||
210 | } | 220 | } |
211 | } | 221 | } |
212 | 222 | ||
213 | static struct cfi_fixup cfi_fixup_table[] = { | 223 | static struct cfi_fixup cfi_fixup_table[] = { |
214 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 224 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
215 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, | 225 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, |
216 | #endif | 226 | #endif |
217 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND | 227 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND |
218 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, | 228 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, |
@@ -252,12 +262,21 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
252 | if (!extp) | 262 | if (!extp) |
253 | return NULL; | 263 | return NULL; |
254 | 264 | ||
265 | if (extp->MajorVersion != '1' || | ||
266 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | ||
267 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " | ||
268 | "version %c.%c.\n", extp->MajorVersion, | ||
269 | extp->MinorVersion); | ||
270 | kfree(extp); | ||
271 | return NULL; | ||
272 | } | ||
273 | |||
255 | /* Do some byteswapping if necessary */ | 274 | /* Do some byteswapping if necessary */ |
256 | extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); | 275 | extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); |
257 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); | 276 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); |
258 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); | 277 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); |
259 | 278 | ||
260 | if (extp->MajorVersion == '1' && extp->MinorVersion == '3') { | 279 | if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') { |
261 | unsigned int extra_size = 0; | 280 | unsigned int extra_size = 0; |
262 | int nb_parts, i; | 281 | int nb_parts, i; |
263 | 282 | ||
@@ -266,7 +285,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
266 | sizeof(struct cfi_intelext_otpinfo); | 285 | sizeof(struct cfi_intelext_otpinfo); |
267 | 286 | ||
268 | /* Burst Read info */ | 287 | /* Burst Read info */ |
269 | extra_size += 6; | 288 | extra_size += 2; |
289 | if (extp_size < sizeof(*extp) + extra_size) | ||
290 | goto need_more; | ||
291 | extra_size += extp->extra[extra_size-1]; | ||
270 | 292 | ||
271 | /* Number of hardware-partitions */ | 293 | /* Number of hardware-partitions */ |
272 | extra_size += 1; | 294 | extra_size += 1; |
@@ -274,6 +296,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
274 | goto need_more; | 296 | goto need_more; |
275 | nb_parts = extp->extra[extra_size - 1]; | 297 | nb_parts = extp->extra[extra_size - 1]; |
276 | 298 | ||
299 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
300 | if (extp->MinorVersion >= '4') | ||
301 | extra_size += 2; | ||
302 | |||
277 | for (i = 0; i < nb_parts; i++) { | 303 | for (i = 0; i < nb_parts; i++) { |
278 | struct cfi_intelext_regioninfo *rinfo; | 304 | struct cfi_intelext_regioninfo *rinfo; |
279 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; | 305 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; |
@@ -285,6 +311,9 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
285 | * sizeof(struct cfi_intelext_blockinfo); | 311 | * sizeof(struct cfi_intelext_blockinfo); |
286 | } | 312 | } |
287 | 313 | ||
314 | if (extp->MinorVersion >= '4') | ||
315 | extra_size += sizeof(struct cfi_intelext_programming_regioninfo); | ||
316 | |||
288 | if (extp_size < sizeof(*extp) + extra_size) { | 317 | if (extp_size < sizeof(*extp) + extra_size) { |
289 | need_more: | 318 | need_more: |
290 | extp_size = sizeof(*extp) + extra_size; | 319 | extp_size = sizeof(*extp) + extra_size; |
@@ -298,7 +327,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
298 | goto again; | 327 | goto again; |
299 | } | 328 | } |
300 | } | 329 | } |
301 | 330 | ||
302 | return extp; | 331 | return extp; |
303 | } | 332 | } |
304 | 333 | ||
@@ -339,7 +368,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
339 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | 368 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; |
340 | 369 | ||
341 | if (cfi->cfi_mode == CFI_MODE_CFI) { | 370 | if (cfi->cfi_mode == CFI_MODE_CFI) { |
342 | /* | 371 | /* |
343 | * It's a real CFI chip, not one for which the probe | 372 | * It's a real CFI chip, not one for which the probe |
344 | * routine faked a CFI structure. So we read the feature | 373 | * routine faked a CFI structure. So we read the feature |
345 | * table from it. | 374 | * table from it. |
@@ -354,14 +383,14 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
354 | } | 383 | } |
355 | 384 | ||
356 | /* Install our own private info structure */ | 385 | /* Install our own private info structure */ |
357 | cfi->cmdset_priv = extp; | 386 | cfi->cmdset_priv = extp; |
358 | 387 | ||
359 | cfi_fixup(mtd, cfi_fixup_table); | 388 | cfi_fixup(mtd, cfi_fixup_table); |
360 | 389 | ||
361 | #ifdef DEBUG_CFI_FEATURES | 390 | #ifdef DEBUG_CFI_FEATURES |
362 | /* Tell the user about it in lots of lovely detail */ | 391 | /* Tell the user about it in lots of lovely detail */ |
363 | cfi_tell_features(extp); | 392 | cfi_tell_features(extp); |
364 | #endif | 393 | #endif |
365 | 394 | ||
366 | if(extp->SuspendCmdSupport & 1) { | 395 | if(extp->SuspendCmdSupport & 1) { |
367 | printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); | 396 | printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); |
@@ -379,10 +408,10 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
379 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; | 408 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; |
380 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; | 409 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; |
381 | cfi->chips[i].ref_point_counter = 0; | 410 | cfi->chips[i].ref_point_counter = 0; |
382 | } | 411 | } |
383 | 412 | ||
384 | map->fldrv = &cfi_intelext_chipdrv; | 413 | map->fldrv = &cfi_intelext_chipdrv; |
385 | 414 | ||
386 | return cfi_intelext_setup(mtd); | 415 | return cfi_intelext_setup(mtd); |
387 | } | 416 | } |
388 | 417 | ||
@@ -399,13 +428,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
399 | mtd->size = devsize * cfi->numchips; | 428 | mtd->size = devsize * cfi->numchips; |
400 | 429 | ||
401 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 430 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
402 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 431 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
403 | * mtd->numeraseregions, GFP_KERNEL); | 432 | * mtd->numeraseregions, GFP_KERNEL); |
404 | if (!mtd->eraseregions) { | 433 | if (!mtd->eraseregions) { |
405 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); | 434 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); |
406 | goto setup_err; | 435 | goto setup_err; |
407 | } | 436 | } |
408 | 437 | ||
409 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 438 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
410 | unsigned long ernum, ersize; | 439 | unsigned long ernum, ersize; |
411 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 440 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
@@ -429,7 +458,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
429 | } | 458 | } |
430 | 459 | ||
431 | for (i=0; i<mtd->numeraseregions;i++){ | 460 | for (i=0; i<mtd->numeraseregions;i++){ |
432 | printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", | 461 | printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", |
433 | i,mtd->eraseregions[i].offset, | 462 | i,mtd->eraseregions[i].offset, |
434 | mtd->eraseregions[i].erasesize, | 463 | mtd->eraseregions[i].erasesize, |
435 | mtd->eraseregions[i].numblocks); | 464 | mtd->eraseregions[i].numblocks); |
@@ -480,7 +509,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
480 | * arrangement at this point. This can be rearranged in the future | 509 | * arrangement at this point. This can be rearranged in the future |
481 | * if someone feels motivated enough. --nico | 510 | * if someone feels motivated enough. --nico |
482 | */ | 511 | */ |
483 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3' | 512 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3' |
484 | && extp->FeatureSupport & (1 << 9)) { | 513 | && extp->FeatureSupport & (1 << 9)) { |
485 | struct cfi_private *newcfi; | 514 | struct cfi_private *newcfi; |
486 | struct flchip *chip; | 515 | struct flchip *chip; |
@@ -492,12 +521,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
492 | sizeof(struct cfi_intelext_otpinfo); | 521 | sizeof(struct cfi_intelext_otpinfo); |
493 | 522 | ||
494 | /* Burst Read info */ | 523 | /* Burst Read info */ |
495 | offs += 6; | 524 | offs += extp->extra[offs+1]+2; |
496 | 525 | ||
497 | /* Number of partition regions */ | 526 | /* Number of partition regions */ |
498 | numregions = extp->extra[offs]; | 527 | numregions = extp->extra[offs]; |
499 | offs += 1; | 528 | offs += 1; |
500 | 529 | ||
530 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
531 | if (extp->MinorVersion >= '4') | ||
532 | offs += 2; | ||
533 | |||
501 | /* Number of hardware partitions */ | 534 | /* Number of hardware partitions */ |
502 | numparts = 0; | 535 | numparts = 0; |
503 | for (i = 0; i < numregions; i++) { | 536 | for (i = 0; i < numregions; i++) { |
@@ -509,6 +542,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
509 | sizeof(struct cfi_intelext_blockinfo); | 542 | sizeof(struct cfi_intelext_blockinfo); |
510 | } | 543 | } |
511 | 544 | ||
545 | /* Programming Region info */ | ||
546 | if (extp->MinorVersion >= '4') { | ||
547 | struct cfi_intelext_programming_regioninfo *prinfo; | ||
548 | prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; | ||
549 | MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift; | ||
550 | MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; | ||
551 | MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; | ||
552 | mtd->flags |= MTD_PROGRAM_REGIONS; | ||
553 | printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", | ||
554 | map->name, MTD_PROGREGION_SIZE(mtd), | ||
555 | MTD_PROGREGION_CTRLMODE_VALID(mtd), | ||
556 | MTD_PROGREGION_CTRLMODE_INVALID(mtd)); | ||
557 | } | ||
558 | |||
512 | /* | 559 | /* |
513 | * All functions below currently rely on all chips having | 560 | * All functions below currently rely on all chips having |
514 | * the same geometry so we'll just assume that all hardware | 561 | * the same geometry so we'll just assume that all hardware |
@@ -653,8 +700,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
653 | break; | 700 | break; |
654 | 701 | ||
655 | if (time_after(jiffies, timeo)) { | 702 | if (time_after(jiffies, timeo)) { |
656 | printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", | 703 | printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n", |
657 | status.x[0]); | 704 | map->name, status.x[0]); |
658 | return -EIO; | 705 | return -EIO; |
659 | } | 706 | } |
660 | spin_unlock(chip->mutex); | 707 | spin_unlock(chip->mutex); |
@@ -663,7 +710,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
663 | /* Someone else might have been playing with it. */ | 710 | /* Someone else might have been playing with it. */ |
664 | goto retry; | 711 | goto retry; |
665 | } | 712 | } |
666 | 713 | ||
667 | case FL_READY: | 714 | case FL_READY: |
668 | case FL_CFI_QUERY: | 715 | case FL_CFI_QUERY: |
669 | case FL_JEDEC_QUERY: | 716 | case FL_JEDEC_QUERY: |
@@ -701,8 +748,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
701 | map_write(map, CMD(0x70), adr); | 748 | map_write(map, CMD(0x70), adr); |
702 | chip->state = FL_ERASING; | 749 | chip->state = FL_ERASING; |
703 | chip->oldstate = FL_READY; | 750 | chip->oldstate = FL_READY; |
704 | printk(KERN_ERR "Chip not ready after erase " | 751 | printk(KERN_ERR "%s: Chip not ready after erase " |
705 | "suspended: status = 0x%lx\n", status.x[0]); | 752 | "suspended: status = 0x%lx\n", map->name, status.x[0]); |
706 | return -EIO; | 753 | return -EIO; |
707 | } | 754 | } |
708 | 755 | ||
@@ -782,14 +829,14 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
782 | switch(chip->oldstate) { | 829 | switch(chip->oldstate) { |
783 | case FL_ERASING: | 830 | case FL_ERASING: |
784 | chip->state = chip->oldstate; | 831 | chip->state = chip->oldstate; |
785 | /* What if one interleaved chip has finished and the | 832 | /* What if one interleaved chip has finished and the |
786 | other hasn't? The old code would leave the finished | 833 | other hasn't? The old code would leave the finished |
787 | one in READY mode. That's bad, and caused -EROFS | 834 | one in READY mode. That's bad, and caused -EROFS |
788 | errors to be returned from do_erase_oneblock because | 835 | errors to be returned from do_erase_oneblock because |
789 | that's the only bit it checked for at the time. | 836 | that's the only bit it checked for at the time. |
790 | As the state machine appears to explicitly allow | 837 | As the state machine appears to explicitly allow |
791 | sending the 0x70 (Read Status) command to an erasing | 838 | sending the 0x70 (Read Status) command to an erasing |
792 | chip and expecting it to be ignored, that's what we | 839 | chip and expecting it to be ignored, that's what we |
793 | do. */ | 840 | do. */ |
794 | map_write(map, CMD(0xd0), adr); | 841 | map_write(map, CMD(0xd0), adr); |
795 | map_write(map, CMD(0x70), adr); | 842 | map_write(map, CMD(0x70), adr); |
@@ -809,7 +856,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
809 | DISABLE_VPP(map); | 856 | DISABLE_VPP(map); |
810 | break; | 857 | break; |
811 | default: | 858 | default: |
812 | printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); | 859 | printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate); |
813 | } | 860 | } |
814 | wake_up(&chip->wq); | 861 | wake_up(&chip->wq); |
815 | } | 862 | } |
@@ -1025,8 +1072,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a | |||
1025 | 1072 | ||
1026 | adr += chip->start; | 1073 | adr += chip->start; |
1027 | 1074 | ||
1028 | /* Ensure cmd read/writes are aligned. */ | 1075 | /* Ensure cmd read/writes are aligned. */ |
1029 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 1076 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
1030 | 1077 | ||
1031 | spin_lock(chip->mutex); | 1078 | spin_lock(chip->mutex); |
1032 | 1079 | ||
@@ -1054,7 +1101,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si | |||
1054 | 1101 | ||
1055 | if (!map->virt || (from + len > mtd->size)) | 1102 | if (!map->virt || (from + len > mtd->size)) |
1056 | return -EINVAL; | 1103 | return -EINVAL; |
1057 | 1104 | ||
1058 | *mtdbuf = (void *)map->virt + from; | 1105 | *mtdbuf = (void *)map->virt + from; |
1059 | *retlen = 0; | 1106 | *retlen = 0; |
1060 | 1107 | ||
@@ -1081,7 +1128,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si | |||
1081 | 1128 | ||
1082 | *retlen += thislen; | 1129 | *retlen += thislen; |
1083 | len -= thislen; | 1130 | len -= thislen; |
1084 | 1131 | ||
1085 | ofs = 0; | 1132 | ofs = 0; |
1086 | chipnum++; | 1133 | chipnum++; |
1087 | } | 1134 | } |
@@ -1120,7 +1167,7 @@ static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t fro | |||
1120 | if(chip->ref_point_counter == 0) | 1167 | if(chip->ref_point_counter == 0) |
1121 | chip->state = FL_READY; | 1168 | chip->state = FL_READY; |
1122 | } else | 1169 | } else |
1123 | printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ | 1170 | printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */ |
1124 | 1171 | ||
1125 | put_chip(map, chip, chip->start); | 1172 | put_chip(map, chip, chip->start); |
1126 | spin_unlock(chip->mutex); | 1173 | spin_unlock(chip->mutex); |
@@ -1139,8 +1186,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
1139 | 1186 | ||
1140 | adr += chip->start; | 1187 | adr += chip->start; |
1141 | 1188 | ||
1142 | /* Ensure cmd read/writes are aligned. */ | 1189 | /* Ensure cmd read/writes are aligned. */ |
1143 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 1190 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
1144 | 1191 | ||
1145 | spin_lock(chip->mutex); | 1192 | spin_lock(chip->mutex); |
1146 | ret = get_chip(map, chip, cmd_addr, FL_READY); | 1193 | ret = get_chip(map, chip, cmd_addr, FL_READY); |
@@ -1195,7 +1242,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz | |||
1195 | *retlen += thislen; | 1242 | *retlen += thislen; |
1196 | len -= thislen; | 1243 | len -= thislen; |
1197 | buf += thislen; | 1244 | buf += thislen; |
1198 | 1245 | ||
1199 | ofs = 0; | 1246 | ofs = 0; |
1200 | chipnum++; | 1247 | chipnum++; |
1201 | } | 1248 | } |
@@ -1212,12 +1259,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1212 | 1259 | ||
1213 | adr += chip->start; | 1260 | adr += chip->start; |
1214 | 1261 | ||
1215 | /* Let's determine this according to the interleave only once */ | 1262 | /* Let's determine those according to the interleave only once */ |
1216 | status_OK = CMD(0x80); | 1263 | status_OK = CMD(0x80); |
1217 | switch (mode) { | 1264 | switch (mode) { |
1218 | case FL_WRITING: write_cmd = CMD(0x40); break; | 1265 | case FL_WRITING: |
1219 | case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; | 1266 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); |
1220 | default: return -EINVAL; | 1267 | break; |
1268 | case FL_OTP_WRITE: | ||
1269 | write_cmd = CMD(0xc0); | ||
1270 | break; | ||
1271 | default: | ||
1272 | return -EINVAL; | ||
1221 | } | 1273 | } |
1222 | 1274 | ||
1223 | spin_lock(chip->mutex); | 1275 | spin_lock(chip->mutex); |
@@ -1258,12 +1310,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1258 | status = map_read(map, adr); | 1310 | status = map_read(map, adr); |
1259 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1311 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1260 | break; | 1312 | break; |
1261 | 1313 | ||
1262 | /* OK Still waiting */ | 1314 | /* OK Still waiting */ |
1263 | if (time_after(jiffies, timeo)) { | 1315 | if (time_after(jiffies, timeo)) { |
1316 | map_write(map, CMD(0x70), adr); | ||
1264 | chip->state = FL_STATUS; | 1317 | chip->state = FL_STATUS; |
1265 | xip_enable(map, chip, adr); | 1318 | xip_enable(map, chip, adr); |
1266 | printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); | 1319 | printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); |
1267 | ret = -EIO; | 1320 | ret = -EIO; |
1268 | goto out; | 1321 | goto out; |
1269 | } | 1322 | } |
@@ -1275,27 +1328,39 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1275 | if (!z) { | 1328 | if (!z) { |
1276 | chip->word_write_time--; | 1329 | chip->word_write_time--; |
1277 | if (!chip->word_write_time) | 1330 | if (!chip->word_write_time) |
1278 | chip->word_write_time++; | 1331 | chip->word_write_time = 1; |
1279 | } | 1332 | } |
1280 | if (z > 1) | 1333 | if (z > 1) |
1281 | chip->word_write_time++; | 1334 | chip->word_write_time++; |
1282 | 1335 | ||
1283 | /* Done and happy. */ | 1336 | /* Done and happy. */ |
1284 | chip->state = FL_STATUS; | 1337 | chip->state = FL_STATUS; |
1285 | 1338 | ||
1286 | /* check for lock bit */ | 1339 | /* check for errors */ |
1287 | if (map_word_bitsset(map, status, CMD(0x02))) { | 1340 | if (map_word_bitsset(map, status, CMD(0x1a))) { |
1288 | /* clear status */ | 1341 | unsigned long chipstatus = MERGESTATUS(status); |
1342 | |||
1343 | /* reset status */ | ||
1289 | map_write(map, CMD(0x50), adr); | 1344 | map_write(map, CMD(0x50), adr); |
1290 | /* put back into read status register mode */ | ||
1291 | map_write(map, CMD(0x70), adr); | 1345 | map_write(map, CMD(0x70), adr); |
1292 | ret = -EROFS; | 1346 | xip_enable(map, chip, adr); |
1347 | |||
1348 | if (chipstatus & 0x02) { | ||
1349 | ret = -EROFS; | ||
1350 | } else if (chipstatus & 0x08) { | ||
1351 | printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name); | ||
1352 | ret = -EIO; | ||
1353 | } else { | ||
1354 | printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus); | ||
1355 | ret = -EINVAL; | ||
1356 | } | ||
1357 | |||
1358 | goto out; | ||
1293 | } | 1359 | } |
1294 | 1360 | ||
1295 | xip_enable(map, chip, adr); | 1361 | xip_enable(map, chip, adr); |
1296 | out: put_chip(map, chip, adr); | 1362 | out: put_chip(map, chip, adr); |
1297 | spin_unlock(chip->mutex); | 1363 | spin_unlock(chip->mutex); |
1298 | |||
1299 | return ret; | 1364 | return ret; |
1300 | } | 1365 | } |
1301 | 1366 | ||
@@ -1328,7 +1393,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1328 | 1393 | ||
1329 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1394 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1330 | bus_ofs, datum, FL_WRITING); | 1395 | bus_ofs, datum, FL_WRITING); |
1331 | if (ret) | 1396 | if (ret) |
1332 | return ret; | 1397 | return ret; |
1333 | 1398 | ||
1334 | len -= n; | 1399 | len -= n; |
@@ -1337,13 +1402,13 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1337 | (*retlen) += n; | 1402 | (*retlen) += n; |
1338 | 1403 | ||
1339 | if (ofs >> cfi->chipshift) { | 1404 | if (ofs >> cfi->chipshift) { |
1340 | chipnum ++; | 1405 | chipnum ++; |
1341 | ofs = 0; | 1406 | ofs = 0; |
1342 | if (chipnum == cfi->numchips) | 1407 | if (chipnum == cfi->numchips) |
1343 | return 0; | 1408 | return 0; |
1344 | } | 1409 | } |
1345 | } | 1410 | } |
1346 | 1411 | ||
1347 | while(len >= map_bankwidth(map)) { | 1412 | while(len >= map_bankwidth(map)) { |
1348 | map_word datum = map_word_load(map, buf); | 1413 | map_word datum = map_word_load(map, buf); |
1349 | 1414 | ||
@@ -1358,7 +1423,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1358 | len -= map_bankwidth(map); | 1423 | len -= map_bankwidth(map); |
1359 | 1424 | ||
1360 | if (ofs >> cfi->chipshift) { | 1425 | if (ofs >> cfi->chipshift) { |
1361 | chipnum ++; | 1426 | chipnum ++; |
1362 | ofs = 0; | 1427 | ofs = 0; |
1363 | if (chipnum == cfi->numchips) | 1428 | if (chipnum == cfi->numchips) |
1364 | return 0; | 1429 | return 0; |
@@ -1373,9 +1438,9 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1373 | 1438 | ||
1374 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1439 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1375 | ofs, datum, FL_WRITING); | 1440 | ofs, datum, FL_WRITING); |
1376 | if (ret) | 1441 | if (ret) |
1377 | return ret; | 1442 | return ret; |
1378 | 1443 | ||
1379 | (*retlen) += len; | 1444 | (*retlen) += len; |
1380 | } | 1445 | } |
1381 | 1446 | ||
@@ -1383,20 +1448,24 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1383 | } | 1448 | } |
1384 | 1449 | ||
1385 | 1450 | ||
1386 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | 1451 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, |
1387 | unsigned long adr, const u_char *buf, int len) | 1452 | unsigned long adr, const struct kvec **pvec, |
1453 | unsigned long *pvec_seek, int len) | ||
1388 | { | 1454 | { |
1389 | struct cfi_private *cfi = map->fldrv_priv; | 1455 | struct cfi_private *cfi = map->fldrv_priv; |
1390 | map_word status, status_OK; | 1456 | map_word status, status_OK, write_cmd, datum; |
1391 | unsigned long cmd_adr, timeo; | 1457 | unsigned long cmd_adr, timeo; |
1392 | int wbufsize, z, ret=0, bytes, words; | 1458 | int wbufsize, z, ret=0, word_gap, words; |
1459 | const struct kvec *vec; | ||
1460 | unsigned long vec_seek; | ||
1393 | 1461 | ||
1394 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 1462 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
1395 | adr += chip->start; | 1463 | adr += chip->start; |
1396 | cmd_adr = adr & ~(wbufsize-1); | 1464 | cmd_adr = adr & ~(wbufsize-1); |
1397 | 1465 | ||
1398 | /* Let's determine this according to the interleave only once */ | 1466 | /* Let's determine this according to the interleave only once */ |
1399 | status_OK = CMD(0x80); | 1467 | status_OK = CMD(0x80); |
1468 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); | ||
1400 | 1469 | ||
1401 | spin_lock(chip->mutex); | 1470 | spin_lock(chip->mutex); |
1402 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); | 1471 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); |
@@ -1410,7 +1479,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1410 | xip_disable(map, chip, cmd_adr); | 1479 | xip_disable(map, chip, cmd_adr); |
1411 | 1480 | ||
1412 | /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set | 1481 | /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set |
1413 | [...], the device will not accept any more Write to Buffer commands". | 1482 | [...], the device will not accept any more Write to Buffer commands". |
1414 | So we must check here and reset those bits if they're set. Otherwise | 1483 | So we must check here and reset those bits if they're set. Otherwise |
1415 | we're just pissing in the wind */ | 1484 | we're just pissing in the wind */ |
1416 | if (chip->state != FL_STATUS) | 1485 | if (chip->state != FL_STATUS) |
@@ -1428,7 +1497,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1428 | 1497 | ||
1429 | z = 0; | 1498 | z = 0; |
1430 | for (;;) { | 1499 | for (;;) { |
1431 | map_write(map, CMD(0xe8), cmd_adr); | 1500 | map_write(map, write_cmd, cmd_adr); |
1432 | 1501 | ||
1433 | status = map_read(map, cmd_adr); | 1502 | status = map_read(map, cmd_adr); |
1434 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1503 | if (map_word_andequal(map, status, status_OK, status_OK)) |
@@ -1446,41 +1515,66 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1446 | map_write(map, CMD(0x50), cmd_adr); | 1515 | map_write(map, CMD(0x50), cmd_adr); |
1447 | map_write(map, CMD(0x70), cmd_adr); | 1516 | map_write(map, CMD(0x70), cmd_adr); |
1448 | xip_enable(map, chip, cmd_adr); | 1517 | xip_enable(map, chip, cmd_adr); |
1449 | printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", | 1518 | printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", |
1450 | status.x[0], Xstatus.x[0]); | 1519 | map->name, status.x[0], Xstatus.x[0]); |
1451 | ret = -EIO; | 1520 | ret = -EIO; |
1452 | goto out; | 1521 | goto out; |
1453 | } | 1522 | } |
1454 | } | 1523 | } |
1455 | 1524 | ||
1525 | /* Figure out the number of words to write */ | ||
1526 | word_gap = (-adr & (map_bankwidth(map)-1)); | ||
1527 | words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); | ||
1528 | if (!word_gap) { | ||
1529 | words--; | ||
1530 | } else { | ||
1531 | word_gap = map_bankwidth(map) - word_gap; | ||
1532 | adr -= word_gap; | ||
1533 | datum = map_word_ff(map); | ||
1534 | } | ||
1535 | |||
1456 | /* Write length of data to come */ | 1536 | /* Write length of data to come */ |
1457 | bytes = len & (map_bankwidth(map)-1); | 1537 | map_write(map, CMD(words), cmd_adr ); |
1458 | words = len / map_bankwidth(map); | ||
1459 | map_write(map, CMD(words - !bytes), cmd_adr ); | ||
1460 | 1538 | ||
1461 | /* Write data */ | 1539 | /* Write data */ |
1462 | z = 0; | 1540 | vec = *pvec; |
1463 | while(z < words * map_bankwidth(map)) { | 1541 | vec_seek = *pvec_seek; |
1464 | map_word datum = map_word_load(map, buf); | 1542 | do { |
1465 | map_write(map, datum, adr+z); | 1543 | int n = map_bankwidth(map) - word_gap; |
1544 | if (n > vec->iov_len - vec_seek) | ||
1545 | n = vec->iov_len - vec_seek; | ||
1546 | if (n > len) | ||
1547 | n = len; | ||
1466 | 1548 | ||
1467 | z += map_bankwidth(map); | 1549 | if (!word_gap && len < map_bankwidth(map)) |
1468 | buf += map_bankwidth(map); | 1550 | datum = map_word_ff(map); |
1469 | } | ||
1470 | 1551 | ||
1471 | if (bytes) { | 1552 | datum = map_word_load_partial(map, datum, |
1472 | map_word datum; | 1553 | vec->iov_base + vec_seek, |
1554 | word_gap, n); | ||
1473 | 1555 | ||
1474 | datum = map_word_ff(map); | 1556 | len -= n; |
1475 | datum = map_word_load_partial(map, datum, buf, 0, bytes); | 1557 | word_gap += n; |
1476 | map_write(map, datum, adr+z); | 1558 | if (!len || word_gap == map_bankwidth(map)) { |
1477 | } | 1559 | map_write(map, datum, adr); |
1560 | adr += map_bankwidth(map); | ||
1561 | word_gap = 0; | ||
1562 | } | ||
1563 | |||
1564 | vec_seek += n; | ||
1565 | if (vec_seek == vec->iov_len) { | ||
1566 | vec++; | ||
1567 | vec_seek = 0; | ||
1568 | } | ||
1569 | } while (len); | ||
1570 | *pvec = vec; | ||
1571 | *pvec_seek = vec_seek; | ||
1478 | 1572 | ||
1479 | /* GO GO GO */ | 1573 | /* GO GO GO */ |
1480 | map_write(map, CMD(0xd0), cmd_adr); | 1574 | map_write(map, CMD(0xd0), cmd_adr); |
1481 | chip->state = FL_WRITING; | 1575 | chip->state = FL_WRITING; |
1482 | 1576 | ||
1483 | INVALIDATE_CACHE_UDELAY(map, chip, | 1577 | INVALIDATE_CACHE_UDELAY(map, chip, |
1484 | cmd_adr, len, | 1578 | cmd_adr, len, |
1485 | chip->buffer_write_time); | 1579 | chip->buffer_write_time); |
1486 | 1580 | ||
@@ -1506,13 +1600,14 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1506 | 1600 | ||
1507 | /* OK Still waiting */ | 1601 | /* OK Still waiting */ |
1508 | if (time_after(jiffies, timeo)) { | 1602 | if (time_after(jiffies, timeo)) { |
1603 | map_write(map, CMD(0x70), cmd_adr); | ||
1509 | chip->state = FL_STATUS; | 1604 | chip->state = FL_STATUS; |
1510 | xip_enable(map, chip, cmd_adr); | 1605 | xip_enable(map, chip, cmd_adr); |
1511 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); | 1606 | printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); |
1512 | ret = -EIO; | 1607 | ret = -EIO; |
1513 | goto out; | 1608 | goto out; |
1514 | } | 1609 | } |
1515 | 1610 | ||
1516 | /* Latency issues. Drop the lock, wait a while and retry */ | 1611 | /* Latency issues. Drop the lock, wait a while and retry */ |
1517 | z++; | 1612 | z++; |
1518 | UDELAY(map, chip, cmd_adr, 1); | 1613 | UDELAY(map, chip, cmd_adr, 1); |
@@ -1520,21 +1615,34 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1520 | if (!z) { | 1615 | if (!z) { |
1521 | chip->buffer_write_time--; | 1616 | chip->buffer_write_time--; |
1522 | if (!chip->buffer_write_time) | 1617 | if (!chip->buffer_write_time) |
1523 | chip->buffer_write_time++; | 1618 | chip->buffer_write_time = 1; |
1524 | } | 1619 | } |
1525 | if (z > 1) | 1620 | if (z > 1) |
1526 | chip->buffer_write_time++; | 1621 | chip->buffer_write_time++; |
1527 | 1622 | ||
1528 | /* Done and happy. */ | 1623 | /* Done and happy. */ |
1529 | chip->state = FL_STATUS; | 1624 | chip->state = FL_STATUS; |
1530 | 1625 | ||
1531 | /* check for lock bit */ | 1626 | /* check for errors */ |
1532 | if (map_word_bitsset(map, status, CMD(0x02))) { | 1627 | if (map_word_bitsset(map, status, CMD(0x1a))) { |
1533 | /* clear status */ | 1628 | unsigned long chipstatus = MERGESTATUS(status); |
1629 | |||
1630 | /* reset status */ | ||
1534 | map_write(map, CMD(0x50), cmd_adr); | 1631 | map_write(map, CMD(0x50), cmd_adr); |
1535 | /* put back into read status register mode */ | 1632 | map_write(map, CMD(0x70), cmd_adr); |
1536 | map_write(map, CMD(0x70), adr); | 1633 | xip_enable(map, chip, cmd_adr); |
1537 | ret = -EROFS; | 1634 | |
1635 | if (chipstatus & 0x02) { | ||
1636 | ret = -EROFS; | ||
1637 | } else if (chipstatus & 0x08) { | ||
1638 | printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name); | ||
1639 | ret = -EIO; | ||
1640 | } else { | ||
1641 | printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus); | ||
1642 | ret = -EINVAL; | ||
1643 | } | ||
1644 | |||
1645 | goto out; | ||
1538 | } | 1646 | } |
1539 | 1647 | ||
1540 | xip_enable(map, chip, cmd_adr); | 1648 | xip_enable(map, chip, cmd_adr); |
@@ -1543,70 +1651,65 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1543 | return ret; | 1651 | return ret; |
1544 | } | 1652 | } |
1545 | 1653 | ||
1546 | static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, | 1654 | static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, |
1547 | size_t len, size_t *retlen, const u_char *buf) | 1655 | unsigned long count, loff_t to, size_t *retlen) |
1548 | { | 1656 | { |
1549 | struct map_info *map = mtd->priv; | 1657 | struct map_info *map = mtd->priv; |
1550 | struct cfi_private *cfi = map->fldrv_priv; | 1658 | struct cfi_private *cfi = map->fldrv_priv; |
1551 | int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 1659 | int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
1552 | int ret = 0; | 1660 | int ret = 0; |
1553 | int chipnum; | 1661 | int chipnum; |
1554 | unsigned long ofs; | 1662 | unsigned long ofs, vec_seek, i; |
1663 | size_t len = 0; | ||
1664 | |||
1665 | for (i = 0; i < count; i++) | ||
1666 | len += vecs[i].iov_len; | ||
1555 | 1667 | ||
1556 | *retlen = 0; | 1668 | *retlen = 0; |
1557 | if (!len) | 1669 | if (!len) |
1558 | return 0; | 1670 | return 0; |
1559 | 1671 | ||
1560 | chipnum = to >> cfi->chipshift; | 1672 | chipnum = to >> cfi->chipshift; |
1561 | ofs = to - (chipnum << cfi->chipshift); | 1673 | ofs = to - (chipnum << cfi->chipshift); |
1562 | 1674 | vec_seek = 0; | |
1563 | /* If it's not bus-aligned, do the first word write */ | ||
1564 | if (ofs & (map_bankwidth(map)-1)) { | ||
1565 | size_t local_len = (-ofs)&(map_bankwidth(map)-1); | ||
1566 | if (local_len > len) | ||
1567 | local_len = len; | ||
1568 | ret = cfi_intelext_write_words(mtd, to, local_len, | ||
1569 | retlen, buf); | ||
1570 | if (ret) | ||
1571 | return ret; | ||
1572 | ofs += local_len; | ||
1573 | buf += local_len; | ||
1574 | len -= local_len; | ||
1575 | |||
1576 | if (ofs >> cfi->chipshift) { | ||
1577 | chipnum ++; | ||
1578 | ofs = 0; | ||
1579 | if (chipnum == cfi->numchips) | ||
1580 | return 0; | ||
1581 | } | ||
1582 | } | ||
1583 | 1675 | ||
1584 | while(len) { | 1676 | do { |
1585 | /* We must not cross write block boundaries */ | 1677 | /* We must not cross write block boundaries */ |
1586 | int size = wbufsize - (ofs & (wbufsize-1)); | 1678 | int size = wbufsize - (ofs & (wbufsize-1)); |
1587 | 1679 | ||
1588 | if (size > len) | 1680 | if (size > len) |
1589 | size = len; | 1681 | size = len; |
1590 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 1682 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
1591 | ofs, buf, size); | 1683 | ofs, &vecs, &vec_seek, size); |
1592 | if (ret) | 1684 | if (ret) |
1593 | return ret; | 1685 | return ret; |
1594 | 1686 | ||
1595 | ofs += size; | 1687 | ofs += size; |
1596 | buf += size; | ||
1597 | (*retlen) += size; | 1688 | (*retlen) += size; |
1598 | len -= size; | 1689 | len -= size; |
1599 | 1690 | ||
1600 | if (ofs >> cfi->chipshift) { | 1691 | if (ofs >> cfi->chipshift) { |
1601 | chipnum ++; | 1692 | chipnum ++; |
1602 | ofs = 0; | 1693 | ofs = 0; |
1603 | if (chipnum == cfi->numchips) | 1694 | if (chipnum == cfi->numchips) |
1604 | return 0; | 1695 | return 0; |
1605 | } | 1696 | } |
1606 | } | 1697 | } while (len); |
1698 | |||
1607 | return 0; | 1699 | return 0; |
1608 | } | 1700 | } |
1609 | 1701 | ||
1702 | static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, | ||
1703 | size_t len, size_t *retlen, const u_char *buf) | ||
1704 | { | ||
1705 | struct kvec vec; | ||
1706 | |||
1707 | vec.iov_base = (void *) buf; | ||
1708 | vec.iov_len = len; | ||
1709 | |||
1710 | return cfi_intelext_writev(mtd, &vec, 1, to, retlen); | ||
1711 | } | ||
1712 | |||
1610 | static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | 1713 | static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, |
1611 | unsigned long adr, int len, void *thunk) | 1714 | unsigned long adr, int len, void *thunk) |
1612 | { | 1715 | { |
@@ -1672,23 +1775,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
1672 | status = map_read(map, adr); | 1775 | status = map_read(map, adr); |
1673 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1776 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1674 | break; | 1777 | break; |
1675 | 1778 | ||
1676 | /* OK Still waiting */ | 1779 | /* OK Still waiting */ |
1677 | if (time_after(jiffies, timeo)) { | 1780 | if (time_after(jiffies, timeo)) { |
1678 | map_word Xstatus; | ||
1679 | map_write(map, CMD(0x70), adr); | 1781 | map_write(map, CMD(0x70), adr); |
1680 | chip->state = FL_STATUS; | 1782 | chip->state = FL_STATUS; |
1681 | Xstatus = map_read(map, adr); | ||
1682 | /* Clear status bits */ | ||
1683 | map_write(map, CMD(0x50), adr); | ||
1684 | map_write(map, CMD(0x70), adr); | ||
1685 | xip_enable(map, chip, adr); | 1783 | xip_enable(map, chip, adr); |
1686 | printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n", | 1784 | printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); |
1687 | adr, status.x[0], Xstatus.x[0]); | ||
1688 | ret = -EIO; | 1785 | ret = -EIO; |
1689 | goto out; | 1786 | goto out; |
1690 | } | 1787 | } |
1691 | 1788 | ||
1692 | /* Latency issues. Drop the lock, wait a while and retry */ | 1789 | /* Latency issues. Drop the lock, wait a while and retry */ |
1693 | UDELAY(map, chip, adr, 1000000/HZ); | 1790 | UDELAY(map, chip, adr, 1000000/HZ); |
1694 | } | 1791 | } |
@@ -1698,43 +1795,40 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
1698 | chip->state = FL_STATUS; | 1795 | chip->state = FL_STATUS; |
1699 | status = map_read(map, adr); | 1796 | status = map_read(map, adr); |
1700 | 1797 | ||
1701 | /* check for lock bit */ | 1798 | /* check for errors */ |
1702 | if (map_word_bitsset(map, status, CMD(0x3a))) { | 1799 | if (map_word_bitsset(map, status, CMD(0x3a))) { |
1703 | unsigned long chipstatus; | 1800 | unsigned long chipstatus = MERGESTATUS(status); |
1704 | 1801 | ||
1705 | /* Reset the error bits */ | 1802 | /* Reset the error bits */ |
1706 | map_write(map, CMD(0x50), adr); | 1803 | map_write(map, CMD(0x50), adr); |
1707 | map_write(map, CMD(0x70), adr); | 1804 | map_write(map, CMD(0x70), adr); |
1708 | xip_enable(map, chip, adr); | 1805 | xip_enable(map, chip, adr); |
1709 | 1806 | ||
1710 | chipstatus = MERGESTATUS(status); | ||
1711 | |||
1712 | if ((chipstatus & 0x30) == 0x30) { | 1807 | if ((chipstatus & 0x30) == 0x30) { |
1713 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus); | 1808 | printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus); |
1714 | ret = -EIO; | 1809 | ret = -EINVAL; |
1715 | } else if (chipstatus & 0x02) { | 1810 | } else if (chipstatus & 0x02) { |
1716 | /* Protection bit set */ | 1811 | /* Protection bit set */ |
1717 | ret = -EROFS; | 1812 | ret = -EROFS; |
1718 | } else if (chipstatus & 0x8) { | 1813 | } else if (chipstatus & 0x8) { |
1719 | /* Voltage */ | 1814 | /* Voltage */ |
1720 | printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus); | 1815 | printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name); |
1721 | ret = -EIO; | 1816 | ret = -EIO; |
1722 | } else if (chipstatus & 0x20) { | 1817 | } else if (chipstatus & 0x20 && retries--) { |
1723 | if (retries--) { | 1818 | printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); |
1724 | printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); | 1819 | timeo = jiffies + HZ; |
1725 | timeo = jiffies + HZ; | 1820 | put_chip(map, chip, adr); |
1726 | put_chip(map, chip, adr); | 1821 | spin_unlock(chip->mutex); |
1727 | spin_unlock(chip->mutex); | 1822 | goto retry; |
1728 | goto retry; | 1823 | } else { |
1729 | } | 1824 | printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus); |
1730 | printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus); | ||
1731 | ret = -EIO; | 1825 | ret = -EIO; |
1732 | } | 1826 | } |
1733 | } else { | 1827 | |
1734 | xip_enable(map, chip, adr); | 1828 | goto out; |
1735 | ret = 0; | ||
1736 | } | 1829 | } |
1737 | 1830 | ||
1831 | xip_enable(map, chip, adr); | ||
1738 | out: put_chip(map, chip, adr); | 1832 | out: put_chip(map, chip, adr); |
1739 | spin_unlock(chip->mutex); | 1833 | spin_unlock(chip->mutex); |
1740 | return ret; | 1834 | return ret; |
@@ -1754,7 +1848,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
1754 | 1848 | ||
1755 | instr->state = MTD_ERASE_DONE; | 1849 | instr->state = MTD_ERASE_DONE; |
1756 | mtd_erase_callback(instr); | 1850 | mtd_erase_callback(instr); |
1757 | 1851 | ||
1758 | return 0; | 1852 | return 0; |
1759 | } | 1853 | } |
1760 | 1854 | ||
@@ -1775,7 +1869,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) | |||
1775 | if (!ret) { | 1869 | if (!ret) { |
1776 | chip->oldstate = chip->state; | 1870 | chip->oldstate = chip->state; |
1777 | chip->state = FL_SYNCING; | 1871 | chip->state = FL_SYNCING; |
1778 | /* No need to wake_up() on this state change - | 1872 | /* No need to wake_up() on this state change - |
1779 | * as the whole point is that nobody can do anything | 1873 | * as the whole point is that nobody can do anything |
1780 | * with the chip now anyway. | 1874 | * with the chip now anyway. |
1781 | */ | 1875 | */ |
@@ -1789,7 +1883,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) | |||
1789 | chip = &cfi->chips[i]; | 1883 | chip = &cfi->chips[i]; |
1790 | 1884 | ||
1791 | spin_lock(chip->mutex); | 1885 | spin_lock(chip->mutex); |
1792 | 1886 | ||
1793 | if (chip->state == FL_SYNCING) { | 1887 | if (chip->state == FL_SYNCING) { |
1794 | chip->state = chip->oldstate; | 1888 | chip->state = chip->oldstate; |
1795 | chip->oldstate = FL_READY; | 1889 | chip->oldstate = FL_READY; |
@@ -1846,7 +1940,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip | |||
1846 | 1940 | ||
1847 | ENABLE_VPP(map); | 1941 | ENABLE_VPP(map); |
1848 | xip_disable(map, chip, adr); | 1942 | xip_disable(map, chip, adr); |
1849 | 1943 | ||
1850 | map_write(map, CMD(0x60), adr); | 1944 | map_write(map, CMD(0x60), adr); |
1851 | if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { | 1945 | if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { |
1852 | map_write(map, CMD(0x01), adr); | 1946 | map_write(map, CMD(0x01), adr); |
@@ -1874,25 +1968,22 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip | |||
1874 | status = map_read(map, adr); | 1968 | status = map_read(map, adr); |
1875 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1969 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1876 | break; | 1970 | break; |
1877 | 1971 | ||
1878 | /* OK Still waiting */ | 1972 | /* OK Still waiting */ |
1879 | if (time_after(jiffies, timeo)) { | 1973 | if (time_after(jiffies, timeo)) { |
1880 | map_word Xstatus; | ||
1881 | map_write(map, CMD(0x70), adr); | 1974 | map_write(map, CMD(0x70), adr); |
1882 | chip->state = FL_STATUS; | 1975 | chip->state = FL_STATUS; |
1883 | Xstatus = map_read(map, adr); | ||
1884 | xip_enable(map, chip, adr); | 1976 | xip_enable(map, chip, adr); |
1885 | printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n", | 1977 | printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); |
1886 | status.x[0], Xstatus.x[0]); | ||
1887 | put_chip(map, chip, adr); | 1978 | put_chip(map, chip, adr); |
1888 | spin_unlock(chip->mutex); | 1979 | spin_unlock(chip->mutex); |
1889 | return -EIO; | 1980 | return -EIO; |
1890 | } | 1981 | } |
1891 | 1982 | ||
1892 | /* Latency issues. Drop the lock, wait a while and retry */ | 1983 | /* Latency issues. Drop the lock, wait a while and retry */ |
1893 | UDELAY(map, chip, adr, 1); | 1984 | UDELAY(map, chip, adr, 1); |
1894 | } | 1985 | } |
1895 | 1986 | ||
1896 | /* Done and happy. */ | 1987 | /* Done and happy. */ |
1897 | chip->state = FL_STATUS; | 1988 | chip->state = FL_STATUS; |
1898 | xip_enable(map, chip, adr); | 1989 | xip_enable(map, chip, adr); |
@@ -1912,9 +2003,9 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1912 | ofs, len, 0); | 2003 | ofs, len, 0); |
1913 | #endif | 2004 | #endif |
1914 | 2005 | ||
1915 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, | 2006 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, |
1916 | ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); | 2007 | ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); |
1917 | 2008 | ||
1918 | #ifdef DEBUG_LOCK_BITS | 2009 | #ifdef DEBUG_LOCK_BITS |
1919 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2010 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
1920 | __FUNCTION__, ret); | 2011 | __FUNCTION__, ret); |
@@ -1938,20 +2029,20 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1938 | 2029 | ||
1939 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, | 2030 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, |
1940 | ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); | 2031 | ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); |
1941 | 2032 | ||
1942 | #ifdef DEBUG_LOCK_BITS | 2033 | #ifdef DEBUG_LOCK_BITS |
1943 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2034 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
1944 | __FUNCTION__, ret); | 2035 | __FUNCTION__, ret); |
1945 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2036 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
1946 | ofs, len, 0); | 2037 | ofs, len, 0); |
1947 | #endif | 2038 | #endif |
1948 | 2039 | ||
1949 | return ret; | 2040 | return ret; |
1950 | } | 2041 | } |
1951 | 2042 | ||
1952 | #ifdef CONFIG_MTD_OTP | 2043 | #ifdef CONFIG_MTD_OTP |
1953 | 2044 | ||
1954 | typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, | 2045 | typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, |
1955 | u_long data_offset, u_char *buf, u_int size, | 2046 | u_long data_offset, u_char *buf, u_int size, |
1956 | u_long prot_offset, u_int groupno, u_int groupsize); | 2047 | u_long prot_offset, u_int groupno, u_int groupsize); |
1957 | 2048 | ||
@@ -2002,7 +2093,7 @@ do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, | |||
2002 | 2093 | ||
2003 | datum = map_word_load_partial(map, datum, buf, gap, n); | 2094 | datum = map_word_load_partial(map, datum, buf, gap, n); |
2004 | ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); | 2095 | ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); |
2005 | if (ret) | 2096 | if (ret) |
2006 | return ret; | 2097 | return ret; |
2007 | 2098 | ||
2008 | offset += n; | 2099 | offset += n; |
@@ -2195,7 +2286,7 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, | |||
2195 | NULL, do_otp_lock, 1); | 2286 | NULL, do_otp_lock, 1); |
2196 | } | 2287 | } |
2197 | 2288 | ||
2198 | static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, | 2289 | static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, |
2199 | struct otp_info *buf, size_t len) | 2290 | struct otp_info *buf, size_t len) |
2200 | { | 2291 | { |
2201 | size_t retlen; | 2292 | size_t retlen; |
@@ -2238,7 +2329,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2238 | if (chip->oldstate == FL_READY) { | 2329 | if (chip->oldstate == FL_READY) { |
2239 | chip->oldstate = chip->state; | 2330 | chip->oldstate = chip->state; |
2240 | chip->state = FL_PM_SUSPENDED; | 2331 | chip->state = FL_PM_SUSPENDED; |
2241 | /* No need to wake_up() on this state change - | 2332 | /* No need to wake_up() on this state change - |
2242 | * as the whole point is that nobody can do anything | 2333 | * as the whole point is that nobody can do anything |
2243 | * with the chip now anyway. | 2334 | * with the chip now anyway. |
2244 | */ | 2335 | */ |
@@ -2266,9 +2357,9 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2266 | if (ret) { | 2357 | if (ret) { |
2267 | for (i--; i >=0; i--) { | 2358 | for (i--; i >=0; i--) { |
2268 | chip = &cfi->chips[i]; | 2359 | chip = &cfi->chips[i]; |
2269 | 2360 | ||
2270 | spin_lock(chip->mutex); | 2361 | spin_lock(chip->mutex); |
2271 | 2362 | ||
2272 | if (chip->state == FL_PM_SUSPENDED) { | 2363 | if (chip->state == FL_PM_SUSPENDED) { |
2273 | /* No need to force it into a known state here, | 2364 | /* No need to force it into a known state here, |
2274 | because we're returning failure, and it didn't | 2365 | because we're returning failure, and it didn't |
@@ -2279,8 +2370,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2279 | } | 2370 | } |
2280 | spin_unlock(chip->mutex); | 2371 | spin_unlock(chip->mutex); |
2281 | } | 2372 | } |
2282 | } | 2373 | } |
2283 | 2374 | ||
2284 | return ret; | 2375 | return ret; |
2285 | } | 2376 | } |
2286 | 2377 | ||
@@ -2292,11 +2383,11 @@ static void cfi_intelext_resume(struct mtd_info *mtd) | |||
2292 | struct flchip *chip; | 2383 | struct flchip *chip; |
2293 | 2384 | ||
2294 | for (i=0; i<cfi->numchips; i++) { | 2385 | for (i=0; i<cfi->numchips; i++) { |
2295 | 2386 | ||
2296 | chip = &cfi->chips[i]; | 2387 | chip = &cfi->chips[i]; |
2297 | 2388 | ||
2298 | spin_lock(chip->mutex); | 2389 | spin_lock(chip->mutex); |
2299 | 2390 | ||
2300 | /* Go to known state. Chip may have been power cycled */ | 2391 | /* Go to known state. Chip may have been power cycled */ |
2301 | if (chip->state == FL_PM_SUSPENDED) { | 2392 | if (chip->state == FL_PM_SUSPENDED) { |
2302 | map_write(map, CMD(0xFF), cfi->chips[i].start); | 2393 | map_write(map, CMD(0xFF), cfi->chips[i].start); |
@@ -2318,7 +2409,7 @@ static int cfi_intelext_reset(struct mtd_info *mtd) | |||
2318 | struct flchip *chip = &cfi->chips[i]; | 2409 | struct flchip *chip = &cfi->chips[i]; |
2319 | 2410 | ||
2320 | /* force the completion of any ongoing operation | 2411 | /* force the completion of any ongoing operation |
2321 | and switch to array mode so any bootloader in | 2412 | and switch to array mode so any bootloader in |
2322 | flash is accessible for soft reboot. */ | 2413 | flash is accessible for soft reboot. */ |
2323 | spin_lock(chip->mutex); | 2414 | spin_lock(chip->mutex); |
2324 | ret = get_chip(map, chip, chip->start, FL_SYNCING); | 2415 | ret = get_chip(map, chip, chip->start, FL_SYNCING); |
@@ -2355,20 +2446,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) | |||
2355 | kfree(mtd->eraseregions); | 2446 | kfree(mtd->eraseregions); |
2356 | } | 2447 | } |
2357 | 2448 | ||
2358 | static char im_name_1[]="cfi_cmdset_0001"; | 2449 | static char im_name_0001[] = "cfi_cmdset_0001"; |
2359 | static char im_name_3[]="cfi_cmdset_0003"; | 2450 | static char im_name_0003[] = "cfi_cmdset_0003"; |
2451 | static char im_name_0200[] = "cfi_cmdset_0200"; | ||
2360 | 2452 | ||
2361 | static int __init cfi_intelext_init(void) | 2453 | static int __init cfi_intelext_init(void) |
2362 | { | 2454 | { |
2363 | inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001); | 2455 | inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001); |
2364 | inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001); | 2456 | inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001); |
2457 | inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); | ||
2365 | return 0; | 2458 | return 0; |
2366 | } | 2459 | } |
2367 | 2460 | ||
2368 | static void __exit cfi_intelext_exit(void) | 2461 | static void __exit cfi_intelext_exit(void) |
2369 | { | 2462 | { |
2370 | inter_module_unregister(im_name_1); | 2463 | inter_module_unregister(im_name_0001); |
2371 | inter_module_unregister(im_name_3); | 2464 | inter_module_unregister(im_name_0003); |
2465 | inter_module_unregister(im_name_0200); | ||
2372 | } | 2466 | } |
2373 | 2467 | ||
2374 | module_init(cfi_intelext_init); | 2468 | module_init(cfi_intelext_init); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 0e6475050da9..aed10bd5c3c3 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -10,14 +10,14 @@ | |||
10 | * | 10 | * |
11 | * 4_by_16 work by Carolyn J. Smith | 11 | * 4_by_16 work by Carolyn J. Smith |
12 | * | 12 | * |
13 | * XIP support hooks by Vitaly Wool (based on code for Intel flash | 13 | * XIP support hooks by Vitaly Wool (based on code for Intel flash |
14 | * by Nicolas Pitre) | 14 | * by Nicolas Pitre) |
15 | * | 15 | * |
16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com | 16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com |
17 | * | 17 | * |
18 | * This code is GPL | 18 | * This code is GPL |
19 | * | 19 | * |
20 | * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $ | 20 | * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $ |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
@@ -93,7 +93,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) | |||
93 | }; | 93 | }; |
94 | 94 | ||
95 | printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); | 95 | printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); |
96 | printk(" Address sensitive unlock: %s\n", | 96 | printk(" Address sensitive unlock: %s\n", |
97 | (extp->SiliconRevision & 1) ? "Not required" : "Required"); | 97 | (extp->SiliconRevision & 1) ? "Not required" : "Required"); |
98 | 98 | ||
99 | if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) | 99 | if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) |
@@ -118,9 +118,9 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) | |||
118 | else | 118 | else |
119 | printk(" Page mode: %d word page\n", extp->PageMode << 2); | 119 | printk(" Page mode: %d word page\n", extp->PageMode << 2); |
120 | 120 | ||
121 | printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", | 121 | printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", |
122 | extp->VppMin >> 4, extp->VppMin & 0xf); | 122 | extp->VppMin >> 4, extp->VppMin & 0xf); |
123 | printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", | 123 | printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", |
124 | extp->VppMax >> 4, extp->VppMax & 0xf); | 124 | extp->VppMax >> 4, extp->VppMax & 0xf); |
125 | 125 | ||
126 | if (extp->TopBottom < ARRAY_SIZE(top_bottom)) | 126 | if (extp->TopBottom < ARRAY_SIZE(top_bottom)) |
@@ -177,7 +177,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) | |||
177 | ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { | 177 | ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { |
178 | mtd->erase = cfi_amdstd_erase_chip; | 178 | mtd->erase = cfi_amdstd_erase_chip; |
179 | } | 179 | } |
180 | 180 | ||
181 | } | 181 | } |
182 | 182 | ||
183 | static struct cfi_fixup cfi_fixup_table[] = { | 183 | static struct cfi_fixup cfi_fixup_table[] = { |
@@ -239,7 +239,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
239 | 239 | ||
240 | if (cfi->cfi_mode==CFI_MODE_CFI){ | 240 | if (cfi->cfi_mode==CFI_MODE_CFI){ |
241 | unsigned char bootloc; | 241 | unsigned char bootloc; |
242 | /* | 242 | /* |
243 | * It's a real CFI chip, not one for which the probe | 243 | * It's a real CFI chip, not one for which the probe |
244 | * routine faked a CFI structure. So we read the feature | 244 | * routine faked a CFI structure. So we read the feature |
245 | * table from it. | 245 | * table from it. |
@@ -253,8 +253,18 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
253 | return NULL; | 253 | return NULL; |
254 | } | 254 | } |
255 | 255 | ||
256 | if (extp->MajorVersion != '1' || | ||
257 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | ||
258 | printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " | ||
259 | "version %c.%c.\n", extp->MajorVersion, | ||
260 | extp->MinorVersion); | ||
261 | kfree(extp); | ||
262 | kfree(mtd); | ||
263 | return NULL; | ||
264 | } | ||
265 | |||
256 | /* Install our own private info structure */ | 266 | /* Install our own private info structure */ |
257 | cfi->cmdset_priv = extp; | 267 | cfi->cmdset_priv = extp; |
258 | 268 | ||
259 | /* Apply cfi device specific fixups */ | 269 | /* Apply cfi device specific fixups */ |
260 | cfi_fixup(mtd, cfi_fixup_table); | 270 | cfi_fixup(mtd, cfi_fixup_table); |
@@ -262,7 +272,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
262 | #ifdef DEBUG_CFI_FEATURES | 272 | #ifdef DEBUG_CFI_FEATURES |
263 | /* Tell the user about it in lots of lovely detail */ | 273 | /* Tell the user about it in lots of lovely detail */ |
264 | cfi_tell_features(extp); | 274 | cfi_tell_features(extp); |
265 | #endif | 275 | #endif |
266 | 276 | ||
267 | bootloc = extp->TopBottom; | 277 | bootloc = extp->TopBottom; |
268 | if ((bootloc != 2) && (bootloc != 3)) { | 278 | if ((bootloc != 2) && (bootloc != 3)) { |
@@ -273,11 +283,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
273 | 283 | ||
274 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { | 284 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { |
275 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); | 285 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); |
276 | 286 | ||
277 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { | 287 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { |
278 | int j = (cfi->cfiq->NumEraseRegions-1)-i; | 288 | int j = (cfi->cfiq->NumEraseRegions-1)-i; |
279 | __u32 swap; | 289 | __u32 swap; |
280 | 290 | ||
281 | swap = cfi->cfiq->EraseRegionInfo[i]; | 291 | swap = cfi->cfiq->EraseRegionInfo[i]; |
282 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; | 292 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; |
283 | cfi->cfiq->EraseRegionInfo[j] = swap; | 293 | cfi->cfiq->EraseRegionInfo[j] = swap; |
@@ -288,11 +298,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
288 | cfi->addr_unlock2 = 0x2aa; | 298 | cfi->addr_unlock2 = 0x2aa; |
289 | /* Modify the unlock address if we are in compatibility mode */ | 299 | /* Modify the unlock address if we are in compatibility mode */ |
290 | if ( /* x16 in x8 mode */ | 300 | if ( /* x16 in x8 mode */ |
291 | ((cfi->device_type == CFI_DEVICETYPE_X8) && | 301 | ((cfi->device_type == CFI_DEVICETYPE_X8) && |
292 | (cfi->cfiq->InterfaceDesc == 2)) || | 302 | (cfi->cfiq->InterfaceDesc == 2)) || |
293 | /* x32 in x16 mode */ | 303 | /* x32 in x16 mode */ |
294 | ((cfi->device_type == CFI_DEVICETYPE_X16) && | 304 | ((cfi->device_type == CFI_DEVICETYPE_X16) && |
295 | (cfi->cfiq->InterfaceDesc == 4))) | 305 | (cfi->cfiq->InterfaceDesc == 4))) |
296 | { | 306 | { |
297 | cfi->addr_unlock1 = 0xaaa; | 307 | cfi->addr_unlock1 = 0xaaa; |
298 | cfi->addr_unlock2 = 0x555; | 308 | cfi->addr_unlock2 = 0x555; |
@@ -310,10 +320,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
310 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; | 320 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; |
311 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; | 321 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; |
312 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; | 322 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; |
313 | } | 323 | } |
314 | 324 | ||
315 | map->fldrv = &cfi_amdstd_chipdrv; | 325 | map->fldrv = &cfi_amdstd_chipdrv; |
316 | 326 | ||
317 | return cfi_amdstd_setup(mtd); | 327 | return cfi_amdstd_setup(mtd); |
318 | } | 328 | } |
319 | 329 | ||
@@ -326,24 +336,24 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) | |||
326 | unsigned long offset = 0; | 336 | unsigned long offset = 0; |
327 | int i,j; | 337 | int i,j; |
328 | 338 | ||
329 | printk(KERN_NOTICE "number of %s chips: %d\n", | 339 | printk(KERN_NOTICE "number of %s chips: %d\n", |
330 | (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); | 340 | (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); |
331 | /* Select the correct geometry setup */ | 341 | /* Select the correct geometry setup */ |
332 | mtd->size = devsize * cfi->numchips; | 342 | mtd->size = devsize * cfi->numchips; |
333 | 343 | ||
334 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 344 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
335 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 345 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
336 | * mtd->numeraseregions, GFP_KERNEL); | 346 | * mtd->numeraseregions, GFP_KERNEL); |
337 | if (!mtd->eraseregions) { | 347 | if (!mtd->eraseregions) { |
338 | printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); | 348 | printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); |
339 | goto setup_err; | 349 | goto setup_err; |
340 | } | 350 | } |
341 | 351 | ||
342 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 352 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
343 | unsigned long ernum, ersize; | 353 | unsigned long ernum, ersize; |
344 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 354 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
345 | ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; | 355 | ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; |
346 | 356 | ||
347 | if (mtd->erasesize < ersize) { | 357 | if (mtd->erasesize < ersize) { |
348 | mtd->erasesize = ersize; | 358 | mtd->erasesize = ersize; |
349 | } | 359 | } |
@@ -429,7 +439,7 @@ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word | |||
429 | oldd = map_read(map, addr); | 439 | oldd = map_read(map, addr); |
430 | curd = map_read(map, addr); | 440 | curd = map_read(map, addr); |
431 | 441 | ||
432 | return map_word_equal(map, oldd, curd) && | 442 | return map_word_equal(map, oldd, curd) && |
433 | map_word_equal(map, curd, expected); | 443 | map_word_equal(map, curd, expected); |
434 | } | 444 | } |
435 | 445 | ||
@@ -461,7 +471,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
461 | /* Someone else might have been playing with it. */ | 471 | /* Someone else might have been playing with it. */ |
462 | goto retry; | 472 | goto retry; |
463 | } | 473 | } |
464 | 474 | ||
465 | case FL_READY: | 475 | case FL_READY: |
466 | case FL_CFI_QUERY: | 476 | case FL_CFI_QUERY: |
467 | case FL_JEDEC_QUERY: | 477 | case FL_JEDEC_QUERY: |
@@ -504,7 +514,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
504 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); | 514 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); |
505 | return -EIO; | 515 | return -EIO; |
506 | } | 516 | } |
507 | 517 | ||
508 | spin_unlock(chip->mutex); | 518 | spin_unlock(chip->mutex); |
509 | cfi_udelay(1); | 519 | cfi_udelay(1); |
510 | spin_lock(chip->mutex); | 520 | spin_lock(chip->mutex); |
@@ -607,7 +617,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, | |||
607 | * When a delay is required for the flash operation to complete, the | 617 | * When a delay is required for the flash operation to complete, the |
608 | * xip_udelay() function is polling for both the given timeout and pending | 618 | * xip_udelay() function is polling for both the given timeout and pending |
609 | * (but still masked) hardware interrupts. Whenever there is an interrupt | 619 | * (but still masked) hardware interrupts. Whenever there is an interrupt |
610 | * pending then the flash erase operation is suspended, array mode restored | 620 | * pending then the flash erase operation is suspended, array mode restored |
611 | * and interrupts unmasked. Task scheduling might also happen at that | 621 | * and interrupts unmasked. Task scheduling might also happen at that |
612 | * point. The CPU eventually returns from the interrupt or the call to | 622 | * point. The CPU eventually returns from the interrupt or the call to |
613 | * schedule() and the suspended flash operation is resumed for the remaining | 623 | * schedule() and the suspended flash operation is resumed for the remaining |
@@ -631,9 +641,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, | |||
631 | ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && | 641 | ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && |
632 | (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { | 642 | (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { |
633 | /* | 643 | /* |
634 | * Let's suspend the erase operation when supported. | 644 | * Let's suspend the erase operation when supported. |
635 | * Note that we currently don't try to suspend | 645 | * Note that we currently don't try to suspend |
636 | * interleaved chips if there is already another | 646 | * interleaved chips if there is already another |
637 | * operation suspended (imagine what happens | 647 | * operation suspended (imagine what happens |
638 | * when one chip was already done with the current | 648 | * when one chip was already done with the current |
639 | * operation while another chip suspended it, then | 649 | * operation while another chip suspended it, then |
@@ -769,8 +779,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
769 | 779 | ||
770 | adr += chip->start; | 780 | adr += chip->start; |
771 | 781 | ||
772 | /* Ensure cmd read/writes are aligned. */ | 782 | /* Ensure cmd read/writes are aligned. */ |
773 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 783 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
774 | 784 | ||
775 | spin_lock(chip->mutex); | 785 | spin_lock(chip->mutex); |
776 | ret = get_chip(map, chip, cmd_addr, FL_READY); | 786 | ret = get_chip(map, chip, cmd_addr, FL_READY); |
@@ -850,7 +860,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
850 | #endif | 860 | #endif |
851 | set_current_state(TASK_UNINTERRUPTIBLE); | 861 | set_current_state(TASK_UNINTERRUPTIBLE); |
852 | add_wait_queue(&chip->wq, &wait); | 862 | add_wait_queue(&chip->wq, &wait); |
853 | 863 | ||
854 | spin_unlock(chip->mutex); | 864 | spin_unlock(chip->mutex); |
855 | 865 | ||
856 | schedule(); | 866 | schedule(); |
@@ -862,7 +872,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
862 | timeo = jiffies + HZ; | 872 | timeo = jiffies + HZ; |
863 | 873 | ||
864 | goto retry; | 874 | goto retry; |
865 | } | 875 | } |
866 | 876 | ||
867 | adr += chip->start; | 877 | adr += chip->start; |
868 | 878 | ||
@@ -871,14 +881,14 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
871 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 881 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
872 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 882 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
873 | cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 883 | cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
874 | 884 | ||
875 | map_copy_from(map, buf, adr, len); | 885 | map_copy_from(map, buf, adr, len); |
876 | 886 | ||
877 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 887 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
878 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 888 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
879 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 889 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
880 | cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 890 | cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
881 | 891 | ||
882 | wake_up(&chip->wq); | 892 | wake_up(&chip->wq); |
883 | spin_unlock(chip->mutex); | 893 | spin_unlock(chip->mutex); |
884 | 894 | ||
@@ -987,7 +997,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
987 | chip->word_write_time); | 997 | chip->word_write_time); |
988 | 998 | ||
989 | /* See comment above for timeout value. */ | 999 | /* See comment above for timeout value. */ |
990 | timeo = jiffies + uWriteTimeout; | 1000 | timeo = jiffies + uWriteTimeout; |
991 | for (;;) { | 1001 | for (;;) { |
992 | if (chip->state != FL_WRITING) { | 1002 | if (chip->state != FL_WRITING) { |
993 | /* Someone's suspended the write. Sleep */ | 1003 | /* Someone's suspended the write. Sleep */ |
@@ -1003,16 +1013,16 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1003 | continue; | 1013 | continue; |
1004 | } | 1014 | } |
1005 | 1015 | ||
1006 | if (chip_ready(map, adr)) | 1016 | if (time_after(jiffies, timeo) && !chip_ready(map, adr)){ |
1007 | break; | ||
1008 | |||
1009 | if (time_after(jiffies, timeo)) { | ||
1010 | xip_enable(map, chip, adr); | 1017 | xip_enable(map, chip, adr); |
1011 | printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); | 1018 | printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); |
1012 | xip_disable(map, chip, adr); | 1019 | xip_disable(map, chip, adr); |
1013 | break; | 1020 | break; |
1014 | } | 1021 | } |
1015 | 1022 | ||
1023 | if (chip_ready(map, adr)) | ||
1024 | break; | ||
1025 | |||
1016 | /* Latency issues. Drop the lock, wait a while and retry */ | 1026 | /* Latency issues. Drop the lock, wait a while and retry */ |
1017 | UDELAY(map, chip, adr, 1); | 1027 | UDELAY(map, chip, adr, 1); |
1018 | } | 1028 | } |
@@ -1022,7 +1032,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1022 | map_write( map, CMD(0xF0), chip->start ); | 1032 | map_write( map, CMD(0xF0), chip->start ); |
1023 | /* FIXME - should have reset delay before continuing */ | 1033 | /* FIXME - should have reset delay before continuing */ |
1024 | 1034 | ||
1025 | if (++retry_cnt <= MAX_WORD_RETRIES) | 1035 | if (++retry_cnt <= MAX_WORD_RETRIES) |
1026 | goto retry; | 1036 | goto retry; |
1027 | 1037 | ||
1028 | ret = -EIO; | 1038 | ret = -EIO; |
@@ -1090,27 +1100,27 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1090 | 1100 | ||
1091 | /* Number of bytes to copy from buffer */ | 1101 | /* Number of bytes to copy from buffer */ |
1092 | n = min_t(int, len, map_bankwidth(map)-i); | 1102 | n = min_t(int, len, map_bankwidth(map)-i); |
1093 | 1103 | ||
1094 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); | 1104 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); |
1095 | 1105 | ||
1096 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1106 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1097 | bus_ofs, tmp_buf); | 1107 | bus_ofs, tmp_buf); |
1098 | if (ret) | 1108 | if (ret) |
1099 | return ret; | 1109 | return ret; |
1100 | 1110 | ||
1101 | ofs += n; | 1111 | ofs += n; |
1102 | buf += n; | 1112 | buf += n; |
1103 | (*retlen) += n; | 1113 | (*retlen) += n; |
1104 | len -= n; | 1114 | len -= n; |
1105 | 1115 | ||
1106 | if (ofs >> cfi->chipshift) { | 1116 | if (ofs >> cfi->chipshift) { |
1107 | chipnum ++; | 1117 | chipnum ++; |
1108 | ofs = 0; | 1118 | ofs = 0; |
1109 | if (chipnum == cfi->numchips) | 1119 | if (chipnum == cfi->numchips) |
1110 | return 0; | 1120 | return 0; |
1111 | } | 1121 | } |
1112 | } | 1122 | } |
1113 | 1123 | ||
1114 | /* We are now aligned, write as much as possible */ | 1124 | /* We are now aligned, write as much as possible */ |
1115 | while(len >= map_bankwidth(map)) { | 1125 | while(len >= map_bankwidth(map)) { |
1116 | map_word datum; | 1126 | map_word datum; |
@@ -1128,7 +1138,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1128 | len -= map_bankwidth(map); | 1138 | len -= map_bankwidth(map); |
1129 | 1139 | ||
1130 | if (ofs >> cfi->chipshift) { | 1140 | if (ofs >> cfi->chipshift) { |
1131 | chipnum ++; | 1141 | chipnum ++; |
1132 | ofs = 0; | 1142 | ofs = 0; |
1133 | if (chipnum == cfi->numchips) | 1143 | if (chipnum == cfi->numchips) |
1134 | return 0; | 1144 | return 0; |
@@ -1166,12 +1176,12 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1166 | spin_unlock(cfi->chips[chipnum].mutex); | 1176 | spin_unlock(cfi->chips[chipnum].mutex); |
1167 | 1177 | ||
1168 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); | 1178 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); |
1169 | 1179 | ||
1170 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1180 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1171 | ofs, tmp_buf); | 1181 | ofs, tmp_buf); |
1172 | if (ret) | 1182 | if (ret) |
1173 | return ret; | 1183 | return ret; |
1174 | 1184 | ||
1175 | (*retlen) += len; | 1185 | (*retlen) += len; |
1176 | } | 1186 | } |
1177 | 1187 | ||
@@ -1183,7 +1193,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1183 | * FIXME: interleaved mode not tested, and probably not supported! | 1193 | * FIXME: interleaved mode not tested, and probably not supported! |
1184 | */ | 1194 | */ |
1185 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | 1195 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, |
1186 | unsigned long adr, const u_char *buf, | 1196 | unsigned long adr, const u_char *buf, |
1187 | int len) | 1197 | int len) |
1188 | { | 1198 | { |
1189 | struct cfi_private *cfi = map->fldrv_priv; | 1199 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -1213,7 +1223,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1213 | XIP_INVAL_CACHED_RANGE(map, adr, len); | 1223 | XIP_INVAL_CACHED_RANGE(map, adr, len); |
1214 | ENABLE_VPP(map); | 1224 | ENABLE_VPP(map); |
1215 | xip_disable(map, chip, cmd_adr); | 1225 | xip_disable(map, chip, cmd_adr); |
1216 | 1226 | ||
1217 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1227 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
1218 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 1228 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
1219 | //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1229 | //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
@@ -1247,8 +1257,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1247 | adr, map_bankwidth(map), | 1257 | adr, map_bankwidth(map), |
1248 | chip->word_write_time); | 1258 | chip->word_write_time); |
1249 | 1259 | ||
1250 | timeo = jiffies + uWriteTimeout; | 1260 | timeo = jiffies + uWriteTimeout; |
1251 | 1261 | ||
1252 | for (;;) { | 1262 | for (;;) { |
1253 | if (chip->state != FL_WRITING) { | 1263 | if (chip->state != FL_WRITING) { |
1254 | /* Someone's suspended the write. Sleep */ | 1264 | /* Someone's suspended the write. Sleep */ |
@@ -1264,13 +1274,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1264 | continue; | 1274 | continue; |
1265 | } | 1275 | } |
1266 | 1276 | ||
1277 | if (time_after(jiffies, timeo) && !chip_ready(map, adr)) | ||
1278 | break; | ||
1279 | |||
1267 | if (chip_ready(map, adr)) { | 1280 | if (chip_ready(map, adr)) { |
1268 | xip_enable(map, chip, adr); | 1281 | xip_enable(map, chip, adr); |
1269 | goto op_done; | 1282 | goto op_done; |
1270 | } | 1283 | } |
1271 | |||
1272 | if( time_after(jiffies, timeo)) | ||
1273 | break; | ||
1274 | 1284 | ||
1275 | /* Latency issues. Drop the lock, wait a while and retry */ | 1285 | /* Latency issues. Drop the lock, wait a while and retry */ |
1276 | UDELAY(map, chip, adr, 1); | 1286 | UDELAY(map, chip, adr, 1); |
@@ -1342,7 +1352,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, | |||
1342 | if (size % map_bankwidth(map)) | 1352 | if (size % map_bankwidth(map)) |
1343 | size -= size % map_bankwidth(map); | 1353 | size -= size % map_bankwidth(map); |
1344 | 1354 | ||
1345 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 1355 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
1346 | ofs, buf, size); | 1356 | ofs, buf, size); |
1347 | if (ret) | 1357 | if (ret) |
1348 | return ret; | 1358 | return ret; |
@@ -1353,7 +1363,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, | |||
1353 | len -= size; | 1363 | len -= size; |
1354 | 1364 | ||
1355 | if (ofs >> cfi->chipshift) { | 1365 | if (ofs >> cfi->chipshift) { |
1356 | chipnum ++; | 1366 | chipnum ++; |
1357 | ofs = 0; | 1367 | ofs = 0; |
1358 | if (chipnum == cfi->numchips) | 1368 | if (chipnum == cfi->numchips) |
1359 | return 0; | 1369 | return 0; |
@@ -1570,7 +1580,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
1570 | 1580 | ||
1571 | instr->state = MTD_ERASE_DONE; | 1581 | instr->state = MTD_ERASE_DONE; |
1572 | mtd_erase_callback(instr); | 1582 | mtd_erase_callback(instr); |
1573 | 1583 | ||
1574 | return 0; | 1584 | return 0; |
1575 | } | 1585 | } |
1576 | 1586 | ||
@@ -1593,7 +1603,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) | |||
1593 | 1603 | ||
1594 | instr->state = MTD_ERASE_DONE; | 1604 | instr->state = MTD_ERASE_DONE; |
1595 | mtd_erase_callback(instr); | 1605 | mtd_erase_callback(instr); |
1596 | 1606 | ||
1597 | return 0; | 1607 | return 0; |
1598 | } | 1608 | } |
1599 | 1609 | ||
@@ -1620,7 +1630,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1620 | case FL_JEDEC_QUERY: | 1630 | case FL_JEDEC_QUERY: |
1621 | chip->oldstate = chip->state; | 1631 | chip->oldstate = chip->state; |
1622 | chip->state = FL_SYNCING; | 1632 | chip->state = FL_SYNCING; |
1623 | /* No need to wake_up() on this state change - | 1633 | /* No need to wake_up() on this state change - |
1624 | * as the whole point is that nobody can do anything | 1634 | * as the whole point is that nobody can do anything |
1625 | * with the chip now anyway. | 1635 | * with the chip now anyway. |
1626 | */ | 1636 | */ |
@@ -1631,13 +1641,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1631 | default: | 1641 | default: |
1632 | /* Not an idle state */ | 1642 | /* Not an idle state */ |
1633 | add_wait_queue(&chip->wq, &wait); | 1643 | add_wait_queue(&chip->wq, &wait); |
1634 | 1644 | ||
1635 | spin_unlock(chip->mutex); | 1645 | spin_unlock(chip->mutex); |
1636 | 1646 | ||
1637 | schedule(); | 1647 | schedule(); |
1638 | 1648 | ||
1639 | remove_wait_queue(&chip->wq, &wait); | 1649 | remove_wait_queue(&chip->wq, &wait); |
1640 | 1650 | ||
1641 | goto retry; | 1651 | goto retry; |
1642 | } | 1652 | } |
1643 | } | 1653 | } |
@@ -1648,7 +1658,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1648 | chip = &cfi->chips[i]; | 1658 | chip = &cfi->chips[i]; |
1649 | 1659 | ||
1650 | spin_lock(chip->mutex); | 1660 | spin_lock(chip->mutex); |
1651 | 1661 | ||
1652 | if (chip->state == FL_SYNCING) { | 1662 | if (chip->state == FL_SYNCING) { |
1653 | chip->state = chip->oldstate; | 1663 | chip->state = chip->oldstate; |
1654 | wake_up(&chip->wq); | 1664 | wake_up(&chip->wq); |
@@ -1678,7 +1688,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1678 | case FL_JEDEC_QUERY: | 1688 | case FL_JEDEC_QUERY: |
1679 | chip->oldstate = chip->state; | 1689 | chip->oldstate = chip->state; |
1680 | chip->state = FL_PM_SUSPENDED; | 1690 | chip->state = FL_PM_SUSPENDED; |
1681 | /* No need to wake_up() on this state change - | 1691 | /* No need to wake_up() on this state change - |
1682 | * as the whole point is that nobody can do anything | 1692 | * as the whole point is that nobody can do anything |
1683 | * with the chip now anyway. | 1693 | * with the chip now anyway. |
1684 | */ | 1694 | */ |
@@ -1699,7 +1709,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1699 | chip = &cfi->chips[i]; | 1709 | chip = &cfi->chips[i]; |
1700 | 1710 | ||
1701 | spin_lock(chip->mutex); | 1711 | spin_lock(chip->mutex); |
1702 | 1712 | ||
1703 | if (chip->state == FL_PM_SUSPENDED) { | 1713 | if (chip->state == FL_PM_SUSPENDED) { |
1704 | chip->state = chip->oldstate; | 1714 | chip->state = chip->oldstate; |
1705 | wake_up(&chip->wq); | 1715 | wake_up(&chip->wq); |
@@ -1707,7 +1717,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1707 | spin_unlock(chip->mutex); | 1717 | spin_unlock(chip->mutex); |
1708 | } | 1718 | } |
1709 | } | 1719 | } |
1710 | 1720 | ||
1711 | return ret; | 1721 | return ret; |
1712 | } | 1722 | } |
1713 | 1723 | ||
@@ -1720,11 +1730,11 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) | |||
1720 | struct flchip *chip; | 1730 | struct flchip *chip; |
1721 | 1731 | ||
1722 | for (i=0; i<cfi->numchips; i++) { | 1732 | for (i=0; i<cfi->numchips; i++) { |
1723 | 1733 | ||
1724 | chip = &cfi->chips[i]; | 1734 | chip = &cfi->chips[i]; |
1725 | 1735 | ||
1726 | spin_lock(chip->mutex); | 1736 | spin_lock(chip->mutex); |
1727 | 1737 | ||
1728 | if (chip->state == FL_PM_SUSPENDED) { | 1738 | if (chip->state == FL_PM_SUSPENDED) { |
1729 | chip->state = FL_READY; | 1739 | chip->state = FL_READY; |
1730 | map_write(map, CMD(0xF0), chip->start); | 1740 | map_write(map, CMD(0xF0), chip->start); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index c894f8801578..c4a19d2dc67f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0020.c,v 1.19 2005/07/13 15:52:45 dwmw2 Exp $ | 7 | * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $ |
8 | * | 8 | * |
9 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 9 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
10 | * - completely revamped method functions so they are aware and | 10 | * - completely revamped method functions so they are aware and |
11 | * independent of the flash geometry (buswidth, interleave, etc.) | 11 | * independent of the flash geometry (buswidth, interleave, etc.) |
@@ -81,17 +81,17 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
81 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); | 81 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); |
82 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); | 82 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); |
83 | for (i=9; i<32; i++) { | 83 | for (i=9; i<32; i++) { |
84 | if (extp->FeatureSupport & (1<<i)) | 84 | if (extp->FeatureSupport & (1<<i)) |
85 | printk(" - Unknown Bit %X: supported\n", i); | 85 | printk(" - Unknown Bit %X: supported\n", i); |
86 | } | 86 | } |
87 | 87 | ||
88 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); | 88 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); |
89 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); | 89 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); |
90 | for (i=1; i<8; i++) { | 90 | for (i=1; i<8; i++) { |
91 | if (extp->SuspendCmdSupport & (1<<i)) | 91 | if (extp->SuspendCmdSupport & (1<<i)) |
92 | printk(" - Unknown Bit %X: supported\n", i); | 92 | printk(" - Unknown Bit %X: supported\n", i); |
93 | } | 93 | } |
94 | 94 | ||
95 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); | 95 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); |
96 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); | 96 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); |
97 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); | 97 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); |
@@ -99,11 +99,11 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
99 | if (extp->BlkStatusRegMask & (1<<i)) | 99 | if (extp->BlkStatusRegMask & (1<<i)) |
100 | printk(" - Unknown Bit %X Active: yes\n",i); | 100 | printk(" - Unknown Bit %X Active: yes\n",i); |
101 | } | 101 | } |
102 | 102 | ||
103 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | 103 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", |
104 | extp->VccOptimal >> 8, extp->VccOptimal & 0xf); | 104 | extp->VccOptimal >> 8, extp->VccOptimal & 0xf); |
105 | if (extp->VppOptimal) | 105 | if (extp->VppOptimal) |
106 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", | 106 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", |
107 | extp->VppOptimal >> 8, extp->VppOptimal & 0xf); | 107 | extp->VppOptimal >> 8, extp->VppOptimal & 0xf); |
108 | } | 108 | } |
109 | #endif | 109 | #endif |
@@ -121,7 +121,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) | |||
121 | int i; | 121 | int i; |
122 | 122 | ||
123 | if (cfi->cfi_mode) { | 123 | if (cfi->cfi_mode) { |
124 | /* | 124 | /* |
125 | * It's a real CFI chip, not one for which the probe | 125 | * It's a real CFI chip, not one for which the probe |
126 | * routine faked a CFI structure. So we read the feature | 126 | * routine faked a CFI structure. So we read the feature |
127 | * table from it. | 127 | * table from it. |
@@ -133,24 +133,33 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) | |||
133 | if (!extp) | 133 | if (!extp) |
134 | return NULL; | 134 | return NULL; |
135 | 135 | ||
136 | if (extp->MajorVersion != '1' || | ||
137 | (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { | ||
138 | printk(KERN_ERR " Unknown ST Microelectronics" | ||
139 | " Extended Query version %c.%c.\n", | ||
140 | extp->MajorVersion, extp->MinorVersion); | ||
141 | kfree(extp); | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
136 | /* Do some byteswapping if necessary */ | 145 | /* Do some byteswapping if necessary */ |
137 | extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); | 146 | extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); |
138 | extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); | 147 | extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); |
139 | 148 | ||
140 | #ifdef DEBUG_CFI_FEATURES | 149 | #ifdef DEBUG_CFI_FEATURES |
141 | /* Tell the user about it in lots of lovely detail */ | 150 | /* Tell the user about it in lots of lovely detail */ |
142 | cfi_tell_features(extp); | 151 | cfi_tell_features(extp); |
143 | #endif | 152 | #endif |
144 | 153 | ||
145 | /* Install our own private info structure */ | 154 | /* Install our own private info structure */ |
146 | cfi->cmdset_priv = extp; | 155 | cfi->cmdset_priv = extp; |
147 | } | 156 | } |
148 | 157 | ||
149 | for (i=0; i< cfi->numchips; i++) { | 158 | for (i=0; i< cfi->numchips; i++) { |
150 | cfi->chips[i].word_write_time = 128; | 159 | cfi->chips[i].word_write_time = 128; |
151 | cfi->chips[i].buffer_write_time = 128; | 160 | cfi->chips[i].buffer_write_time = 128; |
152 | cfi->chips[i].erase_time = 1024; | 161 | cfi->chips[i].erase_time = 1024; |
153 | } | 162 | } |
154 | 163 | ||
155 | return cfi_staa_setup(map); | 164 | return cfi_staa_setup(map); |
156 | } | 165 | } |
@@ -178,15 +187,15 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
178 | mtd->size = devsize * cfi->numchips; | 187 | mtd->size = devsize * cfi->numchips; |
179 | 188 | ||
180 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 189 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
181 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 190 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
182 | * mtd->numeraseregions, GFP_KERNEL); | 191 | * mtd->numeraseregions, GFP_KERNEL); |
183 | if (!mtd->eraseregions) { | 192 | if (!mtd->eraseregions) { |
184 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); | 193 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); |
185 | kfree(cfi->cmdset_priv); | 194 | kfree(cfi->cmdset_priv); |
186 | kfree(mtd); | 195 | kfree(mtd); |
187 | return NULL; | 196 | return NULL; |
188 | } | 197 | } |
189 | 198 | ||
190 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 199 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
191 | unsigned long ernum, ersize; | 200 | unsigned long ernum, ersize; |
192 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 201 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
@@ -219,7 +228,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
219 | mtd->eraseregions[i].numblocks); | 228 | mtd->eraseregions[i].numblocks); |
220 | } | 229 | } |
221 | 230 | ||
222 | /* Also select the correct geometry setup too */ | 231 | /* Also select the correct geometry setup too */ |
223 | mtd->erase = cfi_staa_erase_varsize; | 232 | mtd->erase = cfi_staa_erase_varsize; |
224 | mtd->read = cfi_staa_read; | 233 | mtd->read = cfi_staa_read; |
225 | mtd->write = cfi_staa_write_buffers; | 234 | mtd->write = cfi_staa_write_buffers; |
@@ -250,8 +259,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
250 | 259 | ||
251 | adr += chip->start; | 260 | adr += chip->start; |
252 | 261 | ||
253 | /* Ensure cmd read/writes are aligned. */ | 262 | /* Ensure cmd read/writes are aligned. */ |
254 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 263 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
255 | 264 | ||
256 | /* Let's determine this according to the interleave only once */ | 265 | /* Let's determine this according to the interleave only once */ |
257 | status_OK = CMD(0x80); | 266 | status_OK = CMD(0x80); |
@@ -267,7 +276,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
267 | case FL_ERASING: | 276 | case FL_ERASING: |
268 | if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) | 277 | if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) |
269 | goto sleep; /* We don't support erase suspend */ | 278 | goto sleep; /* We don't support erase suspend */ |
270 | 279 | ||
271 | map_write (map, CMD(0xb0), cmd_addr); | 280 | map_write (map, CMD(0xb0), cmd_addr); |
272 | /* If the flash has finished erasing, then 'erase suspend' | 281 | /* If the flash has finished erasing, then 'erase suspend' |
273 | * appears to make some (28F320) flash devices switch to | 282 | * appears to make some (28F320) flash devices switch to |
@@ -282,7 +291,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
282 | status = map_read(map, cmd_addr); | 291 | status = map_read(map, cmd_addr); |
283 | if (map_word_andequal(map, status, status_OK, status_OK)) | 292 | if (map_word_andequal(map, status, status_OK, status_OK)) |
284 | break; | 293 | break; |
285 | 294 | ||
286 | if (time_after(jiffies, timeo)) { | 295 | if (time_after(jiffies, timeo)) { |
287 | /* Urgh */ | 296 | /* Urgh */ |
288 | map_write(map, CMD(0xd0), cmd_addr); | 297 | map_write(map, CMD(0xd0), cmd_addr); |
@@ -294,17 +303,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
294 | "suspended: status = 0x%lx\n", status.x[0]); | 303 | "suspended: status = 0x%lx\n", status.x[0]); |
295 | return -EIO; | 304 | return -EIO; |
296 | } | 305 | } |
297 | 306 | ||
298 | spin_unlock_bh(chip->mutex); | 307 | spin_unlock_bh(chip->mutex); |
299 | cfi_udelay(1); | 308 | cfi_udelay(1); |
300 | spin_lock_bh(chip->mutex); | 309 | spin_lock_bh(chip->mutex); |
301 | } | 310 | } |
302 | 311 | ||
303 | suspended = 1; | 312 | suspended = 1; |
304 | map_write(map, CMD(0xff), cmd_addr); | 313 | map_write(map, CMD(0xff), cmd_addr); |
305 | chip->state = FL_READY; | 314 | chip->state = FL_READY; |
306 | break; | 315 | break; |
307 | 316 | ||
308 | #if 0 | 317 | #if 0 |
309 | case FL_WRITING: | 318 | case FL_WRITING: |
310 | /* Not quite yet */ | 319 | /* Not quite yet */ |
@@ -325,7 +334,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
325 | chip->state = FL_READY; | 334 | chip->state = FL_READY; |
326 | break; | 335 | break; |
327 | } | 336 | } |
328 | 337 | ||
329 | /* Urgh. Chip not yet ready to talk to us. */ | 338 | /* Urgh. Chip not yet ready to talk to us. */ |
330 | if (time_after(jiffies, timeo)) { | 339 | if (time_after(jiffies, timeo)) { |
331 | spin_unlock_bh(chip->mutex); | 340 | spin_unlock_bh(chip->mutex); |
@@ -355,17 +364,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
355 | 364 | ||
356 | if (suspended) { | 365 | if (suspended) { |
357 | chip->state = chip->oldstate; | 366 | chip->state = chip->oldstate; |
358 | /* What if one interleaved chip has finished and the | 367 | /* What if one interleaved chip has finished and the |
359 | other hasn't? The old code would leave the finished | 368 | other hasn't? The old code would leave the finished |
360 | one in READY mode. That's bad, and caused -EROFS | 369 | one in READY mode. That's bad, and caused -EROFS |
361 | errors to be returned from do_erase_oneblock because | 370 | errors to be returned from do_erase_oneblock because |
362 | that's the only bit it checked for at the time. | 371 | that's the only bit it checked for at the time. |
363 | As the state machine appears to explicitly allow | 372 | As the state machine appears to explicitly allow |
364 | sending the 0x70 (Read Status) command to an erasing | 373 | sending the 0x70 (Read Status) command to an erasing |
365 | chip and expecting it to be ignored, that's what we | 374 | chip and expecting it to be ignored, that's what we |
366 | do. */ | 375 | do. */ |
367 | map_write(map, CMD(0xd0), cmd_addr); | 376 | map_write(map, CMD(0xd0), cmd_addr); |
368 | map_write(map, CMD(0x70), cmd_addr); | 377 | map_write(map, CMD(0x70), cmd_addr); |
369 | } | 378 | } |
370 | 379 | ||
371 | wake_up(&chip->wq); | 380 | wake_up(&chip->wq); |
@@ -405,14 +414,14 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
405 | *retlen += thislen; | 414 | *retlen += thislen; |
406 | len -= thislen; | 415 | len -= thislen; |
407 | buf += thislen; | 416 | buf += thislen; |
408 | 417 | ||
409 | ofs = 0; | 418 | ofs = 0; |
410 | chipnum++; | 419 | chipnum++; |
411 | } | 420 | } |
412 | return ret; | 421 | return ret; |
413 | } | 422 | } |
414 | 423 | ||
415 | static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | 424 | static inline int do_write_buffer(struct map_info *map, struct flchip *chip, |
416 | unsigned long adr, const u_char *buf, int len) | 425 | unsigned long adr, const u_char *buf, int len) |
417 | { | 426 | { |
418 | struct cfi_private *cfi = map->fldrv_priv; | 427 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -420,7 +429,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
420 | unsigned long cmd_adr, timeo; | 429 | unsigned long cmd_adr, timeo; |
421 | DECLARE_WAITQUEUE(wait, current); | 430 | DECLARE_WAITQUEUE(wait, current); |
422 | int wbufsize, z; | 431 | int wbufsize, z; |
423 | 432 | ||
424 | /* M58LW064A requires bus alignment for buffer wriets -- saw */ | 433 | /* M58LW064A requires bus alignment for buffer wriets -- saw */ |
425 | if (adr & (map_bankwidth(map)-1)) | 434 | if (adr & (map_bankwidth(map)-1)) |
426 | return -EINVAL; | 435 | return -EINVAL; |
@@ -428,10 +437,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
428 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 437 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
429 | adr += chip->start; | 438 | adr += chip->start; |
430 | cmd_adr = adr & ~(wbufsize-1); | 439 | cmd_adr = adr & ~(wbufsize-1); |
431 | 440 | ||
432 | /* Let's determine this according to the interleave only once */ | 441 | /* Let's determine this according to the interleave only once */ |
433 | status_OK = CMD(0x80); | 442 | status_OK = CMD(0x80); |
434 | 443 | ||
435 | timeo = jiffies + HZ; | 444 | timeo = jiffies + HZ; |
436 | retry: | 445 | retry: |
437 | 446 | ||
@@ -439,7 +448,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
439 | printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); | 448 | printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); |
440 | #endif | 449 | #endif |
441 | spin_lock_bh(chip->mutex); | 450 | spin_lock_bh(chip->mutex); |
442 | 451 | ||
443 | /* Check that the chip's ready to talk to us. | 452 | /* Check that the chip's ready to talk to us. |
444 | * Later, we can actually think about interrupting it | 453 | * Later, we can actually think about interrupting it |
445 | * if it's in FL_ERASING state. | 454 | * if it's in FL_ERASING state. |
@@ -448,7 +457,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
448 | switch (chip->state) { | 457 | switch (chip->state) { |
449 | case FL_READY: | 458 | case FL_READY: |
450 | break; | 459 | break; |
451 | 460 | ||
452 | case FL_CFI_QUERY: | 461 | case FL_CFI_QUERY: |
453 | case FL_JEDEC_QUERY: | 462 | case FL_JEDEC_QUERY: |
454 | map_write(map, CMD(0x70), cmd_adr); | 463 | map_write(map, CMD(0x70), cmd_adr); |
@@ -513,7 +522,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
513 | 522 | ||
514 | /* Write length of data to come */ | 523 | /* Write length of data to come */ |
515 | map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr ); | 524 | map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr ); |
516 | 525 | ||
517 | /* Write data */ | 526 | /* Write data */ |
518 | for (z = 0; z < len; | 527 | for (z = 0; z < len; |
519 | z += map_bankwidth(map), buf += map_bankwidth(map)) { | 528 | z += map_bankwidth(map), buf += map_bankwidth(map)) { |
@@ -560,7 +569,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
560 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); | 569 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); |
561 | return -EIO; | 570 | return -EIO; |
562 | } | 571 | } |
563 | 572 | ||
564 | /* Latency issues. Drop the lock, wait a while and retry */ | 573 | /* Latency issues. Drop the lock, wait a while and retry */ |
565 | spin_unlock_bh(chip->mutex); | 574 | spin_unlock_bh(chip->mutex); |
566 | cfi_udelay(1); | 575 | cfi_udelay(1); |
@@ -572,9 +581,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
572 | if (!chip->buffer_write_time) | 581 | if (!chip->buffer_write_time) |
573 | chip->buffer_write_time++; | 582 | chip->buffer_write_time++; |
574 | } | 583 | } |
575 | if (z > 1) | 584 | if (z > 1) |
576 | chip->buffer_write_time++; | 585 | chip->buffer_write_time++; |
577 | 586 | ||
578 | /* Done and happy. */ | 587 | /* Done and happy. */ |
579 | DISABLE_VPP(map); | 588 | DISABLE_VPP(map); |
580 | chip->state = FL_STATUS; | 589 | chip->state = FL_STATUS; |
@@ -598,7 +607,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
598 | return 0; | 607 | return 0; |
599 | } | 608 | } |
600 | 609 | ||
601 | static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | 610 | static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, |
602 | size_t len, size_t *retlen, const u_char *buf) | 611 | size_t len, size_t *retlen, const u_char *buf) |
603 | { | 612 | { |
604 | struct map_info *map = mtd->priv; | 613 | struct map_info *map = mtd->priv; |
@@ -620,7 +629,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
620 | printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); | 629 | printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); |
621 | printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); | 630 | printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); |
622 | #endif | 631 | #endif |
623 | 632 | ||
624 | /* Write buffer is worth it only if more than one word to write... */ | 633 | /* Write buffer is worth it only if more than one word to write... */ |
625 | while (len > 0) { | 634 | while (len > 0) { |
626 | /* We must not cross write block boundaries */ | 635 | /* We must not cross write block boundaries */ |
@@ -629,7 +638,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
629 | if (size > len) | 638 | if (size > len) |
630 | size = len; | 639 | size = len; |
631 | 640 | ||
632 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 641 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
633 | ofs, buf, size); | 642 | ofs, buf, size); |
634 | if (ret) | 643 | if (ret) |
635 | return ret; | 644 | return ret; |
@@ -640,13 +649,13 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
640 | len -= size; | 649 | len -= size; |
641 | 650 | ||
642 | if (ofs >> cfi->chipshift) { | 651 | if (ofs >> cfi->chipshift) { |
643 | chipnum ++; | 652 | chipnum ++; |
644 | ofs = 0; | 653 | ofs = 0; |
645 | if (chipnum == cfi->numchips) | 654 | if (chipnum == cfi->numchips) |
646 | return 0; | 655 | return 0; |
647 | } | 656 | } |
648 | } | 657 | } |
649 | 658 | ||
650 | return 0; | 659 | return 0; |
651 | } | 660 | } |
652 | 661 | ||
@@ -756,7 +765,7 @@ retry: | |||
756 | status = map_read(map, adr); | 765 | status = map_read(map, adr); |
757 | if (map_word_andequal(map, status, status_OK, status_OK)) | 766 | if (map_word_andequal(map, status, status_OK, status_OK)) |
758 | break; | 767 | break; |
759 | 768 | ||
760 | /* Urgh. Chip not yet ready to talk to us. */ | 769 | /* Urgh. Chip not yet ready to talk to us. */ |
761 | if (time_after(jiffies, timeo)) { | 770 | if (time_after(jiffies, timeo)) { |
762 | spin_unlock_bh(chip->mutex); | 771 | spin_unlock_bh(chip->mutex); |
@@ -789,7 +798,7 @@ retry: | |||
789 | map_write(map, CMD(0x20), adr); | 798 | map_write(map, CMD(0x20), adr); |
790 | map_write(map, CMD(0xD0), adr); | 799 | map_write(map, CMD(0xD0), adr); |
791 | chip->state = FL_ERASING; | 800 | chip->state = FL_ERASING; |
792 | 801 | ||
793 | spin_unlock_bh(chip->mutex); | 802 | spin_unlock_bh(chip->mutex); |
794 | msleep(1000); | 803 | msleep(1000); |
795 | spin_lock_bh(chip->mutex); | 804 | spin_lock_bh(chip->mutex); |
@@ -814,7 +823,7 @@ retry: | |||
814 | status = map_read(map, adr); | 823 | status = map_read(map, adr); |
815 | if (map_word_andequal(map, status, status_OK, status_OK)) | 824 | if (map_word_andequal(map, status, status_OK, status_OK)) |
816 | break; | 825 | break; |
817 | 826 | ||
818 | /* OK Still waiting */ | 827 | /* OK Still waiting */ |
819 | if (time_after(jiffies, timeo)) { | 828 | if (time_after(jiffies, timeo)) { |
820 | map_write(map, CMD(0x70), adr); | 829 | map_write(map, CMD(0x70), adr); |
@@ -824,13 +833,13 @@ retry: | |||
824 | spin_unlock_bh(chip->mutex); | 833 | spin_unlock_bh(chip->mutex); |
825 | return -EIO; | 834 | return -EIO; |
826 | } | 835 | } |
827 | 836 | ||
828 | /* Latency issues. Drop the lock, wait a while and retry */ | 837 | /* Latency issues. Drop the lock, wait a while and retry */ |
829 | spin_unlock_bh(chip->mutex); | 838 | spin_unlock_bh(chip->mutex); |
830 | cfi_udelay(1); | 839 | cfi_udelay(1); |
831 | spin_lock_bh(chip->mutex); | 840 | spin_lock_bh(chip->mutex); |
832 | } | 841 | } |
833 | 842 | ||
834 | DISABLE_VPP(map); | 843 | DISABLE_VPP(map); |
835 | ret = 0; | 844 | ret = 0; |
836 | 845 | ||
@@ -855,7 +864,7 @@ retry: | |||
855 | /* Reset the error bits */ | 864 | /* Reset the error bits */ |
856 | map_write(map, CMD(0x50), adr); | 865 | map_write(map, CMD(0x50), adr); |
857 | map_write(map, CMD(0x70), adr); | 866 | map_write(map, CMD(0x70), adr); |
858 | 867 | ||
859 | if ((chipstatus & 0x30) == 0x30) { | 868 | if ((chipstatus & 0x30) == 0x30) { |
860 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); | 869 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); |
861 | ret = -EIO; | 870 | ret = -EIO; |
@@ -904,17 +913,17 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
904 | 913 | ||
905 | i = 0; | 914 | i = 0; |
906 | 915 | ||
907 | /* Skip all erase regions which are ended before the start of | 916 | /* Skip all erase regions which are ended before the start of |
908 | the requested erase. Actually, to save on the calculations, | 917 | the requested erase. Actually, to save on the calculations, |
909 | we skip to the first erase region which starts after the | 918 | we skip to the first erase region which starts after the |
910 | start of the requested erase, and then go back one. | 919 | start of the requested erase, and then go back one. |
911 | */ | 920 | */ |
912 | 921 | ||
913 | while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) | 922 | while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) |
914 | i++; | 923 | i++; |
915 | i--; | 924 | i--; |
916 | 925 | ||
917 | /* OK, now i is pointing at the erase region in which this | 926 | /* OK, now i is pointing at the erase region in which this |
918 | erase request starts. Check the start of the requested | 927 | erase request starts. Check the start of the requested |
919 | erase range is aligned with the erase size which is in | 928 | erase range is aligned with the erase size which is in |
920 | effect here. | 929 | effect here. |
@@ -937,7 +946,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
937 | the address actually falls | 946 | the address actually falls |
938 | */ | 947 | */ |
939 | i--; | 948 | i--; |
940 | 949 | ||
941 | if ((instr->addr + instr->len) & (regions[i].erasesize-1)) | 950 | if ((instr->addr + instr->len) & (regions[i].erasesize-1)) |
942 | return -EINVAL; | 951 | return -EINVAL; |
943 | 952 | ||
@@ -949,7 +958,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
949 | 958 | ||
950 | while(len) { | 959 | while(len) { |
951 | ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); | 960 | ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); |
952 | 961 | ||
953 | if (ret) | 962 | if (ret) |
954 | return ret; | 963 | return ret; |
955 | 964 | ||
@@ -962,15 +971,15 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
962 | if (adr >> cfi->chipshift) { | 971 | if (adr >> cfi->chipshift) { |
963 | adr = 0; | 972 | adr = 0; |
964 | chipnum++; | 973 | chipnum++; |
965 | 974 | ||
966 | if (chipnum >= cfi->numchips) | 975 | if (chipnum >= cfi->numchips) |
967 | break; | 976 | break; |
968 | } | 977 | } |
969 | } | 978 | } |
970 | 979 | ||
971 | instr->state = MTD_ERASE_DONE; | 980 | instr->state = MTD_ERASE_DONE; |
972 | mtd_erase_callback(instr); | 981 | mtd_erase_callback(instr); |
973 | 982 | ||
974 | return 0; | 983 | return 0; |
975 | } | 984 | } |
976 | 985 | ||
@@ -996,7 +1005,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
996 | case FL_JEDEC_QUERY: | 1005 | case FL_JEDEC_QUERY: |
997 | chip->oldstate = chip->state; | 1006 | chip->oldstate = chip->state; |
998 | chip->state = FL_SYNCING; | 1007 | chip->state = FL_SYNCING; |
999 | /* No need to wake_up() on this state change - | 1008 | /* No need to wake_up() on this state change - |
1000 | * as the whole point is that nobody can do anything | 1009 | * as the whole point is that nobody can do anything |
1001 | * with the chip now anyway. | 1010 | * with the chip now anyway. |
1002 | */ | 1011 | */ |
@@ -1007,11 +1016,11 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
1007 | default: | 1016 | default: |
1008 | /* Not an idle state */ | 1017 | /* Not an idle state */ |
1009 | add_wait_queue(&chip->wq, &wait); | 1018 | add_wait_queue(&chip->wq, &wait); |
1010 | 1019 | ||
1011 | spin_unlock_bh(chip->mutex); | 1020 | spin_unlock_bh(chip->mutex); |
1012 | schedule(); | 1021 | schedule(); |
1013 | remove_wait_queue(&chip->wq, &wait); | 1022 | remove_wait_queue(&chip->wq, &wait); |
1014 | 1023 | ||
1015 | goto retry; | 1024 | goto retry; |
1016 | } | 1025 | } |
1017 | } | 1026 | } |
@@ -1022,7 +1031,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
1022 | chip = &cfi->chips[i]; | 1031 | chip = &cfi->chips[i]; |
1023 | 1032 | ||
1024 | spin_lock_bh(chip->mutex); | 1033 | spin_lock_bh(chip->mutex); |
1025 | 1034 | ||
1026 | if (chip->state == FL_SYNCING) { | 1035 | if (chip->state == FL_SYNCING) { |
1027 | chip->state = chip->oldstate; | 1036 | chip->state = chip->oldstate; |
1028 | wake_up(&chip->wq); | 1037 | wake_up(&chip->wq); |
@@ -1057,9 +1066,9 @@ retry: | |||
1057 | 1066 | ||
1058 | case FL_STATUS: | 1067 | case FL_STATUS: |
1059 | status = map_read(map, adr); | 1068 | status = map_read(map, adr); |
1060 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1069 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1061 | break; | 1070 | break; |
1062 | 1071 | ||
1063 | /* Urgh. Chip not yet ready to talk to us. */ | 1072 | /* Urgh. Chip not yet ready to talk to us. */ |
1064 | if (time_after(jiffies, timeo)) { | 1073 | if (time_after(jiffies, timeo)) { |
1065 | spin_unlock_bh(chip->mutex); | 1074 | spin_unlock_bh(chip->mutex); |
@@ -1088,7 +1097,7 @@ retry: | |||
1088 | map_write(map, CMD(0x60), adr); | 1097 | map_write(map, CMD(0x60), adr); |
1089 | map_write(map, CMD(0x01), adr); | 1098 | map_write(map, CMD(0x01), adr); |
1090 | chip->state = FL_LOCKING; | 1099 | chip->state = FL_LOCKING; |
1091 | 1100 | ||
1092 | spin_unlock_bh(chip->mutex); | 1101 | spin_unlock_bh(chip->mutex); |
1093 | msleep(1000); | 1102 | msleep(1000); |
1094 | spin_lock_bh(chip->mutex); | 1103 | spin_lock_bh(chip->mutex); |
@@ -1102,7 +1111,7 @@ retry: | |||
1102 | status = map_read(map, adr); | 1111 | status = map_read(map, adr); |
1103 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1112 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1104 | break; | 1113 | break; |
1105 | 1114 | ||
1106 | /* OK Still waiting */ | 1115 | /* OK Still waiting */ |
1107 | if (time_after(jiffies, timeo)) { | 1116 | if (time_after(jiffies, timeo)) { |
1108 | map_write(map, CMD(0x70), adr); | 1117 | map_write(map, CMD(0x70), adr); |
@@ -1112,13 +1121,13 @@ retry: | |||
1112 | spin_unlock_bh(chip->mutex); | 1121 | spin_unlock_bh(chip->mutex); |
1113 | return -EIO; | 1122 | return -EIO; |
1114 | } | 1123 | } |
1115 | 1124 | ||
1116 | /* Latency issues. Drop the lock, wait a while and retry */ | 1125 | /* Latency issues. Drop the lock, wait a while and retry */ |
1117 | spin_unlock_bh(chip->mutex); | 1126 | spin_unlock_bh(chip->mutex); |
1118 | cfi_udelay(1); | 1127 | cfi_udelay(1); |
1119 | spin_lock_bh(chip->mutex); | 1128 | spin_lock_bh(chip->mutex); |
1120 | } | 1129 | } |
1121 | 1130 | ||
1122 | /* Done and happy. */ | 1131 | /* Done and happy. */ |
1123 | chip->state = FL_STATUS; | 1132 | chip->state = FL_STATUS; |
1124 | DISABLE_VPP(map); | 1133 | DISABLE_VPP(map); |
@@ -1162,8 +1171,8 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1162 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1171 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1163 | printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); | 1172 | printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); |
1164 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1173 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1165 | #endif | 1174 | #endif |
1166 | 1175 | ||
1167 | if (ret) | 1176 | if (ret) |
1168 | return ret; | 1177 | return ret; |
1169 | 1178 | ||
@@ -1173,7 +1182,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1173 | if (adr >> cfi->chipshift) { | 1182 | if (adr >> cfi->chipshift) { |
1174 | adr = 0; | 1183 | adr = 0; |
1175 | chipnum++; | 1184 | chipnum++; |
1176 | 1185 | ||
1177 | if (chipnum >= cfi->numchips) | 1186 | if (chipnum >= cfi->numchips) |
1178 | break; | 1187 | break; |
1179 | } | 1188 | } |
@@ -1208,7 +1217,7 @@ retry: | |||
1208 | status = map_read(map, adr); | 1217 | status = map_read(map, adr); |
1209 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1218 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1210 | break; | 1219 | break; |
1211 | 1220 | ||
1212 | /* Urgh. Chip not yet ready to talk to us. */ | 1221 | /* Urgh. Chip not yet ready to talk to us. */ |
1213 | if (time_after(jiffies, timeo)) { | 1222 | if (time_after(jiffies, timeo)) { |
1214 | spin_unlock_bh(chip->mutex); | 1223 | spin_unlock_bh(chip->mutex); |
@@ -1237,7 +1246,7 @@ retry: | |||
1237 | map_write(map, CMD(0x60), adr); | 1246 | map_write(map, CMD(0x60), adr); |
1238 | map_write(map, CMD(0xD0), adr); | 1247 | map_write(map, CMD(0xD0), adr); |
1239 | chip->state = FL_UNLOCKING; | 1248 | chip->state = FL_UNLOCKING; |
1240 | 1249 | ||
1241 | spin_unlock_bh(chip->mutex); | 1250 | spin_unlock_bh(chip->mutex); |
1242 | msleep(1000); | 1251 | msleep(1000); |
1243 | spin_lock_bh(chip->mutex); | 1252 | spin_lock_bh(chip->mutex); |
@@ -1251,7 +1260,7 @@ retry: | |||
1251 | status = map_read(map, adr); | 1260 | status = map_read(map, adr); |
1252 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1261 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1253 | break; | 1262 | break; |
1254 | 1263 | ||
1255 | /* OK Still waiting */ | 1264 | /* OK Still waiting */ |
1256 | if (time_after(jiffies, timeo)) { | 1265 | if (time_after(jiffies, timeo)) { |
1257 | map_write(map, CMD(0x70), adr); | 1266 | map_write(map, CMD(0x70), adr); |
@@ -1261,13 +1270,13 @@ retry: | |||
1261 | spin_unlock_bh(chip->mutex); | 1270 | spin_unlock_bh(chip->mutex); |
1262 | return -EIO; | 1271 | return -EIO; |
1263 | } | 1272 | } |
1264 | 1273 | ||
1265 | /* Latency issues. Drop the unlock, wait a while and retry */ | 1274 | /* Latency issues. Drop the unlock, wait a while and retry */ |
1266 | spin_unlock_bh(chip->mutex); | 1275 | spin_unlock_bh(chip->mutex); |
1267 | cfi_udelay(1); | 1276 | cfi_udelay(1); |
1268 | spin_lock_bh(chip->mutex); | 1277 | spin_lock_bh(chip->mutex); |
1269 | } | 1278 | } |
1270 | 1279 | ||
1271 | /* Done and happy. */ | 1280 | /* Done and happy. */ |
1272 | chip->state = FL_STATUS; | 1281 | chip->state = FL_STATUS; |
1273 | DISABLE_VPP(map); | 1282 | DISABLE_VPP(map); |
@@ -1292,7 +1301,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1292 | { | 1301 | { |
1293 | unsigned long temp_adr = adr; | 1302 | unsigned long temp_adr = adr; |
1294 | unsigned long temp_len = len; | 1303 | unsigned long temp_len = len; |
1295 | 1304 | ||
1296 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1305 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1297 | while (temp_len) { | 1306 | while (temp_len) { |
1298 | printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); | 1307 | printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); |
@@ -1310,7 +1319,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1310 | printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); | 1319 | printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); |
1311 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1320 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1312 | #endif | 1321 | #endif |
1313 | 1322 | ||
1314 | return ret; | 1323 | return ret; |
1315 | } | 1324 | } |
1316 | 1325 | ||
@@ -1334,7 +1343,7 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1334 | case FL_JEDEC_QUERY: | 1343 | case FL_JEDEC_QUERY: |
1335 | chip->oldstate = chip->state; | 1344 | chip->oldstate = chip->state; |
1336 | chip->state = FL_PM_SUSPENDED; | 1345 | chip->state = FL_PM_SUSPENDED; |
1337 | /* No need to wake_up() on this state change - | 1346 | /* No need to wake_up() on this state change - |
1338 | * as the whole point is that nobody can do anything | 1347 | * as the whole point is that nobody can do anything |
1339 | * with the chip now anyway. | 1348 | * with the chip now anyway. |
1340 | */ | 1349 | */ |
@@ -1353,9 +1362,9 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1353 | if (ret) { | 1362 | if (ret) { |
1354 | for (i--; i >=0; i--) { | 1363 | for (i--; i >=0; i--) { |
1355 | chip = &cfi->chips[i]; | 1364 | chip = &cfi->chips[i]; |
1356 | 1365 | ||
1357 | spin_lock_bh(chip->mutex); | 1366 | spin_lock_bh(chip->mutex); |
1358 | 1367 | ||
1359 | if (chip->state == FL_PM_SUSPENDED) { | 1368 | if (chip->state == FL_PM_SUSPENDED) { |
1360 | /* No need to force it into a known state here, | 1369 | /* No need to force it into a known state here, |
1361 | because we're returning failure, and it didn't | 1370 | because we're returning failure, and it didn't |
@@ -1365,8 +1374,8 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1365 | } | 1374 | } |
1366 | spin_unlock_bh(chip->mutex); | 1375 | spin_unlock_bh(chip->mutex); |
1367 | } | 1376 | } |
1368 | } | 1377 | } |
1369 | 1378 | ||
1370 | return ret; | 1379 | return ret; |
1371 | } | 1380 | } |
1372 | 1381 | ||
@@ -1378,11 +1387,11 @@ static void cfi_staa_resume(struct mtd_info *mtd) | |||
1378 | struct flchip *chip; | 1387 | struct flchip *chip; |
1379 | 1388 | ||
1380 | for (i=0; i<cfi->numchips; i++) { | 1389 | for (i=0; i<cfi->numchips; i++) { |
1381 | 1390 | ||
1382 | chip = &cfi->chips[i]; | 1391 | chip = &cfi->chips[i]; |
1383 | 1392 | ||
1384 | spin_lock_bh(chip->mutex); | 1393 | spin_lock_bh(chip->mutex); |
1385 | 1394 | ||
1386 | /* Go to known state. Chip may have been power cycled */ | 1395 | /* Go to known state. Chip may have been power cycled */ |
1387 | if (chip->state == FL_PM_SUSPENDED) { | 1396 | if (chip->state == FL_PM_SUSPENDED) { |
1388 | map_write(map, CMD(0xFF), 0); | 1397 | map_write(map, CMD(0xFF), 0); |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index cf750038ce6a..90eb30e06b7c 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
4 | $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $ | 4 | $Id: cfi_probe.c,v 1.84 2005/11/07 11:14:23 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/mtd/cfi.h> | 20 | #include <linux/mtd/cfi.h> |
21 | #include <linux/mtd/gen_probe.h> | 21 | #include <linux/mtd/gen_probe.h> |
22 | 22 | ||
23 | //#define DEBUG_CFI | 23 | //#define DEBUG_CFI |
24 | 24 | ||
25 | #ifdef DEBUG_CFI | 25 | #ifdef DEBUG_CFI |
26 | static void print_cfi_ident(struct cfi_ident *); | 26 | static void print_cfi_ident(struct cfi_ident *); |
@@ -103,7 +103,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
103 | unsigned long *chip_map, struct cfi_private *cfi) | 103 | unsigned long *chip_map, struct cfi_private *cfi) |
104 | { | 104 | { |
105 | int i; | 105 | int i; |
106 | 106 | ||
107 | if ((base + 0) >= map->size) { | 107 | if ((base + 0) >= map->size) { |
108 | printk(KERN_NOTICE | 108 | printk(KERN_NOTICE |
109 | "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", | 109 | "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", |
@@ -128,7 +128,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
128 | } | 128 | } |
129 | 129 | ||
130 | if (!cfi->numchips) { | 130 | if (!cfi->numchips) { |
131 | /* This is the first time we're called. Set up the CFI | 131 | /* This is the first time we're called. Set up the CFI |
132 | stuff accordingly and return */ | 132 | stuff accordingly and return */ |
133 | return cfi_chip_setup(map, cfi); | 133 | return cfi_chip_setup(map, cfi); |
134 | } | 134 | } |
@@ -138,13 +138,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
138 | unsigned long start; | 138 | unsigned long start; |
139 | if(!test_bit(i, chip_map)) { | 139 | if(!test_bit(i, chip_map)) { |
140 | /* Skip location; no valid chip at this address */ | 140 | /* Skip location; no valid chip at this address */ |
141 | continue; | 141 | continue; |
142 | } | 142 | } |
143 | start = i << cfi->chipshift; | 143 | start = i << cfi->chipshift; |
144 | /* This chip should be in read mode if it's one | 144 | /* This chip should be in read mode if it's one |
145 | we've already touched. */ | 145 | we've already touched. */ |
146 | if (qry_present(map, start, cfi)) { | 146 | if (qry_present(map, start, cfi)) { |
147 | /* Eep. This chip also had the QRY marker. | 147 | /* Eep. This chip also had the QRY marker. |
148 | * Is it an alias for the new one? */ | 148 | * Is it an alias for the new one? */ |
149 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); | 149 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); |
150 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | 150 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); |
@@ -156,13 +156,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
156 | map->name, base, start); | 156 | map->name, base, start); |
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | /* Yes, it's actually got QRY for data. Most | 159 | /* Yes, it's actually got QRY for data. Most |
160 | * unfortunate. Stick the new chip in read mode | 160 | * unfortunate. Stick the new chip in read mode |
161 | * too and if it's the same, assume it's an alias. */ | 161 | * too and if it's the same, assume it's an alias. */ |
162 | /* FIXME: Use other modes to do a proper check */ | 162 | /* FIXME: Use other modes to do a proper check */ |
163 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 163 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
164 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | 164 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); |
165 | 165 | ||
166 | if (qry_present(map, base, cfi)) { | 166 | if (qry_present(map, base, cfi)) { |
167 | xip_allowed(base, map); | 167 | xip_allowed(base, map); |
168 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", | 168 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", |
@@ -171,12 +171,12 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
171 | } | 171 | } |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | /* OK, if we got to here, then none of the previous chips appear to | 175 | /* OK, if we got to here, then none of the previous chips appear to |
176 | be aliases for the current one. */ | 176 | be aliases for the current one. */ |
177 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ | 177 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ |
178 | cfi->numchips++; | 178 | cfi->numchips++; |
179 | 179 | ||
180 | /* Put it back into Read Mode */ | 180 | /* Put it back into Read Mode */ |
181 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 181 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
182 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | 182 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); |
@@ -185,11 +185,11 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
185 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 185 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
186 | map->name, cfi->interleave, cfi->device_type*8, base, | 186 | map->name, cfi->interleave, cfi->device_type*8, base, |
187 | map->bankwidth*8); | 187 | map->bankwidth*8); |
188 | 188 | ||
189 | return 1; | 189 | return 1; |
190 | } | 190 | } |
191 | 191 | ||
192 | static int __xipram cfi_chip_setup(struct map_info *map, | 192 | static int __xipram cfi_chip_setup(struct map_info *map, |
193 | struct cfi_private *cfi) | 193 | struct cfi_private *cfi) |
194 | { | 194 | { |
195 | int ofs_factor = cfi->interleave*cfi->device_type; | 195 | int ofs_factor = cfi->interleave*cfi->device_type; |
@@ -209,11 +209,11 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
209 | printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); | 209 | printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); |
210 | return 0; | 210 | return 0; |
211 | } | 211 | } |
212 | 212 | ||
213 | memset(cfi->cfiq,0,sizeof(struct cfi_ident)); | 213 | memset(cfi->cfiq,0,sizeof(struct cfi_ident)); |
214 | 214 | ||
215 | cfi->cfi_mode = CFI_MODE_CFI; | 215 | cfi->cfi_mode = CFI_MODE_CFI; |
216 | 216 | ||
217 | /* Read the CFI info structure */ | 217 | /* Read the CFI info structure */ |
218 | xip_disable_qry(base, map, cfi); | 218 | xip_disable_qry(base, map, cfi); |
219 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) | 219 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) |
@@ -231,7 +231,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
231 | cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); | 231 | cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); |
232 | cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); | 232 | cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); |
233 | cfi->mfr = cfi_read_query(map, base); | 233 | cfi->mfr = cfi_read_query(map, base); |
234 | cfi->id = cfi_read_query(map, base + ofs_factor); | 234 | cfi->id = cfi_read_query(map, base + ofs_factor); |
235 | 235 | ||
236 | /* Put it back into Read Mode */ | 236 | /* Put it back into Read Mode */ |
237 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 237 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
@@ -255,10 +255,10 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
255 | 255 | ||
256 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 256 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
257 | cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); | 257 | cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); |
258 | 258 | ||
259 | #ifdef DEBUG_CFI | 259 | #ifdef DEBUG_CFI |
260 | printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", | 260 | printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", |
261 | i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, | 261 | i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, |
262 | (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); | 262 | (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); |
263 | #endif | 263 | #endif |
264 | } | 264 | } |
@@ -271,33 +271,33 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
271 | } | 271 | } |
272 | 272 | ||
273 | #ifdef DEBUG_CFI | 273 | #ifdef DEBUG_CFI |
274 | static char *vendorname(__u16 vendor) | 274 | static char *vendorname(__u16 vendor) |
275 | { | 275 | { |
276 | switch (vendor) { | 276 | switch (vendor) { |
277 | case P_ID_NONE: | 277 | case P_ID_NONE: |
278 | return "None"; | 278 | return "None"; |
279 | 279 | ||
280 | case P_ID_INTEL_EXT: | 280 | case P_ID_INTEL_EXT: |
281 | return "Intel/Sharp Extended"; | 281 | return "Intel/Sharp Extended"; |
282 | 282 | ||
283 | case P_ID_AMD_STD: | 283 | case P_ID_AMD_STD: |
284 | return "AMD/Fujitsu Standard"; | 284 | return "AMD/Fujitsu Standard"; |
285 | 285 | ||
286 | case P_ID_INTEL_STD: | 286 | case P_ID_INTEL_STD: |
287 | return "Intel/Sharp Standard"; | 287 | return "Intel/Sharp Standard"; |
288 | 288 | ||
289 | case P_ID_AMD_EXT: | 289 | case P_ID_AMD_EXT: |
290 | return "AMD/Fujitsu Extended"; | 290 | return "AMD/Fujitsu Extended"; |
291 | 291 | ||
292 | case P_ID_WINBOND: | 292 | case P_ID_WINBOND: |
293 | return "Winbond Standard"; | 293 | return "Winbond Standard"; |
294 | 294 | ||
295 | case P_ID_ST_ADV: | 295 | case P_ID_ST_ADV: |
296 | return "ST Advanced"; | 296 | return "ST Advanced"; |
297 | 297 | ||
298 | case P_ID_MITSUBISHI_STD: | 298 | case P_ID_MITSUBISHI_STD: |
299 | return "Mitsubishi Standard"; | 299 | return "Mitsubishi Standard"; |
300 | 300 | ||
301 | case P_ID_MITSUBISHI_EXT: | 301 | case P_ID_MITSUBISHI_EXT: |
302 | return "Mitsubishi Extended"; | 302 | return "Mitsubishi Extended"; |
303 | 303 | ||
@@ -306,13 +306,13 @@ static char *vendorname(__u16 vendor) | |||
306 | 306 | ||
307 | case P_ID_INTEL_PERFORMANCE: | 307 | case P_ID_INTEL_PERFORMANCE: |
308 | return "Intel Performance Code"; | 308 | return "Intel Performance Code"; |
309 | 309 | ||
310 | case P_ID_INTEL_DATA: | 310 | case P_ID_INTEL_DATA: |
311 | return "Intel Data"; | 311 | return "Intel Data"; |
312 | 312 | ||
313 | case P_ID_RESERVED: | 313 | case P_ID_RESERVED: |
314 | return "Not Allowed / Reserved for Future Use"; | 314 | return "Not Allowed / Reserved for Future Use"; |
315 | 315 | ||
316 | default: | 316 | default: |
317 | return "Unknown"; | 317 | return "Unknown"; |
318 | } | 318 | } |
@@ -325,21 +325,21 @@ static void print_cfi_ident(struct cfi_ident *cfip) | |||
325 | if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { | 325 | if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { |
326 | printk("Invalid CFI ident structure.\n"); | 326 | printk("Invalid CFI ident structure.\n"); |
327 | return; | 327 | return; |
328 | } | 328 | } |
329 | #endif | 329 | #endif |
330 | printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); | 330 | printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); |
331 | if (cfip->P_ADR) | 331 | if (cfip->P_ADR) |
332 | printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); | 332 | printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); |
333 | else | 333 | else |
334 | printk("No Primary Algorithm Table\n"); | 334 | printk("No Primary Algorithm Table\n"); |
335 | 335 | ||
336 | printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); | 336 | printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); |
337 | if (cfip->A_ADR) | 337 | if (cfip->A_ADR) |
338 | printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); | 338 | printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); |
339 | else | 339 | else |
340 | printk("No Alternate Algorithm Table\n"); | 340 | printk("No Alternate Algorithm Table\n"); |
341 | 341 | ||
342 | 342 | ||
343 | printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); | 343 | printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); |
344 | printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); | 344 | printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); |
345 | if (cfip->VppMin) { | 345 | if (cfip->VppMin) { |
@@ -348,61 +348,61 @@ static void print_cfi_ident(struct cfi_ident *cfip) | |||
348 | } | 348 | } |
349 | else | 349 | else |
350 | printk("No Vpp line\n"); | 350 | printk("No Vpp line\n"); |
351 | 351 | ||
352 | printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp); | 352 | printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp); |
353 | printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp)); | 353 | printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp)); |
354 | 354 | ||
355 | if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { | 355 | if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { |
356 | printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp); | 356 | printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp); |
357 | printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp)); | 357 | printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp)); |
358 | } | 358 | } |
359 | else | 359 | else |
360 | printk("Full buffer write not supported\n"); | 360 | printk("Full buffer write not supported\n"); |
361 | 361 | ||
362 | printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp); | 362 | printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp); |
363 | printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); | 363 | printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); |
364 | if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { | 364 | if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { |
365 | printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); | 365 | printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); |
366 | printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); | 366 | printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); |
367 | } | 367 | } |
368 | else | 368 | else |
369 | printk("Chip erase not supported\n"); | 369 | printk("Chip erase not supported\n"); |
370 | 370 | ||
371 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); | 371 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); |
372 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); | 372 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); |
373 | switch(cfip->InterfaceDesc) { | 373 | switch(cfip->InterfaceDesc) { |
374 | case 0: | 374 | case 0: |
375 | printk(" - x8-only asynchronous interface\n"); | 375 | printk(" - x8-only asynchronous interface\n"); |
376 | break; | 376 | break; |
377 | 377 | ||
378 | case 1: | 378 | case 1: |
379 | printk(" - x16-only asynchronous interface\n"); | 379 | printk(" - x16-only asynchronous interface\n"); |
380 | break; | 380 | break; |
381 | 381 | ||
382 | case 2: | 382 | case 2: |
383 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); | 383 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); |
384 | break; | 384 | break; |
385 | 385 | ||
386 | case 3: | 386 | case 3: |
387 | printk(" - x32-only asynchronous interface\n"); | 387 | printk(" - x32-only asynchronous interface\n"); |
388 | break; | 388 | break; |
389 | 389 | ||
390 | case 4: | 390 | case 4: |
391 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); | 391 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); |
392 | break; | 392 | break; |
393 | 393 | ||
394 | case 65535: | 394 | case 65535: |
395 | printk(" - Not Allowed / Reserved\n"); | 395 | printk(" - Not Allowed / Reserved\n"); |
396 | break; | 396 | break; |
397 | 397 | ||
398 | default: | 398 | default: |
399 | printk(" - Unknown\n"); | 399 | printk(" - Unknown\n"); |
400 | break; | 400 | break; |
401 | } | 401 | } |
402 | 402 | ||
403 | printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); | 403 | printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); |
404 | printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); | 404 | printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); |
405 | 405 | ||
406 | } | 406 | } |
407 | #endif /* DEBUG_CFI */ | 407 | #endif /* DEBUG_CFI */ |
408 | 408 | ||
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 2b2ede2bfcca..d8e7a026ba5a 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * This code is covered by the GPL. | 8 | * This code is covered by the GPL. |
9 | * | 9 | * |
10 | * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $ | 10 | * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -56,7 +56,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
56 | 56 | ||
57 | /* Read in the Extended Query Table */ | 57 | /* Read in the Extended Query Table */ |
58 | for (i=0; i<size; i++) { | 58 | for (i=0; i<size; i++) { |
59 | ((unsigned char *)extp)[i] = | 59 | ((unsigned char *)extp)[i] = |
60 | cfi_read_query(map, base+((adr+i)*ofs_factor)); | 60 | cfi_read_query(map, base+((adr+i)*ofs_factor)); |
61 | } | 61 | } |
62 | 62 | ||
@@ -70,15 +70,6 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
70 | local_irq_enable(); | 70 | local_irq_enable(); |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | if (extp->MajorVersion != '1' || | ||
74 | (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { | ||
75 | printk(KERN_WARNING " Unknown %s Extended Query " | ||
76 | "version %c.%c.\n", name, extp->MajorVersion, | ||
77 | extp->MinorVersion); | ||
78 | kfree(extp); | ||
79 | extp = NULL; | ||
80 | } | ||
81 | |||
82 | out: return extp; | 73 | out: return extp; |
83 | } | 74 | } |
84 | 75 | ||
@@ -122,17 +113,17 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
122 | 113 | ||
123 | i = 0; | 114 | i = 0; |
124 | 115 | ||
125 | /* Skip all erase regions which are ended before the start of | 116 | /* Skip all erase regions which are ended before the start of |
126 | the requested erase. Actually, to save on the calculations, | 117 | the requested erase. Actually, to save on the calculations, |
127 | we skip to the first erase region which starts after the | 118 | we skip to the first erase region which starts after the |
128 | start of the requested erase, and then go back one. | 119 | start of the requested erase, and then go back one. |
129 | */ | 120 | */ |
130 | 121 | ||
131 | while (i < mtd->numeraseregions && ofs >= regions[i].offset) | 122 | while (i < mtd->numeraseregions && ofs >= regions[i].offset) |
132 | i++; | 123 | i++; |
133 | i--; | 124 | i--; |
134 | 125 | ||
135 | /* OK, now i is pointing at the erase region in which this | 126 | /* OK, now i is pointing at the erase region in which this |
136 | erase request starts. Check the start of the requested | 127 | erase request starts. Check the start of the requested |
137 | erase range is aligned with the erase size which is in | 128 | erase range is aligned with the erase size which is in |
138 | effect here. | 129 | effect here. |
@@ -155,7 +146,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
155 | the address actually falls | 146 | the address actually falls |
156 | */ | 147 | */ |
157 | i--; | 148 | i--; |
158 | 149 | ||
159 | if ((ofs + len) & (regions[i].erasesize-1)) | 150 | if ((ofs + len) & (regions[i].erasesize-1)) |
160 | return -EINVAL; | 151 | return -EINVAL; |
161 | 152 | ||
@@ -168,7 +159,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
168 | int size = regions[i].erasesize; | 159 | int size = regions[i].erasesize; |
169 | 160 | ||
170 | ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); | 161 | ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); |
171 | 162 | ||
172 | if (ret) | 163 | if (ret) |
173 | return ret; | 164 | return ret; |
174 | 165 | ||
@@ -182,7 +173,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
182 | if (adr >> cfi->chipshift) { | 173 | if (adr >> cfi->chipshift) { |
183 | adr = 0; | 174 | adr = 0; |
184 | chipnum++; | 175 | chipnum++; |
185 | 176 | ||
186 | if (chipnum >= cfi->numchips) | 177 | if (chipnum >= cfi->numchips) |
187 | break; | 178 | break; |
188 | } | 179 | } |
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index d7d739a108ae..c2127840a183 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c | |||
@@ -41,7 +41,7 @@ static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) | |||
41 | 41 | ||
42 | list_for_each(pos, &chip_drvs_list) { | 42 | list_for_each(pos, &chip_drvs_list) { |
43 | this = list_entry(pos, typeof(*this), list); | 43 | this = list_entry(pos, typeof(*this), list); |
44 | 44 | ||
45 | if (!strcmp(this->name, name)) { | 45 | if (!strcmp(this->name, name)) { |
46 | ret = this; | 46 | ret = this; |
47 | break; | 47 | break; |
@@ -73,7 +73,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) | |||
73 | 73 | ||
74 | ret = drv->probe(map); | 74 | ret = drv->probe(map); |
75 | 75 | ||
76 | /* We decrease the use count here. It may have been a | 76 | /* We decrease the use count here. It may have been a |
77 | probe-only module, which is no longer required from this | 77 | probe-only module, which is no longer required from this |
78 | point, having given us a handle on (and increased the use | 78 | point, having given us a handle on (and increased the use |
79 | count of) the actual driver code. | 79 | count of) the actual driver code. |
@@ -82,7 +82,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) | |||
82 | 82 | ||
83 | if (ret) | 83 | if (ret) |
84 | return ret; | 84 | return ret; |
85 | 85 | ||
86 | return NULL; | 86 | return NULL; |
87 | } | 87 | } |
88 | /* | 88 | /* |
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index e1a5b76596c5..77303ce5dcf1 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h | |||
@@ -25,7 +25,7 @@ struct fwh_xxlock_thunk { | |||
25 | * so this code has not been tested with interleaved chips, | 25 | * so this code has not been tested with interleaved chips, |
26 | * and will likely fail in that context. | 26 | * and will likely fail in that context. |
27 | */ | 27 | */ |
28 | static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, | 28 | static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, |
29 | unsigned long adr, int len, void *thunk) | 29 | unsigned long adr, int len, void *thunk) |
30 | { | 30 | { |
31 | struct cfi_private *cfi = map->fldrv_priv; | 31 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -44,7 +44,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, | |||
44 | * - on 64k boundariesand | 44 | * - on 64k boundariesand |
45 | * - bit 1 set high | 45 | * - bit 1 set high |
46 | * - block lock registers are 4MiB lower - overflow subtract (danger) | 46 | * - block lock registers are 4MiB lower - overflow subtract (danger) |
47 | * | 47 | * |
48 | * The address manipulation is first done on the logical address | 48 | * The address manipulation is first done on the logical address |
49 | * which is 0 at the start of the chip, and then the offset of | 49 | * which is 0 at the start of the chip, and then the offset of |
50 | * the individual chip is addted to it. Any other order a weird | 50 | * the individual chip is addted to it. Any other order a weird |
@@ -93,7 +93,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
93 | 93 | ||
94 | ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, | 94 | ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, |
95 | (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); | 95 | (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); |
96 | 96 | ||
97 | return ret; | 97 | return ret; |
98 | } | 98 | } |
99 | 99 | ||
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index dc065b22f79e..41bd59d20d85 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Routines common to all CFI-type probes. | 2 | * Routines common to all CFI-type probes. |
3 | * (C) 2001-2003 Red Hat, Inc. | 3 | * (C) 2001-2003 Red Hat, Inc. |
4 | * GPL'd | 4 | * GPL'd |
5 | * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ | 5 | * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
@@ -26,7 +26,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) | |||
26 | 26 | ||
27 | /* First probe the map to see if we have CFI stuff there. */ | 27 | /* First probe the map to see if we have CFI stuff there. */ |
28 | cfi = genprobe_ident_chips(map, cp); | 28 | cfi = genprobe_ident_chips(map, cp); |
29 | 29 | ||
30 | if (!cfi) | 30 | if (!cfi) |
31 | return NULL; | 31 | return NULL; |
32 | 32 | ||
@@ -36,12 +36,12 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) | |||
36 | mtd = check_cmd_set(map, 1); /* First the primary cmdset */ | 36 | mtd = check_cmd_set(map, 1); /* First the primary cmdset */ |
37 | if (!mtd) | 37 | if (!mtd) |
38 | mtd = check_cmd_set(map, 0); /* Then the secondary */ | 38 | mtd = check_cmd_set(map, 0); /* Then the secondary */ |
39 | 39 | ||
40 | if (mtd) | 40 | if (mtd) |
41 | return mtd; | 41 | return mtd; |
42 | 42 | ||
43 | printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); | 43 | printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); |
44 | 44 | ||
45 | kfree(cfi->cfiq); | 45 | kfree(cfi->cfiq); |
46 | kfree(cfi); | 46 | kfree(cfi); |
47 | map->fldrv_priv = NULL; | 47 | map->fldrv_priv = NULL; |
@@ -60,14 +60,14 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
60 | 60 | ||
61 | memset(&cfi, 0, sizeof(cfi)); | 61 | memset(&cfi, 0, sizeof(cfi)); |
62 | 62 | ||
63 | /* Call the probetype-specific code with all permutations of | 63 | /* Call the probetype-specific code with all permutations of |
64 | interleave and device type, etc. */ | 64 | interleave and device type, etc. */ |
65 | if (!genprobe_new_chip(map, cp, &cfi)) { | 65 | if (!genprobe_new_chip(map, cp, &cfi)) { |
66 | /* The probe didn't like it */ | 66 | /* The probe didn't like it */ |
67 | printk(KERN_DEBUG "%s: Found no %s device at location zero\n", | 67 | printk(KERN_DEBUG "%s: Found no %s device at location zero\n", |
68 | cp->name, map->name); | 68 | cp->name, map->name); |
69 | return NULL; | 69 | return NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD | 72 | #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD |
73 | probe routines won't ever return a broken CFI structure anyway, | 73 | probe routines won't ever return a broken CFI structure anyway, |
@@ -92,13 +92,13 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
92 | } else { | 92 | } else { |
93 | BUG(); | 93 | BUG(); |
94 | } | 94 | } |
95 | 95 | ||
96 | cfi.numchips = 1; | 96 | cfi.numchips = 1; |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Allocate memory for bitmap of valid chips. | 99 | * Allocate memory for bitmap of valid chips. |
100 | * Align bitmap storage size to full byte. | 100 | * Align bitmap storage size to full byte. |
101 | */ | 101 | */ |
102 | max_chips = map->size >> cfi.chipshift; | 102 | max_chips = map->size >> cfi.chipshift; |
103 | mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); | 103 | mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); |
104 | chip_map = kmalloc(mapsize, GFP_KERNEL); | 104 | chip_map = kmalloc(mapsize, GFP_KERNEL); |
@@ -122,7 +122,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
122 | } | 122 | } |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * Now allocate the space for the structures we need to return to | 125 | * Now allocate the space for the structures we need to return to |
126 | * our caller, and copy the appropriate data into them. | 126 | * our caller, and copy the appropriate data into them. |
127 | */ | 127 | */ |
128 | 128 | ||
@@ -154,7 +154,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
154 | return retcfi; | 154 | return retcfi; |
155 | } | 155 | } |
156 | 156 | ||
157 | 157 | ||
158 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, | 158 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, |
159 | struct cfi_private *cfi) | 159 | struct cfi_private *cfi) |
160 | { | 160 | { |
@@ -189,7 +189,7 @@ extern cfi_cmdset_fn_t cfi_cmdset_0001; | |||
189 | extern cfi_cmdset_fn_t cfi_cmdset_0002; | 189 | extern cfi_cmdset_fn_t cfi_cmdset_0002; |
190 | extern cfi_cmdset_fn_t cfi_cmdset_0020; | 190 | extern cfi_cmdset_fn_t cfi_cmdset_0020; |
191 | 191 | ||
192 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, | 192 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, |
193 | int primary) | 193 | int primary) |
194 | { | 194 | { |
195 | struct cfi_private *cfi = map->fldrv_priv; | 195 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -199,7 +199,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, | |||
199 | cfi_cmdset_fn_t *probe_function; | 199 | cfi_cmdset_fn_t *probe_function; |
200 | 200 | ||
201 | sprintf(probename, "cfi_cmdset_%4.4X", type); | 201 | sprintf(probename, "cfi_cmdset_%4.4X", type); |
202 | 202 | ||
203 | probe_function = inter_module_get_request(probename, probename); | 203 | probe_function = inter_module_get_request(probename, probename); |
204 | 204 | ||
205 | if (probe_function) { | 205 | if (probe_function) { |
@@ -221,7 +221,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |||
221 | { | 221 | { |
222 | struct cfi_private *cfi = map->fldrv_priv; | 222 | struct cfi_private *cfi = map->fldrv_priv; |
223 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | 223 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; |
224 | 224 | ||
225 | if (type == P_ID_NONE || type == P_ID_RESERVED) | 225 | if (type == P_ID_NONE || type == P_ID_RESERVED) |
226 | return NULL; | 226 | return NULL; |
227 | 227 | ||
@@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |||
235 | #ifdef CONFIG_MTD_CFI_INTELEXT | 235 | #ifdef CONFIG_MTD_CFI_INTELEXT |
236 | case 0x0001: | 236 | case 0x0001: |
237 | case 0x0003: | 237 | case 0x0003: |
238 | case 0x0200: | ||
238 | return cfi_cmdset_0001(map, primary); | 239 | return cfi_cmdset_0001(map, primary); |
239 | #endif | 240 | #endif |
240 | #ifdef CONFIG_MTD_CFI_AMDSTD | 241 | #ifdef CONFIG_MTD_CFI_AMDSTD |
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 4f6778f3ee3e..c40b48dabed3 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c | |||
@@ -1,6 +1,6 @@ | |||
1 | 1 | ||
2 | /* JEDEC Flash Interface. | 2 | /* JEDEC Flash Interface. |
3 | * This is an older type of interface for self programming flash. It is | 3 | * This is an older type of interface for self programming flash. It is |
4 | * commonly use in older AMD chips and is obsolete compared with CFI. | 4 | * commonly use in older AMD chips and is obsolete compared with CFI. |
5 | * It is called JEDEC because the JEDEC association distributes the ID codes | 5 | * It is called JEDEC because the JEDEC association distributes the ID codes |
6 | * for the chips. | 6 | * for the chips. |
@@ -88,9 +88,9 @@ static const struct JEDECTable JEDEC_table[] = { | |||
88 | 88 | ||
89 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); | 89 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); |
90 | static void jedec_sync(struct mtd_info *mtd) {}; | 90 | static void jedec_sync(struct mtd_info *mtd) {}; |
91 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | 91 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, |
92 | size_t *retlen, u_char *buf); | 92 | size_t *retlen, u_char *buf); |
93 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | 93 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, |
94 | size_t *retlen, u_char *buf); | 94 | size_t *retlen, u_char *buf); |
95 | 95 | ||
96 | static struct mtd_info *jedec_probe(struct map_info *map); | 96 | static struct mtd_info *jedec_probe(struct map_info *map); |
@@ -122,7 +122,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
122 | 122 | ||
123 | memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); | 123 | memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); |
124 | priv = (struct jedec_private *)&MTD[1]; | 124 | priv = (struct jedec_private *)&MTD[1]; |
125 | 125 | ||
126 | my_bank_size = map->size; | 126 | my_bank_size = map->size; |
127 | 127 | ||
128 | if (map->size/my_bank_size > MAX_JEDEC_CHIPS) | 128 | if (map->size/my_bank_size > MAX_JEDEC_CHIPS) |
@@ -131,13 +131,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
131 | kfree(MTD); | 131 | kfree(MTD); |
132 | return NULL; | 132 | return NULL; |
133 | } | 133 | } |
134 | 134 | ||
135 | for (Base = 0; Base < map->size; Base += my_bank_size) | 135 | for (Base = 0; Base < map->size; Base += my_bank_size) |
136 | { | 136 | { |
137 | // Perhaps zero could designate all tests? | 137 | // Perhaps zero could designate all tests? |
138 | if (map->buswidth == 0) | 138 | if (map->buswidth == 0) |
139 | map->buswidth = 1; | 139 | map->buswidth = 1; |
140 | 140 | ||
141 | if (map->buswidth == 1){ | 141 | if (map->buswidth == 1){ |
142 | if (jedec_probe8(map,Base,priv) == 0) { | 142 | if (jedec_probe8(map,Base,priv) == 0) { |
143 | printk("did recognize jedec chip\n"); | 143 | printk("did recognize jedec chip\n"); |
@@ -150,7 +150,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
150 | if (map->buswidth == 4) | 150 | if (map->buswidth == 4) |
151 | jedec_probe32(map,Base,priv); | 151 | jedec_probe32(map,Base,priv); |
152 | } | 152 | } |
153 | 153 | ||
154 | // Get the biggest sector size | 154 | // Get the biggest sector size |
155 | SectorSize = 0; | 155 | SectorSize = 0; |
156 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 156 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
@@ -160,7 +160,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
160 | if (priv->chips[I].sectorsize > SectorSize) | 160 | if (priv->chips[I].sectorsize > SectorSize) |
161 | SectorSize = priv->chips[I].sectorsize; | 161 | SectorSize = priv->chips[I].sectorsize; |
162 | } | 162 | } |
163 | 163 | ||
164 | // Quickly ensure that the other sector sizes are factors of the largest | 164 | // Quickly ensure that the other sector sizes are factors of the largest |
165 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 165 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
166 | { | 166 | { |
@@ -169,9 +169,9 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
169 | printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); | 169 | printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); |
170 | kfree(MTD); | 170 | kfree(MTD); |
171 | return NULL; | 171 | return NULL; |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | /* Generate a part name that includes the number of different chips and | 175 | /* Generate a part name that includes the number of different chips and |
176 | other configuration information */ | 176 | other configuration information */ |
177 | count = 1; | 177 | count = 1; |
@@ -181,13 +181,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
181 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 181 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
182 | { | 182 | { |
183 | const struct JEDECTable *JEDEC; | 183 | const struct JEDECTable *JEDEC; |
184 | 184 | ||
185 | if (priv->chips[I+1].jedec == priv->chips[I].jedec) | 185 | if (priv->chips[I+1].jedec == priv->chips[I].jedec) |
186 | { | 186 | { |
187 | count++; | 187 | count++; |
188 | continue; | 188 | continue; |
189 | } | 189 | } |
190 | 190 | ||
191 | // Locate the chip in the jedec table | 191 | // Locate the chip in the jedec table |
192 | JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); | 192 | JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); |
193 | if (JEDEC == 0) | 193 | if (JEDEC == 0) |
@@ -196,11 +196,11 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
196 | kfree(MTD); | 196 | kfree(MTD); |
197 | return NULL; | 197 | return NULL; |
198 | } | 198 | } |
199 | 199 | ||
200 | if (Uniq != 0) | 200 | if (Uniq != 0) |
201 | strcat(Part,","); | 201 | strcat(Part,","); |
202 | Uniq++; | 202 | Uniq++; |
203 | 203 | ||
204 | if (count != 1) | 204 | if (count != 1) |
205 | sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); | 205 | sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); |
206 | else | 206 | else |
@@ -208,7 +208,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
208 | if (strlen(Part) > sizeof(Part)*2/3) | 208 | if (strlen(Part) > sizeof(Part)*2/3) |
209 | break; | 209 | break; |
210 | count = 1; | 210 | count = 1; |
211 | } | 211 | } |
212 | 212 | ||
213 | /* Determine if the chips are organized in a linear fashion, or if there | 213 | /* Determine if the chips are organized in a linear fashion, or if there |
214 | are empty banks. Note, the last bank does not count here, only the | 214 | are empty banks. Note, the last bank does not count here, only the |
@@ -233,7 +233,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
233 | { | 233 | { |
234 | if (priv->bank_fill[I] != my_bank_size) | 234 | if (priv->bank_fill[I] != my_bank_size) |
235 | priv->is_banked = 1; | 235 | priv->is_banked = 1; |
236 | 236 | ||
237 | /* This even could be eliminated, but new de-optimized read/write | 237 | /* This even could be eliminated, but new de-optimized read/write |
238 | functions have to be written */ | 238 | functions have to be written */ |
239 | printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); | 239 | printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); |
@@ -242,7 +242,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
242 | printk("mtd: Failed. Cannot handle unsymmetric banking\n"); | 242 | printk("mtd: Failed. Cannot handle unsymmetric banking\n"); |
243 | kfree(MTD); | 243 | kfree(MTD); |
244 | return NULL; | 244 | return NULL; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | } | 247 | } |
248 | } | 248 | } |
@@ -250,7 +250,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
250 | strcat(Part,", banked"); | 250 | strcat(Part,", banked"); |
251 | 251 | ||
252 | // printk("Part: '%s'\n",Part); | 252 | // printk("Part: '%s'\n",Part); |
253 | 253 | ||
254 | memset(MTD,0,sizeof(*MTD)); | 254 | memset(MTD,0,sizeof(*MTD)); |
255 | // strlcpy(MTD->name,Part,sizeof(MTD->name)); | 255 | // strlcpy(MTD->name,Part,sizeof(MTD->name)); |
256 | MTD->name = map->name; | 256 | MTD->name = map->name; |
@@ -291,7 +291,7 @@ static int checkparity(u_char C) | |||
291 | 291 | ||
292 | /* Take an array of JEDEC numbers that represent interleved flash chips | 292 | /* Take an array of JEDEC numbers that represent interleved flash chips |
293 | and process them. Check to make sure they are good JEDEC numbers, look | 293 | and process them. Check to make sure they are good JEDEC numbers, look |
294 | them up and then add them to the chip list */ | 294 | them up and then add them to the chip list */ |
295 | static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | 295 | static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, |
296 | unsigned long base,struct jedec_private *priv) | 296 | unsigned long base,struct jedec_private *priv) |
297 | { | 297 | { |
@@ -306,16 +306,16 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
306 | if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) | 306 | if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) |
307 | return 0; | 307 | return 0; |
308 | } | 308 | } |
309 | 309 | ||
310 | // Finally, just make sure all the chip sizes are the same | 310 | // Finally, just make sure all the chip sizes are the same |
311 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); | 311 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); |
312 | 312 | ||
313 | if (JEDEC == 0) | 313 | if (JEDEC == 0) |
314 | { | 314 | { |
315 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); | 315 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); |
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | Size = JEDEC->size; | 319 | Size = JEDEC->size; |
320 | SectorSize = JEDEC->sectorsize; | 320 | SectorSize = JEDEC->sectorsize; |
321 | for (I = 0; I != Count; I++) | 321 | for (I = 0; I != Count; I++) |
@@ -331,7 +331,7 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
331 | { | 331 | { |
332 | printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); | 332 | printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); |
333 | return 0; | 333 | return 0; |
334 | } | 334 | } |
335 | } | 335 | } |
336 | 336 | ||
337 | // Load the Chips | 337 | // Load the Chips |
@@ -345,13 +345,13 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
345 | { | 345 | { |
346 | printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); | 346 | printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | // Add them to the table | 350 | // Add them to the table |
351 | for (J = 0; J != Count; J++) | 351 | for (J = 0; J != Count; J++) |
352 | { | 352 | { |
353 | unsigned long Bank; | 353 | unsigned long Bank; |
354 | 354 | ||
355 | JEDEC = jedec_idtoinf(Mfg[J],Id[J]); | 355 | JEDEC = jedec_idtoinf(Mfg[J],Id[J]); |
356 | priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; | 356 | priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; |
357 | priv->chips[I].size = JEDEC->size; | 357 | priv->chips[I].size = JEDEC->size; |
@@ -364,17 +364,17 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
364 | // log2 n :| | 364 | // log2 n :| |
365 | priv->chips[I].addrshift = 0; | 365 | priv->chips[I].addrshift = 0; |
366 | for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); | 366 | for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); |
367 | 367 | ||
368 | // Determine how filled this bank is. | 368 | // Determine how filled this bank is. |
369 | Bank = base & (~(my_bank_size-1)); | 369 | Bank = base & (~(my_bank_size-1)); |
370 | if (priv->bank_fill[Bank/my_bank_size] < base + | 370 | if (priv->bank_fill[Bank/my_bank_size] < base + |
371 | (JEDEC->size << priv->chips[I].addrshift) - Bank) | 371 | (JEDEC->size << priv->chips[I].addrshift) - Bank) |
372 | priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; | 372 | priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; |
373 | I++; | 373 | I++; |
374 | } | 374 | } |
375 | 375 | ||
376 | priv->size += priv->chips[I-1].size*Count; | 376 | priv->size += priv->chips[I-1].size*Count; |
377 | 377 | ||
378 | return priv->chips[I-1].size; | 378 | return priv->chips[I-1].size; |
379 | } | 379 | } |
380 | 380 | ||
@@ -392,7 +392,7 @@ static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) | |||
392 | // Look for flash using an 8 bit bus interface | 392 | // Look for flash using an 8 bit bus interface |
393 | static int jedec_probe8(struct map_info *map,unsigned long base, | 393 | static int jedec_probe8(struct map_info *map,unsigned long base, |
394 | struct jedec_private *priv) | 394 | struct jedec_private *priv) |
395 | { | 395 | { |
396 | #define flread(x) map_read8(map,base+x) | 396 | #define flread(x) map_read8(map,base+x) |
397 | #define flwrite(v,x) map_write8(map,v,base+x) | 397 | #define flwrite(v,x) map_write8(map,v,base+x) |
398 | 398 | ||
@@ -410,20 +410,20 @@ static int jedec_probe8(struct map_info *map,unsigned long base, | |||
410 | OldVal = flread(base); | 410 | OldVal = flread(base); |
411 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | 411 | for (I = 0; OldVal != flread(base) && I < 10000; I++) |
412 | OldVal = flread(base); | 412 | OldVal = flread(base); |
413 | 413 | ||
414 | // Reset the chip | 414 | // Reset the chip |
415 | flwrite(Reset,0x555); | 415 | flwrite(Reset,0x555); |
416 | 416 | ||
417 | // Send the sequence | 417 | // Send the sequence |
418 | flwrite(AutoSel1,0x555); | 418 | flwrite(AutoSel1,0x555); |
419 | flwrite(AutoSel2,0x2AA); | 419 | flwrite(AutoSel2,0x2AA); |
420 | flwrite(AutoSel3,0x555); | 420 | flwrite(AutoSel3,0x555); |
421 | 421 | ||
422 | // Get the JEDEC numbers | 422 | // Get the JEDEC numbers |
423 | Mfg[0] = flread(0); | 423 | Mfg[0] = flread(0); |
424 | Id[0] = flread(1); | 424 | Id[0] = flread(1); |
425 | // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); | 425 | // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); |
426 | 426 | ||
427 | Size = handle_jedecs(map,Mfg,Id,1,base,priv); | 427 | Size = handle_jedecs(map,Mfg,Id,1,base,priv); |
428 | // printk("handle_jedecs Size is %x\n",(unsigned int)Size); | 428 | // printk("handle_jedecs Size is %x\n",(unsigned int)Size); |
429 | if (Size == 0) | 429 | if (Size == 0) |
@@ -431,13 +431,13 @@ static int jedec_probe8(struct map_info *map,unsigned long base, | |||
431 | flwrite(Reset,0x555); | 431 | flwrite(Reset,0x555); |
432 | return 0; | 432 | return 0; |
433 | } | 433 | } |
434 | 434 | ||
435 | 435 | ||
436 | // Reset. | 436 | // Reset. |
437 | flwrite(Reset,0x555); | 437 | flwrite(Reset,0x555); |
438 | 438 | ||
439 | return 1; | 439 | return 1; |
440 | 440 | ||
441 | #undef flread | 441 | #undef flread |
442 | #undef flwrite | 442 | #undef flwrite |
443 | } | 443 | } |
@@ -470,17 +470,17 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
470 | OldVal = flread(base); | 470 | OldVal = flread(base); |
471 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | 471 | for (I = 0; OldVal != flread(base) && I < 10000; I++) |
472 | OldVal = flread(base); | 472 | OldVal = flread(base); |
473 | 473 | ||
474 | // Reset the chip | 474 | // Reset the chip |
475 | flwrite(Reset,0x555); | 475 | flwrite(Reset,0x555); |
476 | 476 | ||
477 | // Send the sequence | 477 | // Send the sequence |
478 | flwrite(AutoSel1,0x555); | 478 | flwrite(AutoSel1,0x555); |
479 | flwrite(AutoSel2,0x2AA); | 479 | flwrite(AutoSel2,0x2AA); |
480 | flwrite(AutoSel3,0x555); | 480 | flwrite(AutoSel3,0x555); |
481 | 481 | ||
482 | // Test #1, JEDEC numbers are readable from 0x??00/0x??01 | 482 | // Test #1, JEDEC numbers are readable from 0x??00/0x??01 |
483 | if (flread(0) != flread(0x100) || | 483 | if (flread(0) != flread(0x100) || |
484 | flread(1) != flread(0x101)) | 484 | flread(1) != flread(0x101)) |
485 | { | 485 | { |
486 | flwrite(Reset,0x555); | 486 | flwrite(Reset,0x555); |
@@ -494,14 +494,14 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
494 | OldVal = flread(1); | 494 | OldVal = flread(1); |
495 | for (I = 0; I != 4; I++) | 495 | for (I = 0; I != 4; I++) |
496 | Id[I] = (OldVal >> (I*8)); | 496 | Id[I] = (OldVal >> (I*8)); |
497 | 497 | ||
498 | Size = handle_jedecs(map,Mfg,Id,4,base,priv); | 498 | Size = handle_jedecs(map,Mfg,Id,4,base,priv); |
499 | if (Size == 0) | 499 | if (Size == 0) |
500 | { | 500 | { |
501 | flwrite(Reset,0x555); | 501 | flwrite(Reset,0x555); |
502 | return 0; | 502 | return 0; |
503 | } | 503 | } |
504 | 504 | ||
505 | /* Check if there is address wrap around within a single bank, if this | 505 | /* Check if there is address wrap around within a single bank, if this |
506 | returns JEDEC numbers then we assume that it is wrap around. Notice | 506 | returns JEDEC numbers then we assume that it is wrap around. Notice |
507 | we call this routine with the JEDEC return still enabled, if two or | 507 | we call this routine with the JEDEC return still enabled, if two or |
@@ -519,27 +519,27 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
519 | 519 | ||
520 | // Reset. | 520 | // Reset. |
521 | flwrite(0xF0F0F0F0,0x555); | 521 | flwrite(0xF0F0F0F0,0x555); |
522 | 522 | ||
523 | return 1; | 523 | return 1; |
524 | 524 | ||
525 | #undef flread | 525 | #undef flread |
526 | #undef flwrite | 526 | #undef flwrite |
527 | } | 527 | } |
528 | 528 | ||
529 | /* Linear read. */ | 529 | /* Linear read. */ |
530 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | 530 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, |
531 | size_t *retlen, u_char *buf) | 531 | size_t *retlen, u_char *buf) |
532 | { | 532 | { |
533 | struct map_info *map = mtd->priv; | 533 | struct map_info *map = mtd->priv; |
534 | 534 | ||
535 | map_copy_from(map, buf, from, len); | 535 | map_copy_from(map, buf, from, len); |
536 | *retlen = len; | 536 | *retlen = len; |
537 | return 0; | 537 | return 0; |
538 | } | 538 | } |
539 | 539 | ||
540 | /* Banked read. Take special care to jump past the holes in the bank | 540 | /* Banked read. Take special care to jump past the holes in the bank |
541 | mapping. This version assumes symetry in the holes.. */ | 541 | mapping. This version assumes symetry in the holes.. */ |
542 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | 542 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, |
543 | size_t *retlen, u_char *buf) | 543 | size_t *retlen, u_char *buf) |
544 | { | 544 | { |
545 | struct map_info *map = mtd->priv; | 545 | struct map_info *map = mtd->priv; |
@@ -555,17 +555,17 @@ static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | |||
555 | if (priv->bank_fill[0] - offset < len) | 555 | if (priv->bank_fill[0] - offset < len) |
556 | get = priv->bank_fill[0] - offset; | 556 | get = priv->bank_fill[0] - offset; |
557 | 557 | ||
558 | bank /= priv->bank_fill[0]; | 558 | bank /= priv->bank_fill[0]; |
559 | map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); | 559 | map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); |
560 | 560 | ||
561 | len -= get; | 561 | len -= get; |
562 | *retlen += get; | 562 | *retlen += get; |
563 | from += get; | 563 | from += get; |
564 | } | 564 | } |
565 | return 0; | 565 | return 0; |
566 | } | 566 | } |
567 | 567 | ||
568 | /* Pass the flags value that the flash return before it re-entered read | 568 | /* Pass the flags value that the flash return before it re-entered read |
569 | mode. */ | 569 | mode. */ |
570 | static void jedec_flash_failed(unsigned char code) | 570 | static void jedec_flash_failed(unsigned char code) |
571 | { | 571 | { |
@@ -579,17 +579,17 @@ static void jedec_flash_failed(unsigned char code) | |||
579 | printk("mtd: Programming didn't take\n"); | 579 | printk("mtd: Programming didn't take\n"); |
580 | } | 580 | } |
581 | 581 | ||
582 | /* This uses the erasure function described in the AMD Flash Handbook, | 582 | /* This uses the erasure function described in the AMD Flash Handbook, |
583 | it will work for flashes with a fixed sector size only. Flashes with | 583 | it will work for flashes with a fixed sector size only. Flashes with |
584 | a selection of sector sizes (ie the AMD Am29F800B) will need a different | 584 | a selection of sector sizes (ie the AMD Am29F800B) will need a different |
585 | routine. This routine tries to parallize erasing multiple chips/sectors | 585 | routine. This routine tries to parallize erasing multiple chips/sectors |
586 | where possible */ | 586 | where possible */ |
587 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | 587 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) |
588 | { | 588 | { |
589 | // Does IO to the currently selected chip | 589 | // Does IO to the currently selected chip |
590 | #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) | 590 | #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) |
591 | #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) | 591 | #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) |
592 | 592 | ||
593 | unsigned long Time = 0; | 593 | unsigned long Time = 0; |
594 | unsigned long NoTime = 0; | 594 | unsigned long NoTime = 0; |
595 | unsigned long start = instr->addr, len = instr->len; | 595 | unsigned long start = instr->addr, len = instr->len; |
@@ -603,7 +603,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
603 | (len % mtd->erasesize) != 0 || | 603 | (len % mtd->erasesize) != 0 || |
604 | (len/mtd->erasesize) == 0) | 604 | (len/mtd->erasesize) == 0) |
605 | return -EINVAL; | 605 | return -EINVAL; |
606 | 606 | ||
607 | jedec_flash_chip_scan(priv,start,len); | 607 | jedec_flash_chip_scan(priv,start,len); |
608 | 608 | ||
609 | // Start the erase sequence on each chip | 609 | // Start the erase sequence on each chip |
@@ -611,16 +611,16 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
611 | { | 611 | { |
612 | unsigned long off; | 612 | unsigned long off; |
613 | struct jedec_flash_chip *chip = priv->chips + I; | 613 | struct jedec_flash_chip *chip = priv->chips + I; |
614 | 614 | ||
615 | if (chip->length == 0) | 615 | if (chip->length == 0) |
616 | continue; | 616 | continue; |
617 | 617 | ||
618 | if (chip->start + chip->length > chip->size) | 618 | if (chip->start + chip->length > chip->size) |
619 | { | 619 | { |
620 | printk("DIE\n"); | 620 | printk("DIE\n"); |
621 | return -EIO; | 621 | return -EIO; |
622 | } | 622 | } |
623 | 623 | ||
624 | flwrite(0xF0,chip->start + 0x555); | 624 | flwrite(0xF0,chip->start + 0x555); |
625 | flwrite(0xAA,chip->start + 0x555); | 625 | flwrite(0xAA,chip->start + 0x555); |
626 | flwrite(0x55,chip->start + 0x2AA); | 626 | flwrite(0x55,chip->start + 0x2AA); |
@@ -628,8 +628,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
628 | flwrite(0xAA,chip->start + 0x555); | 628 | flwrite(0xAA,chip->start + 0x555); |
629 | flwrite(0x55,chip->start + 0x2AA); | 629 | flwrite(0x55,chip->start + 0x2AA); |
630 | 630 | ||
631 | /* Once we start selecting the erase sectors the delay between each | 631 | /* Once we start selecting the erase sectors the delay between each |
632 | command must not exceed 50us or it will immediately start erasing | 632 | command must not exceed 50us or it will immediately start erasing |
633 | and ignore the other sectors */ | 633 | and ignore the other sectors */ |
634 | for (off = 0; off < len; off += chip->sectorsize) | 634 | for (off = 0; off < len; off += chip->sectorsize) |
635 | { | 635 | { |
@@ -641,19 +641,19 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
641 | { | 641 | { |
642 | printk("mtd: Ack! We timed out the erase timer!\n"); | 642 | printk("mtd: Ack! We timed out the erase timer!\n"); |
643 | return -EIO; | 643 | return -EIO; |
644 | } | 644 | } |
645 | } | 645 | } |
646 | } | 646 | } |
647 | 647 | ||
648 | /* We could split this into a timer routine and return early, performing | 648 | /* We could split this into a timer routine and return early, performing |
649 | background erasure.. Maybe later if the need warrents */ | 649 | background erasure.. Maybe later if the need warrents */ |
650 | 650 | ||
651 | /* Poll the flash for erasure completion, specs say this can take as long | 651 | /* Poll the flash for erasure completion, specs say this can take as long |
652 | as 480 seconds to do all the sectors (for a 2 meg flash). | 652 | as 480 seconds to do all the sectors (for a 2 meg flash). |
653 | Erasure time is dependent on chip age, temp and wear.. */ | 653 | Erasure time is dependent on chip age, temp and wear.. */ |
654 | 654 | ||
655 | /* This being a generic routine assumes a 32 bit bus. It does read32s | 655 | /* This being a generic routine assumes a 32 bit bus. It does read32s |
656 | and bundles interleved chips into the same grouping. This will work | 656 | and bundles interleved chips into the same grouping. This will work |
657 | for all bus widths */ | 657 | for all bus widths */ |
658 | Time = 0; | 658 | Time = 0; |
659 | NoTime = 0; | 659 | NoTime = 0; |
@@ -664,20 +664,20 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
664 | unsigned todo[4] = {0,0,0,0}; | 664 | unsigned todo[4] = {0,0,0,0}; |
665 | unsigned todo_left = 0; | 665 | unsigned todo_left = 0; |
666 | unsigned J; | 666 | unsigned J; |
667 | 667 | ||
668 | if (chip->length == 0) | 668 | if (chip->length == 0) |
669 | continue; | 669 | continue; |
670 | 670 | ||
671 | /* Find all chips in this data line, realistically this is all | 671 | /* Find all chips in this data line, realistically this is all |
672 | or nothing up to the interleve count */ | 672 | or nothing up to the interleve count */ |
673 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | 673 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) |
674 | { | 674 | { |
675 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | 675 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == |
676 | (chip->base & (~((1<<chip->addrshift)-1)))) | 676 | (chip->base & (~((1<<chip->addrshift)-1)))) |
677 | { | 677 | { |
678 | todo_left++; | 678 | todo_left++; |
679 | todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1; | 679 | todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1; |
680 | } | 680 | } |
681 | } | 681 | } |
682 | 682 | ||
683 | /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], | 683 | /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], |
@@ -687,7 +687,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
687 | { | 687 | { |
688 | __u32 Last[4]; | 688 | __u32 Last[4]; |
689 | unsigned long Count = 0; | 689 | unsigned long Count = 0; |
690 | 690 | ||
691 | /* During erase bit 7 is held low and bit 6 toggles, we watch this, | 691 | /* During erase bit 7 is held low and bit 6 toggles, we watch this, |
692 | should it stop toggling or go high then the erase is completed, | 692 | should it stop toggling or go high then the erase is completed, |
693 | or this is not really flash ;> */ | 693 | or this is not really flash ;> */ |
@@ -718,23 +718,23 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
718 | __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; | 718 | __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; |
719 | if (todo[J] == 0) | 719 | if (todo[J] == 0) |
720 | continue; | 720 | continue; |
721 | 721 | ||
722 | if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) | 722 | if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) |
723 | { | 723 | { |
724 | // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); | 724 | // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); |
725 | continue; | 725 | continue; |
726 | } | 726 | } |
727 | 727 | ||
728 | if (Byte1 == Byte2) | 728 | if (Byte1 == Byte2) |
729 | { | 729 | { |
730 | jedec_flash_failed(Byte3); | 730 | jedec_flash_failed(Byte3); |
731 | return -EIO; | 731 | return -EIO; |
732 | } | 732 | } |
733 | 733 | ||
734 | todo[J] = 0; | 734 | todo[J] = 0; |
735 | todo_left--; | 735 | todo_left--; |
736 | } | 736 | } |
737 | 737 | ||
738 | /* if (NoTime == 0) | 738 | /* if (NoTime == 0) |
739 | Time += HZ/10 - schedule_timeout(HZ/10);*/ | 739 | Time += HZ/10 - schedule_timeout(HZ/10);*/ |
740 | NoTime = 0; | 740 | NoTime = 0; |
@@ -751,7 +751,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
751 | break; | 751 | break; |
752 | } | 752 | } |
753 | Count++; | 753 | Count++; |
754 | 754 | ||
755 | /* // Count time, max of 15s per sector (according to AMD) | 755 | /* // Count time, max of 15s per sector (according to AMD) |
756 | if (Time > 15*len/mtd->erasesize*HZ) | 756 | if (Time > 15*len/mtd->erasesize*HZ) |
757 | { | 757 | { |
@@ -759,38 +759,38 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
759 | return -EIO; | 759 | return -EIO; |
760 | } */ | 760 | } */ |
761 | } | 761 | } |
762 | 762 | ||
763 | // Skip to the next chip if we used chip erase | 763 | // Skip to the next chip if we used chip erase |
764 | if (chip->length == chip->size) | 764 | if (chip->length == chip->size) |
765 | off = chip->size; | 765 | off = chip->size; |
766 | else | 766 | else |
767 | off += chip->sectorsize; | 767 | off += chip->sectorsize; |
768 | 768 | ||
769 | if (off >= chip->length) | 769 | if (off >= chip->length) |
770 | break; | 770 | break; |
771 | NoTime = 1; | 771 | NoTime = 1; |
772 | } | 772 | } |
773 | 773 | ||
774 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | 774 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) |
775 | { | 775 | { |
776 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | 776 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == |
777 | (chip->base & (~((1<<chip->addrshift)-1)))) | 777 | (chip->base & (~((1<<chip->addrshift)-1)))) |
778 | priv->chips[J].length = 0; | 778 | priv->chips[J].length = 0; |
779 | } | 779 | } |
780 | } | 780 | } |
781 | 781 | ||
782 | //printk("done\n"); | 782 | //printk("done\n"); |
783 | instr->state = MTD_ERASE_DONE; | 783 | instr->state = MTD_ERASE_DONE; |
784 | mtd_erase_callback(instr); | 784 | mtd_erase_callback(instr); |
785 | return 0; | 785 | return 0; |
786 | 786 | ||
787 | #undef flread | 787 | #undef flread |
788 | #undef flwrite | 788 | #undef flwrite |
789 | } | 789 | } |
790 | 790 | ||
791 | /* This is the simple flash writing function. It writes to every byte, in | 791 | /* This is the simple flash writing function. It writes to every byte, in |
792 | sequence. It takes care of how to properly address the flash if | 792 | sequence. It takes care of how to properly address the flash if |
793 | the flash is interleved. It can only be used if all the chips in the | 793 | the flash is interleved. It can only be used if all the chips in the |
794 | array are identical!*/ | 794 | array are identical!*/ |
795 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | 795 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, |
796 | size_t *retlen, const u_char *buf) | 796 | size_t *retlen, const u_char *buf) |
@@ -800,25 +800,25 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
800 | of addrshift (interleave index) and then adds the control register index. */ | 800 | of addrshift (interleave index) and then adds the control register index. */ |
801 | #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | 801 | #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) |
802 | #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | 802 | #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) |
803 | 803 | ||
804 | struct map_info *map = mtd->priv; | 804 | struct map_info *map = mtd->priv; |
805 | struct jedec_private *priv = map->fldrv_priv; | 805 | struct jedec_private *priv = map->fldrv_priv; |
806 | unsigned long base; | 806 | unsigned long base; |
807 | unsigned long off; | 807 | unsigned long off; |
808 | size_t save_len = len; | 808 | size_t save_len = len; |
809 | 809 | ||
810 | if (start + len > mtd->size) | 810 | if (start + len > mtd->size) |
811 | return -EIO; | 811 | return -EIO; |
812 | 812 | ||
813 | //printk("Here"); | 813 | //printk("Here"); |
814 | 814 | ||
815 | //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); | 815 | //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); |
816 | while (len != 0) | 816 | while (len != 0) |
817 | { | 817 | { |
818 | struct jedec_flash_chip *chip = priv->chips; | 818 | struct jedec_flash_chip *chip = priv->chips; |
819 | unsigned long bank; | 819 | unsigned long bank; |
820 | unsigned long boffset; | 820 | unsigned long boffset; |
821 | 821 | ||
822 | // Compute the base of the flash. | 822 | // Compute the base of the flash. |
823 | off = ((unsigned long)start) % (chip->size << chip->addrshift); | 823 | off = ((unsigned long)start) % (chip->size << chip->addrshift); |
824 | base = start - off; | 824 | base = start - off; |
@@ -828,10 +828,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
828 | boffset = base & (priv->bank_fill[0]-1); | 828 | boffset = base & (priv->bank_fill[0]-1); |
829 | bank = (bank/priv->bank_fill[0])*my_bank_size; | 829 | bank = (bank/priv->bank_fill[0])*my_bank_size; |
830 | base = bank + boffset; | 830 | base = bank + boffset; |
831 | 831 | ||
832 | // printk("Flasing %X %X %X\n",base,chip->size,len); | 832 | // printk("Flasing %X %X %X\n",base,chip->size,len); |
833 | // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); | 833 | // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); |
834 | 834 | ||
835 | // Loop over this page | 835 | // Loop over this page |
836 | for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) | 836 | for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) |
837 | { | 837 | { |
@@ -845,7 +845,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
845 | } | 845 | } |
846 | if (((~oldbyte) & *buf) != 0) | 846 | if (((~oldbyte) & *buf) != 0) |
847 | printk("mtd: warn: Trying to set a 0 to a 1\n"); | 847 | printk("mtd: warn: Trying to set a 0 to a 1\n"); |
848 | 848 | ||
849 | // Write | 849 | // Write |
850 | flwrite(0xAA,0x555); | 850 | flwrite(0xAA,0x555); |
851 | flwrite(0x55,0x2AA); | 851 | flwrite(0x55,0x2AA); |
@@ -854,10 +854,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
854 | Last[0] = map_read8(map,base + off); | 854 | Last[0] = map_read8(map,base + off); |
855 | Last[1] = map_read8(map,base + off); | 855 | Last[1] = map_read8(map,base + off); |
856 | Last[2] = map_read8(map,base + off); | 856 | Last[2] = map_read8(map,base + off); |
857 | 857 | ||
858 | /* Wait for the flash to finish the operation. We store the last 4 | 858 | /* Wait for the flash to finish the operation. We store the last 4 |
859 | status bytes that have been retrieved so we can determine why | 859 | status bytes that have been retrieved so we can determine why |
860 | it failed. The toggle bits keep toggling when there is a | 860 | it failed. The toggle bits keep toggling when there is a |
861 | failure */ | 861 | failure */ |
862 | for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && | 862 | for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && |
863 | Count < 10000; Count++) | 863 | Count < 10000; Count++) |
@@ -866,7 +866,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
866 | { | 866 | { |
867 | jedec_flash_failed(Last[(Count - 3) % 4]); | 867 | jedec_flash_failed(Last[(Count - 3) % 4]); |
868 | return -EIO; | 868 | return -EIO; |
869 | } | 869 | } |
870 | } | 870 | } |
871 | } | 871 | } |
872 | *retlen = save_len; | 872 | *retlen = save_len; |
@@ -885,24 +885,24 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start | |||
885 | // Zero the records | 885 | // Zero the records |
886 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 886 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
887 | priv->chips[I].start = priv->chips[I].length = 0; | 887 | priv->chips[I].start = priv->chips[I].length = 0; |
888 | 888 | ||
889 | // Intersect the region with each chip | 889 | // Intersect the region with each chip |
890 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 890 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
891 | { | 891 | { |
892 | struct jedec_flash_chip *chip = priv->chips + I; | 892 | struct jedec_flash_chip *chip = priv->chips + I; |
893 | unsigned long ByteStart; | 893 | unsigned long ByteStart; |
894 | unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); | 894 | unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); |
895 | 895 | ||
896 | // End is before this chip or the start is after it | 896 | // End is before this chip or the start is after it |
897 | if (start+len < chip->offset || | 897 | if (start+len < chip->offset || |
898 | ChipEndByte - (1 << chip->addrshift) < start) | 898 | ChipEndByte - (1 << chip->addrshift) < start) |
899 | continue; | 899 | continue; |
900 | 900 | ||
901 | if (start < chip->offset) | 901 | if (start < chip->offset) |
902 | { | 902 | { |
903 | ByteStart = chip->offset; | 903 | ByteStart = chip->offset; |
904 | chip->start = 0; | 904 | chip->start = 0; |
905 | } | 905 | } |
906 | else | 906 | else |
907 | { | 907 | { |
908 | chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; | 908 | chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; |
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 30da428eb7b9..edb306c03c0a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
4 | $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $ | 4 | $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $ |
5 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) | 5 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) |
6 | for the standard this probe goes back to. | 6 | for the standard this probe goes back to. |
7 | 7 | ||
@@ -1719,7 +1719,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
1719 | 1719 | ||
1720 | static struct mtd_info *jedec_probe(struct map_info *map); | 1720 | static struct mtd_info *jedec_probe(struct map_info *map); |
1721 | 1721 | ||
1722 | static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | 1722 | static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, |
1723 | struct cfi_private *cfi) | 1723 | struct cfi_private *cfi) |
1724 | { | 1724 | { |
1725 | map_word result; | 1725 | map_word result; |
@@ -1730,7 +1730,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | |||
1730 | return result.x[0] & mask; | 1730 | return result.x[0] & mask; |
1731 | } | 1731 | } |
1732 | 1732 | ||
1733 | static inline u32 jedec_read_id(struct map_info *map, __u32 base, | 1733 | static inline u32 jedec_read_id(struct map_info *map, __u32 base, |
1734 | struct cfi_private *cfi) | 1734 | struct cfi_private *cfi) |
1735 | { | 1735 | { |
1736 | map_word result; | 1736 | map_word result; |
@@ -1741,7 +1741,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base, | |||
1741 | return result.x[0] & mask; | 1741 | return result.x[0] & mask; |
1742 | } | 1742 | } |
1743 | 1743 | ||
1744 | static inline void jedec_reset(u32 base, struct map_info *map, | 1744 | static inline void jedec_reset(u32 base, struct map_info *map, |
1745 | struct cfi_private *cfi) | 1745 | struct cfi_private *cfi) |
1746 | { | 1746 | { |
1747 | /* Reset */ | 1747 | /* Reset */ |
@@ -1765,7 +1765,7 @@ static inline void jedec_reset(u32 base, struct map_info *map, | |||
1765 | * so ensure we're in read mode. Send both the Intel and the AMD command | 1765 | * so ensure we're in read mode. Send both the Intel and the AMD command |
1766 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so | 1766 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so |
1767 | * this should be safe. | 1767 | * this should be safe. |
1768 | */ | 1768 | */ |
1769 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | 1769 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); |
1770 | /* FIXME - should have reset delay before continuing */ | 1770 | /* FIXME - should have reset delay before continuing */ |
1771 | } | 1771 | } |
@@ -1807,14 +1807,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | |||
1807 | printk("Found: %s\n",jedec_table[index].name); | 1807 | printk("Found: %s\n",jedec_table[index].name); |
1808 | 1808 | ||
1809 | num_erase_regions = jedec_table[index].NumEraseRegions; | 1809 | num_erase_regions = jedec_table[index].NumEraseRegions; |
1810 | 1810 | ||
1811 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); | 1811 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); |
1812 | if (!p_cfi->cfiq) { | 1812 | if (!p_cfi->cfiq) { |
1813 | //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); | 1813 | //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); |
1814 | return 0; | 1814 | return 0; |
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); | 1817 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); |
1818 | 1818 | ||
1819 | p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; | 1819 | p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; |
1820 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; | 1820 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; |
@@ -1969,7 +1969,7 @@ static inline int jedec_match( __u32 base, | |||
1969 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); | 1969 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); |
1970 | /* FIXME - should have a delay before continuing */ | 1970 | /* FIXME - should have a delay before continuing */ |
1971 | 1971 | ||
1972 | match_done: | 1972 | match_done: |
1973 | return rc; | 1973 | return rc; |
1974 | } | 1974 | } |
1975 | 1975 | ||
@@ -1998,23 +1998,23 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
1998 | "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", | 1998 | "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", |
1999 | base, map->size -1); | 1999 | base, map->size -1); |
2000 | return 0; | 2000 | return 0; |
2001 | 2001 | ||
2002 | } | 2002 | } |
2003 | /* Ensure the unlock addresses we try stay inside the map */ | 2003 | /* Ensure the unlock addresses we try stay inside the map */ |
2004 | probe_offset1 = cfi_build_cmd_addr( | 2004 | probe_offset1 = cfi_build_cmd_addr( |
2005 | cfi->addr_unlock1, | 2005 | cfi->addr_unlock1, |
2006 | cfi_interleave(cfi), | 2006 | cfi_interleave(cfi), |
2007 | cfi->device_type); | 2007 | cfi->device_type); |
2008 | probe_offset2 = cfi_build_cmd_addr( | 2008 | probe_offset2 = cfi_build_cmd_addr( |
2009 | cfi->addr_unlock1, | 2009 | cfi->addr_unlock1, |
2010 | cfi_interleave(cfi), | 2010 | cfi_interleave(cfi), |
2011 | cfi->device_type); | 2011 | cfi->device_type); |
2012 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || | 2012 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || |
2013 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) | 2013 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) |
2014 | { | 2014 | { |
2015 | goto retry; | 2015 | goto retry; |
2016 | } | 2016 | } |
2017 | 2017 | ||
2018 | /* Reset */ | 2018 | /* Reset */ |
2019 | jedec_reset(base, map, cfi); | 2019 | jedec_reset(base, map, cfi); |
2020 | 2020 | ||
@@ -2027,13 +2027,13 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2027 | /* FIXME - should have a delay before continuing */ | 2027 | /* FIXME - should have a delay before continuing */ |
2028 | 2028 | ||
2029 | if (!cfi->numchips) { | 2029 | if (!cfi->numchips) { |
2030 | /* This is the first time we're called. Set up the CFI | 2030 | /* This is the first time we're called. Set up the CFI |
2031 | stuff accordingly and return */ | 2031 | stuff accordingly and return */ |
2032 | 2032 | ||
2033 | cfi->mfr = jedec_read_mfr(map, base, cfi); | 2033 | cfi->mfr = jedec_read_mfr(map, base, cfi); |
2034 | cfi->id = jedec_read_id(map, base, cfi); | 2034 | cfi->id = jedec_read_id(map, base, cfi); |
2035 | DEBUG(MTD_DEBUG_LEVEL3, | 2035 | DEBUG(MTD_DEBUG_LEVEL3, |
2036 | "Search for id:(%02x %02x) interleave(%d) type(%d)\n", | 2036 | "Search for id:(%02x %02x) interleave(%d) type(%d)\n", |
2037 | cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); | 2037 | cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); |
2038 | for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { | 2038 | for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { |
2039 | if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { | 2039 | if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { |
@@ -2062,7 +2062,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2062 | return 0; | 2062 | return 0; |
2063 | } | 2063 | } |
2064 | } | 2064 | } |
2065 | 2065 | ||
2066 | /* Check each previous chip locations to see if it's an alias */ | 2066 | /* Check each previous chip locations to see if it's an alias */ |
2067 | for (i=0; i < (base >> cfi->chipshift); i++) { | 2067 | for (i=0; i < (base >> cfi->chipshift); i++) { |
2068 | unsigned long start; | 2068 | unsigned long start; |
@@ -2083,7 +2083,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2083 | map->name, base, start); | 2083 | map->name, base, start); |
2084 | return 0; | 2084 | return 0; |
2085 | } | 2085 | } |
2086 | 2086 | ||
2087 | /* Yes, it's actually got the device IDs as data. Most | 2087 | /* Yes, it's actually got the device IDs as data. Most |
2088 | * unfortunate. Stick the new chip in read mode | 2088 | * unfortunate. Stick the new chip in read mode |
2089 | * too and if it's the same, assume it's an alias. */ | 2089 | * too and if it's the same, assume it's an alias. */ |
@@ -2097,20 +2097,20 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2097 | } | 2097 | } |
2098 | } | 2098 | } |
2099 | } | 2099 | } |
2100 | 2100 | ||
2101 | /* OK, if we got to here, then none of the previous chips appear to | 2101 | /* OK, if we got to here, then none of the previous chips appear to |
2102 | be aliases for the current one. */ | 2102 | be aliases for the current one. */ |
2103 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ | 2103 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ |
2104 | cfi->numchips++; | 2104 | cfi->numchips++; |
2105 | 2105 | ||
2106 | ok_out: | 2106 | ok_out: |
2107 | /* Put it back into Read Mode */ | 2107 | /* Put it back into Read Mode */ |
2108 | jedec_reset(base, map, cfi); | 2108 | jedec_reset(base, map, cfi); |
2109 | 2109 | ||
2110 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 2110 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
2111 | map->name, cfi_interleave(cfi), cfi->device_type*8, base, | 2111 | map->name, cfi_interleave(cfi), cfi->device_type*8, base, |
2112 | map->bankwidth*8); | 2112 | map->bankwidth*8); |
2113 | 2113 | ||
2114 | return 1; | 2114 | return 1; |
2115 | } | 2115 | } |
2116 | 2116 | ||
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index c6c83833cc32..a611de9b1515 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Common code to handle absent "placeholder" devices | 2 | * Common code to handle absent "placeholder" devices |
3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> | 3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> |
4 | * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $ | 4 | * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $ |
5 | * | 5 | * |
6 | * This map driver is used to allocate "placeholder" MTD | 6 | * This map driver is used to allocate "placeholder" MTD |
7 | * devices on systems that have socketed/removable media. | 7 | * devices on systems that have socketed/removable media. |
8 | * Use of this driver as a fallback preserves the expected | 8 | * Use of this driver as a fallback preserves the expected |
9 | * registration of MTD device nodes regardless of probe outcome. | 9 | * registration of MTD device nodes regardless of probe outcome. |
10 | * A usage example is as follows: | 10 | * A usage example is as follows: |
11 | * | 11 | * |
@@ -80,7 +80,7 @@ static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
80 | static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) | 80 | static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) |
81 | { | 81 | { |
82 | *retlen = 0; | 82 | *retlen = 0; |
83 | return -ENODEV; | 83 | return -ENODEV; |
84 | } | 84 | } |
85 | 85 | ||
86 | static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) | 86 | static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) |
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c index c3cf0f63bc93..2d26bdef82d5 100644 --- a/drivers/mtd/chips/sharp.c +++ b/drivers/mtd/chips/sharp.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2000,2001 David A. Schleef <ds@schleef.org> | 4 | * Copyright 2000,2001 David A. Schleef <ds@schleef.org> |
5 | * 2000,2001 Lineo, Inc. | 5 | * 2000,2001 Lineo, Inc. |
6 | * | 6 | * |
7 | * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $ | 7 | * $Id: sharp.c,v 1.16 2005/11/07 11:14:23 gleixner Exp $ |
8 | * | 8 | * |
9 | * Devices supported: | 9 | * Devices supported: |
10 | * LH28F016SCT Symmetrical block flash memory, 2Mx8 | 10 | * LH28F016SCT Symmetrical block flash memory, 2Mx8 |
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mtd/cfi.h> | 31 | #include <linux/mtd/cfi.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/slab.h> | ||
34 | 35 | ||
35 | #define CMD_RESET 0xffffffff | 36 | #define CMD_RESET 0xffffffff |
36 | #define CMD_READ_ID 0x90909090 | 37 | #define CMD_READ_ID 0x90909090 |
@@ -214,7 +215,7 @@ static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) | |||
214 | /* This function returns with the chip->mutex lock held. */ | 215 | /* This function returns with the chip->mutex lock held. */ |
215 | static int sharp_wait(struct map_info *map, struct flchip *chip) | 216 | static int sharp_wait(struct map_info *map, struct flchip *chip) |
216 | { | 217 | { |
217 | __u16 status; | 218 | int status, i; |
218 | unsigned long timeo = jiffies + HZ; | 219 | unsigned long timeo = jiffies + HZ; |
219 | DECLARE_WAITQUEUE(wait, current); | 220 | DECLARE_WAITQUEUE(wait, current); |
220 | int adr = 0; | 221 | int adr = 0; |
@@ -227,13 +228,11 @@ retry: | |||
227 | map_write32(map,CMD_READ_STATUS,adr); | 228 | map_write32(map,CMD_READ_STATUS,adr); |
228 | chip->state = FL_STATUS; | 229 | chip->state = FL_STATUS; |
229 | case FL_STATUS: | 230 | case FL_STATUS: |
230 | status = map_read32(map,adr); | 231 | for(i=0;i<100;i++){ |
231 | //printk("status=%08x\n",status); | 232 | status = map_read32(map,adr); |
232 | 233 | if((status & SR_READY)==SR_READY) | |
233 | udelay(100); | 234 | break; |
234 | if((status & SR_READY)!=SR_READY){ | 235 | udelay(1); |
235 | //printk(".status=%08x\n",status); | ||
236 | udelay(100); | ||
237 | } | 236 | } |
238 | break; | 237 | break; |
239 | default: | 238 | default: |
@@ -460,12 +459,12 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, | |||
460 | remove_wait_queue(&chip->wq, &wait); | 459 | remove_wait_queue(&chip->wq, &wait); |
461 | 460 | ||
462 | //spin_lock_bh(chip->mutex); | 461 | //spin_lock_bh(chip->mutex); |
463 | 462 | ||
464 | if (signal_pending(current)){ | 463 | if (signal_pending(current)){ |
465 | ret = -EINTR; | 464 | ret = -EINTR; |
466 | goto out; | 465 | goto out; |
467 | } | 466 | } |
468 | 467 | ||
469 | } | 468 | } |
470 | ret = -ETIME; | 469 | ret = -ETIME; |
471 | out: | 470 | out: |
@@ -564,7 +563,7 @@ static int sharp_suspend(struct mtd_info *mtd) | |||
564 | static void sharp_resume(struct mtd_info *mtd) | 563 | static void sharp_resume(struct mtd_info *mtd) |
565 | { | 564 | { |
566 | printk("sharp_resume()\n"); | 565 | printk("sharp_resume()\n"); |
567 | 566 | ||
568 | } | 567 | } |
569 | 568 | ||
570 | static void sharp_destroy(struct mtd_info *mtd) | 569 | static void sharp_destroy(struct mtd_info *mtd) |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index ef24837019d3..6b8bb2e4dcfd 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
@@ -1,24 +1,24 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $ | 2 | * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ |
3 | * | 3 | * |
4 | * Read flash partition table from command line | 4 | * Read flash partition table from command line |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * The format for the command line is as follows: | 8 | * The format for the command line is as follows: |
9 | * | 9 | * |
10 | * mtdparts=<mtddef>[;<mtddef] | 10 | * mtdparts=<mtddef>[;<mtddef] |
11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] | 11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
12 | * <partdef> := <size>[@offset][<name>][ro] | 12 | * <partdef> := <size>[@offset][<name>][ro] |
13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) | 13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) |
14 | * <size> := standard linux memsize OR "-" to denote all remaining space | 14 | * <size> := standard linux memsize OR "-" to denote all remaining space |
15 | * <name> := '(' NAME ')' | 15 | * <name> := '(' NAME ')' |
16 | * | 16 | * |
17 | * Examples: | 17 | * Examples: |
18 | * | 18 | * |
19 | * 1 NOR Flash, with 1 single writable partition: | 19 | * 1 NOR Flash, with 1 single writable partition: |
20 | * edb7312-nor:- | 20 | * edb7312-nor:- |
21 | * | 21 | * |
22 | * 1 NOR Flash with 2 partitions, 1 NAND with one | 22 | * 1 NOR Flash with 2 partitions, 1 NAND with one |
23 | * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) | 23 | * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) |
24 | */ | 24 | */ |
@@ -60,17 +60,17 @@ static int cmdline_parsed = 0; | |||
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Parse one partition definition for an MTD. Since there can be many | 62 | * Parse one partition definition for an MTD. Since there can be many |
63 | * comma separated partition definitions, this function calls itself | 63 | * comma separated partition definitions, this function calls itself |
64 | * recursively until no more partition definitions are found. Nice side | 64 | * recursively until no more partition definitions are found. Nice side |
65 | * effect: the memory to keep the mtd_partition structs and the names | 65 | * effect: the memory to keep the mtd_partition structs and the names |
66 | * is allocated upon the last definition being found. At that point the | 66 | * is allocated upon the last definition being found. At that point the |
67 | * syntax has been verified ok. | 67 | * syntax has been verified ok. |
68 | */ | 68 | */ |
69 | static struct mtd_partition * newpart(char *s, | 69 | static struct mtd_partition * newpart(char *s, |
70 | char **retptr, | 70 | char **retptr, |
71 | int *num_parts, | 71 | int *num_parts, |
72 | int this_part, | 72 | int this_part, |
73 | unsigned char **extra_mem_ptr, | 73 | unsigned char **extra_mem_ptr, |
74 | int extra_mem_size) | 74 | int extra_mem_size) |
75 | { | 75 | { |
76 | struct mtd_partition *parts; | 76 | struct mtd_partition *parts; |
@@ -102,7 +102,7 @@ static struct mtd_partition * newpart(char *s, | |||
102 | mask_flags = 0; /* this is going to be a regular partition */ | 102 | mask_flags = 0; /* this is going to be a regular partition */ |
103 | delim = 0; | 103 | delim = 0; |
104 | /* check for offset */ | 104 | /* check for offset */ |
105 | if (*s == '@') | 105 | if (*s == '@') |
106 | { | 106 | { |
107 | s++; | 107 | s++; |
108 | offset = memparse(s, &s); | 108 | offset = memparse(s, &s); |
@@ -112,7 +112,7 @@ static struct mtd_partition * newpart(char *s, | |||
112 | { | 112 | { |
113 | delim = ')'; | 113 | delim = ')'; |
114 | } | 114 | } |
115 | 115 | ||
116 | if (delim) | 116 | if (delim) |
117 | { | 117 | { |
118 | char *p; | 118 | char *p; |
@@ -131,12 +131,12 @@ static struct mtd_partition * newpart(char *s, | |||
131 | name = NULL; | 131 | name = NULL; |
132 | name_len = 13; /* Partition_000 */ | 132 | name_len = 13; /* Partition_000 */ |
133 | } | 133 | } |
134 | 134 | ||
135 | /* record name length for memory allocation later */ | 135 | /* record name length for memory allocation later */ |
136 | extra_mem_size += name_len + 1; | 136 | extra_mem_size += name_len + 1; |
137 | 137 | ||
138 | /* test for options */ | 138 | /* test for options */ |
139 | if (strncmp(s, "ro", 2) == 0) | 139 | if (strncmp(s, "ro", 2) == 0) |
140 | { | 140 | { |
141 | mask_flags |= MTD_WRITEABLE; | 141 | mask_flags |= MTD_WRITEABLE; |
142 | s += 2; | 142 | s += 2; |
@@ -151,7 +151,7 @@ static struct mtd_partition * newpart(char *s, | |||
151 | return NULL; | 151 | return NULL; |
152 | } | 152 | } |
153 | /* more partitions follow, parse them */ | 153 | /* more partitions follow, parse them */ |
154 | if ((parts = newpart(s + 1, &s, num_parts, | 154 | if ((parts = newpart(s + 1, &s, num_parts, |
155 | this_part + 1, &extra_mem, extra_mem_size)) == 0) | 155 | this_part + 1, &extra_mem, extra_mem_size)) == 0) |
156 | return NULL; | 156 | return NULL; |
157 | } | 157 | } |
@@ -187,7 +187,7 @@ static struct mtd_partition * newpart(char *s, | |||
187 | extra_mem += name_len + 1; | 187 | extra_mem += name_len + 1; |
188 | 188 | ||
189 | dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", | 189 | dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", |
190 | this_part, | 190 | this_part, |
191 | parts[this_part].name, | 191 | parts[this_part].name, |
192 | parts[this_part].offset, | 192 | parts[this_part].offset, |
193 | parts[this_part].size, | 193 | parts[this_part].size, |
@@ -204,8 +204,8 @@ static struct mtd_partition * newpart(char *s, | |||
204 | return parts; | 204 | return parts; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* | 207 | /* |
208 | * Parse the command line. | 208 | * Parse the command line. |
209 | */ | 209 | */ |
210 | static int mtdpart_setup_real(char *s) | 210 | static int mtdpart_setup_real(char *s) |
211 | { | 211 | { |
@@ -230,7 +230,7 @@ static int mtdpart_setup_real(char *s) | |||
230 | 230 | ||
231 | dbg(("parsing <%s>\n", p+1)); | 231 | dbg(("parsing <%s>\n", p+1)); |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * parse one mtd. have it reserve memory for the | 234 | * parse one mtd. have it reserve memory for the |
235 | * struct cmdline_mtd_partition and the mtd-id string. | 235 | * struct cmdline_mtd_partition and the mtd-id string. |
236 | */ | 236 | */ |
@@ -239,7 +239,7 @@ static int mtdpart_setup_real(char *s) | |||
239 | &num_parts, /* out: number of parts */ | 239 | &num_parts, /* out: number of parts */ |
240 | 0, /* first partition */ | 240 | 0, /* first partition */ |
241 | (unsigned char**)&this_mtd, /* out: extra mem */ | 241 | (unsigned char**)&this_mtd, /* out: extra mem */ |
242 | mtd_id_len + 1 + sizeof(*this_mtd) + | 242 | mtd_id_len + 1 + sizeof(*this_mtd) + |
243 | sizeof(void*)-1 /*alignment*/); | 243 | sizeof(void*)-1 /*alignment*/); |
244 | if(!parts) | 244 | if(!parts) |
245 | { | 245 | { |
@@ -254,21 +254,21 @@ static int mtdpart_setup_real(char *s) | |||
254 | } | 254 | } |
255 | 255 | ||
256 | /* align this_mtd */ | 256 | /* align this_mtd */ |
257 | this_mtd = (struct cmdline_mtd_partition *) | 257 | this_mtd = (struct cmdline_mtd_partition *) |
258 | ALIGN((unsigned long)this_mtd, sizeof(void*)); | 258 | ALIGN((unsigned long)this_mtd, sizeof(void*)); |
259 | /* enter results */ | 259 | /* enter results */ |
260 | this_mtd->parts = parts; | 260 | this_mtd->parts = parts; |
261 | this_mtd->num_parts = num_parts; | 261 | this_mtd->num_parts = num_parts; |
262 | this_mtd->mtd_id = (char*)(this_mtd + 1); | 262 | this_mtd->mtd_id = (char*)(this_mtd + 1); |
263 | strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); | 263 | strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); |
264 | 264 | ||
265 | /* link into chain */ | 265 | /* link into chain */ |
266 | this_mtd->next = partitions; | 266 | this_mtd->next = partitions; |
267 | partitions = this_mtd; | 267 | partitions = this_mtd; |
268 | 268 | ||
269 | dbg(("mtdid=<%s> num_parts=<%d>\n", | 269 | dbg(("mtdid=<%s> num_parts=<%d>\n", |
270 | this_mtd->mtd_id, this_mtd->num_parts)); | 270 | this_mtd->mtd_id, this_mtd->num_parts)); |
271 | 271 | ||
272 | 272 | ||
273 | /* EOS - we're done */ | 273 | /* EOS - we're done */ |
274 | if (*s == 0) | 274 | if (*s == 0) |
@@ -292,7 +292,7 @@ static int mtdpart_setup_real(char *s) | |||
292 | * information. It returns partitions for the requested mtd device, or | 292 | * information. It returns partitions for the requested mtd device, or |
293 | * the first one in the chain if a NULL mtd_id is passed in. | 293 | * the first one in the chain if a NULL mtd_id is passed in. |
294 | */ | 294 | */ |
295 | static int parse_cmdline_partitions(struct mtd_info *master, | 295 | static int parse_cmdline_partitions(struct mtd_info *master, |
296 | struct mtd_partition **pparts, | 296 | struct mtd_partition **pparts, |
297 | unsigned long origin) | 297 | unsigned long origin) |
298 | { | 298 | { |
@@ -322,7 +322,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
322 | part->parts[i].size = master->size - offset; | 322 | part->parts[i].size = master->size - offset; |
323 | if (offset + part->parts[i].size > master->size) | 323 | if (offset + part->parts[i].size > master->size) |
324 | { | 324 | { |
325 | printk(KERN_WARNING ERRP | 325 | printk(KERN_WARNING ERRP |
326 | "%s: partitioning exceeds flash size, truncating\n", | 326 | "%s: partitioning exceeds flash size, truncating\n", |
327 | part->mtd_id); | 327 | part->mtd_id); |
328 | part->parts[i].size = master->size - offset; | 328 | part->parts[i].size = master->size - offset; |
@@ -338,8 +338,8 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
338 | } | 338 | } |
339 | 339 | ||
340 | 340 | ||
341 | /* | 341 | /* |
342 | * This is the handler for our kernel parameter, called from | 342 | * This is the handler for our kernel parameter, called from |
343 | * main.c::checksetup(). Note that we can not yet kmalloc() anything, | 343 | * main.c::checksetup(). Note that we can not yet kmalloc() anything, |
344 | * so we only save the commandline for later processing. | 344 | * so we only save the commandline for later processing. |
345 | * | 345 | * |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index c4a56a4ac5e2..9a2aa4033c6a 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
2 | # $Id: Kconfig,v 1.15 2004/12/22 17:51:15 joern Exp $ | 2 | # $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $ |
3 | 3 | ||
4 | menu "Self-contained MTD device drivers" | 4 | menu "Self-contained MTD device drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -110,7 +110,7 @@ config MTDRAM_ABS_POS | |||
110 | If you have system RAM accessible by the CPU but not used by Linux | 110 | If you have system RAM accessible by the CPU but not used by Linux |
111 | in normal operation, you can give the physical address at which the | 111 | in normal operation, you can give the physical address at which the |
112 | available RAM starts, and the MTDRAM driver will use it instead of | 112 | available RAM starts, and the MTDRAM driver will use it instead of |
113 | allocating space from Linux's available memory. Otherwise, leave | 113 | allocating space from Linux's available memory. Otherwise, leave |
114 | this set to zero. Most people will want to leave this as zero. | 114 | this set to zero. Most people will want to leave this as zero. |
115 | 115 | ||
116 | config MTD_BLKMTD | 116 | config MTD_BLKMTD |
@@ -165,7 +165,7 @@ config MTD_DOC2001 | |||
165 | select MTD_DOCPROBE | 165 | select MTD_DOCPROBE |
166 | select MTD_NAND_IDS | 166 | select MTD_NAND_IDS |
167 | ---help--- | 167 | ---help--- |
168 | This provides an alternative MTD device driver for the M-Systems | 168 | This provides an alternative MTD device driver for the M-Systems |
169 | DiskOnChip Millennium devices. Use this if you have problems with | 169 | DiskOnChip Millennium devices. Use this if you have problems with |
170 | the combined DiskOnChip 2000 and Millennium driver above. To get | 170 | the combined DiskOnChip 2000 and Millennium driver above. To get |
171 | the DiskOnChip probe code to load and use this driver instead of | 171 | the DiskOnChip probe code to load and use this driver instead of |
@@ -192,7 +192,7 @@ config MTD_DOC2001PLUS | |||
192 | 192 | ||
193 | If you use this device, you probably also want to enable the INFTL | 193 | If you use this device, you probably also want to enable the INFTL |
194 | 'Inverse NAND Flash Translation Layer' option below, which is used | 194 | 'Inverse NAND Flash Translation Layer' option below, which is used |
195 | to emulate a block device by using a kind of file system on the | 195 | to emulate a block device by using a kind of file system on the |
196 | flash chips. | 196 | flash chips. |
197 | 197 | ||
198 | NOTE: This driver will soon be replaced by the new DiskOnChip driver | 198 | NOTE: This driver will soon be replaced by the new DiskOnChip driver |
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c index 59a29e616a22..f9db52f6bf00 100644 --- a/drivers/mtd/devices/blkmtd.c +++ b/drivers/mtd/devices/blkmtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $ | 2 | * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $ |
3 | * | 3 | * |
4 | * blkmtd.c - use a block device as a fake MTD | 4 | * blkmtd.c - use a block device as a fake MTD |
5 | * | 5 | * |
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | /* Default erase size in K, always make it a multiple of PAGE_SIZE */ | 40 | /* Default erase size in K, always make it a multiple of PAGE_SIZE */ |
41 | #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ | 41 | #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ |
42 | #define VERSION "$Revision: 1.24 $" | 42 | #define VERSION "$Revision: 1.27 $" |
43 | 43 | ||
44 | /* Info for the block device */ | 44 | /* Info for the block device */ |
45 | struct blkmtd_dev { | 45 | struct blkmtd_dev { |
@@ -117,7 +117,7 @@ static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error | |||
117 | unlock_page(page); | 117 | unlock_page(page); |
118 | page_cache_release(page); | 118 | page_cache_release(page); |
119 | } while (bvec >= bio->bi_io_vec); | 119 | } while (bvec >= bio->bi_io_vec); |
120 | 120 | ||
121 | complete((struct completion*)bio->bi_private); | 121 | complete((struct completion*)bio->bi_private); |
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
@@ -135,7 +135,7 @@ static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page) | |||
135 | unlock_page(page); | 135 | unlock_page(page); |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | ClearPageUptodate(page); | 139 | ClearPageUptodate(page); |
140 | ClearPageError(page); | 140 | ClearPageError(page); |
141 | 141 | ||
@@ -707,7 +707,7 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size | |||
707 | dev->mtd_info.erasesize >> 10, | 707 | dev->mtd_info.erasesize >> 10, |
708 | readonly ? "(read-only)" : ""); | 708 | readonly ? "(read-only)" : ""); |
709 | } | 709 | } |
710 | 710 | ||
711 | return dev; | 711 | return dev; |
712 | 712 | ||
713 | devinit_err: | 713 | devinit_err: |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 4a7a805e7564..0aaa0ced9aba 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $ | 2 | * $Id: block2mtd.c,v 1.29 2005/11/07 11:14:24 gleixner Exp $ |
3 | * | 3 | * |
4 | * block2mtd.c - create an mtd from a block device | 4 | * block2mtd.c - create an mtd from a block device |
5 | * | 5 | * |
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | 21 | ||
22 | #define VERSION "$Revision: 1.28 $" | 22 | #define VERSION "$Revision: 1.29 $" |
23 | 23 | ||
24 | 24 | ||
25 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) | 25 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) |
@@ -111,7 +111,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) | |||
111 | return PTR_ERR(page); | 111 | return PTR_ERR(page); |
112 | 112 | ||
113 | max = (u_long*)page_address(page) + PAGE_SIZE; | 113 | max = (u_long*)page_address(page) + PAGE_SIZE; |
114 | for (p=(u_long*)page_address(page); p<max; p++) | 114 | for (p=(u_long*)page_address(page); p<max; p++) |
115 | if (*p != -1UL) { | 115 | if (*p != -1UL) { |
116 | lock_page(page); | 116 | lock_page(page); |
117 | memset(page_address(page), 0xff, PAGE_SIZE); | 117 | memset(page_address(page), 0xff, PAGE_SIZE); |
@@ -206,7 +206,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, | |||
206 | if (retlen) | 206 | if (retlen) |
207 | *retlen = 0; | 207 | *retlen = 0; |
208 | while (len) { | 208 | while (len) { |
209 | if ((offset+len) > PAGE_SIZE) | 209 | if ((offset+len) > PAGE_SIZE) |
210 | cpylen = PAGE_SIZE - offset; // multiple pages | 210 | cpylen = PAGE_SIZE - offset; // multiple pages |
211 | else | 211 | else |
212 | cpylen = len; // this page | 212 | cpylen = len; // this page |
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 5fc532895a24..be5e88b3888d 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
6 | * | 6 | * |
7 | * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $ | 7 | * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -58,7 +58,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
58 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 58 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
59 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 59 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, |
60 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 60 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
61 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | 61 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, |
62 | unsigned long count, loff_t to, size_t *retlen, | 62 | unsigned long count, loff_t to, size_t *retlen, |
63 | u_char *eccbuf, struct nand_oobinfo *oobsel); | 63 | u_char *eccbuf, struct nand_oobinfo *oobsel); |
64 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 64 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
@@ -76,14 +76,14 @@ static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles) | |||
76 | { | 76 | { |
77 | volatile char dummy; | 77 | volatile char dummy; |
78 | int i; | 78 | int i; |
79 | 79 | ||
80 | for (i = 0; i < cycles; i++) { | 80 | for (i = 0; i < cycles; i++) { |
81 | if (DoC_is_Millennium(doc)) | 81 | if (DoC_is_Millennium(doc)) |
82 | dummy = ReadDOC(doc->virtadr, NOP); | 82 | dummy = ReadDOC(doc->virtadr, NOP); |
83 | else | 83 | else |
84 | dummy = ReadDOC(doc->virtadr, DOCStatus); | 84 | dummy = ReadDOC(doc->virtadr, DOCStatus); |
85 | } | 85 | } |
86 | 86 | ||
87 | } | 87 | } |
88 | 88 | ||
89 | /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ | 89 | /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ |
@@ -220,8 +220,8 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs, | |||
220 | WriteDOC(ofs & 0xff, docptr, WritePipeTerm); | 220 | WriteDOC(ofs & 0xff, docptr, WritePipeTerm); |
221 | 221 | ||
222 | DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ | 222 | DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ |
223 | 223 | ||
224 | /* FIXME: The SlowIO's for millennium could be replaced by | 224 | /* FIXME: The SlowIO's for millennium could be replaced by |
225 | a single WritePipeTerm here. mf. */ | 225 | a single WritePipeTerm here. mf. */ |
226 | 226 | ||
227 | /* Lower the ALE line */ | 227 | /* Lower the ALE line */ |
@@ -377,9 +377,9 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
377 | if (mfr == 0xff || mfr == 0) | 377 | if (mfr == 0xff || mfr == 0) |
378 | return 0; | 378 | return 0; |
379 | 379 | ||
380 | /* Check it's the same as the first chip we identified. | 380 | /* Check it's the same as the first chip we identified. |
381 | * M-Systems say that any given DiskOnChip device should only | 381 | * M-Systems say that any given DiskOnChip device should only |
382 | * contain _one_ type of flash part, although that's not a | 382 | * contain _one_ type of flash part, although that's not a |
383 | * hardware restriction. */ | 383 | * hardware restriction. */ |
384 | if (doc->mfr) { | 384 | if (doc->mfr) { |
385 | if (doc->mfr == mfr && doc->id == id) | 385 | if (doc->mfr == mfr && doc->id == id) |
@@ -397,7 +397,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
397 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { | 397 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { |
398 | if (nand_manuf_ids[j].id == mfr) | 398 | if (nand_manuf_ids[j].id == mfr) |
399 | break; | 399 | break; |
400 | } | 400 | } |
401 | printk(KERN_INFO | 401 | printk(KERN_INFO |
402 | "Flash chip found: Manufacturer ID: %2.2X, " | 402 | "Flash chip found: Manufacturer ID: %2.2X, " |
403 | "Chip ID: %2.2X (%s:%s)\n", mfr, id, | 403 | "Chip ID: %2.2X (%s:%s)\n", mfr, id, |
@@ -405,7 +405,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
405 | if (!doc->mfr) { | 405 | if (!doc->mfr) { |
406 | doc->mfr = mfr; | 406 | doc->mfr = mfr; |
407 | doc->id = id; | 407 | doc->id = id; |
408 | doc->chipshift = | 408 | doc->chipshift = |
409 | ffs((nand_flash_ids[i].chipsize << 20)) - 1; | 409 | ffs((nand_flash_ids[i].chipsize << 20)) - 1; |
410 | doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; | 410 | doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; |
411 | doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; | 411 | doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; |
@@ -467,7 +467,7 @@ static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) | |||
467 | 467 | ||
468 | ret = 0; | 468 | ret = 0; |
469 | 469 | ||
470 | /* Fill out the chip array with {floor, chipno} for each | 470 | /* Fill out the chip array with {floor, chipno} for each |
471 | * detected chip in the device. */ | 471 | * detected chip in the device. */ |
472 | for (floor = 0; floor < MAX_FLOORS; floor++) { | 472 | for (floor = 0; floor < MAX_FLOORS; floor++) { |
473 | for (chip = 0; chip < numchips[floor]; chip++) { | 473 | for (chip = 0; chip < numchips[floor]; chip++) { |
@@ -757,12 +757,12 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
757 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], | 757 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], |
758 | eccbuf[3], eccbuf[4], eccbuf[5]); | 758 | eccbuf[3], eccbuf[4], eccbuf[5]); |
759 | #endif | 759 | #endif |
760 | 760 | ||
761 | /* disable the ECC engine */ | 761 | /* disable the ECC engine */ |
762 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); | 762 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); |
763 | } | 763 | } |
764 | 764 | ||
765 | /* according to 11.4.1, we need to wait for the busy line | 765 | /* according to 11.4.1, we need to wait for the busy line |
766 | * drop if we read to the end of the page. */ | 766 | * drop if we read to the end of the page. */ |
767 | if(0 == ((from + len) & 0x1ff)) | 767 | if(0 == ((from + len) & 0x1ff)) |
768 | { | 768 | { |
@@ -941,7 +941,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
941 | 941 | ||
942 | /* Let the caller know we completed it */ | 942 | /* Let the caller know we completed it */ |
943 | *retlen += len; | 943 | *retlen += len; |
944 | 944 | ||
945 | if (eccbuf) { | 945 | if (eccbuf) { |
946 | unsigned char x[8]; | 946 | unsigned char x[8]; |
947 | size_t dummy; | 947 | size_t dummy; |
@@ -950,10 +950,10 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
950 | /* Write the ECC data to flash */ | 950 | /* Write the ECC data to flash */ |
951 | for (di=0; di<6; di++) | 951 | for (di=0; di<6; di++) |
952 | x[di] = eccbuf[di]; | 952 | x[di] = eccbuf[di]; |
953 | 953 | ||
954 | x[6]=0x55; | 954 | x[6]=0x55; |
955 | x[7]=0x55; | 955 | x[7]=0x55; |
956 | 956 | ||
957 | ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); | 957 | ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); |
958 | if (ret) { | 958 | if (ret) { |
959 | up(&this->lock); | 959 | up(&this->lock); |
@@ -970,7 +970,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
970 | return 0; | 970 | return 0; |
971 | } | 971 | } |
972 | 972 | ||
973 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | 973 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, |
974 | unsigned long count, loff_t to, size_t *retlen, | 974 | unsigned long count, loff_t to, size_t *retlen, |
975 | u_char *eccbuf, struct nand_oobinfo *oobsel) | 975 | u_char *eccbuf, struct nand_oobinfo *oobsel) |
976 | { | 976 | { |
@@ -1022,7 +1022,7 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | |||
1022 | break; | 1022 | break; |
1023 | 1023 | ||
1024 | to += thislen; | 1024 | to += thislen; |
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | up(&writev_buf_sem); | 1027 | up(&writev_buf_sem); |
1028 | *retlen = totretlen; | 1028 | *retlen = totretlen; |
@@ -1080,7 +1080,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
1080 | /* Reading the full OOB data drops us off of the end of the page, | 1080 | /* Reading the full OOB data drops us off of the end of the page, |
1081 | * causing the flash device to go into busy mode, so we need | 1081 | * causing the flash device to go into busy mode, so we need |
1082 | * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ | 1082 | * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ |
1083 | 1083 | ||
1084 | ret = DoC_WaitReady(this); | 1084 | ret = DoC_WaitReady(this); |
1085 | 1085 | ||
1086 | up(&this->lock); | 1086 | up(&this->lock); |
@@ -1190,7 +1190,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
1190 | return 0; | 1190 | return 0; |
1191 | 1191 | ||
1192 | } | 1192 | } |
1193 | 1193 | ||
1194 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 1194 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
1195 | size_t * retlen, const u_char * buf) | 1195 | size_t * retlen, const u_char * buf) |
1196 | { | 1196 | { |
@@ -1222,7 +1222,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | instr->state = MTD_ERASING; | 1224 | instr->state = MTD_ERASING; |
1225 | 1225 | ||
1226 | /* FIXME: Do this in the background. Use timers or schedule_task() */ | 1226 | /* FIXME: Do this in the background. Use timers or schedule_task() */ |
1227 | while(len) { | 1227 | while(len) { |
1228 | mychip = &this->chips[ofs >> this->chipshift]; | 1228 | mychip = &this->chips[ofs >> this->chipshift]; |
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 1e704915ef08..fcb28a6fd89f 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
6 | * | 6 | * |
7 | * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $ | 7 | * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -196,10 +196,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
196 | DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); | 196 | DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); |
197 | DoC_WaitReady(doc->virtadr); | 197 | DoC_WaitReady(doc->virtadr); |
198 | 198 | ||
199 | /* Read the NAND chip ID: 1. Send ReadID command */ | 199 | /* Read the NAND chip ID: 1. Send ReadID command */ |
200 | DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); | 200 | DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); |
201 | 201 | ||
202 | /* Read the NAND chip ID: 2. Send address byte zero */ | 202 | /* Read the NAND chip ID: 2. Send address byte zero */ |
203 | DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); | 203 | DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); |
204 | 204 | ||
205 | /* Read the manufacturer and device id codes of the flash device through | 205 | /* Read the manufacturer and device id codes of the flash device through |
@@ -223,7 +223,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
223 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { | 223 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { |
224 | if (nand_manuf_ids[j].id == mfr) | 224 | if (nand_manuf_ids[j].id == mfr) |
225 | break; | 225 | break; |
226 | } | 226 | } |
227 | printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " | 227 | printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " |
228 | "Chip ID: %2.2X (%s:%s)\n", | 228 | "Chip ID: %2.2X (%s:%s)\n", |
229 | mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); | 229 | mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); |
@@ -275,7 +275,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
275 | return; | 275 | return; |
276 | } | 276 | } |
277 | 277 | ||
278 | /* Fill out the chip array with {floor, chipno} for each | 278 | /* Fill out the chip array with {floor, chipno} for each |
279 | * detected chip in the device. */ | 279 | * detected chip in the device. */ |
280 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { | 280 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { |
281 | for (chip = 0 ; chip < numchips[floor] ; chip++) { | 281 | for (chip = 0 ; chip < numchips[floor] ; chip++) { |
@@ -309,7 +309,7 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) | |||
309 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); | 309 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); |
310 | if (tmp1 != tmp2) | 310 | if (tmp1 != tmp2) |
311 | return 0; | 311 | return 0; |
312 | 312 | ||
313 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); | 313 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); |
314 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); | 314 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); |
315 | if (tmp2 == (tmp1+1) % 0xff) | 315 | if (tmp2 == (tmp1+1) % 0xff) |
@@ -425,7 +425,7 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
425 | return -EINVAL; | 425 | return -EINVAL; |
426 | 426 | ||
427 | /* Don't allow a single read to cross a 512-byte block boundary */ | 427 | /* Don't allow a single read to cross a 512-byte block boundary */ |
428 | if (from + len > ((from | 0x1ff) + 1)) | 428 | if (from + len > ((from | 0x1ff) + 1)) |
429 | len = ((from | 0x1ff) + 1) - from; | 429 | len = ((from | 0x1ff) + 1) - from; |
430 | 430 | ||
431 | /* Find the chip which is to be used and select it */ | 431 | /* Find the chip which is to be used and select it */ |
@@ -552,7 +552,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
552 | 552 | ||
553 | #if 0 | 553 | #if 0 |
554 | /* Don't allow a single write to cross a 512-byte block boundary */ | 554 | /* Don't allow a single write to cross a 512-byte block boundary */ |
555 | if (to + len > ( (to | 0x1ff) + 1)) | 555 | if (to + len > ( (to | 0x1ff) + 1)) |
556 | len = ((to | 0x1ff) + 1) - to; | 556 | len = ((to | 0x1ff) + 1) - to; |
557 | #else | 557 | #else |
558 | /* Don't allow writes which aren't exactly one block */ | 558 | /* Don't allow writes which aren't exactly one block */ |
@@ -632,7 +632,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
632 | 632 | ||
633 | /* write the block status BLOCK_USED (0x5555) at the end of ECC data | 633 | /* write the block status BLOCK_USED (0x5555) at the end of ECC data |
634 | FIXME: this is only a hack for programming the IPL area for LinuxBIOS | 634 | FIXME: this is only a hack for programming the IPL area for LinuxBIOS |
635 | and should be replace with proper codes in user space utilities */ | 635 | and should be replace with proper codes in user space utilities */ |
636 | WriteDOC(0x55, docptr, Mil_CDSN_IO); | 636 | WriteDOC(0x55, docptr, Mil_CDSN_IO); |
637 | WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); | 637 | WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); |
638 | 638 | ||
@@ -802,7 +802,7 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
802 | void __iomem *docptr = this->virtadr; | 802 | void __iomem *docptr = this->virtadr; |
803 | struct Nand *mychip = &this->chips[ofs >> this->chipshift]; | 803 | struct Nand *mychip = &this->chips[ofs >> this->chipshift]; |
804 | 804 | ||
805 | if (len != mtd->erasesize) | 805 | if (len != mtd->erasesize) |
806 | printk(KERN_WARNING "Erase not right size (%x != %x)n", | 806 | printk(KERN_WARNING "Erase not right size (%x != %x)n", |
807 | len, mtd->erasesize); | 807 | len, mtd->erasesize); |
808 | 808 | ||
@@ -870,9 +870,9 @@ static void __exit cleanup_doc2001(void) | |||
870 | while ((mtd=docmillist)) { | 870 | while ((mtd=docmillist)) { |
871 | this = mtd->priv; | 871 | this = mtd->priv; |
872 | docmillist = this->nextdoc; | 872 | docmillist = this->nextdoc; |
873 | 873 | ||
874 | del_mtd_device(mtd); | 874 | del_mtd_device(mtd); |
875 | 875 | ||
876 | iounmap(this->virtadr); | 876 | iounmap(this->virtadr); |
877 | kfree(this->chips); | 877 | kfree(this->chips); |
878 | kfree(mtd); | 878 | kfree(mtd); |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index ed47bafb2ce2..0595cc7324b2 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * (c) 1999 Machine Vision Holdings, Inc. | 6 | * (c) 1999 Machine Vision Holdings, Inc. |
7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
8 | * | 8 | * |
9 | * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $ | 9 | * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $ |
10 | * | 10 | * |
11 | * Released under GPL | 11 | * Released under GPL |
12 | */ | 12 | */ |
@@ -293,10 +293,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
293 | DoC_Command(docptr, NAND_CMD_RESET, 0); | 293 | DoC_Command(docptr, NAND_CMD_RESET, 0); |
294 | DoC_WaitReady(docptr); | 294 | DoC_WaitReady(docptr); |
295 | 295 | ||
296 | /* Read the NAND chip ID: 1. Send ReadID command */ | 296 | /* Read the NAND chip ID: 1. Send ReadID command */ |
297 | DoC_Command(docptr, NAND_CMD_READID, 0); | 297 | DoC_Command(docptr, NAND_CMD_READID, 0); |
298 | 298 | ||
299 | /* Read the NAND chip ID: 2. Send address byte zero */ | 299 | /* Read the NAND chip ID: 2. Send address byte zero */ |
300 | DoC_Address(doc, 1, 0x00, 0, 0x00); | 300 | DoC_Address(doc, 1, 0x00, 0, 0x00); |
301 | 301 | ||
302 | WriteDOC(0, docptr, Mplus_FlashControl); | 302 | WriteDOC(0, docptr, Mplus_FlashControl); |
@@ -365,7 +365,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
365 | this->interleave = 1; | 365 | this->interleave = 1; |
366 | 366 | ||
367 | /* Check the ASIC agrees */ | 367 | /* Check the ASIC agrees */ |
368 | if ( (this->interleave << 2) != | 368 | if ( (this->interleave << 2) != |
369 | (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { | 369 | (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { |
370 | u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); | 370 | u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); |
371 | printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", | 371 | printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", |
@@ -398,7 +398,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
398 | return; | 398 | return; |
399 | } | 399 | } |
400 | 400 | ||
401 | /* Fill out the chip array with {floor, chipno} for each | 401 | /* Fill out the chip array with {floor, chipno} for each |
402 | * detected chip in the device. */ | 402 | * detected chip in the device. */ |
403 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { | 403 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { |
404 | for (chip = 0 ; chip < numchips[floor] ; chip++) { | 404 | for (chip = 0 ; chip < numchips[floor] ; chip++) { |
@@ -432,7 +432,7 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) | |||
432 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); | 432 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); |
433 | if (tmp1 != tmp2) | 433 | if (tmp1 != tmp2) |
434 | return 0; | 434 | return 0; |
435 | 435 | ||
436 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); | 436 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); |
437 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); | 437 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); |
438 | if (tmp2 == (tmp1+1) % 0xff) | 438 | if (tmp2 == (tmp1+1) % 0xff) |
@@ -624,7 +624,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
624 | return -EINVAL; | 624 | return -EINVAL; |
625 | 625 | ||
626 | /* Don't allow a single read to cross a 512-byte block boundary */ | 626 | /* Don't allow a single read to cross a 512-byte block boundary */ |
627 | if (from + len > ((from | 0x1ff) + 1)) | 627 | if (from + len > ((from | 0x1ff) + 1)) |
628 | len = ((from | 0x1ff) + 1) - from; | 628 | len = ((from | 0x1ff) + 1) - from; |
629 | 629 | ||
630 | DoC_CheckASIC(docptr); | 630 | DoC_CheckASIC(docptr); |
@@ -1066,7 +1066,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1066 | 1066 | ||
1067 | DoC_CheckASIC(docptr); | 1067 | DoC_CheckASIC(docptr); |
1068 | 1068 | ||
1069 | if (len != mtd->erasesize) | 1069 | if (len != mtd->erasesize) |
1070 | printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", | 1070 | printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", |
1071 | len, mtd->erasesize); | 1071 | len, mtd->erasesize); |
1072 | 1072 | ||
@@ -1136,9 +1136,9 @@ static void __exit cleanup_doc2001plus(void) | |||
1136 | while ((mtd=docmilpluslist)) { | 1136 | while ((mtd=docmilpluslist)) { |
1137 | this = mtd->priv; | 1137 | this = mtd->priv; |
1138 | docmilpluslist = this->nextdoc; | 1138 | docmilpluslist = this->nextdoc; |
1139 | 1139 | ||
1140 | del_mtd_device(mtd); | 1140 | del_mtd_device(mtd); |
1141 | 1141 | ||
1142 | iounmap(this->virtadr); | 1142 | iounmap(this->virtadr); |
1143 | kfree(this->chips); | 1143 | kfree(this->chips); |
1144 | kfree(mtd); | 1144 | kfree(mtd); |
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 24f670b5a4f3..cd3db72bef96 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c | |||
@@ -4,10 +4,10 @@ | |||
4 | * GNU GPL License. The rest is simply to convert the disk on chip | 4 | * GNU GPL License. The rest is simply to convert the disk on chip |
5 | * syndrom into a standard syndom. | 5 | * syndrom into a standard syndom. |
6 | * | 6 | * |
7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
8 | * Copyright (C) 2000 Netgem S.A. | 8 | * Copyright (C) 2000 Netgem S.A. |
9 | * | 9 | * |
10 | * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $ | 10 | * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 gleixner Exp $ |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -122,7 +122,7 @@ for(ci=(n)-1;ci >=0;ci--)\ | |||
122 | a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) | 122 | a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) |
123 | we consider the integer "i" whose binary representation with a(0) being LSB | 123 | we consider the integer "i" whose binary representation with a(0) being LSB |
124 | and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry | 124 | and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry |
125 | "index_of[i]". Now, @^index_of[i] is that element whose polynomial | 125 | "index_of[i]". Now, @^index_of[i] is that element whose polynomial |
126 | representation is (a(0),a(1),a(2),...,a(m-1)). | 126 | representation is (a(0),a(1),a(2),...,a(m-1)). |
127 | NOTE: | 127 | NOTE: |
128 | The element alpha_to[2^m-1] = 0 always signifying that the | 128 | The element alpha_to[2^m-1] = 0 always signifying that the |
@@ -130,7 +130,7 @@ for(ci=(n)-1;ci >=0;ci--)\ | |||
130 | Similarily, the element index_of[0] = A0 always signifying | 130 | Similarily, the element index_of[0] = A0 always signifying |
131 | that the power of alpha which has the polynomial representation | 131 | that the power of alpha which has the polynomial representation |
132 | (0,0,...,0) is "infinity". | 132 | (0,0,...,0) is "infinity". |
133 | 133 | ||
134 | */ | 134 | */ |
135 | 135 | ||
136 | static void | 136 | static void |
@@ -176,7 +176,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) | |||
176 | * are written back. NOTE! This array must be at least NN-KK elements long. | 176 | * are written back. NOTE! This array must be at least NN-KK elements long. |
177 | * The corrected data are written in eras_val[]. They must be xor with the data | 177 | * The corrected data are written in eras_val[]. They must be xor with the data |
178 | * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . | 178 | * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . |
179 | * | 179 | * |
180 | * First "no_eras" erasures are declared by the calling program. Then, the | 180 | * First "no_eras" erasures are declared by the calling program. Then, the |
181 | * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). | 181 | * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). |
182 | * If the number of channel errors is not greater than "t_after_eras" the | 182 | * If the number of channel errors is not greater than "t_after_eras" the |
@@ -189,7 +189,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) | |||
189 | * */ | 189 | * */ |
190 | static int | 190 | static int |
191 | eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | 191 | eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], |
192 | gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], | 192 | gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], |
193 | int no_eras) | 193 | int no_eras) |
194 | { | 194 | { |
195 | int deg_lambda, el, deg_omega; | 195 | int deg_lambda, el, deg_omega; |
@@ -212,7 +212,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
212 | count = 0; | 212 | count = 0; |
213 | goto finish; | 213 | goto finish; |
214 | } | 214 | } |
215 | 215 | ||
216 | for(i=1;i<=NN-KK;i++){ | 216 | for(i=1;i<=NN-KK;i++){ |
217 | s[i] = bb[0]; | 217 | s[i] = bb[0]; |
218 | } | 218 | } |
@@ -220,7 +220,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
220 | if(bb[j] == 0) | 220 | if(bb[j] == 0) |
221 | continue; | 221 | continue; |
222 | tmp = Index_of[bb[j]]; | 222 | tmp = Index_of[bb[j]]; |
223 | 223 | ||
224 | for(i=1;i<=NN-KK;i++) | 224 | for(i=1;i<=NN-KK;i++) |
225 | s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)]; | 225 | s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)]; |
226 | } | 226 | } |
@@ -234,7 +234,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
234 | tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM); | 234 | tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM); |
235 | s[i] = tmp; | 235 | s[i] = tmp; |
236 | } | 236 | } |
237 | 237 | ||
238 | CLEAR(&lambda[1],NN-KK); | 238 | CLEAR(&lambda[1],NN-KK); |
239 | lambda[0] = 1; | 239 | lambda[0] = 1; |
240 | 240 | ||
@@ -252,7 +252,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
252 | #if DEBUG_ECC >= 1 | 252 | #if DEBUG_ECC >= 1 |
253 | /* Test code that verifies the erasure locator polynomial just constructed | 253 | /* Test code that verifies the erasure locator polynomial just constructed |
254 | Needed only for decoder debugging. */ | 254 | Needed only for decoder debugging. */ |
255 | 255 | ||
256 | /* find roots of the erasure location polynomial */ | 256 | /* find roots of the erasure location polynomial */ |
257 | for(i=1;i<=no_eras;i++) | 257 | for(i=1;i<=no_eras;i++) |
258 | reg[i] = Index_of[lambda[i]]; | 258 | reg[i] = Index_of[lambda[i]]; |
@@ -286,7 +286,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
286 | } | 286 | } |
287 | for(i=0;i<NN-KK+1;i++) | 287 | for(i=0;i<NN-KK+1;i++) |
288 | b[i] = Index_of[lambda[i]]; | 288 | b[i] = Index_of[lambda[i]]; |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Begin Berlekamp-Massey algorithm to determine error+erasure | 291 | * Begin Berlekamp-Massey algorithm to determine error+erasure |
292 | * locator polynomial | 292 | * locator polynomial |
@@ -389,7 +389,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
389 | omega[i] = Index_of[tmp]; | 389 | omega[i] = Index_of[tmp]; |
390 | } | 390 | } |
391 | omega[NN-KK] = A0; | 391 | omega[NN-KK] = A0; |
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = | 394 | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = |
395 | * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form | 395 | * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form |
@@ -402,7 +402,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
402 | } | 402 | } |
403 | num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; | 403 | num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; |
404 | den = 0; | 404 | den = 0; |
405 | 405 | ||
406 | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ | 406 | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ |
407 | for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { | 407 | for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { |
408 | if(lambda[i+1] != A0) | 408 | if(lambda[i+1] != A0) |
@@ -436,11 +436,11 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
436 | /* The sector bytes are packed into NB_DATA MM bits words */ | 436 | /* The sector bytes are packed into NB_DATA MM bits words */ |
437 | #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM) | 437 | #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM) |
438 | 438 | ||
439 | /* | 439 | /* |
440 | * Correct the errors in 'sector[]' by using 'ecc1[]' which is the | 440 | * Correct the errors in 'sector[]' by using 'ecc1[]' which is the |
441 | * content of the feedback shift register applyied to the sector and | 441 | * content of the feedback shift register applyied to the sector and |
442 | * the ECC. Return the number of errors corrected (and correct them in | 442 | * the ECC. Return the number of errors corrected (and correct them in |
443 | * sector), or -1 if error | 443 | * sector), or -1 if error |
444 | */ | 444 | */ |
445 | int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | 445 | int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) |
446 | { | 446 | { |
@@ -454,7 +454,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
454 | Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); | 454 | Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); |
455 | if (!Alpha_to) | 455 | if (!Alpha_to) |
456 | return -1; | 456 | return -1; |
457 | 457 | ||
458 | Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); | 458 | Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); |
459 | if (!Index_of) { | 459 | if (!Index_of) { |
460 | kfree(Alpha_to); | 460 | kfree(Alpha_to); |
@@ -470,7 +470,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
470 | bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); | 470 | bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); |
471 | bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); | 471 | bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); |
472 | 472 | ||
473 | nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, | 473 | nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, |
474 | error_val, error_pos, 0); | 474 | error_val, error_pos, 0); |
475 | if (nb_errors <= 0) | 475 | if (nb_errors <= 0) |
476 | goto the_end; | 476 | goto the_end; |
@@ -489,7 +489,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
489 | can be modified since pos is even */ | 489 | can be modified since pos is even */ |
490 | index = (pos >> 3) ^ 1; | 490 | index = (pos >> 3) ^ 1; |
491 | bitpos = pos & 7; | 491 | bitpos = pos & 7; |
492 | if ((index >= 0 && index < SECTOR_SIZE) || | 492 | if ((index >= 0 && index < SECTOR_SIZE) || |
493 | index == (SECTOR_SIZE + 1)) { | 493 | index == (SECTOR_SIZE + 1)) { |
494 | val = error_val[i] >> (2 + bitpos); | 494 | val = error_val[i] >> (2 + bitpos); |
495 | parity ^= val; | 495 | parity ^= val; |
@@ -500,7 +500,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
500 | bitpos = (bitpos + 10) & 7; | 500 | bitpos = (bitpos + 10) & 7; |
501 | if (bitpos == 0) | 501 | if (bitpos == 0) |
502 | bitpos = 8; | 502 | bitpos = 8; |
503 | if ((index >= 0 && index < SECTOR_SIZE) || | 503 | if ((index >= 0 && index < SECTOR_SIZE) || |
504 | index == (SECTOR_SIZE + 1)) { | 504 | index == (SECTOR_SIZE + 1)) { |
505 | val = error_val[i] << (8 - bitpos); | 505 | val = error_val[i] << (8 - bitpos); |
506 | parity ^= val; | 506 | parity ^= val; |
@@ -509,7 +509,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
509 | } | 509 | } |
510 | } | 510 | } |
511 | } | 511 | } |
512 | 512 | ||
513 | /* use parity to test extra errors */ | 513 | /* use parity to test extra errors */ |
514 | if ((parity & 0xff) != 0) | 514 | if ((parity & 0xff) != 0) |
515 | nb_errors = -1; | 515 | nb_errors = -1; |
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 197d67045e1e..13178b9dd00a 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c | |||
@@ -4,22 +4,22 @@ | |||
4 | /* (C) 1999 Machine Vision Holdings, Inc. */ | 4 | /* (C) 1999 Machine Vision Holdings, Inc. */ |
5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ | 5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ |
6 | 6 | ||
7 | /* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $ */ | 7 | /* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $ */ |
8 | 8 | ||
9 | 9 | ||
10 | 10 | ||
11 | /* DOC_PASSIVE_PROBE: | 11 | /* DOC_PASSIVE_PROBE: |
12 | In order to ensure that the BIOS checksum is correct at boot time, and | 12 | In order to ensure that the BIOS checksum is correct at boot time, and |
13 | hence that the onboard BIOS extension gets executed, the DiskOnChip | 13 | hence that the onboard BIOS extension gets executed, the DiskOnChip |
14 | goes into reset mode when it is read sequentially: all registers | 14 | goes into reset mode when it is read sequentially: all registers |
15 | return 0xff until the chip is woken up again by writing to the | 15 | return 0xff until the chip is woken up again by writing to the |
16 | DOCControl register. | 16 | DOCControl register. |
17 | 17 | ||
18 | Unfortunately, this means that the probe for the DiskOnChip is unsafe, | 18 | Unfortunately, this means that the probe for the DiskOnChip is unsafe, |
19 | because one of the first things it does is write to where it thinks | 19 | because one of the first things it does is write to where it thinks |
20 | the DOCControl register should be - which may well be shared memory | 20 | the DOCControl register should be - which may well be shared memory |
21 | for another device. I've had machines which lock up when this is | 21 | for another device. I've had machines which lock up when this is |
22 | attempted. Hence the possibility to do a passive probe, which will fail | 22 | attempted. Hence the possibility to do a passive probe, which will fail |
23 | to detect a chip in reset mode, but is at least guaranteed not to lock | 23 | to detect a chip in reset mode, but is at least guaranteed not to lock |
24 | the machine. | 24 | the machine. |
25 | 25 | ||
@@ -33,9 +33,9 @@ | |||
33 | 33 | ||
34 | The old Millennium-only driver has been retained just in case there | 34 | The old Millennium-only driver has been retained just in case there |
35 | are problems with the new code. If the combined driver doesn't work | 35 | are problems with the new code. If the combined driver doesn't work |
36 | for you, you can try the old one by undefining DOC_SINGLE_DRIVER | 36 | for you, you can try the old one by undefining DOC_SINGLE_DRIVER |
37 | below and also enabling it in your configuration. If this fixes the | 37 | below and also enabling it in your configuration. If this fixes the |
38 | problems, please send a report to the MTD mailing list at | 38 | problems, please send a report to the MTD mailing list at |
39 | <linux-mtd@lists.infradead.org>. | 39 | <linux-mtd@lists.infradead.org>. |
40 | */ | 40 | */ |
41 | #define DOC_SINGLE_DRIVER | 41 | #define DOC_SINGLE_DRIVER |
@@ -68,16 +68,16 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe | |||
68 | static unsigned long __initdata doc_locations[] = { | 68 | static unsigned long __initdata doc_locations[] = { |
69 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) | 69 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) |
70 | #ifdef CONFIG_MTD_DOCPROBE_HIGH | 70 | #ifdef CONFIG_MTD_DOCPROBE_HIGH |
71 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, | 71 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, |
72 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, | 72 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, |
73 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, | 73 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, |
74 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, | 74 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, |
75 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, | 75 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, |
76 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ | 76 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ |
77 | 0xc8000, 0xca000, 0xcc000, 0xce000, | 77 | 0xc8000, 0xca000, 0xcc000, 0xce000, |
78 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, | 78 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, |
79 | 0xd8000, 0xda000, 0xdc000, 0xde000, | 79 | 0xd8000, 0xda000, 0xdc000, 0xde000, |
80 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 80 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
81 | 0xe8000, 0xea000, 0xec000, 0xee000, | 81 | 0xe8000, 0xea000, 0xec000, 0xee000, |
82 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 82 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
83 | #elif defined(__PPC__) | 83 | #elif defined(__PPC__) |
@@ -111,35 +111,35 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
111 | return 0; | 111 | return 0; |
112 | #endif /* CONFIG_MTD_DOCPROBE_55AA */ | 112 | #endif /* CONFIG_MTD_DOCPROBE_55AA */ |
113 | 113 | ||
114 | #ifndef DOC_PASSIVE_PROBE | 114 | #ifndef DOC_PASSIVE_PROBE |
115 | /* It's not possible to cleanly detect the DiskOnChip - the | 115 | /* It's not possible to cleanly detect the DiskOnChip - the |
116 | * bootup procedure will put the device into reset mode, and | 116 | * bootup procedure will put the device into reset mode, and |
117 | * it's not possible to talk to it without actually writing | 117 | * it's not possible to talk to it without actually writing |
118 | * to the DOCControl register. So we store the current contents | 118 | * to the DOCControl register. So we store the current contents |
119 | * of the DOCControl register's location, in case we later decide | 119 | * of the DOCControl register's location, in case we later decide |
120 | * that it's not a DiskOnChip, and want to put it back how we | 120 | * that it's not a DiskOnChip, and want to put it back how we |
121 | * found it. | 121 | * found it. |
122 | */ | 122 | */ |
123 | tmp2 = ReadDOC(window, DOCControl); | 123 | tmp2 = ReadDOC(window, DOCControl); |
124 | 124 | ||
125 | /* Reset the DiskOnChip ASIC */ | 125 | /* Reset the DiskOnChip ASIC */ |
126 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 126 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
127 | window, DOCControl); | 127 | window, DOCControl); |
128 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 128 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
129 | window, DOCControl); | 129 | window, DOCControl); |
130 | 130 | ||
131 | /* Enable the DiskOnChip ASIC */ | 131 | /* Enable the DiskOnChip ASIC */ |
132 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 132 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
133 | window, DOCControl); | 133 | window, DOCControl); |
134 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 134 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
135 | window, DOCControl); | 135 | window, DOCControl); |
136 | #endif /* !DOC_PASSIVE_PROBE */ | 136 | #endif /* !DOC_PASSIVE_PROBE */ |
137 | 137 | ||
138 | /* We need to read the ChipID register four times. For some | 138 | /* We need to read the ChipID register four times. For some |
139 | newer DiskOnChip 2000 units, the first three reads will | 139 | newer DiskOnChip 2000 units, the first three reads will |
140 | return the DiskOnChip Millennium ident. Don't ask. */ | 140 | return the DiskOnChip Millennium ident. Don't ask. */ |
141 | ChipID = ReadDOC(window, ChipID); | 141 | ChipID = ReadDOC(window, ChipID); |
142 | 142 | ||
143 | switch (ChipID) { | 143 | switch (ChipID) { |
144 | case DOC_ChipID_Doc2k: | 144 | case DOC_ChipID_Doc2k: |
145 | /* Check the TOGGLE bit in the ECC register */ | 145 | /* Check the TOGGLE bit in the ECC register */ |
@@ -149,7 +149,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
149 | if (tmp != tmpb && tmp == tmpc) | 149 | if (tmp != tmpb && tmp == tmpc) |
150 | return ChipID; | 150 | return ChipID; |
151 | break; | 151 | break; |
152 | 152 | ||
153 | case DOC_ChipID_DocMil: | 153 | case DOC_ChipID_DocMil: |
154 | /* Check for the new 2000 with Millennium ASIC */ | 154 | /* Check for the new 2000 with Millennium ASIC */ |
155 | ReadDOC(window, ChipID); | 155 | ReadDOC(window, ChipID); |
@@ -164,7 +164,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
164 | if (tmp != tmpb && tmp == tmpc) | 164 | if (tmp != tmpb && tmp == tmpc) |
165 | return ChipID; | 165 | return ChipID; |
166 | break; | 166 | break; |
167 | 167 | ||
168 | case DOC_ChipID_DocMilPlus16: | 168 | case DOC_ChipID_DocMilPlus16: |
169 | case DOC_ChipID_DocMilPlus32: | 169 | case DOC_ChipID_DocMilPlus32: |
170 | case 0: | 170 | case 0: |
@@ -179,7 +179,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
179 | DOC_MODE_BDECT; | 179 | DOC_MODE_BDECT; |
180 | WriteDOC(tmp, window, Mplus_DOCControl); | 180 | WriteDOC(tmp, window, Mplus_DOCControl); |
181 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); | 181 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); |
182 | 182 | ||
183 | mdelay(1); | 183 | mdelay(1); |
184 | /* Enable the DiskOnChip ASIC */ | 184 | /* Enable the DiskOnChip ASIC */ |
185 | tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | | 185 | tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | |
@@ -187,7 +187,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
187 | WriteDOC(tmp, window, Mplus_DOCControl); | 187 | WriteDOC(tmp, window, Mplus_DOCControl); |
188 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); | 188 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); |
189 | mdelay(1); | 189 | mdelay(1); |
190 | #endif /* !DOC_PASSIVE_PROBE */ | 190 | #endif /* !DOC_PASSIVE_PROBE */ |
191 | 191 | ||
192 | ChipID = ReadDOC(window, ChipID); | 192 | ChipID = ReadDOC(window, ChipID); |
193 | 193 | ||
@@ -227,7 +227,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
227 | WriteDOC(tmp2, window, DOCControl); | 227 | WriteDOC(tmp2, window, DOCControl); |
228 | #endif | 228 | #endif |
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | 231 | ||
232 | static int docfound; | 232 | static int docfound; |
233 | 233 | ||
@@ -244,10 +244,10 @@ static void __init DoC_Probe(unsigned long physadr) | |||
244 | void (*initroutine)(struct mtd_info *) = NULL; | 244 | void (*initroutine)(struct mtd_info *) = NULL; |
245 | 245 | ||
246 | docptr = ioremap(physadr, DOC_IOREMAP_LEN); | 246 | docptr = ioremap(physadr, DOC_IOREMAP_LEN); |
247 | 247 | ||
248 | if (!docptr) | 248 | if (!docptr) |
249 | return; | 249 | return; |
250 | 250 | ||
251 | if ((ChipID = doccheck(docptr, physadr))) { | 251 | if ((ChipID = doccheck(docptr, physadr))) { |
252 | if (ChipID == DOC_ChipID_Doc2kTSOP) { | 252 | if (ChipID == DOC_ChipID_Doc2kTSOP) { |
253 | /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ | 253 | /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ |
@@ -263,9 +263,9 @@ static void __init DoC_Probe(unsigned long physadr) | |||
263 | iounmap(docptr); | 263 | iounmap(docptr); |
264 | return; | 264 | return; |
265 | } | 265 | } |
266 | 266 | ||
267 | this = (struct DiskOnChip *)(&mtd[1]); | 267 | this = (struct DiskOnChip *)(&mtd[1]); |
268 | 268 | ||
269 | memset((char *)mtd,0, sizeof(struct mtd_info)); | 269 | memset((char *)mtd,0, sizeof(struct mtd_info)); |
270 | memset((char *)this, 0, sizeof(struct DiskOnChip)); | 270 | memset((char *)this, 0, sizeof(struct DiskOnChip)); |
271 | 271 | ||
@@ -281,13 +281,13 @@ static void __init DoC_Probe(unsigned long physadr) | |||
281 | im_funcname = "DoC2k_init"; | 281 | im_funcname = "DoC2k_init"; |
282 | im_modname = "doc2000"; | 282 | im_modname = "doc2000"; |
283 | break; | 283 | break; |
284 | 284 | ||
285 | case DOC_ChipID_Doc2k: | 285 | case DOC_ChipID_Doc2k: |
286 | name="2000"; | 286 | name="2000"; |
287 | im_funcname = "DoC2k_init"; | 287 | im_funcname = "DoC2k_init"; |
288 | im_modname = "doc2000"; | 288 | im_modname = "doc2000"; |
289 | break; | 289 | break; |
290 | 290 | ||
291 | case DOC_ChipID_DocMil: | 291 | case DOC_ChipID_DocMil: |
292 | name="Millennium"; | 292 | name="Millennium"; |
293 | #ifdef DOC_SINGLE_DRIVER | 293 | #ifdef DOC_SINGLE_DRIVER |
@@ -331,7 +331,7 @@ static void __init DoC_Probe(unsigned long physadr) | |||
331 | static int __init init_doc(void) | 331 | static int __init init_doc(void) |
332 | { | 332 | { |
333 | int i; | 333 | int i; |
334 | 334 | ||
335 | if (doc_config_location) { | 335 | if (doc_config_location) { |
336 | printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); | 336 | printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); |
337 | DoC_Probe(doc_config_location); | 337 | DoC_Probe(doc_config_location); |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index df987a53ed9c..1e876fcb0408 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. | 3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. |
4 | * | 4 | * |
5 | * $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $ | 5 | * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $ |
6 | * | 6 | * |
7 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> | 7 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> |
8 | * | 8 | * |
@@ -122,7 +122,7 @@ static char module_name[] = "lart"; | |||
122 | 122 | ||
123 | /* | 123 | /* |
124 | * The data line mapping on LART is as follows: | 124 | * The data line mapping on LART is as follows: |
125 | * | 125 | * |
126 | * U2 CPU | U3 CPU | 126 | * U2 CPU | U3 CPU |
127 | * ------------------- | 127 | * ------------------- |
128 | * 0 20 | 0 12 | 128 | * 0 20 | 0 12 |
@@ -181,7 +181,7 @@ static char module_name[] = "lart"; | |||
181 | (((x) & 0x00004000) >> 13) \ | 181 | (((x) & 0x00004000) >> 13) \ |
182 | ) | 182 | ) |
183 | 183 | ||
184 | /* | 184 | /* |
185 | * The address line mapping on LART is as follows: | 185 | * The address line mapping on LART is as follows: |
186 | * | 186 | * |
187 | * U3 CPU | U2 CPU | 187 | * U3 CPU | U2 CPU |
@@ -204,7 +204,7 @@ static char module_name[] = "lart"; | |||
204 | * 12 15 | 12 15 | 204 | * 12 15 | 12 15 |
205 | * 13 14 | 13 14 | 205 | * 13 14 | 13 14 |
206 | * 14 16 | 14 16 | 206 | * 14 16 | 14 16 |
207 | * | 207 | * |
208 | * MAIN BLOCK BOUNDARY | 208 | * MAIN BLOCK BOUNDARY |
209 | * | 209 | * |
210 | * 15 17 | 15 18 | 210 | * 15 17 | 15 18 |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 765c0179c8df..e8685ee6c1e4 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /** | 1 | /** |
2 | * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $ | 2 | * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ |
3 | * | 3 | * |
4 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> | 4 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> |
5 | * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de> | 5 | * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de> |
@@ -41,10 +41,10 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
41 | 41 | ||
42 | if (instr->addr + instr->len > mtd->size) | 42 | if (instr->addr + instr->len > mtd->size) |
43 | return -EINVAL; | 43 | return -EINVAL; |
44 | 44 | ||
45 | memset(start + instr->addr, 0xff, instr->len); | 45 | memset(start + instr->addr, 0xff, instr->len); |
46 | 46 | ||
47 | /* This'll catch a few races. Free the thing before returning :) | 47 | /* This'll catch a few races. Free the thing before returning :) |
48 | * I don't feel at all ashamed. This kind of thing is possible anyway | 48 | * I don't feel at all ashamed. This kind of thing is possible anyway |
49 | * with flash, but unlikely. | 49 | * with flash, but unlikely. |
50 | */ | 50 | */ |
@@ -63,7 +63,7 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, | |||
63 | 63 | ||
64 | if (from + len > mtd->size) | 64 | if (from + len > mtd->size) |
65 | return -EINVAL; | 65 | return -EINVAL; |
66 | 66 | ||
67 | *mtdbuf = start + from; | 67 | *mtdbuf = start + from; |
68 | *retlen = len; | 68 | *retlen = len; |
69 | return 0; | 69 | return 0; |
@@ -84,7 +84,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
84 | 84 | ||
85 | if (len > mtd->size - from) | 85 | if (len > mtd->size - from) |
86 | len = mtd->size - from; | 86 | len = mtd->size - from; |
87 | 87 | ||
88 | memcpy(buf, start + from, len); | 88 | memcpy(buf, start + from, len); |
89 | 89 | ||
90 | *retlen = len; | 90 | *retlen = len; |
@@ -101,7 +101,7 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
101 | 101 | ||
102 | if (len > mtd->size - to) | 102 | if (len > mtd->size - to) |
103 | len = mtd->size - to; | 103 | len = mtd->size - to; |
104 | 104 | ||
105 | memcpy(start + to, buf, len); | 105 | memcpy(start + to, buf, len); |
106 | 106 | ||
107 | *retlen = len; | 107 | *retlen = len; |
@@ -159,7 +159,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) | |||
159 | } | 159 | } |
160 | 160 | ||
161 | list_add_tail(&new->list, &phram_list); | 161 | list_add_tail(&new->list, &phram_list); |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | out2: | 164 | out2: |
165 | iounmap(new->mtd.priv); | 165 | iounmap(new->mtd.priv); |
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 5b3defadf884..de48b35f5609 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $ | 2 | * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $ |
3 | * | 3 | * |
4 | * PMC551 PCI Mezzanine Ram Device | 4 | * PMC551 PCI Mezzanine Ram Device |
5 | * | 5 | * |
@@ -27,7 +27,7 @@ | |||
27 | * it as high speed swap or for a high speed disk device of some | 27 | * it as high speed swap or for a high speed disk device of some |
28 | * sort. Which becomes very useful on diskless systems in the | 28 | * sort. Which becomes very useful on diskless systems in the |
29 | * embedded market I might add. | 29 | * embedded market I might add. |
30 | * | 30 | * |
31 | * Notes: | 31 | * Notes: |
32 | * Due to what I assume is more buggy SROM, the 64M PMC551 I | 32 | * Due to what I assume is more buggy SROM, the 64M PMC551 I |
33 | * have available claims that all 4 of it's DRAM banks have 64M | 33 | * have available claims that all 4 of it's DRAM banks have 64M |
@@ -63,10 +63,10 @@ | |||
63 | * Minyard set up the card to utilize a 1M sliding apature. | 63 | * Minyard set up the card to utilize a 1M sliding apature. |
64 | * | 64 | * |
65 | * Corey Minyard <minyard@nortelnetworks.com> | 65 | * Corey Minyard <minyard@nortelnetworks.com> |
66 | * * Modified driver to utilize a sliding aperture instead of | 66 | * * Modified driver to utilize a sliding aperture instead of |
67 | * mapping all memory into kernel space which turned out to | 67 | * mapping all memory into kernel space which turned out to |
68 | * be very wasteful. | 68 | * be very wasteful. |
69 | * * Located a bug in the SROM's initialization sequence that | 69 | * * Located a bug in the SROM's initialization sequence that |
70 | * made the memory unusable, added a fix to code to touch up | 70 | * made the memory unusable, added a fix to code to touch up |
71 | * the DRAM some. | 71 | * the DRAM some. |
72 | * | 72 | * |
@@ -390,7 +390,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
390 | bcmd |= (0x40|0x20); | 390 | bcmd |= (0x40|0x20); |
391 | pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); | 391 | pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); |
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Take care and turn off the memory on the device while we | 394 | * Take care and turn off the memory on the device while we |
395 | * tweak the configurations | 395 | * tweak the configurations |
396 | */ | 396 | */ |
@@ -408,7 +408,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
408 | * Grab old BAR0 config so that we can figure out memory size | 408 | * Grab old BAR0 config so that we can figure out memory size |
409 | * This is another bit of kludge going on. The reason for the | 409 | * This is another bit of kludge going on. The reason for the |
410 | * redundancy is I am hoping to retain the original configuration | 410 | * redundancy is I am hoping to retain the original configuration |
411 | * previously assigned to the card by the BIOS or some previous | 411 | * previously assigned to the card by the BIOS or some previous |
412 | * fixup routine in the kernel. So we read the old config into cfg, | 412 | * fixup routine in the kernel. So we read the old config into cfg, |
413 | * then write all 1's to the memory space, read back the result into | 413 | * then write all 1's to the memory space, read back the result into |
414 | * "size", and then write back all the old config. | 414 | * "size", and then write back all the old config. |
@@ -480,7 +480,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
480 | } while ( (PCI_COMMAND_IO) & cmd ); | 480 | } while ( (PCI_COMMAND_IO) & cmd ); |
481 | 481 | ||
482 | /* | 482 | /* |
483 | * Turn on auto refresh | 483 | * Turn on auto refresh |
484 | * The loop is taken directly from Ramix's example code. I assume that | 484 | * The loop is taken directly from Ramix's example code. I assume that |
485 | * this must be held high for some duration of time, but I can find no | 485 | * this must be held high for some duration of time, but I can find no |
486 | * documentation refrencing the reasons why. | 486 | * documentation refrencing the reasons why. |
@@ -615,7 +615,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
615 | pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); | 615 | pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); |
616 | printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" | 616 | printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" |
617 | "pmc551: System Control Register is %slocked to PCI access\n" | 617 | "pmc551: System Control Register is %slocked to PCI access\n" |
618 | "pmc551: System Control Register is %slocked to EEPROM access\n", | 618 | "pmc551: System Control Register is %slocked to EEPROM access\n", |
619 | (bcmd&0x1)?"software":"hardware", | 619 | (bcmd&0x1)?"software":"hardware", |
620 | (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); | 620 | (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); |
621 | #endif | 621 | #endif |
@@ -744,7 +744,7 @@ static int __init init_pmc551(void) | |||
744 | priv->start = ioremap(((PCI_Device->resource[0].start) | 744 | priv->start = ioremap(((PCI_Device->resource[0].start) |
745 | & PCI_BASE_ADDRESS_MEM_MASK), | 745 | & PCI_BASE_ADDRESS_MEM_MASK), |
746 | priv->asize); | 746 | priv->asize); |
747 | 747 | ||
748 | if (!priv->start) { | 748 | if (!priv->start) { |
749 | printk(KERN_NOTICE "pmc551: Unable to map IO space\n"); | 749 | printk(KERN_NOTICE "pmc551: Unable to map IO space\n"); |
750 | kfree(mtd->priv); | 750 | kfree(mtd->priv); |
@@ -765,7 +765,7 @@ static int __init init_pmc551(void) | |||
765 | priv->curr_map0 ); | 765 | priv->curr_map0 ); |
766 | 766 | ||
767 | #ifdef CONFIG_MTD_PMC551_DEBUG | 767 | #ifdef CONFIG_MTD_PMC551_DEBUG |
768 | printk( KERN_DEBUG "pmc551: aperture set to %d\n", | 768 | printk( KERN_DEBUG "pmc551: aperture set to %d\n", |
769 | (priv->base_map0 & 0xF0)>>4 ); | 769 | (priv->base_map0 & 0xF0)>>4 ); |
770 | #endif | 770 | #endif |
771 | 771 | ||
@@ -823,13 +823,13 @@ static void __exit cleanup_pmc551(void) | |||
823 | while((mtd=pmc551list)) { | 823 | while((mtd=pmc551list)) { |
824 | priv = mtd->priv; | 824 | priv = mtd->priv; |
825 | pmc551list = priv->nextpmc551; | 825 | pmc551list = priv->nextpmc551; |
826 | 826 | ||
827 | if(priv->start) { | 827 | if(priv->start) { |
828 | printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n", | 828 | printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n", |
829 | priv->asize>>20, priv->start); | 829 | priv->asize>>20, priv->start); |
830 | iounmap (priv->start); | 830 | iounmap (priv->start); |
831 | } | 831 | } |
832 | 832 | ||
833 | kfree (mtd->priv); | 833 | kfree (mtd->priv); |
834 | del_mtd_device (mtd); | 834 | del_mtd_device (mtd); |
835 | kfree (mtd); | 835 | kfree (mtd); |
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 84fa91392a8c..6faee6c6958c 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $ | 3 | $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner Exp $ |
4 | 4 | ||
5 | This driver provides a method to access memory not used by the kernel | 5 | This driver provides a method to access memory not used by the kernel |
6 | itself (i.e. if the kernel commandline mem=xxx is used). To actually | 6 | itself (i.e. if the kernel commandline mem=xxx is used). To actually |
@@ -18,14 +18,14 @@ | |||
18 | <start>: start of the memory region, decimal or hex (0xabcdef) | 18 | <start>: start of the memory region, decimal or hex (0xabcdef) |
19 | <end/offset>: end of the memory region. It's possible to use +0x1234 | 19 | <end/offset>: end of the memory region. It's possible to use +0x1234 |
20 | to specify the offset instead of the absolute address | 20 | to specify the offset instead of the absolute address |
21 | 21 | ||
22 | NOTE: | 22 | NOTE: |
23 | With slram it's only possible to map a contigous memory region. Therfore | 23 | With slram it's only possible to map a contigous memory region. Therfore |
24 | if there's a device mapped somewhere in the region specified slram will | 24 | if there's a device mapped somewhere in the region specified slram will |
25 | fail to load (see kernel log if modprobe fails). | 25 | fail to load (see kernel log if modprobe fails). |
26 | 26 | ||
27 | - | 27 | - |
28 | 28 | ||
29 | Jochen Schaeuble <psionic@psionic.de> | 29 | Jochen Schaeuble <psionic@psionic.de> |
30 | 30 | ||
31 | ======================================================================*/ | 31 | ======================================================================*/ |
@@ -89,10 +89,10 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
89 | if (instr->addr + instr->len > mtd->size) { | 89 | if (instr->addr + instr->len > mtd->size) { |
90 | return(-EINVAL); | 90 | return(-EINVAL); |
91 | } | 91 | } |
92 | 92 | ||
93 | memset(priv->start + instr->addr, 0xff, instr->len); | 93 | memset(priv->start + instr->addr, 0xff, instr->len); |
94 | 94 | ||
95 | /* This'll catch a few races. Free the thing before returning :) | 95 | /* This'll catch a few races. Free the thing before returning :) |
96 | * I don't feel at all ashamed. This kind of thing is possible anyway | 96 | * I don't feel at all ashamed. This kind of thing is possible anyway |
97 | * with flash, but unlikely. | 97 | * with flash, but unlikely. |
98 | */ | 98 | */ |
@@ -170,12 +170,12 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
170 | } | 170 | } |
171 | (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); | 171 | (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); |
172 | (*curmtd)->next = NULL; | 172 | (*curmtd)->next = NULL; |
173 | 173 | ||
174 | if ((*curmtd)->mtdinfo) { | 174 | if ((*curmtd)->mtdinfo) { |
175 | memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); | 175 | memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); |
176 | (*curmtd)->mtdinfo->priv = | 176 | (*curmtd)->mtdinfo->priv = |
177 | kmalloc(sizeof(slram_priv_t), GFP_KERNEL); | 177 | kmalloc(sizeof(slram_priv_t), GFP_KERNEL); |
178 | 178 | ||
179 | if (!(*curmtd)->mtdinfo->priv) { | 179 | if (!(*curmtd)->mtdinfo->priv) { |
180 | kfree((*curmtd)->mtdinfo); | 180 | kfree((*curmtd)->mtdinfo); |
181 | (*curmtd)->mtdinfo = NULL; | 181 | (*curmtd)->mtdinfo = NULL; |
@@ -188,7 +188,7 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
188 | E("slram: Cannot allocate new MTD device.\n"); | 188 | E("slram: Cannot allocate new MTD device.\n"); |
189 | return(-ENOMEM); | 189 | return(-ENOMEM); |
190 | } | 190 | } |
191 | 191 | ||
192 | if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = | 192 | if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = |
193 | ioremap(start, length))) { | 193 | ioremap(start, length))) { |
194 | E("slram: ioremap failed\n"); | 194 | E("slram: ioremap failed\n"); |
@@ -223,7 +223,7 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
223 | T("slram: Mapped from 0x%p to 0x%p\n", | 223 | T("slram: Mapped from 0x%p to 0x%p\n", |
224 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, | 224 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, |
225 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end); | 225 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end); |
226 | return(0); | 226 | return(0); |
227 | } | 227 | } |
228 | 228 | ||
229 | static void unregister_devices(void) | 229 | static void unregister_devices(void) |
@@ -256,7 +256,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
256 | char *buffer; | 256 | char *buffer; |
257 | unsigned long devstart; | 257 | unsigned long devstart; |
258 | unsigned long devlength; | 258 | unsigned long devlength; |
259 | 259 | ||
260 | if ((!devname) || (!szstart) || (!szlength)) { | 260 | if ((!devname) || (!szstart) || (!szlength)) { |
261 | unregister_devices(); | 261 | unregister_devices(); |
262 | return(-EINVAL); | 262 | return(-EINVAL); |
@@ -264,7 +264,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
264 | 264 | ||
265 | devstart = simple_strtoul(szstart, &buffer, 0); | 265 | devstart = simple_strtoul(szstart, &buffer, 0); |
266 | devstart = handle_unit(devstart, buffer); | 266 | devstart = handle_unit(devstart, buffer); |
267 | 267 | ||
268 | if (*(szlength) != '+') { | 268 | if (*(szlength) != '+') { |
269 | devlength = simple_strtoul(szlength, &buffer, 0); | 269 | devlength = simple_strtoul(szlength, &buffer, 0); |
270 | devlength = handle_unit(devlength, buffer) - devstart; | 270 | devlength = handle_unit(devlength, buffer) - devstart; |
@@ -278,7 +278,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
278 | E("slram: Illegal start / length parameter.\n"); | 278 | E("slram: Illegal start / length parameter.\n"); |
279 | return(-EINVAL); | 279 | return(-EINVAL); |
280 | } | 280 | } |
281 | 281 | ||
282 | if ((devstart = register_device(devname, devstart, devlength))){ | 282 | if ((devstart = register_device(devname, devstart, devlength))){ |
283 | unregister_devices(); | 283 | unregister_devices(); |
284 | return((int)devstart); | 284 | return((int)devstart); |
@@ -335,7 +335,7 @@ static int init_slram(void) | |||
335 | } | 335 | } |
336 | #else | 336 | #else |
337 | int count; | 337 | int count; |
338 | 338 | ||
339 | for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); | 339 | for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); |
340 | count++) { | 340 | count++) { |
341 | } | 341 | } |
@@ -350,10 +350,10 @@ static int init_slram(void) | |||
350 | if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) { | 350 | if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) { |
351 | return(-EINVAL); | 351 | return(-EINVAL); |
352 | } | 352 | } |
353 | 353 | ||
354 | } | 354 | } |
355 | #endif /* !MODULE */ | 355 | #endif /* !MODULE */ |
356 | 356 | ||
357 | return(0); | 357 | return(0); |
358 | } | 358 | } |
359 | 359 | ||
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index d32c1b3a8ce3..de7e231d6d18 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org | 1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org |
2 | * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $ | 2 | * $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $ |
3 | * | 3 | * |
4 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 4 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
5 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups | 5 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups |
@@ -53,7 +53,7 @@ | |||
53 | Use of the FTL format for non-PCMCIA applications may be an | 53 | Use of the FTL format for non-PCMCIA applications may be an |
54 | infringement of these patents. For additional information, | 54 | infringement of these patents. For additional information, |
55 | contact M-Systems (http://www.m-sys.com) directly. | 55 | contact M-Systems (http://www.m-sys.com) directly. |
56 | 56 | ||
57 | ======================================================================*/ | 57 | ======================================================================*/ |
58 | #include <linux/mtd/blktrans.h> | 58 | #include <linux/mtd/blktrans.h> |
59 | #include <linux/module.h> | 59 | #include <linux/module.h> |
@@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done); | |||
160 | Scan_header() checks to see if a memory region contains an FTL | 160 | Scan_header() checks to see if a memory region contains an FTL |
161 | partition. build_maps() reads all the erase unit headers, builds | 161 | partition. build_maps() reads all the erase unit headers, builds |
162 | the erase unit map, and then builds the virtual page map. | 162 | the erase unit map, and then builds the virtual page map. |
163 | 163 | ||
164 | ======================================================================*/ | 164 | ======================================================================*/ |
165 | 165 | ||
166 | static int scan_header(partition_t *part) | 166 | static int scan_header(partition_t *part) |
@@ -176,10 +176,10 @@ static int scan_header(partition_t *part) | |||
176 | (offset + sizeof(header)) < max_offset; | 176 | (offset + sizeof(header)) < max_offset; |
177 | offset += part->mbd.mtd->erasesize ? : 0x2000) { | 177 | offset += part->mbd.mtd->erasesize ? : 0x2000) { |
178 | 178 | ||
179 | err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, | 179 | err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, |
180 | (unsigned char *)&header); | 180 | (unsigned char *)&header); |
181 | 181 | ||
182 | if (err) | 182 | if (err) |
183 | return err; | 183 | return err; |
184 | 184 | ||
185 | if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; | 185 | if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; |
@@ -232,10 +232,10 @@ static int build_maps(partition_t *part) | |||
232 | for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { | 232 | for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { |
233 | offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) | 233 | offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) |
234 | << part->header.EraseUnitSize); | 234 | << part->header.EraseUnitSize); |
235 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, | 235 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, |
236 | (unsigned char *)&header); | 236 | (unsigned char *)&header); |
237 | 237 | ||
238 | if (ret) | 238 | if (ret) |
239 | goto out_XferInfo; | 239 | goto out_XferInfo; |
240 | 240 | ||
241 | ret = -1; | 241 | ret = -1; |
@@ -274,7 +274,7 @@ static int build_maps(partition_t *part) | |||
274 | "don't add up!\n"); | 274 | "don't add up!\n"); |
275 | goto out_XferInfo; | 275 | goto out_XferInfo; |
276 | } | 276 | } |
277 | 277 | ||
278 | /* Set up virtual page map */ | 278 | /* Set up virtual page map */ |
279 | blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; | 279 | blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; |
280 | part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); | 280 | part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); |
@@ -296,12 +296,12 @@ static int build_maps(partition_t *part) | |||
296 | part->EUNInfo[i].Free = 0; | 296 | part->EUNInfo[i].Free = 0; |
297 | part->EUNInfo[i].Deleted = 0; | 297 | part->EUNInfo[i].Deleted = 0; |
298 | offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); | 298 | offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); |
299 | 299 | ||
300 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, | 300 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, |
301 | part->BlocksPerUnit * sizeof(u_int32_t), &retval, | 301 | part->BlocksPerUnit * sizeof(u_int32_t), &retval, |
302 | (unsigned char *)part->bam_cache); | 302 | (unsigned char *)part->bam_cache); |
303 | 303 | ||
304 | if (ret) | 304 | if (ret) |
305 | goto out_bam_cache; | 305 | goto out_bam_cache; |
306 | 306 | ||
307 | for (j = 0; j < part->BlocksPerUnit; j++) { | 307 | for (j = 0; j < part->BlocksPerUnit; j++) { |
@@ -316,7 +316,7 @@ static int build_maps(partition_t *part) | |||
316 | part->EUNInfo[i].Deleted++; | 316 | part->EUNInfo[i].Deleted++; |
317 | } | 317 | } |
318 | } | 318 | } |
319 | 319 | ||
320 | ret = 0; | 320 | ret = 0; |
321 | goto out; | 321 | goto out; |
322 | 322 | ||
@@ -336,7 +336,7 @@ out: | |||
336 | 336 | ||
337 | Erase_xfer() schedules an asynchronous erase operation for a | 337 | Erase_xfer() schedules an asynchronous erase operation for a |
338 | transfer unit. | 338 | transfer unit. |
339 | 339 | ||
340 | ======================================================================*/ | 340 | ======================================================================*/ |
341 | 341 | ||
342 | static int erase_xfer(partition_t *part, | 342 | static int erase_xfer(partition_t *part, |
@@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part, | |||
351 | xfer->state = XFER_ERASING; | 351 | xfer->state = XFER_ERASING; |
352 | 352 | ||
353 | /* Is there a free erase slot? Always in MTD. */ | 353 | /* Is there a free erase slot? Always in MTD. */ |
354 | 354 | ||
355 | 355 | ||
356 | erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); | 356 | erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); |
357 | if (!erase) | 357 | if (!erase) |
358 | return -ENOMEM; | 358 | return -ENOMEM; |
359 | 359 | ||
360 | erase->mtd = part->mbd.mtd; | 360 | erase->mtd = part->mbd.mtd; |
@@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part, | |||
362 | erase->addr = xfer->Offset; | 362 | erase->addr = xfer->Offset; |
363 | erase->len = 1 << part->header.EraseUnitSize; | 363 | erase->len = 1 << part->header.EraseUnitSize; |
364 | erase->priv = (u_long)part; | 364 | erase->priv = (u_long)part; |
365 | 365 | ||
366 | ret = part->mbd.mtd->erase(part->mbd.mtd, erase); | 366 | ret = part->mbd.mtd->erase(part->mbd.mtd, erase); |
367 | 367 | ||
368 | if (!ret) | 368 | if (!ret) |
@@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part, | |||
377 | 377 | ||
378 | Prepare_xfer() takes a freshly erased transfer unit and gives | 378 | Prepare_xfer() takes a freshly erased transfer unit and gives |
379 | it an appropriate header. | 379 | it an appropriate header. |
380 | 380 | ||
381 | ======================================================================*/ | 381 | ======================================================================*/ |
382 | 382 | ||
383 | static void ftl_erase_callback(struct erase_info *erase) | 383 | static void ftl_erase_callback(struct erase_info *erase) |
@@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase) | |||
385 | partition_t *part; | 385 | partition_t *part; |
386 | struct xfer_info_t *xfer; | 386 | struct xfer_info_t *xfer; |
387 | int i; | 387 | int i; |
388 | 388 | ||
389 | /* Look up the transfer unit */ | 389 | /* Look up the transfer unit */ |
390 | part = (partition_t *)(erase->priv); | 390 | part = (partition_t *)(erase->priv); |
391 | 391 | ||
@@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
422 | 422 | ||
423 | xfer = &part->XferInfo[i]; | 423 | xfer = &part->XferInfo[i]; |
424 | xfer->state = XFER_FAILED; | 424 | xfer->state = XFER_FAILED; |
425 | 425 | ||
426 | DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); | 426 | DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); |
427 | 427 | ||
428 | /* Write the transfer unit header */ | 428 | /* Write the transfer unit header */ |
@@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
446 | 446 | ||
447 | for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { | 447 | for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { |
448 | 448 | ||
449 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), | 449 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), |
450 | &retlen, (u_char *)&ctl); | 450 | &retlen, (u_char *)&ctl); |
451 | 451 | ||
452 | if (ret) | 452 | if (ret) |
@@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
454 | } | 454 | } |
455 | xfer->state = XFER_PREPARED; | 455 | xfer->state = XFER_PREPARED; |
456 | return 0; | 456 | return 0; |
457 | 457 | ||
458 | } /* prepare_xfer */ | 458 | } /* prepare_xfer */ |
459 | 459 | ||
460 | /*====================================================================== | 460 | /*====================================================================== |
@@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
466 | All data blocks are copied to the corresponding blocks in the | 466 | All data blocks are copied to the corresponding blocks in the |
467 | target unit, so the virtual block map does not need to be | 467 | target unit, so the virtual block map does not need to be |
468 | updated. | 468 | updated. |
469 | 469 | ||
470 | ======================================================================*/ | 470 | ======================================================================*/ |
471 | 471 | ||
472 | static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | 472 | static int copy_erase_unit(partition_t *part, u_int16_t srcunit, |
@@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
486 | xfer = &part->XferInfo[xferunit]; | 486 | xfer = &part->XferInfo[xferunit]; |
487 | DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", | 487 | DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", |
488 | eun->Offset, xfer->Offset); | 488 | eun->Offset, xfer->Offset); |
489 | 489 | ||
490 | 490 | ||
491 | /* Read current BAM */ | 491 | /* Read current BAM */ |
492 | if (part->bam_index != srcunit) { | 492 | if (part->bam_index != srcunit) { |
493 | 493 | ||
494 | offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); | 494 | offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); |
495 | 495 | ||
496 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, | 496 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, |
497 | part->BlocksPerUnit * sizeof(u_int32_t), | 497 | part->BlocksPerUnit * sizeof(u_int32_t), |
498 | &retlen, (u_char *) (part->bam_cache)); | 498 | &retlen, (u_char *) (part->bam_cache)); |
499 | 499 | ||
@@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
501 | part->bam_index = 0xffff; | 501 | part->bam_index = 0xffff; |
502 | 502 | ||
503 | if (ret) { | 503 | if (ret) { |
504 | printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); | 504 | printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); |
505 | return ret; | 505 | return ret; |
506 | } | 506 | } |
507 | } | 507 | } |
508 | 508 | ||
509 | /* Write the LogicalEUN for the transfer unit */ | 509 | /* Write the LogicalEUN for the transfer unit */ |
510 | xfer->state = XFER_UNKNOWN; | 510 | xfer->state = XFER_UNKNOWN; |
511 | offset = xfer->Offset + 20; /* Bad! */ | 511 | offset = xfer->Offset + 20; /* Bad! */ |
@@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
513 | 513 | ||
514 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), | 514 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), |
515 | &retlen, (u_char *) &unit); | 515 | &retlen, (u_char *) &unit); |
516 | 516 | ||
517 | if (ret) { | 517 | if (ret) { |
518 | printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); | 518 | printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); |
519 | return ret; | 519 | return ret; |
520 | } | 520 | } |
521 | 521 | ||
522 | /* Copy all data blocks from source unit to transfer unit */ | 522 | /* Copy all data blocks from source unit to transfer unit */ |
523 | src = eun->Offset; dest = xfer->Offset; | 523 | src = eun->Offset; dest = xfer->Offset; |
524 | 524 | ||
@@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
558 | } | 558 | } |
559 | 559 | ||
560 | /* Write the BAM to the transfer unit */ | 560 | /* Write the BAM to the transfer unit */ |
561 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), | 561 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), |
562 | part->BlocksPerUnit * sizeof(int32_t), &retlen, | 562 | part->BlocksPerUnit * sizeof(int32_t), &retlen, |
563 | (u_char *)part->bam_cache); | 563 | (u_char *)part->bam_cache); |
564 | if (ret) { | 564 | if (ret) { |
565 | printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); | 565 | printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); |
566 | return ret; | 566 | return ret; |
567 | } | 567 | } |
568 | 568 | ||
569 | 569 | ||
570 | /* All clear? Then update the LogicalEUN again */ | 570 | /* All clear? Then update the LogicalEUN again */ |
571 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), | 571 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), |
572 | &retlen, (u_char *)&srcunitswap); | 572 | &retlen, (u_char *)&srcunitswap); |
@@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
574 | if (ret) { | 574 | if (ret) { |
575 | printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); | 575 | printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); |
576 | return ret; | 576 | return ret; |
577 | } | 577 | } |
578 | 578 | ||
579 | 579 | ||
580 | /* Update the maps and usage stats*/ | 580 | /* Update the maps and usage stats*/ |
581 | i = xfer->EraseCount; | 581 | i = xfer->EraseCount; |
582 | xfer->EraseCount = eun->EraseCount; | 582 | xfer->EraseCount = eun->EraseCount; |
@@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
588 | part->FreeTotal += free; | 588 | part->FreeTotal += free; |
589 | eun->Free = free; | 589 | eun->Free = free; |
590 | eun->Deleted = 0; | 590 | eun->Deleted = 0; |
591 | 591 | ||
592 | /* Now, the cache should be valid for the new block */ | 592 | /* Now, the cache should be valid for the new block */ |
593 | part->bam_index = srcunit; | 593 | part->bam_index = srcunit; |
594 | 594 | ||
595 | return 0; | 595 | return 0; |
596 | } /* copy_erase_unit */ | 596 | } /* copy_erase_unit */ |
597 | 597 | ||
@@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
608 | oldest data unit instead. This means that we generally postpone | 608 | oldest data unit instead. This means that we generally postpone |
609 | the next reclaimation as long as possible, but shuffle static | 609 | the next reclaimation as long as possible, but shuffle static |
610 | stuff around a bit for wear leveling. | 610 | stuff around a bit for wear leveling. |
611 | 611 | ||
612 | ======================================================================*/ | 612 | ======================================================================*/ |
613 | 613 | ||
614 | static int reclaim_block(partition_t *part) | 614 | static int reclaim_block(partition_t *part) |
@@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) | |||
666 | else | 666 | else |
667 | DEBUG(1, "ftl_cs: reclaim failed: no " | 667 | DEBUG(1, "ftl_cs: reclaim failed: no " |
668 | "suitable transfer units!\n"); | 668 | "suitable transfer units!\n"); |
669 | 669 | ||
670 | return -EIO; | 670 | return -EIO; |
671 | } | 671 | } |
672 | } | 672 | } |
@@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part) | |||
715 | returns the block index -- the erase unit is just the currently | 715 | returns the block index -- the erase unit is just the currently |
716 | cached unit. If there are no free blocks, it returns 0 -- this | 716 | cached unit. If there are no free blocks, it returns 0 -- this |
717 | is never a valid data block because it contains the header. | 717 | is never a valid data block because it contains the header. |
718 | 718 | ||
719 | ======================================================================*/ | 719 | ======================================================================*/ |
720 | 720 | ||
721 | #ifdef PSYCHO_DEBUG | 721 | #ifdef PSYCHO_DEBUG |
@@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part) | |||
737 | u_int32_t blk; | 737 | u_int32_t blk; |
738 | size_t retlen; | 738 | size_t retlen; |
739 | int ret; | 739 | int ret; |
740 | 740 | ||
741 | /* Find an erase unit with some free space */ | 741 | /* Find an erase unit with some free space */ |
742 | stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; | 742 | stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; |
743 | eun = stop; | 743 | eun = stop; |
@@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part) | |||
749 | 749 | ||
750 | if (part->EUNInfo[eun].Free == 0) | 750 | if (part->EUNInfo[eun].Free == 0) |
751 | return 0; | 751 | return 0; |
752 | 752 | ||
753 | /* Is this unit's BAM cached? */ | 753 | /* Is this unit's BAM cached? */ |
754 | if (eun != part->bam_index) { | 754 | if (eun != part->bam_index) { |
755 | /* Invalidate cache */ | 755 | /* Invalidate cache */ |
756 | part->bam_index = 0xffff; | 756 | part->bam_index = 0xffff; |
757 | 757 | ||
758 | ret = part->mbd.mtd->read(part->mbd.mtd, | 758 | ret = part->mbd.mtd->read(part->mbd.mtd, |
759 | part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), | 759 | part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), |
760 | part->BlocksPerUnit * sizeof(u_int32_t), | 760 | part->BlocksPerUnit * sizeof(u_int32_t), |
761 | &retlen, (u_char *) (part->bam_cache)); | 761 | &retlen, (u_char *) (part->bam_cache)); |
762 | 762 | ||
763 | if (ret) { | 763 | if (ret) { |
764 | printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); | 764 | printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); |
765 | return 0; | 765 | return 0; |
@@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part) | |||
781 | } | 781 | } |
782 | DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); | 782 | DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); |
783 | return blk; | 783 | return blk; |
784 | 784 | ||
785 | } /* find_free */ | 785 | } /* find_free */ |
786 | 786 | ||
787 | 787 | ||
788 | /*====================================================================== | 788 | /*====================================================================== |
789 | 789 | ||
790 | Read a series of sectors from an FTL partition. | 790 | Read a series of sectors from an FTL partition. |
791 | 791 | ||
792 | ======================================================================*/ | 792 | ======================================================================*/ |
793 | 793 | ||
794 | static int ftl_read(partition_t *part, caddr_t buffer, | 794 | static int ftl_read(partition_t *part, caddr_t buffer, |
@@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, | |||
798 | u_long i; | 798 | u_long i; |
799 | int ret; | 799 | int ret; |
800 | size_t offset, retlen; | 800 | size_t offset, retlen; |
801 | 801 | ||
802 | DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", | 802 | DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", |
803 | part, sector, nblocks); | 803 | part, sector, nblocks); |
804 | if (!(part->state & FTL_FORMATTED)) { | 804 | if (!(part->state & FTL_FORMATTED)) { |
@@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, | |||
834 | /*====================================================================== | 834 | /*====================================================================== |
835 | 835 | ||
836 | Write a series of sectors to an FTL partition | 836 | Write a series of sectors to an FTL partition |
837 | 837 | ||
838 | ======================================================================*/ | 838 | ======================================================================*/ |
839 | 839 | ||
840 | static int set_bam_entry(partition_t *part, u_int32_t log_addr, | 840 | static int set_bam_entry(partition_t *part, u_int32_t log_addr, |
@@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, | |||
855 | blk = (log_addr % bsize) / SECTOR_SIZE; | 855 | blk = (log_addr % bsize) / SECTOR_SIZE; |
856 | offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + | 856 | offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + |
857 | le32_to_cpu(part->header.BAMOffset)); | 857 | le32_to_cpu(part->header.BAMOffset)); |
858 | 858 | ||
859 | #ifdef PSYCHO_DEBUG | 859 | #ifdef PSYCHO_DEBUG |
860 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), | 860 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), |
861 | &retlen, (u_char *)&old_addr); | 861 | &retlen, (u_char *)&old_addr); |
@@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
925 | if (ret) | 925 | if (ret) |
926 | return ret; | 926 | return ret; |
927 | } | 927 | } |
928 | 928 | ||
929 | bsize = 1 << part->header.EraseUnitSize; | 929 | bsize = 1 << part->header.EraseUnitSize; |
930 | 930 | ||
931 | virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; | 931 | virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; |
@@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
949 | log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; | 949 | log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; |
950 | part->EUNInfo[part->bam_index].Free--; | 950 | part->EUNInfo[part->bam_index].Free--; |
951 | part->FreeTotal--; | 951 | part->FreeTotal--; |
952 | if (set_bam_entry(part, log_addr, 0xfffffffe)) | 952 | if (set_bam_entry(part, log_addr, 0xfffffffe)) |
953 | return -EIO; | 953 | return -EIO; |
954 | part->EUNInfo[part->bam_index].Deleted++; | 954 | part->EUNInfo[part->bam_index].Deleted++; |
955 | offset = (part->EUNInfo[part->bam_index].Offset + | 955 | offset = (part->EUNInfo[part->bam_index].Offset + |
956 | blk * SECTOR_SIZE); | 956 | blk * SECTOR_SIZE); |
957 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, | 957 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, |
958 | buffer); | 958 | buffer); |
959 | 959 | ||
960 | if (ret) { | 960 | if (ret) { |
@@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
964 | offset); | 964 | offset); |
965 | return -EIO; | 965 | return -EIO; |
966 | } | 966 | } |
967 | 967 | ||
968 | /* Only delete the old entry when the new entry is ready */ | 968 | /* Only delete the old entry when the new entry is ready */ |
969 | old_addr = part->VirtualBlockMap[sector+i]; | 969 | old_addr = part->VirtualBlockMap[sector+i]; |
970 | if (old_addr != 0xffffffff) { | 970 | if (old_addr != 0xffffffff) { |
@@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
979 | return -EIO; | 979 | return -EIO; |
980 | part->VirtualBlockMap[sector+i] = log_addr; | 980 | part->VirtualBlockMap[sector+i] = log_addr; |
981 | part->EUNInfo[part->bam_index].Deleted--; | 981 | part->EUNInfo[part->bam_index].Deleted--; |
982 | 982 | ||
983 | buffer += SECTOR_SIZE; | 983 | buffer += SECTOR_SIZE; |
984 | virt_addr += SECTOR_SIZE; | 984 | virt_addr += SECTOR_SIZE; |
985 | } | 985 | } |
@@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
1034 | partition_t *partition; | 1034 | partition_t *partition; |
1035 | 1035 | ||
1036 | partition = kmalloc(sizeof(partition_t), GFP_KERNEL); | 1036 | partition = kmalloc(sizeof(partition_t), GFP_KERNEL); |
1037 | 1037 | ||
1038 | if (!partition) { | 1038 | if (!partition) { |
1039 | printk(KERN_WARNING "No memory to scan for FTL on %s\n", | 1039 | printk(KERN_WARNING "No memory to scan for FTL on %s\n", |
1040 | mtd->name); | 1040 | mtd->name); |
1041 | return; | 1041 | return; |
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | memset(partition, 0, sizeof(partition_t)); | 1044 | memset(partition, 0, sizeof(partition_t)); |
1045 | 1045 | ||
1046 | partition->mbd.mtd = mtd; | 1046 | partition->mbd.mtd = mtd; |
1047 | 1047 | ||
1048 | if ((scan_header(partition) == 0) && | 1048 | if ((scan_header(partition) == 0) && |
1049 | (build_maps(partition) == 0)) { | 1049 | (build_maps(partition) == 0)) { |
1050 | 1050 | ||
1051 | partition->state = FTL_FORMATTED; | 1051 | partition->state = FTL_FORMATTED; |
1052 | #ifdef PCMCIA_DEBUG | 1052 | #ifdef PCMCIA_DEBUG |
1053 | printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", | 1053 | printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", |
@@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = { | |||
1086 | 1086 | ||
1087 | int init_ftl(void) | 1087 | int init_ftl(void) |
1088 | { | 1088 | { |
1089 | DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n"); | 1089 | DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n"); |
1090 | 1090 | ||
1091 | return register_mtd_blktrans(&ftl_tr); | 1091 | return register_mtd_blktrans(&ftl_tr); |
1092 | } | 1092 | } |
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 8db65bf029ea..8a544890173d 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) | 2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) |
3 | * | 3 | * |
4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
@@ -7,7 +7,7 @@ | |||
7 | * (c) 1999 Machine Vision Holdings, Inc. | 7 | * (c) 1999 Machine Vision Holdings, Inc. |
8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
9 | * | 9 | * |
10 | * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $ | 10 | * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -113,14 +113,14 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
113 | 113 | ||
114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { | 114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { |
115 | /* | 115 | /* |
116 | Oh no we don't have | 116 | Oh no we don't have |
117 | mbd.size == heads * cylinders * sectors | 117 | mbd.size == heads * cylinders * sectors |
118 | */ | 118 | */ |
119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " | 119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " |
120 | "match size of 0x%lx.\n", inftl->mbd.size); | 120 | "match size of 0x%lx.\n", inftl->mbd.size); |
121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " | 121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " |
122 | "(== 0x%lx sects)\n", | 122 | "(== 0x%lx sects)\n", |
123 | inftl->cylinders, inftl->heads , inftl->sectors, | 123 | inftl->cylinders, inftl->heads , inftl->sectors, |
124 | (long)inftl->cylinders * (long)inftl->heads * | 124 | (long)inftl->cylinders * (long)inftl->heads * |
125 | (long)inftl->sectors ); | 125 | (long)inftl->sectors ); |
126 | } | 126 | } |
@@ -219,7 +219,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
219 | "Virtual Unit Chain %d!\n", thisVUC); | 219 | "Virtual Unit Chain %d!\n", thisVUC); |
220 | return BLOCK_NIL; | 220 | return BLOCK_NIL; |
221 | } | 221 | } |
222 | 222 | ||
223 | /* | 223 | /* |
224 | * Scan to find the Erase Unit which holds the actual data for each | 224 | * Scan to find the Erase Unit which holds the actual data for each |
225 | * 512-byte block within the Chain. | 225 | * 512-byte block within the Chain. |
@@ -260,7 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
260 | "Unit Chain 0x%x\n", thisVUC); | 260 | "Unit Chain 0x%x\n", thisVUC); |
261 | return BLOCK_NIL; | 261 | return BLOCK_NIL; |
262 | } | 262 | } |
263 | 263 | ||
264 | thisEUN = inftl->PUtable[thisEUN]; | 264 | thisEUN = inftl->PUtable[thisEUN]; |
265 | } | 265 | } |
266 | 266 | ||
@@ -291,15 +291,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
291 | */ | 291 | */ |
292 | if (BlockMap[block] == BLOCK_NIL) | 292 | if (BlockMap[block] == BLOCK_NIL) |
293 | continue; | 293 | continue; |
294 | 294 | ||
295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
296 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, | 296 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, |
297 | &retlen, movebuf); | 297 | &retlen, movebuf); |
298 | if (ret < 0) { | 298 | if (ret < 0) { |
299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
300 | BlockMap[block]) + (block * SECTORSIZE), | 300 | BlockMap[block]) + (block * SECTORSIZE), |
301 | SECTORSIZE, &retlen, movebuf); | 301 | SECTORSIZE, &retlen, movebuf); |
302 | if (ret != -EIO) | 302 | if (ret != -EIO) |
303 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " | 303 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " |
304 | "away on retry?\n"); | 304 | "away on retry?\n"); |
305 | } | 305 | } |
@@ -351,7 +351,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
351 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) | 351 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) |
352 | { | 352 | { |
353 | /* | 353 | /* |
354 | * This is the part that needs some cleverness applied. | 354 | * This is the part that needs some cleverness applied. |
355 | * For now, I'm doing the minimum applicable to actually | 355 | * For now, I'm doing the minimum applicable to actually |
356 | * get the thing to work. | 356 | * get the thing to work. |
357 | * Wear-levelling and other clever stuff needs to be implemented | 357 | * Wear-levelling and other clever stuff needs to be implemented |
@@ -410,7 +410,7 @@ static int nrbits(unsigned int val, int bitcount) | |||
410 | } | 410 | } |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * INFTL_findwriteunit: Return the unit number into which we can write | 413 | * INFTL_findwriteunit: Return the unit number into which we can write |
414 | * for this block. Make it available if it isn't already. | 414 | * for this block. Make it available if it isn't already. |
415 | */ | 415 | */ |
416 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | 416 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) |
@@ -459,10 +459,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | |||
459 | * Invalid block. Don't use it any more. | 459 | * Invalid block. Don't use it any more. |
460 | * Must implement. | 460 | * Must implement. |
461 | */ | 461 | */ |
462 | break; | 462 | break; |
463 | } | 463 | } |
464 | 464 | ||
465 | if (!silly--) { | 465 | if (!silly--) { |
466 | printk(KERN_WARNING "INFTL: infinite loop in " | 466 | printk(KERN_WARNING "INFTL: infinite loop in " |
467 | "Virtual Unit Chain 0x%x\n", thisVUC); | 467 | "Virtual Unit Chain 0x%x\n", thisVUC); |
468 | return 0xffff; | 468 | return 0xffff; |
@@ -478,7 +478,7 @@ hitused: | |||
478 | 478 | ||
479 | 479 | ||
480 | /* | 480 | /* |
481 | * OK. We didn't find one in the existing chain, or there | 481 | * OK. We didn't find one in the existing chain, or there |
482 | * is no existing chain. Allocate a new one. | 482 | * is no existing chain. Allocate a new one. |
483 | */ | 483 | */ |
484 | writeEUN = INFTL_findfreeblock(inftl, 0); | 484 | writeEUN = INFTL_findfreeblock(inftl, 0); |
@@ -502,8 +502,8 @@ hitused: | |||
502 | if (writeEUN == BLOCK_NIL) { | 502 | if (writeEUN == BLOCK_NIL) { |
503 | /* | 503 | /* |
504 | * Ouch. This should never happen - we should | 504 | * Ouch. This should never happen - we should |
505 | * always be able to make some room somehow. | 505 | * always be able to make some room somehow. |
506 | * If we get here, we've allocated more storage | 506 | * If we get here, we've allocated more storage |
507 | * space than actual media, or our makefreeblock | 507 | * space than actual media, or our makefreeblock |
508 | * routine is missing something. | 508 | * routine is missing something. |
509 | */ | 509 | */ |
@@ -514,7 +514,7 @@ hitused: | |||
514 | INFTL_dumpVUchains(inftl); | 514 | INFTL_dumpVUchains(inftl); |
515 | #endif | 515 | #endif |
516 | return BLOCK_NIL; | 516 | return BLOCK_NIL; |
517 | } | 517 | } |
518 | } | 518 | } |
519 | 519 | ||
520 | /* | 520 | /* |
@@ -539,7 +539,7 @@ hitused: | |||
539 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; | 539 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; |
540 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; | 540 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; |
541 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; | 541 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; |
542 | 542 | ||
543 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); | 543 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); |
544 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); | 544 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); |
545 | oob.u.a.ANAC = anac; | 545 | oob.u.a.ANAC = anac; |
@@ -558,7 +558,7 @@ hitused: | |||
558 | oob.u.b.parityPerField = parity; | 558 | oob.u.b.parityPerField = parity; |
559 | oob.u.b.discarded = 0xaa; | 559 | oob.u.b.discarded = 0xaa; |
560 | 560 | ||
561 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + | 561 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + |
562 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); | 562 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); |
563 | 563 | ||
564 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; | 564 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; |
@@ -598,7 +598,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
598 | "Virtual Unit Chain %d!\n", thisVUC); | 598 | "Virtual Unit Chain %d!\n", thisVUC); |
599 | return; | 599 | return; |
600 | } | 600 | } |
601 | 601 | ||
602 | /* | 602 | /* |
603 | * Scan through the Erase Units to determine whether any data is in | 603 | * Scan through the Erase Units to determine whether any data is in |
604 | * each of the 512-byte blocks within the Chain. | 604 | * each of the 512-byte blocks within the Chain. |
@@ -638,7 +638,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
638 | "Unit Chain 0x%x\n", thisVUC); | 638 | "Unit Chain 0x%x\n", thisVUC); |
639 | return; | 639 | return; |
640 | } | 640 | } |
641 | 641 | ||
642 | thisEUN = inftl->PUtable[thisEUN]; | 642 | thisEUN = inftl->PUtable[thisEUN]; |
643 | } | 643 | } |
644 | 644 | ||
@@ -754,7 +754,7 @@ foundit: | |||
754 | return 0; | 754 | return 0; |
755 | } | 755 | } |
756 | 756 | ||
757 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, | 757 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, |
758 | char *buffer) | 758 | char *buffer) |
759 | { | 759 | { |
760 | struct INFTLrecord *inftl = (void *)mbd; | 760 | struct INFTLrecord *inftl = (void *)mbd; |
@@ -889,7 +889,7 @@ extern char inftlmountrev[]; | |||
889 | 889 | ||
890 | static int __init init_inftl(void) | 890 | static int __init init_inftl(void) |
891 | { | 891 | { |
892 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, " | 892 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " |
893 | "inftlmount.c %s\n", inftlmountrev); | 893 | "inftlmount.c %s\n", inftlmountrev); |
894 | 894 | ||
895 | return register_mtd_blktrans(&inftl_tr); | 895 | return register_mtd_blktrans(&inftl_tr); |
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 3dac53feeee2..43fdc9433882 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c | |||
@@ -1,14 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * inftlmount.c -- INFTL mount code with extensive checks. | 2 | * inftlmount.c -- INFTL mount code with extensive checks. |
3 | * | 3 | * |
4 | * Author: Greg Ungerer (gerg@snapgear.com) | 4 | * Author: Greg Ungerer (gerg@snapgear.com) |
5 | * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) | 5 | * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) |
6 | * | 6 | * |
7 | * Based heavily on the nftlmount.c code which is: | 7 | * Based heavily on the nftlmount.c code which is: |
8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
9 | * Copyright (C) 2000 Netgem S.A. | 9 | * Copyright (C) 2000 Netgem S.A. |
10 | * | 10 | * |
11 | * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $ | 11 | * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $ |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/mtd/inftl.h> | 41 | #include <linux/mtd/inftl.h> |
42 | #include <linux/mtd/compatmac.h> | 42 | #include <linux/mtd/compatmac.h> |
43 | 43 | ||
44 | char inftlmountrev[]="$Revision: 1.16 $"; | 44 | char inftlmountrev[]="$Revision: 1.18 $"; |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * find_boot_record: Find the INFTL Media Header and its Spare copy which | 47 | * find_boot_record: Find the INFTL Media Header and its Spare copy which |
@@ -273,7 +273,7 @@ static int find_boot_record(struct INFTLrecord *inftl) | |||
273 | inftl->nb_boot_blocks); | 273 | inftl->nb_boot_blocks); |
274 | return -1; | 274 | return -1; |
275 | } | 275 | } |
276 | 276 | ||
277 | inftl->mbd.size = inftl->numvunits * | 277 | inftl->mbd.size = inftl->numvunits * |
278 | (inftl->EraseSize / SECTORSIZE); | 278 | (inftl->EraseSize / SECTORSIZE); |
279 | 279 | ||
@@ -302,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl) | |||
302 | inftl->nb_blocks * sizeof(u16)); | 302 | inftl->nb_blocks * sizeof(u16)); |
303 | return -ENOMEM; | 303 | return -ENOMEM; |
304 | } | 304 | } |
305 | 305 | ||
306 | /* Mark the blocks before INFTL MediaHeader as reserved */ | 306 | /* Mark the blocks before INFTL MediaHeader as reserved */ |
307 | for (i = 0; i < inftl->nb_boot_blocks; i++) | 307 | for (i = 0; i < inftl->nb_boot_blocks; i++) |
308 | inftl->PUtable[i] = BLOCK_RESERVED; | 308 | inftl->PUtable[i] = BLOCK_RESERVED; |
@@ -380,7 +380,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, | |||
380 | * | 380 | * |
381 | * Return: 0 when succeed, -1 on error. | 381 | * Return: 0 when succeed, -1 on error. |
382 | * | 382 | * |
383 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? | 383 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? |
384 | */ | 384 | */ |
385 | int INFTL_formatblock(struct INFTLrecord *inftl, int block) | 385 | int INFTL_formatblock(struct INFTLrecord *inftl, int block) |
386 | { | 386 | { |
@@ -563,7 +563,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
563 | /* Search for INFTL MediaHeader and Spare INFTL Media Header */ | 563 | /* Search for INFTL MediaHeader and Spare INFTL Media Header */ |
564 | if (find_boot_record(s) < 0) { | 564 | if (find_boot_record(s) < 0) { |
565 | printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); | 565 | printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); |
566 | return -1; | 566 | return -ENXIO; |
567 | } | 567 | } |
568 | 568 | ||
569 | /* Init the logical to physical table */ | 569 | /* Init the logical to physical table */ |
@@ -601,7 +601,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
601 | 601 | ||
602 | for (chain_length = 0; ; chain_length++) { | 602 | for (chain_length = 0; ; chain_length++) { |
603 | 603 | ||
604 | if ((chain_length == 0) && | 604 | if ((chain_length == 0) && |
605 | (s->PUtable[block] != BLOCK_NOTEXPLORED)) { | 605 | (s->PUtable[block] != BLOCK_NOTEXPLORED)) { |
606 | /* Nothing to do here, onto next block */ | 606 | /* Nothing to do here, onto next block */ |
607 | break; | 607 | break; |
@@ -748,7 +748,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
748 | "in virtual chain %d\n", | 748 | "in virtual chain %d\n", |
749 | s->PUtable[block], logical_block); | 749 | s->PUtable[block], logical_block); |
750 | s->PUtable[block] = BLOCK_NIL; | 750 | s->PUtable[block] = BLOCK_NIL; |
751 | 751 | ||
752 | } | 752 | } |
753 | if (ANACtable[block] != ANAC) { | 753 | if (ANACtable[block] != ANAC) { |
754 | /* | 754 | /* |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 44781a83b2e7..48638c8097a5 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
2 | # $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $ | 2 | # $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $ |
3 | 3 | ||
4 | menu "Mapping drivers for chip access" | 4 | menu "Mapping drivers for chip access" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -64,9 +64,9 @@ config MTD_SUN_UFLASH | |||
64 | tristate "Sun Microsystems userflash support" | 64 | tristate "Sun Microsystems userflash support" |
65 | depends on (SPARC32 || SPARC64) && MTD_CFI | 65 | depends on (SPARC32 || SPARC64) && MTD_CFI |
66 | help | 66 | help |
67 | This provides a 'mapping' driver which supports the way in | 67 | This provides a 'mapping' driver which supports the way in |
68 | which user-programmable flash chips are connected on various | 68 | which user-programmable flash chips are connected on various |
69 | Sun Microsystems boardsets. This driver will require CFI support | 69 | Sun Microsystems boardsets. This driver will require CFI support |
70 | in the kernel, so if you did not enable CFI previously, do that now. | 70 | in the kernel, so if you did not enable CFI previously, do that now. |
71 | 71 | ||
72 | config MTD_PNC2000 | 72 | config MTD_PNC2000 |
@@ -89,22 +89,22 @@ config MTD_NETSC520 | |||
89 | depends on X86 && MTD_CFI && MTD_PARTITIONS | 89 | depends on X86 && MTD_CFI && MTD_PARTITIONS |
90 | help | 90 | help |
91 | This enables access routines for the flash chips on the AMD NetSc520 | 91 | This enables access routines for the flash chips on the AMD NetSc520 |
92 | demonstration board. If you have one of these boards and would like | 92 | demonstration board. If you have one of these boards and would like |
93 | to use the flash chips on it, say 'Y'. | 93 | to use the flash chips on it, say 'Y'. |
94 | 94 | ||
95 | config MTD_TS5500 | 95 | config MTD_TS5500 |
96 | tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" | 96 | tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" |
97 | depends on X86 && MTD_JEDECPROBE && MTD_PARTITIONS | 97 | depends on ELAN |
98 | select MTD_PARTITIONS | ||
99 | select MTD_JEDECPROBE | ||
100 | select MTD_CFI_AMDSTD | ||
98 | help | 101 | help |
99 | This provides a driver for the on-board flash of the Technologic | 102 | This provides a driver for the on-board flash of the Technologic |
100 | System's TS-5500 board. The flash is split into 3 partitions | 103 | System's TS-5500 board. The 2MB flash is split into 3 partitions |
101 | which are accessed as separate MTD devices. | 104 | which are accessed as separate MTD devices. |
102 | 105 | ||
103 | mtd0 and mtd2 are the two BIOS drives. Unfortunately the BIOS | 106 | mtd0 and mtd2 are the two BIOS drives, which use the resident |
104 | uses a proprietary flash translation layer from General Software, | 107 | flash disk (RFD) flash translation layer. |
105 | which is not supported (the drives cannot be mounted). You can | ||
106 | create your own file system (jffs for example), but the BIOS | ||
107 | won't be able to boot from it. | ||
108 | 108 | ||
109 | mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. | 109 | mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. |
110 | 110 | ||
@@ -212,11 +212,18 @@ config MTD_NETtel | |||
212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. | 212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. |
213 | 213 | ||
214 | config MTD_ALCHEMY | 214 | config MTD_ALCHEMY |
215 | tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' | 215 | tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' |
216 | depends on MIPS && SOC_AU1X00 | 216 | depends on SOC_AU1X00 |
217 | help | 217 | help |
218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards | 218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards |
219 | 219 | ||
220 | config MTD_MTX1 | ||
221 | tristate "4G Systems MTX-1 Flash device" | ||
222 | depends on MIPS && MIPS_MTX1 | ||
223 | help | ||
224 | Flash memory access on 4G Systems MTX-1 Board. If you have one of | ||
225 | these boards and would like to use the flash chips on it, say 'Y'. | ||
226 | |||
220 | config MTD_DILNETPC | 227 | config MTD_DILNETPC |
221 | tristate "CFI Flash device mapped on DIL/Net PC" | 228 | tristate "CFI Flash device mapped on DIL/Net PC" |
222 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT | 229 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT |
@@ -244,14 +251,14 @@ config MTD_L440GX | |||
244 | 251 | ||
245 | config MTD_SBC8240 | 252 | config MTD_SBC8240 |
246 | tristate "Flash device on SBC8240" | 253 | tristate "Flash device on SBC8240" |
247 | depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260 | 254 | depends on MTD_JEDECPROBE && 8260 |
248 | help | 255 | help |
249 | Flash access on the SBC8240 board from Wind River. See | 256 | Flash access on the SBC8240 board from Wind River. See |
250 | <http://www.windriver.com/products/sbc8240/> | 257 | <http://www.windriver.com/products/sbc8240/> |
251 | 258 | ||
252 | config MTD_TQM8XXL | 259 | config MTD_TQM8XXL |
253 | tristate "CFI Flash device mapped on TQM8XXL" | 260 | tristate "CFI Flash device mapped on TQM8XXL" |
254 | depends on MTD_CFI && PPC32 && 8xx && TQM8xxL | 261 | depends on MTD_CFI && TQM8xxL |
255 | help | 262 | help |
256 | The TQM8xxL PowerPC board has up to two banks of CFI-compliant | 263 | The TQM8xxL PowerPC board has up to two banks of CFI-compliant |
257 | chips, currently uses AMD one. This 'mapping' driver supports | 264 | chips, currently uses AMD one. This 'mapping' driver supports |
@@ -261,7 +268,7 @@ config MTD_TQM8XXL | |||
261 | 268 | ||
262 | config MTD_RPXLITE | 269 | config MTD_RPXLITE |
263 | tristate "CFI Flash device mapped on RPX Lite or CLLF" | 270 | tristate "CFI Flash device mapped on RPX Lite or CLLF" |
264 | depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE) | 271 | depends on MTD_CFI && (RPXCLASSIC || RPXLITE) |
265 | help | 272 | help |
266 | The RPXLite PowerPC board has CFI-compliant chips mapped in | 273 | The RPXLite PowerPC board has CFI-compliant chips mapped in |
267 | a strange sparse mapping. This 'mapping' driver supports that | 274 | a strange sparse mapping. This 'mapping' driver supports that |
@@ -271,7 +278,7 @@ config MTD_RPXLITE | |||
271 | 278 | ||
272 | config MTD_MBX860 | 279 | config MTD_MBX860 |
273 | tristate "System flash on MBX860 board" | 280 | tristate "System flash on MBX860 board" |
274 | depends on MTD_CFI && PPC32 && 8xx && MBX | 281 | depends on MTD_CFI && MBX |
275 | help | 282 | help |
276 | This enables access routines for the flash chips on the Motorola | 283 | This enables access routines for the flash chips on the Motorola |
277 | MBX860 board. If you have one of these boards and would like | 284 | MBX860 board. If you have one of these boards and would like |
@@ -279,7 +286,7 @@ config MTD_MBX860 | |||
279 | 286 | ||
280 | config MTD_DBOX2 | 287 | config MTD_DBOX2 |
281 | tristate "CFI Flash device mapped on D-Box2" | 288 | tristate "CFI Flash device mapped on D-Box2" |
282 | depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD | 289 | depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD |
283 | help | 290 | help |
284 | This enables access routines for the flash chips on the Nokia/Sagem | 291 | This enables access routines for the flash chips on the Nokia/Sagem |
285 | D-Box 2 board. If you have one of these boards and would like to use | 292 | D-Box 2 board. If you have one of these boards and would like to use |
@@ -287,14 +294,14 @@ config MTD_DBOX2 | |||
287 | 294 | ||
288 | config MTD_CFI_FLAGADM | 295 | config MTD_CFI_FLAGADM |
289 | tristate "CFI Flash device mapping on FlagaDM" | 296 | tristate "CFI Flash device mapping on FlagaDM" |
290 | depends on PPC32 && 8xx && MTD_CFI | 297 | depends on 8xx && MTD_CFI |
291 | help | 298 | help |
292 | Mapping for the Flaga digital module. If you don't have one, ignore | 299 | Mapping for the Flaga digital module. If you don't have one, ignore |
293 | this setting. | 300 | this setting. |
294 | 301 | ||
295 | config MTD_BEECH | 302 | config MTD_BEECH |
296 | tristate "CFI Flash device mapped on IBM 405LP Beech" | 303 | tristate "CFI Flash device mapped on IBM 405LP Beech" |
297 | depends on MTD_CFI && PPC32 && 40x && BEECH | 304 | depends on MTD_CFI && BEECH |
298 | help | 305 | help |
299 | This enables access routines for the flash chips on the IBM | 306 | This enables access routines for the flash chips on the IBM |
300 | 405LP Beech board. If you have one of these boards and would like | 307 | 405LP Beech board. If you have one of these boards and would like |
@@ -302,7 +309,7 @@ config MTD_BEECH | |||
302 | 309 | ||
303 | config MTD_ARCTIC | 310 | config MTD_ARCTIC |
304 | tristate "CFI Flash device mapped on IBM 405LP Arctic" | 311 | tristate "CFI Flash device mapped on IBM 405LP Arctic" |
305 | depends on MTD_CFI && PPC32 && 40x && ARCTIC2 | 312 | depends on MTD_CFI && ARCTIC2 |
306 | help | 313 | help |
307 | This enables access routines for the flash chips on the IBM 405LP | 314 | This enables access routines for the flash chips on the IBM 405LP |
308 | Arctic board. If you have one of these boards and would like to | 315 | Arctic board. If you have one of these boards and would like to |
@@ -310,7 +317,7 @@ config MTD_ARCTIC | |||
310 | 317 | ||
311 | config MTD_WALNUT | 318 | config MTD_WALNUT |
312 | tristate "Flash device mapped on IBM 405GP Walnut" | 319 | tristate "Flash device mapped on IBM 405GP Walnut" |
313 | depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT | 320 | depends on MTD_JEDECPROBE && WALNUT |
314 | help | 321 | help |
315 | This enables access routines for the flash chips on the IBM 405GP | 322 | This enables access routines for the flash chips on the IBM 405GP |
316 | Walnut board. If you have one of these boards and would like to | 323 | Walnut board. If you have one of these boards and would like to |
@@ -318,7 +325,7 @@ config MTD_WALNUT | |||
318 | 325 | ||
319 | config MTD_EBONY | 326 | config MTD_EBONY |
320 | tristate "Flash devices mapped on IBM 440GP Ebony" | 327 | tristate "Flash devices mapped on IBM 440GP Ebony" |
321 | depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY | 328 | depends on MTD_JEDECPROBE && EBONY |
322 | help | 329 | help |
323 | This enables access routines for the flash chips on the IBM 440GP | 330 | This enables access routines for the flash chips on the IBM 440GP |
324 | Ebony board. If you have one of these boards and would like to | 331 | Ebony board. If you have one of these boards and would like to |
@@ -326,7 +333,7 @@ config MTD_EBONY | |||
326 | 333 | ||
327 | config MTD_OCOTEA | 334 | config MTD_OCOTEA |
328 | tristate "Flash devices mapped on IBM 440GX Ocotea" | 335 | tristate "Flash devices mapped on IBM 440GX Ocotea" |
329 | depends on MTD_CFI && PPC32 && 44x && OCOTEA | 336 | depends on MTD_CFI && OCOTEA |
330 | help | 337 | help |
331 | This enables access routines for the flash chips on the IBM 440GX | 338 | This enables access routines for the flash chips on the IBM 440GX |
332 | Ocotea board. If you have one of these boards and would like to | 339 | Ocotea board. If you have one of these boards and would like to |
@@ -334,12 +341,20 @@ config MTD_OCOTEA | |||
334 | 341 | ||
335 | config MTD_REDWOOD | 342 | config MTD_REDWOOD |
336 | tristate "CFI Flash devices mapped on IBM Redwood" | 343 | tristate "CFI Flash devices mapped on IBM Redwood" |
337 | depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) | 344 | depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) |
338 | help | 345 | help |
339 | This enables access routines for the flash chips on the IBM | 346 | This enables access routines for the flash chips on the IBM |
340 | Redwood board. If you have one of these boards and would like to | 347 | Redwood board. If you have one of these boards and would like to |
341 | use the flash chips on it, say 'Y'. | 348 | use the flash chips on it, say 'Y'. |
342 | 349 | ||
350 | config MTD_TQM834x | ||
351 | tristate "Flash device mapped on TQ Components TQM834x Boards" | ||
352 | depends on MTD_CFI && TQM834x | ||
353 | help | ||
354 | This enables access routines for the flash chips on the | ||
355 | TQ Components TQM834x boards. If you have one of these boards | ||
356 | and would like to use the flash chips on it, say 'Y'. | ||
357 | |||
343 | config MTD_CSTM_MIPS_IXX | 358 | config MTD_CSTM_MIPS_IXX |
344 | tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" | 359 | tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" |
345 | depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS | 360 | depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS |
@@ -362,8 +377,8 @@ config MTD_CSTM_MIPS_IXX_START | |||
362 | default "0x8000000" | 377 | default "0x8000000" |
363 | help | 378 | help |
364 | This is the physical memory location that the MTD driver will | 379 | This is the physical memory location that the MTD driver will |
365 | use for the flash chips on your particular target board. | 380 | use for the flash chips on your particular target board. |
366 | Refer to the memory map which should hopefully be in the | 381 | Refer to the memory map which should hopefully be in the |
367 | documentation for your board. | 382 | documentation for your board. |
368 | 383 | ||
369 | config MTD_CSTM_MIPS_IXX_LEN | 384 | config MTD_CSTM_MIPS_IXX_LEN |
@@ -371,7 +386,7 @@ config MTD_CSTM_MIPS_IXX_LEN | |||
371 | depends on MTD_CSTM_MIPS_IXX | 386 | depends on MTD_CSTM_MIPS_IXX |
372 | default "0x4000000" | 387 | default "0x4000000" |
373 | help | 388 | help |
374 | This is the total length that the MTD driver will use for the | 389 | This is the total length that the MTD driver will use for the |
375 | flash chips on your particular board. Refer to the memory | 390 | flash chips on your particular board. Refer to the memory |
376 | map which should hopefully be in the documentation for your | 391 | map which should hopefully be in the documentation for your |
377 | board. | 392 | board. |
@@ -405,14 +420,14 @@ config MTD_ARM_INTEGRATOR | |||
405 | 420 | ||
406 | config MTD_CDB89712 | 421 | config MTD_CDB89712 |
407 | tristate "Cirrus CDB89712 evaluation board mappings" | 422 | tristate "Cirrus CDB89712 evaluation board mappings" |
408 | depends on ARM && MTD_CFI && ARCH_CDB89712 | 423 | depends on MTD_CFI && ARCH_CDB89712 |
409 | help | 424 | help |
410 | This enables access to the flash or ROM chips on the CDB89712 board. | 425 | This enables access to the flash or ROM chips on the CDB89712 board. |
411 | If you have such a board, say 'Y'. | 426 | If you have such a board, say 'Y'. |
412 | 427 | ||
413 | config MTD_SA1100 | 428 | config MTD_SA1100 |
414 | tristate "CFI Flash device mapped on StrongARM SA11x0" | 429 | tristate "CFI Flash device mapped on StrongARM SA11x0" |
415 | depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS | 430 | depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS |
416 | help | 431 | help |
417 | This enables access to the flash chips on most platforms based on | 432 | This enables access to the flash chips on most platforms based on |
418 | the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. | 433 | the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. |
@@ -420,13 +435,13 @@ config MTD_SA1100 | |||
420 | 435 | ||
421 | config MTD_IPAQ | 436 | config MTD_IPAQ |
422 | tristate "CFI Flash device mapped on Compaq/HP iPAQ" | 437 | tristate "CFI Flash device mapped on Compaq/HP iPAQ" |
423 | depends on ARM && IPAQ_HANDHELD && MTD_CFI | 438 | depends on IPAQ_HANDHELD && MTD_CFI |
424 | help | 439 | help |
425 | This provides a driver for the on-board flash of the iPAQ. | 440 | This provides a driver for the on-board flash of the iPAQ. |
426 | 441 | ||
427 | config MTD_DC21285 | 442 | config MTD_DC21285 |
428 | tristate "CFI Flash device mapped on DC21285 Footbridge" | 443 | tristate "CFI Flash device mapped on DC21285 Footbridge" |
429 | depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS | 444 | depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS |
430 | help | 445 | help |
431 | This provides a driver for the flash accessed using Intel's | 446 | This provides a driver for the flash accessed using Intel's |
432 | 21285 bridge used with Intel's StrongARM processors. More info at | 447 | 21285 bridge used with Intel's StrongARM processors. More info at |
@@ -434,33 +449,33 @@ config MTD_DC21285 | |||
434 | 449 | ||
435 | config MTD_IQ80310 | 450 | config MTD_IQ80310 |
436 | tristate "CFI Flash device mapped on the XScale IQ80310 board" | 451 | tristate "CFI Flash device mapped on the XScale IQ80310 board" |
437 | depends on ARM && MTD_CFI && ARCH_IQ80310 | 452 | depends on MTD_CFI && ARCH_IQ80310 |
438 | help | 453 | help |
439 | This enables access routines for the flash chips on the Intel XScale | 454 | This enables access routines for the flash chips on the Intel XScale |
440 | IQ80310 evaluation board. If you have one of these boards and would | 455 | IQ80310 evaluation board. If you have one of these boards and would |
441 | like to use the flash chips on it, say 'Y'. | 456 | like to use the flash chips on it, say 'Y'. |
442 | 457 | ||
443 | config MTD_IXP4XX | 458 | config MTD_IXP4XX |
444 | tristate "CFI Flash device mapped on Intel IXP4xx based systems" | 459 | tristate "CFI Flash device mapped on Intel IXP4xx based systems" |
445 | depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX | 460 | depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX |
446 | help | 461 | help |
447 | This enables MTD access to flash devices on platforms based | 462 | This enables MTD access to flash devices on platforms based |
448 | on Intel's IXP4xx family of network processors such as the | 463 | on Intel's IXP4xx family of network processors such as the |
449 | IXDP425 and Coyote. If you have an IXP4xx based board and | 464 | IXDP425 and Coyote. If you have an IXP4xx based board and |
450 | would like to use the flash chips on it, say 'Y'. | 465 | would like to use the flash chips on it, say 'Y'. |
451 | 466 | ||
452 | config MTD_IXP2000 | 467 | config MTD_IXP2000 |
453 | tristate "CFI Flash device mapped on Intel IXP2000 based systems" | 468 | tristate "CFI Flash device mapped on Intel IXP2000 based systems" |
454 | depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 | 469 | depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 |
455 | help | 470 | help |
456 | This enables MTD access to flash devices on platforms based | 471 | This enables MTD access to flash devices on platforms based |
457 | on Intel's IXP2000 family of network processors such as the | 472 | on Intel's IXP2000 family of network processors such as the |
458 | IXDP425 and Coyote. If you have an IXP2000 based board and | 473 | IXDP425 and Coyote. If you have an IXP2000 based board and |
459 | would like to use the flash chips on it, say 'Y'. | 474 | would like to use the flash chips on it, say 'Y'. |
460 | 475 | ||
461 | config MTD_EPXA10DB | 476 | config MTD_EPXA10DB |
462 | tristate "CFI Flash device mapped on Epxa10db" | 477 | tristate "CFI Flash device mapped on Epxa10db" |
463 | depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT | 478 | depends on MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT |
464 | help | 479 | help |
465 | This enables support for the flash devices on the Altera | 480 | This enables support for the flash devices on the Altera |
466 | Excalibur XA10 Development Board. If you are building a kernel | 481 | Excalibur XA10 Development Board. If you are building a kernel |
@@ -468,21 +483,21 @@ config MTD_EPXA10DB | |||
468 | 483 | ||
469 | config MTD_FORTUNET | 484 | config MTD_FORTUNET |
470 | tristate "CFI Flash device mapped on the FortuNet board" | 485 | tristate "CFI Flash device mapped on the FortuNet board" |
471 | depends on ARM && MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET | 486 | depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET |
472 | help | 487 | help |
473 | This enables access to the Flash on the FortuNet board. If you | 488 | This enables access to the Flash on the FortuNet board. If you |
474 | have such a board, say 'Y'. | 489 | have such a board, say 'Y'. |
475 | 490 | ||
476 | config MTD_AUTCPU12 | 491 | config MTD_AUTCPU12 |
477 | tristate "NV-RAM mapping AUTCPU12 board" | 492 | tristate "NV-RAM mapping AUTCPU12 board" |
478 | depends on ARM && ARCH_AUTCPU12 | 493 | depends on ARCH_AUTCPU12 |
479 | help | 494 | help |
480 | This enables access to the NV-RAM on autronix autcpu12 board. | 495 | This enables access to the NV-RAM on autronix autcpu12 board. |
481 | If you have such a board, say 'Y'. | 496 | If you have such a board, say 'Y'. |
482 | 497 | ||
483 | config MTD_EDB7312 | 498 | config MTD_EDB7312 |
484 | tristate "CFI Flash device mapped on EDB7312" | 499 | tristate "CFI Flash device mapped on EDB7312" |
485 | depends on ARM && MTD_CFI | 500 | depends on ARCH_EDB7312 && MTD_CFI |
486 | help | 501 | help |
487 | This enables access to the CFI Flash on the Cogent EDB7312 board. | 502 | This enables access to the CFI Flash on the Cogent EDB7312 board. |
488 | If you have such a board, say 'Y' here. | 503 | If you have such a board, say 'Y' here. |
@@ -496,7 +511,7 @@ config MTD_IMPA7 | |||
496 | 511 | ||
497 | config MTD_CEIVA | 512 | config MTD_CEIVA |
498 | tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" | 513 | tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" |
499 | depends on ARM && MTD_JEDECPROBE && ARCH_CEIVA | 514 | depends on MTD_JEDECPROBE && ARCH_CEIVA |
500 | help | 515 | help |
501 | This enables access to the flash chips on the Ceiva/Polaroid | 516 | This enables access to the flash chips on the Ceiva/Polaroid |
502 | PhotoMax Digital Picture Frame. | 517 | PhotoMax Digital Picture Frame. |
@@ -504,25 +519,31 @@ config MTD_CEIVA | |||
504 | 519 | ||
505 | config MTD_NOR_TOTO | 520 | config MTD_NOR_TOTO |
506 | tristate "NOR Flash device on TOTO board" | 521 | tristate "NOR Flash device on TOTO board" |
507 | depends on ARM && ARCH_OMAP && OMAP_TOTO | 522 | depends on ARCH_OMAP && OMAP_TOTO |
508 | help | 523 | help |
509 | This enables access to the NOR flash on the Texas Instruments | 524 | This enables access to the NOR flash on the Texas Instruments |
510 | TOTO board. | 525 | TOTO board. |
511 | 526 | ||
512 | config MTD_H720X | 527 | config MTD_H720X |
513 | tristate "Hynix evaluation board mappings" | 528 | tristate "Hynix evaluation board mappings" |
514 | depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) | 529 | depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) |
515 | help | 530 | help |
516 | This enables access to the flash chips on the Hynix evaluation boards. | 531 | This enables access to the flash chips on the Hynix evaluation boards. |
517 | If you have such a board, say 'Y'. | 532 | If you have such a board, say 'Y'. |
518 | 533 | ||
519 | config MTD_MPC1211 | 534 | config MTD_MPC1211 |
520 | tristate "CFI Flash device mapped on Interface MPC-1211" | 535 | tristate "CFI Flash device mapped on Interface MPC-1211" |
521 | depends on SUPERH && SH_MPC1211 && MTD_CFI | 536 | depends on SH_MPC1211 && MTD_CFI |
522 | help | 537 | help |
523 | This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). | 538 | This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). |
524 | If you have such a board, say 'Y'. | 539 | If you have such a board, say 'Y'. |
525 | 540 | ||
541 | config MTD_PQ2FADS | ||
542 | tristate "JEDEC flash SIMM mapped on PQ2FADS and 8272ADS boards" | ||
543 | depends on (ADS8272 || PQ2FADS) && MTD_PARTITIONS && MTD_JEDECPROBE && MTD_PHYSMAP && MTD_CFI_GEOMETRY && MTD_CFI_INTELEXT | ||
544 | help | ||
545 | This enables access to flash SIMM on PQ2FADS-like boards | ||
546 | |||
526 | config MTD_OMAP_NOR | 547 | config MTD_OMAP_NOR |
527 | tristate "TI OMAP board mappings" | 548 | tristate "TI OMAP board mappings" |
528 | depends on MTD_CFI && ARCH_OMAP | 549 | depends on MTD_CFI && ARCH_OMAP |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 7bcbc49e329f..7d9e940a1dcd 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # linux/drivers/maps/Makefile | 2 | # linux/drivers/maps/Makefile |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $ | 4 | # $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $ |
5 | 5 | ||
6 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) | 6 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) |
7 | obj-$(CONFIG_MTD) += map_funcs.o | 7 | obj-$(CONFIG_MTD) += map_funcs.o |
@@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o | |||
26 | obj-$(CONFIG_MTD_MBX860) += mbx860.o | 26 | obj-$(CONFIG_MTD_MBX860) += mbx860.o |
27 | obj-$(CONFIG_MTD_CEIVA) += ceiva.o | 27 | obj-$(CONFIG_MTD_CEIVA) += ceiva.o |
28 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o | 28 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o |
29 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o | 29 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o |
30 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o | 30 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o |
31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o | 31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o |
32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o | 32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o |
@@ -70,3 +70,6 @@ obj-$(CONFIG_MTD_DMV182) += dmv182.o | |||
70 | obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o | 70 | obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o |
71 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o | 71 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o |
72 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o | 72 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o |
73 | obj-$(CONFIG_MTD_PQ2FADS) += pq2fads.o | ||
74 | obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o | ||
75 | obj-$(CONFIG_MTD_TQM834x) += tqm834x.o | ||
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 27fd2a3c3b60..a57791a6ce40 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on AMD Alchemy evaluation boards | 2 | * Flash memory access on AMD Alchemy evaluation boards |
3 | * | 3 | * |
4 | * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $ | 4 | * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $ |
5 | * | 5 | * |
6 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> | 6 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> |
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
@@ -22,7 +22,7 @@ | |||
22 | #ifdef DEBUG_RW | 22 | #ifdef DEBUG_RW |
23 | #define DBG(x...) printk(x) | 23 | #define DBG(x...) printk(x) |
24 | #else | 24 | #else |
25 | #define DBG(x...) | 25 | #define DBG(x...) |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #ifdef CONFIG_MIPS_PB1000 | 28 | #ifdef CONFIG_MIPS_PB1000 |
@@ -136,7 +136,7 @@ int __init alchemy_mtd_init(void) | |||
136 | int nb_parts = 0; | 136 | int nb_parts = 0; |
137 | unsigned long window_addr; | 137 | unsigned long window_addr; |
138 | unsigned long window_size; | 138 | unsigned long window_size; |
139 | 139 | ||
140 | /* Default flash buswidth */ | 140 | /* Default flash buswidth */ |
141 | alchemy_map.bankwidth = BOARD_FLASH_WIDTH; | 141 | alchemy_map.bankwidth = BOARD_FLASH_WIDTH; |
142 | 142 | ||
@@ -161,7 +161,7 @@ int __init alchemy_mtd_init(void) | |||
161 | * Now let's probe for the actual flash. Do it here since | 161 | * Now let's probe for the actual flash. Do it here since |
162 | * specific machine settings might have been set above. | 162 | * specific machine settings might have been set above. |
163 | */ | 163 | */ |
164 | printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", | 164 | printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", |
165 | alchemy_map.bankwidth*8); | 165 | alchemy_map.bankwidth*8); |
166 | alchemy_map.virt = ioremap(window_addr, window_size); | 166 | alchemy_map.virt = ioremap(window_addr, window_size); |
167 | mymtd = do_map_probe("cfi_probe", &alchemy_map); | 167 | mymtd = do_map_probe("cfi_probe", &alchemy_map); |
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 9a64149f431d..c350878d4592 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * amd76xrom.c | 2 | * amd76xrom.c |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $ | 5 | * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
@@ -70,7 +70,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window) | |||
70 | list_del(&map->list); | 70 | list_del(&map->list); |
71 | kfree(map); | 71 | kfree(map); |
72 | } | 72 | } |
73 | if (window->rsrc.parent) | 73 | if (window->rsrc.parent) |
74 | release_resource(&window->rsrc); | 74 | release_resource(&window->rsrc); |
75 | 75 | ||
76 | if (window->virt) { | 76 | if (window->virt) { |
@@ -107,7 +107,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
107 | window->phys = 0xffff0000; /* 64KiB */ | 107 | window->phys = 0xffff0000; /* 64KiB */ |
108 | } | 108 | } |
109 | window->size = 0xffffffffUL - window->phys + 1UL; | 109 | window->size = 0xffffffffUL - window->phys + 1UL; |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * Try to reserve the window mem region. If this fails then | 112 | * Try to reserve the window mem region. If this fails then |
113 | * it is likely due to a fragment of the window being | 113 | * it is likely due to a fragment of the window being |
@@ -138,7 +138,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
138 | /* Enable writes through the rom window */ | 138 | /* Enable writes through the rom window */ |
139 | pci_read_config_byte(pdev, 0x40, &byte); | 139 | pci_read_config_byte(pdev, 0x40, &byte); |
140 | pci_write_config_byte(pdev, 0x40, byte | 1); | 140 | pci_write_config_byte(pdev, 0x40, byte | 1); |
141 | 141 | ||
142 | /* FIXME handle registers 0x80 - 0x8C the bios region locks */ | 142 | /* FIXME handle registers 0x80 - 0x8C the bios region locks */ |
143 | 143 | ||
144 | /* For write accesses caches are useless */ | 144 | /* For write accesses caches are useless */ |
@@ -186,7 +186,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
186 | MOD_NAME, map->map.phys); | 186 | MOD_NAME, map->map.phys); |
187 | 187 | ||
188 | /* There is no generic VPP support */ | 188 | /* There is no generic VPP support */ |
189 | for(map->map.bankwidth = 32; map->map.bankwidth; | 189 | for(map->map.bankwidth = 32; map->map.bankwidth; |
190 | map->map.bankwidth >>= 1) | 190 | map->map.bankwidth >>= 1) |
191 | { | 191 | { |
192 | char **probe_type; | 192 | char **probe_type; |
@@ -239,7 +239,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
239 | for(i = 0; i < cfi->numchips; i++) { | 239 | for(i = 0; i < cfi->numchips; i++) { |
240 | cfi->chips[i].start += offset; | 240 | cfi->chips[i].start += offset; |
241 | } | 241 | } |
242 | 242 | ||
243 | /* Now that the mtd devices is complete claim and export it */ | 243 | /* Now that the mtd devices is complete claim and export it */ |
244 | map->mtd->owner = THIS_MODULE; | 244 | map->mtd->owner = THIS_MODULE; |
245 | if (add_mtd_device(map->mtd)) { | 245 | if (add_mtd_device(map->mtd)) { |
@@ -277,9 +277,9 @@ static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) | |||
277 | } | 277 | } |
278 | 278 | ||
279 | static struct pci_device_id amd76xrom_pci_tbl[] = { | 279 | static struct pci_device_id amd76xrom_pci_tbl[] = { |
280 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, | 280 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, |
281 | PCI_ANY_ID, PCI_ANY_ID, }, | 281 | PCI_ANY_ID, PCI_ANY_ID, }, |
282 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, | 282 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, |
283 | PCI_ANY_ID, PCI_ANY_ID, }, | 283 | PCI_ANY_ID, PCI_ANY_ID, }, |
284 | { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ | 284 | { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ |
285 | { 0, } | 285 | { 0, } |
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c index 777276fd0e15..d95ae582fbe9 100644 --- a/drivers/mtd/maps/arctic-mtd.c +++ b/drivers/mtd/maps/arctic-mtd.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: arctic-mtd.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for | 4 | * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for |
5 | * IBM 405LP Arctic boards. | 5 | * IBM 405LP Arctic boards. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index cf362ccc3c8e..7ed3424dd959 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * NV-RAM memory access on autcpu12 | 2 | * NV-RAM memory access on autcpu12 |
3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) | 3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) |
4 | * | 4 | * |
5 | * $Id: autcpu12-nvram.c,v 1.8 2004/11/04 13:24:14 gleixner Exp $ | 5 | * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 gleixner Exp $ |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -55,10 +55,10 @@ static int __init init_autcpu12_sram (void) | |||
55 | } | 55 | } |
56 | simple_map_init(&autcpu_sram_map); | 56 | simple_map_init(&autcpu_sram_map); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Check for 32K/128K | 59 | * Check for 32K/128K |
60 | * read ofs 0 | 60 | * read ofs 0 |
61 | * read ofs 0x10000 | 61 | * read ofs 0x10000 |
62 | * Write complement to ofs 0x100000 | 62 | * Write complement to ofs 0x100000 |
63 | * Read and check result on ofs 0x0 | 63 | * Read and check result on ofs 0x0 |
64 | * Restore contents | 64 | * Restore contents |
@@ -66,7 +66,7 @@ static int __init init_autcpu12_sram (void) | |||
66 | save0 = map_read32(&autcpu12_sram_map,0); | 66 | save0 = map_read32(&autcpu12_sram_map,0); |
67 | save1 = map_read32(&autcpu12_sram_map,0x10000); | 67 | save1 = map_read32(&autcpu12_sram_map,0x10000); |
68 | map_write32(&autcpu12_sram_map,~save0,0x10000); | 68 | map_write32(&autcpu12_sram_map,~save0,0x10000); |
69 | /* if we find this pattern on 0x0, we have 32K size | 69 | /* if we find this pattern on 0x0, we have 32K size |
70 | * restore contents and exit | 70 | * restore contents and exit |
71 | */ | 71 | */ |
72 | if ( map_read32(&autcpu12_sram_map,0) != save0) { | 72 | if ( map_read32(&autcpu12_sram_map,0) != save0) { |
@@ -89,7 +89,7 @@ map: | |||
89 | 89 | ||
90 | sram_mtd->owner = THIS_MODULE; | 90 | sram_mtd->owner = THIS_MODULE; |
91 | sram_mtd->erasesize = 16; | 91 | sram_mtd->erasesize = 16; |
92 | 92 | ||
93 | if (add_mtd_device(sram_mtd)) { | 93 | if (add_mtd_device(sram_mtd)) { |
94 | printk("NV-RAM device addition failed\n"); | 94 | printk("NV-RAM device addition failed\n"); |
95 | err = -ENOMEM; | 95 | err = -ENOMEM; |
@@ -97,7 +97,7 @@ map: | |||
97 | } | 97 | } |
98 | 98 | ||
99 | printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); | 99 | printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); |
100 | 100 | ||
101 | return 0; | 101 | return 0; |
102 | 102 | ||
103 | out_probe: | 103 | out_probe: |
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 8c19d722ac79..b7858eb93534 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * 20-Sep-2004 BJD Initial version | 9 | * 20-Sep-2004 BJD Initial version |
10 | * 17-Jan-2005 BJD Add whole device if no partitions found | 10 | * 17-Jan-2005 BJD Add whole device if no partitions found |
11 | * | 11 | * |
12 | * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $ | 12 | * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 gleixner Exp $ |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -75,7 +75,7 @@ static void bast_flash_setrw(int to) | |||
75 | 75 | ||
76 | local_irq_save(flags); | 76 | local_irq_save(flags); |
77 | val = __raw_readb(BAST_VA_CTRL3); | 77 | val = __raw_readb(BAST_VA_CTRL3); |
78 | 78 | ||
79 | if (to) | 79 | if (to) |
80 | val |= BAST_CPLD_CTRL3_ROMWEN; | 80 | val |= BAST_CPLD_CTRL3_ROMWEN; |
81 | else | 81 | else |
@@ -93,7 +93,7 @@ static int bast_flash_remove(struct device *dev) | |||
93 | 93 | ||
94 | dev_set_drvdata(dev, NULL); | 94 | dev_set_drvdata(dev, NULL); |
95 | 95 | ||
96 | if (info == NULL) | 96 | if (info == NULL) |
97 | return 0; | 97 | return 0; |
98 | 98 | ||
99 | if (info->map.virt != NULL) | 99 | if (info->map.virt != NULL) |
@@ -110,7 +110,7 @@ static int bast_flash_remove(struct device *dev) | |||
110 | release_resource(info->area); | 110 | release_resource(info->area); |
111 | kfree(info->area); | 111 | kfree(info->area); |
112 | } | 112 | } |
113 | 113 | ||
114 | kfree(info); | 114 | kfree(info); |
115 | 115 | ||
116 | return 0; | 116 | return 0; |
@@ -137,15 +137,15 @@ static int bast_flash_probe(struct device *dev) | |||
137 | 137 | ||
138 | info->map.phys = res->start; | 138 | info->map.phys = res->start; |
139 | info->map.size = res->end - res->start + 1; | 139 | info->map.size = res->end - res->start + 1; |
140 | info->map.name = dev->bus_id; | 140 | info->map.name = dev->bus_id; |
141 | info->map.bankwidth = 2; | 141 | info->map.bankwidth = 2; |
142 | 142 | ||
143 | if (info->map.size > AREA_MAXSIZE) | 143 | if (info->map.size > AREA_MAXSIZE) |
144 | info->map.size = AREA_MAXSIZE; | 144 | info->map.size = AREA_MAXSIZE; |
145 | 145 | ||
146 | pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, | 146 | pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, |
147 | info->map.phys, info->map.size); | 147 | info->map.phys, info->map.size); |
148 | 148 | ||
149 | info->area = request_mem_region(res->start, info->map.size, | 149 | info->area = request_mem_region(res->start, info->map.size, |
150 | pdev->name); | 150 | pdev->name); |
151 | if (info->area == NULL) { | 151 | if (info->area == NULL) { |
@@ -162,7 +162,7 @@ static int bast_flash_probe(struct device *dev) | |||
162 | err = -EIO; | 162 | err = -EIO; |
163 | goto exit_error; | 163 | goto exit_error; |
164 | } | 164 | } |
165 | 165 | ||
166 | simple_map_init(&info->map); | 166 | simple_map_init(&info->map); |
167 | 167 | ||
168 | /* enable the write to the flash area */ | 168 | /* enable the write to the flash area */ |
@@ -187,7 +187,7 @@ static int bast_flash_probe(struct device *dev) | |||
187 | err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); | 187 | err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); |
188 | if (err > 0) { | 188 | if (err > 0) { |
189 | err = add_mtd_partitions(info->mtd, info->partitions, err); | 189 | err = add_mtd_partitions(info->mtd, info->partitions, err); |
190 | if (err) | 190 | if (err) |
191 | printk(KERN_ERR PFX "cannot add/parse partitions\n"); | 191 | printk(KERN_ERR PFX "cannot add/parse partitions\n"); |
192 | } else { | 192 | } else { |
193 | err = add_mtd_device(info->mtd); | 193 | err = add_mtd_device(info->mtd); |
@@ -205,6 +205,7 @@ static int bast_flash_probe(struct device *dev) | |||
205 | 205 | ||
206 | static struct device_driver bast_flash_driver = { | 206 | static struct device_driver bast_flash_driver = { |
207 | .name = "bast-nor", | 207 | .name = "bast-nor", |
208 | .owner = THIS_MODULE, | ||
208 | .bus = &platform_bus_type, | 209 | .bus = &platform_bus_type, |
209 | .probe = bast_flash_probe, | 210 | .probe = bast_flash_probe, |
210 | .remove = bast_flash_remove, | 211 | .remove = bast_flash_remove, |
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c index 5e79c9d5da2b..5df7361d1407 100644 --- a/drivers/mtd/maps/beech-mtd.c +++ b/drivers/mtd/maps/beech-mtd.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: beech-mtd.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for | 4 | * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for |
5 | * IBM 405LP Beech boards. | 5 | * IBM 405LP Beech boards. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index ab15dac2f936..9f17bb6c5a9d 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Flash on Cirrus CDB89712 | 2 | * Flash on Cirrus CDB89712 |
3 | * | 3 | * |
4 | * $Id: cdb89712.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ | 4 | * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
@@ -37,13 +37,13 @@ struct resource cdb89712_flash_resource = { | |||
37 | static int __init init_cdb89712_flash (void) | 37 | static int __init init_cdb89712_flash (void) |
38 | { | 38 | { |
39 | int err; | 39 | int err; |
40 | 40 | ||
41 | if (request_resource (&ioport_resource, &cdb89712_flash_resource)) { | 41 | if (request_resource (&ioport_resource, &cdb89712_flash_resource)) { |
42 | printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n"); | 42 | printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n"); |
43 | err = -EBUSY; | 43 | err = -EBUSY; |
44 | goto out; | 44 | goto out; |
45 | } | 45 | } |
46 | 46 | ||
47 | cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE); | 47 | cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE); |
48 | if (!cdb89712_flash_map.virt) { | 48 | if (!cdb89712_flash_map.virt) { |
49 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); | 49 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); |
@@ -64,13 +64,13 @@ static int __init init_cdb89712_flash (void) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | flash_mtd->owner = THIS_MODULE; | 66 | flash_mtd->owner = THIS_MODULE; |
67 | 67 | ||
68 | if (add_mtd_device(flash_mtd)) { | 68 | if (add_mtd_device(flash_mtd)) { |
69 | printk("FLASH device addition failed\n"); | 69 | printk("FLASH device addition failed\n"); |
70 | err = -ENOMEM; | 70 | err = -ENOMEM; |
71 | goto out_probe; | 71 | goto out_probe; |
72 | } | 72 | } |
73 | 73 | ||
74 | return 0; | 74 | return 0; |
75 | 75 | ||
76 | out_probe: | 76 | out_probe: |
@@ -107,13 +107,13 @@ struct resource cdb89712_sram_resource = { | |||
107 | static int __init init_cdb89712_sram (void) | 107 | static int __init init_cdb89712_sram (void) |
108 | { | 108 | { |
109 | int err; | 109 | int err; |
110 | 110 | ||
111 | if (request_resource (&ioport_resource, &cdb89712_sram_resource)) { | 111 | if (request_resource (&ioport_resource, &cdb89712_sram_resource)) { |
112 | printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n"); | 112 | printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n"); |
113 | err = -EBUSY; | 113 | err = -EBUSY; |
114 | goto out; | 114 | goto out; |
115 | } | 115 | } |
116 | 116 | ||
117 | cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE); | 117 | cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE); |
118 | if (!cdb89712_sram_map.virt) { | 118 | if (!cdb89712_sram_map.virt) { |
119 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); | 119 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); |
@@ -130,13 +130,13 @@ static int __init init_cdb89712_sram (void) | |||
130 | 130 | ||
131 | sram_mtd->owner = THIS_MODULE; | 131 | sram_mtd->owner = THIS_MODULE; |
132 | sram_mtd->erasesize = 16; | 132 | sram_mtd->erasesize = 16; |
133 | 133 | ||
134 | if (add_mtd_device(sram_mtd)) { | 134 | if (add_mtd_device(sram_mtd)) { |
135 | printk("SRAM device addition failed\n"); | 135 | printk("SRAM device addition failed\n"); |
136 | err = -ENOMEM; | 136 | err = -ENOMEM; |
137 | goto out_probe; | 137 | goto out_probe; |
138 | } | 138 | } |
139 | 139 | ||
140 | return 0; | 140 | return 0; |
141 | 141 | ||
142 | out_probe: | 142 | out_probe: |
@@ -175,13 +175,13 @@ struct resource cdb89712_bootrom_resource = { | |||
175 | static int __init init_cdb89712_bootrom (void) | 175 | static int __init init_cdb89712_bootrom (void) |
176 | { | 176 | { |
177 | int err; | 177 | int err; |
178 | 178 | ||
179 | if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) { | 179 | if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) { |
180 | printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n"); | 180 | printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n"); |
181 | err = -EBUSY; | 181 | err = -EBUSY; |
182 | goto out; | 182 | goto out; |
183 | } | 183 | } |
184 | 184 | ||
185 | cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE); | 185 | cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE); |
186 | if (!cdb89712_bootrom_map.virt) { | 186 | if (!cdb89712_bootrom_map.virt) { |
187 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); | 187 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); |
@@ -198,13 +198,13 @@ static int __init init_cdb89712_bootrom (void) | |||
198 | 198 | ||
199 | bootrom_mtd->owner = THIS_MODULE; | 199 | bootrom_mtd->owner = THIS_MODULE; |
200 | bootrom_mtd->erasesize = 0x10000; | 200 | bootrom_mtd->erasesize = 0x10000; |
201 | 201 | ||
202 | if (add_mtd_device(bootrom_mtd)) { | 202 | if (add_mtd_device(bootrom_mtd)) { |
203 | printk("BootROM device addition failed\n"); | 203 | printk("BootROM device addition failed\n"); |
204 | err = -ENOMEM; | 204 | err = -ENOMEM; |
205 | goto out_probe; | 205 | goto out_probe; |
206 | } | 206 | } |
207 | 207 | ||
208 | return 0; | 208 | return 0; |
209 | 209 | ||
210 | out_probe: | 210 | out_probe: |
@@ -225,16 +225,16 @@ out: | |||
225 | static int __init init_cdb89712_maps(void) | 225 | static int __init init_cdb89712_maps(void) |
226 | { | 226 | { |
227 | 227 | ||
228 | printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", | 228 | printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", |
229 | FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START); | 229 | FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START); |
230 | 230 | ||
231 | init_cdb89712_flash(); | 231 | init_cdb89712_flash(); |
232 | init_cdb89712_sram(); | 232 | init_cdb89712_sram(); |
233 | init_cdb89712_bootrom(); | 233 | init_cdb89712_bootrom(); |
234 | 234 | ||
235 | return 0; | 235 | return 0; |
236 | } | 236 | } |
237 | 237 | ||
238 | 238 | ||
239 | static void __exit cleanup_cdb89712_maps(void) | 239 | static void __exit cleanup_cdb89712_maps(void) |
240 | { | 240 | { |
@@ -244,7 +244,7 @@ static void __exit cleanup_cdb89712_maps(void) | |||
244 | iounmap((void *)cdb89712_sram_map.virt); | 244 | iounmap((void *)cdb89712_sram_map.virt); |
245 | release_resource (&cdb89712_sram_resource); | 245 | release_resource (&cdb89712_sram_resource); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (flash_mtd) { | 248 | if (flash_mtd) { |
249 | del_mtd_device(flash_mtd); | 249 | del_mtd_device(flash_mtd); |
250 | map_destroy(flash_mtd); | 250 | map_destroy(flash_mtd); |
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index f72e4f894b32..6a8c0415bde8 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> | 2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> |
3 | * | 3 | * |
4 | * $Id: cfi_flagadm.c,v 1.14 2004/11/04 13:24:14 gleixner Exp $ | 4 | * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $ |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; either version 2 of the License, or (at your | 8 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -42,7 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #define FLASH_PHYS_ADDR 0x40000000 | 44 | #define FLASH_PHYS_ADDR 0x40000000 |
45 | #define FLASH_SIZE 0x400000 | 45 | #define FLASH_SIZE 0x400000 |
46 | 46 | ||
47 | #define FLASH_PARTITION0_ADDR 0x00000000 | 47 | #define FLASH_PARTITION0_ADDR 0x00000000 |
48 | #define FLASH_PARTITION0_SIZE 0x00020000 | 48 | #define FLASH_PARTITION0_SIZE 0x00020000 |
@@ -79,7 +79,7 @@ struct mtd_partition flagadm_parts[] = { | |||
79 | .offset = FLASH_PARTITION2_ADDR, | 79 | .offset = FLASH_PARTITION2_ADDR, |
80 | .size = FLASH_PARTITION2_SIZE | 80 | .size = FLASH_PARTITION2_SIZE |
81 | }, | 81 | }, |
82 | { | 82 | { |
83 | .name = "Persistant storage", | 83 | .name = "Persistant storage", |
84 | .offset = FLASH_PARTITION3_ADDR, | 84 | .offset = FLASH_PARTITION3_ADDR, |
85 | .size = FLASH_PARTITION3_SIZE | 85 | .size = FLASH_PARTITION3_SIZE |
@@ -91,10 +91,10 @@ struct mtd_partition flagadm_parts[] = { | |||
91 | static struct mtd_info *mymtd; | 91 | static struct mtd_info *mymtd; |
92 | 92 | ||
93 | int __init init_flagadm(void) | 93 | int __init init_flagadm(void) |
94 | { | 94 | { |
95 | printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", | 95 | printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", |
96 | FLASH_SIZE, FLASH_PHYS_ADDR); | 96 | FLASH_SIZE, FLASH_PHYS_ADDR); |
97 | 97 | ||
98 | flagadm_map.phys = FLASH_PHYS_ADDR; | 98 | flagadm_map.phys = FLASH_PHYS_ADDR; |
99 | flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, | 99 | flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, |
100 | FLASH_SIZE); | 100 | FLASH_SIZE); |
diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c index ae9252fbf176..a370953c1513 100644 --- a/drivers/mtd/maps/cstm_mips_ixx.c +++ b/drivers/mtd/maps/cstm_mips_ixx.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: cstm_mips_ixx.c,v 1.12 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. | 4 | * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. |
5 | * Config with both CFI and JEDEC device support. | 5 | * Config with both CFI and JEDEC device support. |
6 | * | 6 | * |
7 | * Basically physmap.c with the addition of partitions and | 7 | * Basically physmap.c with the addition of partitions and |
8 | * an array of mapping info to accomodate more than one flash type per board. | 8 | * an array of mapping info to accomodate more than one flash type per board. |
9 | * | 9 | * |
10 | * Copyright 2000 MontaVista Software Inc. | 10 | * Copyright 2000 MontaVista Software Inc. |
@@ -69,7 +69,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) | |||
69 | __u16 data; | 69 | __u16 data; |
70 | __u8 data1; | 70 | __u8 data1; |
71 | static u8 first = 1; | 71 | static u8 first = 1; |
72 | 72 | ||
73 | // Set GPIO port B pin3 to high | 73 | // Set GPIO port B pin3 to high |
74 | data = *(__u16 *)(CC_GPBCR); | 74 | data = *(__u16 *)(CC_GPBCR); |
75 | data = (data & 0xff0f) | 0x0040; | 75 | data = (data & 0xff0f) | 0x0040; |
@@ -85,7 +85,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) | |||
85 | } else { | 85 | } else { |
86 | if (!--vpp_count) { | 86 | if (!--vpp_count) { |
87 | __u16 data; | 87 | __u16 data; |
88 | 88 | ||
89 | // Set GPIO port B pin3 to high | 89 | // Set GPIO port B pin3 to high |
90 | data = *(__u16 *)(CC_GPBCR); | 90 | data = *(__u16 *)(CC_GPBCR); |
91 | data = (data & 0xff3f) | 0x0040; | 91 | data = (data & 0xff3f) | 0x0040; |
@@ -109,8 +109,8 @@ struct cstm_mips_ixx_info { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) | 111 | #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) |
112 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type | 112 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type |
113 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | 113 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = |
114 | { | 114 | { |
115 | { // 28F128J3A in 2x16 configuration | 115 | { // 28F128J3A in 2x16 configuration |
116 | "big flash", // name | 116 | "big flash", // name |
@@ -131,10 +131,10 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP | |||
131 | }, | 131 | }, |
132 | }; | 132 | }; |
133 | #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ | 133 | #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ |
134 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type | 134 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type |
135 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | 135 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = |
136 | { | 136 | { |
137 | { | 137 | { |
138 | "MTD flash", // name | 138 | "MTD flash", // name |
139 | CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr | 139 | CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr |
140 | CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size | 140 | CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size |
@@ -144,7 +144,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | |||
144 | 144 | ||
145 | }; | 145 | }; |
146 | static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { | 146 | static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { |
147 | { | 147 | { |
148 | { | 148 | { |
149 | .name = "main partition", | 149 | .name = "main partition", |
150 | .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, | 150 | .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, |
@@ -165,7 +165,7 @@ int __init init_cstm_mips_ixx(void) | |||
165 | 165 | ||
166 | /* Initialize mapping */ | 166 | /* Initialize mapping */ |
167 | for (i=0;i<PHYSMAP_NUMBER;i++) { | 167 | for (i=0;i<PHYSMAP_NUMBER;i++) { |
168 | printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", | 168 | printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", |
169 | cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); | 169 | cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); |
170 | 170 | ||
171 | 171 | ||
@@ -235,7 +235,7 @@ void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 | |||
235 | 235 | ||
236 | offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ; | 236 | offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ; |
237 | 237 | ||
238 | *(__u32 *)CC_CONFADDR = offset; | 238 | *(__u32 *)CC_CONFADDR = offset; |
239 | *(__u32 *)CC_CONFDATA = data; | 239 | *(__u32 *)CC_CONFDATA = data; |
240 | } | 240 | } |
241 | void setup_ITE_IVR_flash() | 241 | void setup_ITE_IVR_flash() |
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index d850a27a4b59..49d90542fc75 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: dbox2-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: dbox2-flash.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * D-Box 2 flash driver | 4 | * D-Box 2 flash driver |
5 | */ | 5 | */ |
@@ -21,38 +21,38 @@ | |||
21 | static struct mtd_partition partition_info[]= { | 21 | static struct mtd_partition partition_info[]= { |
22 | { | 22 | { |
23 | .name = "BR bootloader", | 23 | .name = "BR bootloader", |
24 | .size = 128 * 1024, | 24 | .size = 128 * 1024, |
25 | .offset = 0, | 25 | .offset = 0, |
26 | .mask_flags = MTD_WRITEABLE | 26 | .mask_flags = MTD_WRITEABLE |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | .name = "FLFS (U-Boot)", | 29 | .name = "FLFS (U-Boot)", |
30 | .size = 128 * 1024, | 30 | .size = 128 * 1024, |
31 | .offset = MTDPART_OFS_APPEND, | 31 | .offset = MTDPART_OFS_APPEND, |
32 | .mask_flags = 0 | 32 | .mask_flags = 0 |
33 | }, | 33 | }, |
34 | { | 34 | { |
35 | .name = "Root (SquashFS)", | 35 | .name = "Root (SquashFS)", |
36 | .size = 7040 * 1024, | 36 | .size = 7040 * 1024, |
37 | .offset = MTDPART_OFS_APPEND, | 37 | .offset = MTDPART_OFS_APPEND, |
38 | .mask_flags = 0 | 38 | .mask_flags = 0 |
39 | }, | 39 | }, |
40 | { | 40 | { |
41 | .name = "var (JFFS2)", | 41 | .name = "var (JFFS2)", |
42 | .size = 896 * 1024, | 42 | .size = 896 * 1024, |
43 | .offset = MTDPART_OFS_APPEND, | 43 | .offset = MTDPART_OFS_APPEND, |
44 | .mask_flags = 0 | 44 | .mask_flags = 0 |
45 | }, | 45 | }, |
46 | { | 46 | { |
47 | .name = "Flash without bootloader", | 47 | .name = "Flash without bootloader", |
48 | .size = MTDPART_SIZ_FULL, | 48 | .size = MTDPART_SIZ_FULL, |
49 | .offset = 128 * 1024, | 49 | .offset = 128 * 1024, |
50 | .mask_flags = 0 | 50 | .mask_flags = 0 |
51 | }, | 51 | }, |
52 | { | 52 | { |
53 | .name = "Complete Flash", | 53 | .name = "Complete Flash", |
54 | .size = MTDPART_SIZ_FULL, | 54 | .size = MTDPART_SIZ_FULL, |
55 | .offset = 0, | 55 | .offset = 0, |
56 | .mask_flags = MTD_WRITEABLE | 56 | .mask_flags = MTD_WRITEABLE |
57 | } | 57 | } |
58 | }; | 58 | }; |
@@ -88,16 +88,16 @@ int __init init_dbox2_flash(void) | |||
88 | if (!mymtd) { | 88 | if (!mymtd) { |
89 | // Probe for single Intel 28F640 | 89 | // Probe for single Intel 28F640 |
90 | dbox2_flash_map.bankwidth = 2; | 90 | dbox2_flash_map.bankwidth = 2; |
91 | 91 | ||
92 | mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); | 92 | mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); |
93 | } | 93 | } |
94 | 94 | ||
95 | if (mymtd) { | 95 | if (mymtd) { |
96 | mymtd->owner = THIS_MODULE; | 96 | mymtd->owner = THIS_MODULE; |
97 | 97 | ||
98 | /* Create MTD devices for each partition. */ | 98 | /* Create MTD devices for each partition. */ |
99 | add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); | 99 | add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); |
100 | 100 | ||
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index e5b74169fde6..701620b6baed 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $ | 8 | * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $ |
9 | */ | 9 | */ |
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
@@ -27,9 +27,9 @@ | |||
27 | static struct mtd_info *dc21285_mtd; | 27 | static struct mtd_info *dc21285_mtd; |
28 | 28 | ||
29 | #ifdef CONFIG_ARCH_NETWINDER | 29 | #ifdef CONFIG_ARCH_NETWINDER |
30 | /* | 30 | /* |
31 | * This is really ugly, but it seams to be the only | 31 | * This is really ugly, but it seams to be the only |
32 | * realiable way to do it, as the cpld state machine | 32 | * realiable way to do it, as the cpld state machine |
33 | * is unpredictible. So we have a 25us penalty per | 33 | * is unpredictible. So we have a 25us penalty per |
34 | * write access. | 34 | * write access. |
35 | */ | 35 | */ |
@@ -150,7 +150,7 @@ static struct map_info dc21285_map = { | |||
150 | static struct mtd_partition *dc21285_parts; | 150 | static struct mtd_partition *dc21285_parts; |
151 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | 151 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; |
152 | #endif | 152 | #endif |
153 | 153 | ||
154 | static int __init init_dc21285(void) | 154 | static int __init init_dc21285(void) |
155 | { | 155 | { |
156 | 156 | ||
@@ -160,20 +160,20 @@ static int __init init_dc21285(void) | |||
160 | 160 | ||
161 | /* Determine bankwidth */ | 161 | /* Determine bankwidth */ |
162 | switch (*CSR_SA110_CNTL & (3<<14)) { | 162 | switch (*CSR_SA110_CNTL & (3<<14)) { |
163 | case SA110_CNTL_ROMWIDTH_8: | 163 | case SA110_CNTL_ROMWIDTH_8: |
164 | dc21285_map.bankwidth = 1; | 164 | dc21285_map.bankwidth = 1; |
165 | dc21285_map.read = dc21285_read8; | 165 | dc21285_map.read = dc21285_read8; |
166 | dc21285_map.write = dc21285_write8; | 166 | dc21285_map.write = dc21285_write8; |
167 | dc21285_map.copy_to = dc21285_copy_to_8; | 167 | dc21285_map.copy_to = dc21285_copy_to_8; |
168 | break; | 168 | break; |
169 | case SA110_CNTL_ROMWIDTH_16: | 169 | case SA110_CNTL_ROMWIDTH_16: |
170 | dc21285_map.bankwidth = 2; | 170 | dc21285_map.bankwidth = 2; |
171 | dc21285_map.read = dc21285_read16; | 171 | dc21285_map.read = dc21285_read16; |
172 | dc21285_map.write = dc21285_write16; | 172 | dc21285_map.write = dc21285_write16; |
173 | dc21285_map.copy_to = dc21285_copy_to_16; | 173 | dc21285_map.copy_to = dc21285_copy_to_16; |
174 | break; | 174 | break; |
175 | case SA110_CNTL_ROMWIDTH_32: | 175 | case SA110_CNTL_ROMWIDTH_32: |
176 | dc21285_map.bankwidth = 4; | 176 | dc21285_map.bankwidth = 4; |
177 | dc21285_map.read = dc21285_read32; | 177 | dc21285_map.read = dc21285_read32; |
178 | dc21285_map.write = dc21285_write32; | 178 | dc21285_map.write = dc21285_write32; |
179 | dc21285_map.copy_to = dc21285_copy_to_32; | 179 | dc21285_map.copy_to = dc21285_copy_to_32; |
@@ -201,20 +201,20 @@ static int __init init_dc21285(void) | |||
201 | if (!dc21285_mtd) { | 201 | if (!dc21285_mtd) { |
202 | iounmap(dc21285_map.virt); | 202 | iounmap(dc21285_map.virt); |
203 | return -ENXIO; | 203 | return -ENXIO; |
204 | } | 204 | } |
205 | 205 | ||
206 | dc21285_mtd->owner = THIS_MODULE; | 206 | dc21285_mtd->owner = THIS_MODULE; |
207 | 207 | ||
208 | #ifdef CONFIG_MTD_PARTITIONS | 208 | #ifdef CONFIG_MTD_PARTITIONS |
209 | nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); | 209 | nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); |
210 | if (nrparts > 0) | 210 | if (nrparts > 0) |
211 | add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); | 211 | add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); |
212 | else | 212 | else |
213 | #endif | 213 | #endif |
214 | add_mtd_device(dc21285_mtd); | 214 | add_mtd_device(dc21285_mtd); |
215 | 215 | ||
216 | if(machine_is_ebsa285()) { | 216 | if(machine_is_ebsa285()) { |
217 | /* | 217 | /* |
218 | * Flash timing is determined with bits 19-16 of the | 218 | * Flash timing is determined with bits 19-16 of the |
219 | * CSR_SA110_CNTL. The value is the number of wait cycles, or | 219 | * CSR_SA110_CNTL. The value is the number of wait cycles, or |
220 | * 0 for 16 cycles (the default). Cycles are 20 ns. | 220 | * 0 for 16 cycles (the default). Cycles are 20 ns. |
@@ -227,7 +227,7 @@ static int __init init_dc21285(void) | |||
227 | /* tristate time */ | 227 | /* tristate time */ |
228 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); | 228 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); |
229 | } | 229 | } |
230 | 230 | ||
231 | return 0; | 231 | return 0; |
232 | } | 232 | } |
233 | 233 | ||
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index f99519692cb7..b51c757817d8 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * along with this program; if not, write to the Free Software | 14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
16 | * | 16 | * |
17 | * $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ | 17 | * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $ |
18 | * | 18 | * |
19 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems | 19 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems |
20 | * featuring the AMD Elan SC410 processor. There are two variants of this | 20 | * featuring the AMD Elan SC410 processor. There are two variants of this |
@@ -272,13 +272,13 @@ static struct map_info dnpc_map = { | |||
272 | 272 | ||
273 | static struct mtd_partition partition_info[]= | 273 | static struct mtd_partition partition_info[]= |
274 | { | 274 | { |
275 | { | 275 | { |
276 | .name = "ADNP boot", | 276 | .name = "ADNP boot", |
277 | .offset = 0, | 277 | .offset = 0, |
278 | .size = 0xf0000, | 278 | .size = 0xf0000, |
279 | }, | 279 | }, |
280 | { | 280 | { |
281 | .name = "ADNP system BIOS", | 281 | .name = "ADNP system BIOS", |
282 | .offset = MTDPART_OFS_NXTBLK, | 282 | .offset = MTDPART_OFS_NXTBLK, |
283 | .size = 0x10000, | 283 | .size = 0x10000, |
284 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 284 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -291,7 +291,7 @@ static struct mtd_partition partition_info[]= | |||
291 | .size = 0x2f0000, | 291 | .size = 0x2f0000, |
292 | }, | 292 | }, |
293 | { | 293 | { |
294 | .name = "ADNP system BIOS entry", | 294 | .name = "ADNP system BIOS entry", |
295 | .offset = MTDPART_OFS_NXTBLK, | 295 | .offset = MTDPART_OFS_NXTBLK, |
296 | .size = MTDPART_SIZ_FULL, | 296 | .size = MTDPART_SIZ_FULL, |
297 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 297 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -325,9 +325,9 @@ static struct mtd_info *merged_mtd; | |||
325 | 325 | ||
326 | static struct mtd_partition higlvl_partition_info[]= | 326 | static struct mtd_partition higlvl_partition_info[]= |
327 | { | 327 | { |
328 | { | 328 | { |
329 | .name = "ADNP boot block", | 329 | .name = "ADNP boot block", |
330 | .offset = 0, | 330 | .offset = 0, |
331 | .size = CONFIG_MTD_DILNETPC_BOOTSIZE, | 331 | .size = CONFIG_MTD_DILNETPC_BOOTSIZE, |
332 | }, | 332 | }, |
333 | { | 333 | { |
@@ -335,8 +335,8 @@ static struct mtd_partition higlvl_partition_info[]= | |||
335 | .offset = MTDPART_OFS_NXTBLK, | 335 | .offset = MTDPART_OFS_NXTBLK, |
336 | .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, | 336 | .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, |
337 | }, | 337 | }, |
338 | { | 338 | { |
339 | .name = "ADNP system BIOS + BIOS Entry", | 339 | .name = "ADNP system BIOS + BIOS Entry", |
340 | .offset = MTDPART_OFS_NXTBLK, | 340 | .offset = MTDPART_OFS_NXTBLK, |
341 | .size = MTDPART_SIZ_FULL, | 341 | .size = MTDPART_SIZ_FULL, |
342 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 342 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -371,7 +371,7 @@ static int __init init_dnpc(void) | |||
371 | 371 | ||
372 | /* | 372 | /* |
373 | ** determine hardware (DNP/ADNP/invalid) | 373 | ** determine hardware (DNP/ADNP/invalid) |
374 | */ | 374 | */ |
375 | if((is_dnp = dnp_adnp_probe()) < 0) | 375 | if((is_dnp = dnp_adnp_probe()) < 0) |
376 | return -ENXIO; | 376 | return -ENXIO; |
377 | 377 | ||
@@ -397,13 +397,13 @@ static int __init init_dnpc(void) | |||
397 | ++dnpc_map.name; | 397 | ++dnpc_map.name; |
398 | for(i = 0; i < NUM_PARTITIONS; i++) | 398 | for(i = 0; i < NUM_PARTITIONS; i++) |
399 | ++partition_info[i].name; | 399 | ++partition_info[i].name; |
400 | higlvl_partition_info[1].size = DNP_WINDOW_SIZE - | 400 | higlvl_partition_info[1].size = DNP_WINDOW_SIZE - |
401 | CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; | 401 | CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; |
402 | for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) | 402 | for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) |
403 | ++higlvl_partition_info[i].name; | 403 | ++higlvl_partition_info[i].name; |
404 | } | 404 | } |
405 | 405 | ||
406 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", | 406 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", |
407 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); | 407 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); |
408 | 408 | ||
409 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); | 409 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); |
@@ -436,7 +436,7 @@ static int __init init_dnpc(void) | |||
436 | iounmap(dnpc_map.virt); | 436 | iounmap(dnpc_map.virt); |
437 | return -ENXIO; | 437 | return -ENXIO; |
438 | } | 438 | } |
439 | 439 | ||
440 | mymtd->owner = THIS_MODULE; | 440 | mymtd->owner = THIS_MODULE; |
441 | 441 | ||
442 | /* | 442 | /* |
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index b9bc63503e26..b993ac01a9a5 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c | |||
@@ -1,10 +1,10 @@ | |||
1 | 1 | ||
2 | /* | 2 | /* |
3 | * drivers/mtd/maps/svme182.c | 3 | * drivers/mtd/maps/svme182.c |
4 | * | 4 | * |
5 | * Flash map driver for the Dy4 SVME182 board | 5 | * Flash map driver for the Dy4 SVME182 board |
6 | * | 6 | * |
7 | * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $ | 7 | * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $ |
8 | * | 8 | * |
9 | * Copyright 2003-2004, TimeSys Corporation | 9 | * Copyright 2003-2004, TimeSys Corporation |
10 | * | 10 | * |
@@ -104,7 +104,7 @@ static int __init init_svme182(void) | |||
104 | partitions = svme182_partitions; | 104 | partitions = svme182_partitions; |
105 | 105 | ||
106 | svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); | 106 | svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); |
107 | 107 | ||
108 | if (svme182_map.virt == 0) { | 108 | if (svme182_map.virt == 0) { |
109 | printk("Failed to ioremap FLASH memory area.\n"); | 109 | printk("Failed to ioremap FLASH memory area.\n"); |
110 | return -EIO; | 110 | return -EIO; |
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index b9d9cf4854b6..c0daf58357ca 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $ | 2 | * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for Ebony user flash | 4 | * Mapping for Ebony user flash |
5 | * | 5 | * |
6 | * Matt Porter <mporter@kernel.crashing.org> | 6 | * Matt Porter <mporter@kernel.crashing.org> |
@@ -85,7 +85,7 @@ int __init init_ebony(void) | |||
85 | small_flash_base = EBONY_SMALL_FLASH_LOW2; | 85 | small_flash_base = EBONY_SMALL_FLASH_LOW2; |
86 | else | 86 | else |
87 | small_flash_base = EBONY_SMALL_FLASH_LOW1; | 87 | small_flash_base = EBONY_SMALL_FLASH_LOW1; |
88 | 88 | ||
89 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | 89 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && |
90 | !EBONY_ONBRD_FLASH_EN(fpga0_reg)) | 90 | !EBONY_ONBRD_FLASH_EN(fpga0_reg)) |
91 | large_flash_base = EBONY_LARGE_FLASH_LOW; | 91 | large_flash_base = EBONY_LARGE_FLASH_LOW; |
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 8b0da394f3fa..b48a3473ffc1 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: edb7312.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the NOR flash on Cogent EDB7312 boards | 4 | * Handle mapping of the NOR flash on Cogent EDB7312 boards |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -46,7 +46,7 @@ struct map_info edb7312nor_map = { | |||
46 | #ifdef CONFIG_MTD_PARTITIONS | 46 | #ifdef CONFIG_MTD_PARTITIONS |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * MTD partitioning stuff | 49 | * MTD partitioning stuff |
50 | */ | 50 | */ |
51 | static struct mtd_partition static_partitions[3] = | 51 | static struct mtd_partition static_partitions[3] = |
52 | { | 52 | { |
@@ -80,7 +80,7 @@ int __init init_edb7312nor(void) | |||
80 | const char **type; | 80 | const char **type; |
81 | const char *part_type = 0; | 81 | const char *part_type = 0; |
82 | 82 | ||
83 | printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", | 83 | printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", |
84 | WINDOW_SIZE, WINDOW_ADDR); | 84 | WINDOW_SIZE, WINDOW_ADDR); |
85 | edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); | 85 | edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); |
86 | 86 | ||
@@ -88,7 +88,7 @@ int __init init_edb7312nor(void) | |||
88 | printk(MSG_PREFIX "failed to ioremap\n"); | 88 | printk(MSG_PREFIX "failed to ioremap\n"); |
89 | return -EIO; | 89 | return -EIO; |
90 | } | 90 | } |
91 | 91 | ||
92 | simple_map_init(&edb7312nor_map); | 92 | simple_map_init(&edb7312nor_map); |
93 | 93 | ||
94 | mymtd = 0; | 94 | mymtd = 0; |
diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c index 1df6188926b3..265b079fe934 100644 --- a/drivers/mtd/maps/epxa10db-flash.c +++ b/drivers/mtd/maps/epxa10db-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Copyright (C) 2001 Altera Corporation | 5 | * Copyright (C) 2001 Altera Corporation |
6 | * Copyright (C) 2001 Red Hat, Inc. | 6 | * Copyright (C) 2001 Red Hat, Inc. |
7 | * | 7 | * |
8 | * $Id: epxa10db-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 8 | * $Id: epxa10db-flash.c,v 1.15 2005/11/07 11:14:27 gleixner Exp $ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -62,7 +62,7 @@ static const char *probes[] = { "RedBoot", "afs", NULL }; | |||
62 | static int __init epxa_mtd_init(void) | 62 | static int __init epxa_mtd_init(void) |
63 | { | 63 | { |
64 | int i; | 64 | int i; |
65 | 65 | ||
66 | printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); | 66 | printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); |
67 | 67 | ||
68 | epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); | 68 | epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); |
@@ -126,8 +126,8 @@ static void __exit epxa_mtd_cleanup(void) | |||
126 | } | 126 | } |
127 | 127 | ||
128 | 128 | ||
129 | /* | 129 | /* |
130 | * This will do for now, once we decide which bootldr we're finally | 130 | * This will do for now, once we decide which bootldr we're finally |
131 | * going to use then we'll remove this function and do it properly | 131 | * going to use then we'll remove this function and do it properly |
132 | * | 132 | * |
133 | * Partions are currently (as offsets from base of flash): | 133 | * Partions are currently (as offsets from base of flash): |
@@ -140,7 +140,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa | |||
140 | struct mtd_partition *parts; | 140 | struct mtd_partition *parts; |
141 | int ret, i; | 141 | int ret, i; |
142 | int npartitions = 0; | 142 | int npartitions = 0; |
143 | char *names; | 143 | char *names; |
144 | const char *name = "jffs"; | 144 | const char *name = "jffs"; |
145 | 145 | ||
146 | printk("Using default partitions for %s\n",BOARD_NAME); | 146 | printk("Using default partitions for %s\n",BOARD_NAME); |
@@ -152,7 +152,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa | |||
152 | goto out; | 152 | goto out; |
153 | } | 153 | } |
154 | i=0; | 154 | i=0; |
155 | names = (char *)&parts[npartitions]; | 155 | names = (char *)&parts[npartitions]; |
156 | parts[i].name = names; | 156 | parts[i].name = names; |
157 | names += strlen(name) + 1; | 157 | names += strlen(name) + 1; |
158 | strcpy(parts[i].name, name); | 158 | strcpy(parts[i].name, name); |
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 00f7bbe5479e..c6bf4e1219ef 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fortunet.c memory map | 1 | /* fortunet.c memory map |
2 | * | 2 | * |
3 | * $Id: fortunet.c,v 1.9 2004/11/04 13:24:14 gleixner Exp $ | 3 | * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
@@ -212,7 +212,7 @@ int __init init_fortunet(void) | |||
212 | 212 | ||
213 | map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, | 213 | map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, |
214 | 214 | ||
215 | map_regions[ix].map_info.virt = | 215 | map_regions[ix].map_info.virt = |
216 | ioremap_nocache( | 216 | ioremap_nocache( |
217 | map_regions[ix].window_addr_physical, | 217 | map_regions[ix].window_addr_physical, |
218 | map_regions[ix].map_info.size); | 218 | map_regions[ix].map_info.size); |
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index c73828171d9b..319094821101 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based | 2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based |
3 | * evaluation boards | 3 | * evaluation boards |
4 | * | 4 | * |
5 | * $Id: h720x-flash.c,v 1.11 2004/11/04 13:24:14 gleixner Exp $ | 5 | * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ |
6 | * | 6 | * |
7 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> | 7 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> |
8 | * 2003 Thomas Gleixner <tglx@linutronix.de> | 8 | * 2003 Thomas Gleixner <tglx@linutronix.de> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -72,7 +72,7 @@ int __init h720x_mtd_init(void) | |||
72 | { | 72 | { |
73 | 73 | ||
74 | char *part_type = NULL; | 74 | char *part_type = NULL; |
75 | 75 | ||
76 | h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE); | 76 | h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE); |
77 | 77 | ||
78 | if (!h720x_map.virt) { | 78 | if (!h720x_map.virt) { |
@@ -91,7 +91,7 @@ int __init h720x_mtd_init(void) | |||
91 | h720x_map.bankwidth = 2; | 91 | h720x_map.bankwidth = 2; |
92 | mymtd = do_map_probe("cfi_probe", &h720x_map); | 92 | mymtd = do_map_probe("cfi_probe", &h720x_map); |
93 | } | 93 | } |
94 | 94 | ||
95 | if (mymtd) { | 95 | if (mymtd) { |
96 | mymtd->owner = THIS_MODULE; | 96 | mymtd->owner = THIS_MODULE; |
97 | 97 | ||
@@ -124,11 +124,11 @@ static void __exit h720x_mtd_cleanup(void) | |||
124 | del_mtd_partitions(mymtd); | 124 | del_mtd_partitions(mymtd); |
125 | map_destroy(mymtd); | 125 | map_destroy(mymtd); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* Free partition info, if commandline partition was used */ | 128 | /* Free partition info, if commandline partition was used */ |
129 | if (mtd_parts && (mtd_parts != h720x_partitions)) | 129 | if (mtd_parts && (mtd_parts != h720x_partitions)) |
130 | kfree (mtd_parts); | 130 | kfree (mtd_parts); |
131 | 131 | ||
132 | if (h720x_map.virt) { | 132 | if (h720x_map.virt) { |
133 | iounmap((void *)h720x_map.virt); | 133 | iounmap((void *)h720x_map.virt); |
134 | h720x_map.virt = 0; | 134 | h720x_map.virt = 0; |
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index c5e2111ba146..ea5073781b3a 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * ichxrom.c | 2 | * ichxrom.c |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $ | 5 | * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
@@ -101,7 +101,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
101 | * you can only really attach a FWH to an ICHX there | 101 | * you can only really attach a FWH to an ICHX there |
102 | * a number of simplifications you can make. | 102 | * a number of simplifications you can make. |
103 | * | 103 | * |
104 | * Also you can page firmware hubs if an 8MB window isn't enough | 104 | * Also you can page firmware hubs if an 8MB window isn't enough |
105 | * but don't currently handle that case either. | 105 | * but don't currently handle that case either. |
106 | */ | 106 | */ |
107 | window->pdev = pdev; | 107 | window->pdev = pdev; |
@@ -144,7 +144,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
144 | window->phys = 0xfff00000; | 144 | window->phys = 0xfff00000; |
145 | } | 145 | } |
146 | else if ((byte & 0x80) == 0x80) { | 146 | else if ((byte & 0x80) == 0x80) { |
147 | window->phys = 0xfff80000; | 147 | window->phys = 0xfff80000; |
148 | } | 148 | } |
149 | 149 | ||
150 | if (window->phys == 0) { | 150 | if (window->phys == 0) { |
@@ -233,7 +233,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
233 | * in a factory setting. So in-place programming | 233 | * in a factory setting. So in-place programming |
234 | * needs to use a different method. | 234 | * needs to use a different method. |
235 | */ | 235 | */ |
236 | for(map->map.bankwidth = 32; map->map.bankwidth; | 236 | for(map->map.bankwidth = 32; map->map.bankwidth; |
237 | map->map.bankwidth >>= 1) | 237 | map->map.bankwidth >>= 1) |
238 | { | 238 | { |
239 | char **probe_type; | 239 | char **probe_type; |
@@ -286,7 +286,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
286 | for(i = 0; i < cfi->numchips; i++) { | 286 | for(i = 0; i < cfi->numchips; i++) { |
287 | cfi->chips[i].start += offset; | 287 | cfi->chips[i].start += offset; |
288 | } | 288 | } |
289 | 289 | ||
290 | /* Now that the mtd devices is complete claim and export it */ | 290 | /* Now that the mtd devices is complete claim and export it */ |
291 | map->mtd->owner = THIS_MODULE; | 291 | map->mtd->owner = THIS_MODULE; |
292 | if (add_mtd_device(map->mtd)) { | 292 | if (add_mtd_device(map->mtd)) { |
@@ -324,11 +324,11 @@ static void __devexit ichxrom_remove_one (struct pci_dev *pdev) | |||
324 | } | 324 | } |
325 | 325 | ||
326 | static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { | 326 | static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { |
327 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, | 327 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, |
328 | PCI_ANY_ID, PCI_ANY_ID, }, | 328 | PCI_ANY_ID, PCI_ANY_ID, }, |
329 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, | 329 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, |
330 | PCI_ANY_ID, PCI_ANY_ID, }, | 330 | PCI_ANY_ID, PCI_ANY_ID, }, |
331 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, | 331 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, |
332 | PCI_ANY_ID, PCI_ANY_ID, }, | 332 | PCI_ANY_ID, PCI_ANY_ID, }, |
333 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, | 333 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, |
334 | PCI_ANY_ID, PCI_ANY_ID, }, | 334 | PCI_ANY_ID, PCI_ANY_ID, }, |
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index cb39172c81d2..ba7f40311a7e 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: impa7.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the NOR flash on implementa A7 boards | 4 | * Handle mapping of the NOR flash on implementa A7 boards |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -55,7 +55,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { | |||
55 | #ifdef CONFIG_MTD_PARTITIONS | 55 | #ifdef CONFIG_MTD_PARTITIONS |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * MTD partitioning stuff | 58 | * MTD partitioning stuff |
59 | */ | 59 | */ |
60 | static struct mtd_partition static_partitions[] = | 60 | static struct mtd_partition static_partitions[] = |
61 | { | 61 | { |
@@ -108,9 +108,9 @@ int __init init_impa7(void) | |||
108 | impa7_mtd[i]->owner = THIS_MODULE; | 108 | impa7_mtd[i]->owner = THIS_MODULE; |
109 | devicesfound++; | 109 | devicesfound++; |
110 | #ifdef CONFIG_MTD_PARTITIONS | 110 | #ifdef CONFIG_MTD_PARTITIONS |
111 | mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], | 111 | mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], |
112 | probes, | 112 | probes, |
113 | &mtd_parts[i], | 113 | &mtd_parts[i], |
114 | 0); | 114 | 0); |
115 | if (mtd_parts_nb[i] > 0) { | 115 | if (mtd_parts_nb[i] > 0) { |
116 | part_type = "command line"; | 116 | part_type = "command line"; |
@@ -121,16 +121,16 @@ int __init init_impa7(void) | |||
121 | } | 121 | } |
122 | 122 | ||
123 | printk(KERN_NOTICE MSG_PREFIX | 123 | printk(KERN_NOTICE MSG_PREFIX |
124 | "using %s partition definition\n", | 124 | "using %s partition definition\n", |
125 | part_type); | 125 | part_type); |
126 | add_mtd_partitions(impa7_mtd[i], | 126 | add_mtd_partitions(impa7_mtd[i], |
127 | mtd_parts[i], mtd_parts_nb[i]); | 127 | mtd_parts[i], mtd_parts_nb[i]); |
128 | #else | 128 | #else |
129 | add_mtd_device(impa7_mtd[i]); | 129 | add_mtd_device(impa7_mtd[i]); |
130 | 130 | ||
131 | #endif | 131 | #endif |
132 | } | 132 | } |
133 | else | 133 | else |
134 | iounmap((void *)impa7_map[i].virt); | 134 | iounmap((void *)impa7_map[i].virt); |
135 | } | 135 | } |
136 | return devicesfound == 0 ? -ENXIO : 0; | 136 | return devicesfound == 0 ? -ENXIO : 0; |
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 93f50d6d5488..fe738fd8d6f8 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
@@ -1,28 +1,28 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver | 3 | drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver |
4 | 4 | ||
5 | Copyright (C) 2000 ARM Limited | 5 | Copyright (C) 2000 ARM Limited |
6 | Copyright (C) 2003 Deep Blue Solutions Ltd. | 6 | Copyright (C) 2003 Deep Blue Solutions Ltd. |
7 | 7 | ||
8 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. | 11 | (at your option) any later version. |
12 | 12 | ||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. |
17 | 17 | ||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software | 19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | 21 | ||
22 | This is access code for flashes using ARM's flash partitioning | 22 | This is access code for flashes using ARM's flash partitioning |
23 | standards. | 23 | standards. |
24 | 24 | ||
25 | $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $ | 25 | $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $ |
26 | 26 | ||
27 | ======================================================================*/ | 27 | ======================================================================*/ |
28 | 28 | ||
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index 70b0e0b82c34..35097c9bbf50 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) | 2 | * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) |
3 | * | 3 | * |
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> | 5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> |
6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes | 6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes |
7 | * | 7 | * |
8 | * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $ | 8 | * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -107,7 +107,7 @@ static struct mtd_partition h3xxx_partitions[] = { | |||
107 | #ifndef CONFIG_LAB | 107 | #ifndef CONFIG_LAB |
108 | mask_flags: MTD_WRITEABLE, /* force read-only */ | 108 | mask_flags: MTD_WRITEABLE, /* force read-only */ |
109 | #endif | 109 | #endif |
110 | }, | 110 | }, |
111 | { | 111 | { |
112 | name: "H3XXX root jffs2", | 112 | name: "H3XXX root jffs2", |
113 | #ifndef CONFIG_LAB | 113 | #ifndef CONFIG_LAB |
@@ -148,7 +148,7 @@ static DEFINE_SPINLOCK(ipaq_vpp_lock); | |||
148 | static void h3xxx_set_vpp(struct map_info *map, int vpp) | 148 | static void h3xxx_set_vpp(struct map_info *map, int vpp) |
149 | { | 149 | { |
150 | static int nest = 0; | 150 | static int nest = 0; |
151 | 151 | ||
152 | spin_lock(&ipaq_vpp_lock); | 152 | spin_lock(&ipaq_vpp_lock); |
153 | if (vpp) | 153 | if (vpp) |
154 | nest++; | 154 | nest++; |
@@ -191,7 +191,7 @@ static unsigned long cs_phys[] = { | |||
191 | SA1100_CS3_PHYS, | 191 | SA1100_CS3_PHYS, |
192 | SA1100_CS4_PHYS, | 192 | SA1100_CS4_PHYS, |
193 | SA1100_CS5_PHYS, | 193 | SA1100_CS5_PHYS, |
194 | #else | 194 | #else |
195 | PXA_CS0_PHYS, | 195 | PXA_CS0_PHYS, |
196 | PXA_CS1_PHYS, | 196 | PXA_CS1_PHYS, |
197 | PXA_CS2_PHYS, | 197 | PXA_CS2_PHYS, |
@@ -216,7 +216,7 @@ int __init ipaq_mtd_init(void) | |||
216 | 216 | ||
217 | /* Default flash bankwidth */ | 217 | /* Default flash bankwidth */ |
218 | // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; | 218 | // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; |
219 | 219 | ||
220 | if (machine_is_h1900()) | 220 | if (machine_is_h1900()) |
221 | { | 221 | { |
222 | /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ | 222 | /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ |
@@ -229,7 +229,7 @@ int __init ipaq_mtd_init(void) | |||
229 | else | 229 | else |
230 | for(i=0; i<MAX_IPAQ_CS; i++) | 230 | for(i=0; i<MAX_IPAQ_CS; i++) |
231 | ipaq_map[i].bankwidth = 4; | 231 | ipaq_map[i].bankwidth = 4; |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * Static partition definition selection | 234 | * Static partition definition selection |
235 | */ | 235 | */ |
@@ -309,7 +309,7 @@ int __init ipaq_mtd_init(void) | |||
309 | return -ENXIO; | 309 | return -ENXIO; |
310 | } else | 310 | } else |
311 | printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size); | 311 | printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size); |
312 | 312 | ||
313 | /* do we really need this debugging? --joshua 20030703 */ | 313 | /* do we really need this debugging? --joshua 20030703 */ |
314 | // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); | 314 | // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); |
315 | my_sub_mtd[i]->owner = THIS_MODULE; | 315 | my_sub_mtd[i]->owner = THIS_MODULE; |
@@ -333,11 +333,11 @@ int __init ipaq_mtd_init(void) | |||
333 | #else | 333 | #else |
334 | mymtd = my_sub_mtd[0]; | 334 | mymtd = my_sub_mtd[0]; |
335 | 335 | ||
336 | /* | 336 | /* |
337 | *In the very near future, command line partition parsing | 337 | *In the very near future, command line partition parsing |
338 | * will use the device name as 'mtd-id' instead of a value | 338 | * will use the device name as 'mtd-id' instead of a value |
339 | * passed to the parse_cmdline_partitions() routine. Since | 339 | * passed to the parse_cmdline_partitions() routine. Since |
340 | * the bootldr says 'ipaq', make sure it continues to work. | 340 | * the bootldr says 'ipaq', make sure it continues to work. |
341 | */ | 341 | */ |
342 | mymtd->name = "ipaq"; | 342 | mymtd->name = "ipaq"; |
343 | 343 | ||
@@ -385,7 +385,7 @@ int __init ipaq_mtd_init(void) | |||
385 | */ | 385 | */ |
386 | 386 | ||
387 | i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); | 387 | i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); |
388 | 388 | ||
389 | if (i > 0) { | 389 | if (i > 0) { |
390 | nb_parts = parsed_nr_parts = i; | 390 | nb_parts = parsed_nr_parts = i; |
391 | parts = parsed_parts; | 391 | parts = parsed_parts; |
@@ -423,10 +423,10 @@ static void __exit ipaq_mtd_cleanup(void) | |||
423 | #endif | 423 | #endif |
424 | map_destroy(mymtd); | 424 | map_destroy(mymtd); |
425 | #ifdef CONFIG_MTD_CONCAT | 425 | #ifdef CONFIG_MTD_CONCAT |
426 | for(i=0; i<MAX_IPAQ_CS; i++) | 426 | for(i=0; i<MAX_IPAQ_CS; i++) |
427 | #else | 427 | #else |
428 | for(i=1; i<MAX_IPAQ_CS; i++) | 428 | for(i=1; i<MAX_IPAQ_CS; i++) |
429 | #endif | 429 | #endif |
430 | { | 430 | { |
431 | if (my_sub_mtd[i]) | 431 | if (my_sub_mtd[i]) |
432 | map_destroy(my_sub_mtd[i]); | 432 | map_destroy(my_sub_mtd[i]); |
@@ -444,14 +444,14 @@ static int __init h1900_special_case(void) | |||
444 | ipaq_map[0].phys = 0x0; | 444 | ipaq_map[0].phys = 0x0; |
445 | ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1); | 445 | ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1); |
446 | ipaq_map[0].bankwidth = 2; | 446 | ipaq_map[0].bankwidth = 2; |
447 | 447 | ||
448 | printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); | 448 | printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); |
449 | mymtd = do_map_probe("jedec_probe", &ipaq_map[0]); | 449 | mymtd = do_map_probe("jedec_probe", &ipaq_map[0]); |
450 | if (!mymtd) | 450 | if (!mymtd) |
451 | return -ENODEV; | 451 | return -ENODEV; |
452 | add_mtd_device(mymtd); | 452 | add_mtd_device(mymtd); |
453 | printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n"); | 453 | printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n"); |
454 | 454 | ||
455 | return 0; | 455 | return 0; |
456 | } | 456 | } |
457 | 457 | ||
diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c index 2e7577492a2c..62d9e87d84e2 100644 --- a/drivers/mtd/maps/iq80310.c +++ b/drivers/mtd/maps/iq80310.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: iq80310.c,v 1.20 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for the Intel XScale IQ80310 evaluation board | 4 | * Mapping for the Intel XScale IQ80310 evaluation board |
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 6f36497022d1..641eb2b55e9f 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $ | 2 | * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/ixp2000.c | 4 | * drivers/mtd/maps/ixp2000.c |
5 | * | 5 | * |
@@ -14,7 +14,7 @@ | |||
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
16 | * published by the Free Software Foundation. | 16 | * published by the Free Software Foundation. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -46,8 +46,8 @@ struct ixp2000_flash_info { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) | 48 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) |
49 | { | 49 | { |
50 | unsigned long (*set_bank)(unsigned long) = | 50 | unsigned long (*set_bank)(unsigned long) = |
51 | (unsigned long(*)(unsigned long))map->map_priv_2; | 51 | (unsigned long(*)(unsigned long))map->map_priv_2; |
52 | 52 | ||
53 | return (set_bank ? set_bank(ofs) : ofs); | 53 | return (set_bank ? set_bank(ofs) : ofs); |
@@ -55,8 +55,8 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long | |||
55 | 55 | ||
56 | #ifdef __ARMEB__ | 56 | #ifdef __ARMEB__ |
57 | /* | 57 | /* |
58 | * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which | 58 | * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which |
59 | * causes the lower address bits to be XORed with 0x11 on 8 bit accesses | 59 | * causes the lower address bits to be XORed with 0x11 on 8 bit accesses |
60 | * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. | 60 | * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. |
61 | */ | 61 | */ |
62 | static int erratum44_workaround = 0; | 62 | static int erratum44_workaround = 0; |
@@ -90,7 +90,7 @@ static void ixp2000_flash_copy_from(struct map_info *map, void *to, | |||
90 | unsigned long from, ssize_t len) | 90 | unsigned long from, ssize_t len) |
91 | { | 91 | { |
92 | from = flash_bank_setup(map, from); | 92 | from = flash_bank_setup(map, from); |
93 | while(len--) | 93 | while(len--) |
94 | *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); | 94 | *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); |
95 | } | 95 | } |
96 | 96 | ||
@@ -148,11 +148,11 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
148 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | 148 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; |
149 | struct platform_device *dev = to_platform_device(_dev); | 149 | struct platform_device *dev = to_platform_device(_dev); |
150 | struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; | 150 | struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; |
151 | struct flash_platform_data *plat; | 151 | struct flash_platform_data *plat; |
152 | struct ixp2000_flash_info *info; | 152 | struct ixp2000_flash_info *info; |
153 | unsigned long window_size; | 153 | unsigned long window_size; |
154 | int err = -1; | 154 | int err = -1; |
155 | 155 | ||
156 | if (!ixp_data) | 156 | if (!ixp_data) |
157 | return -ENODEV; | 157 | return -ENODEV; |
158 | 158 | ||
@@ -161,7 +161,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
161 | return -ENODEV; | 161 | return -ENODEV; |
162 | 162 | ||
163 | window_size = dev->resource->end - dev->resource->start + 1; | 163 | window_size = dev->resource->end - dev->resource->start + 1; |
164 | dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", | 164 | dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", |
165 | ixp_data->nr_banks, ((u32)window_size >> 20)); | 165 | ixp_data->nr_banks, ((u32)window_size >> 20)); |
166 | 166 | ||
167 | if (plat->width != 1) { | 167 | if (plat->width != 1) { |
@@ -174,7 +174,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
174 | if(!info) { | 174 | if(!info) { |
175 | err = -ENOMEM; | 175 | err = -ENOMEM; |
176 | goto Error; | 176 | goto Error; |
177 | } | 177 | } |
178 | memzero(info, sizeof(struct ixp2000_flash_info)); | 178 | memzero(info, sizeof(struct ixp2000_flash_info)); |
179 | 179 | ||
180 | dev_set_drvdata(&dev->dev, info); | 180 | dev_set_drvdata(&dev->dev, info); |
@@ -184,7 +184,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
184 | * not attempt to do a direct access on us. | 184 | * not attempt to do a direct access on us. |
185 | */ | 185 | */ |
186 | info->map.phys = NO_XIP; | 186 | info->map.phys = NO_XIP; |
187 | 187 | ||
188 | info->nr_banks = ixp_data->nr_banks; | 188 | info->nr_banks = ixp_data->nr_banks; |
189 | info->map.size = ixp_data->nr_banks * window_size; | 189 | info->map.size = ixp_data->nr_banks * window_size; |
190 | info->map.bankwidth = 1; | 190 | info->map.bankwidth = 1; |
@@ -192,7 +192,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
192 | /* | 192 | /* |
193 | * map_priv_2 is used to store a ptr to to the bank_setup routine | 193 | * map_priv_2 is used to store a ptr to to the bank_setup routine |
194 | */ | 194 | */ |
195 | info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup; | 195 | info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup; |
196 | 196 | ||
197 | info->map.name = dev->dev.bus_id; | 197 | info->map.name = dev->dev.bus_id; |
198 | info->map.read = ixp2000_flash_read8; | 198 | info->map.read = ixp2000_flash_read8; |
@@ -200,8 +200,8 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
200 | info->map.copy_from = ixp2000_flash_copy_from; | 200 | info->map.copy_from = ixp2000_flash_copy_from; |
201 | info->map.copy_to = ixp2000_flash_copy_to; | 201 | info->map.copy_to = ixp2000_flash_copy_to; |
202 | 202 | ||
203 | info->res = request_mem_region(dev->resource->start, | 203 | info->res = request_mem_region(dev->resource->start, |
204 | dev->resource->end - dev->resource->start + 1, | 204 | dev->resource->end - dev->resource->start + 1, |
205 | dev->dev.bus_id); | 205 | dev->dev.bus_id); |
206 | if (!info->res) { | 206 | if (!info->res) { |
207 | dev_err(_dev, "Could not reserve memory region\n"); | 207 | dev_err(_dev, "Could not reserve memory region\n"); |
@@ -209,7 +209,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
209 | goto Error; | 209 | goto Error; |
210 | } | 210 | } |
211 | 211 | ||
212 | info->map.map_priv_1 = ioremap(dev->resource->start, | 212 | info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start, |
213 | dev->resource->end - dev->resource->start + 1); | 213 | dev->resource->end - dev->resource->start + 1); |
214 | if (!info->map.map_priv_1) { | 214 | if (!info->map.map_priv_1) { |
215 | dev_err(_dev, "Failed to ioremap flash region\n"); | 215 | dev_err(_dev, "Failed to ioremap flash region\n"); |
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 0d87c02dee04..56b3a355bf7b 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/ixp4xx.c | 4 | * drivers/mtd/maps/ixp4xx.c |
5 | * | 5 | * |
@@ -45,7 +45,7 @@ | |||
45 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) | 45 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) |
46 | { | 46 | { |
47 | map_word val; | 47 | map_word val; |
48 | val.x[0] = *(__u16 *) (map->map_priv_1 + ofs); | 48 | val.x[0] = le16_to_cpu(readw(map->virt + ofs)); |
49 | return val; | 49 | return val; |
50 | } | 50 | } |
51 | 51 | ||
@@ -59,35 +59,35 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, | |||
59 | { | 59 | { |
60 | int i; | 60 | int i; |
61 | u8 *dest = (u8 *) to; | 61 | u8 *dest = (u8 *) to; |
62 | u16 *src = (u16 *) (map->map_priv_1 + from); | 62 | void __iomem *src = map->virt + from; |
63 | u16 data; | 63 | u16 data; |
64 | 64 | ||
65 | for (i = 0; i < (len / 2); i++) { | 65 | for (i = 0; i < (len / 2); i++) { |
66 | data = src[i]; | 66 | data = le16_to_cpu(readw(src + 2*i)); |
67 | dest[i * 2] = BYTE0(data); | 67 | dest[i * 2] = BYTE0(data); |
68 | dest[i * 2 + 1] = BYTE1(data); | 68 | dest[i * 2 + 1] = BYTE1(data); |
69 | } | 69 | } |
70 | 70 | ||
71 | if (len & 1) | 71 | if (len & 1) |
72 | dest[len - 1] = BYTE0(src[i]); | 72 | dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i))); |
73 | } | 73 | } |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Unaligned writes are ignored, causing the 8-bit | 76 | * Unaligned writes are ignored, causing the 8-bit |
77 | * probe to fail and proceed to the 16-bit probe (which succeeds). | 77 | * probe to fail and proceed to the 16-bit probe (which succeeds). |
78 | */ | 78 | */ |
79 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) | 79 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) |
80 | { | 80 | { |
81 | if (!(adr & 1)) | 81 | if (!(adr & 1)) |
82 | *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; | 82 | writew(cpu_to_le16(d.x[0]), map->virt + adr); |
83 | } | 83 | } |
84 | 84 | ||
85 | /* | 85 | /* |
86 | * Fast write16 function without the probing check above | 86 | * Fast write16 function without the probing check above |
87 | */ | 87 | */ |
88 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) | 88 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) |
89 | { | 89 | { |
90 | *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; | 90 | writew(cpu_to_le16(d.x[0]), map->virt + adr); |
91 | } | 91 | } |
92 | 92 | ||
93 | struct ixp4xx_flash_info { | 93 | struct ixp4xx_flash_info { |
@@ -104,25 +104,18 @@ static int ixp4xx_flash_remove(struct device *_dev) | |||
104 | struct platform_device *dev = to_platform_device(_dev); | 104 | struct platform_device *dev = to_platform_device(_dev); |
105 | struct flash_platform_data *plat = dev->dev.platform_data; | 105 | struct flash_platform_data *plat = dev->dev.platform_data; |
106 | struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); | 106 | struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); |
107 | map_word d; | ||
108 | 107 | ||
109 | dev_set_drvdata(&dev->dev, NULL); | 108 | dev_set_drvdata(&dev->dev, NULL); |
110 | 109 | ||
111 | if(!info) | 110 | if(!info) |
112 | return 0; | 111 | return 0; |
113 | 112 | ||
114 | /* | ||
115 | * This is required for a soft reboot to work. | ||
116 | */ | ||
117 | d.x[0] = 0xff; | ||
118 | ixp4xx_write16(&info->map, d, 0x55 * 0x2); | ||
119 | |||
120 | if (info->mtd) { | 113 | if (info->mtd) { |
121 | del_mtd_partitions(info->mtd); | 114 | del_mtd_partitions(info->mtd); |
122 | map_destroy(info->mtd); | 115 | map_destroy(info->mtd); |
123 | } | 116 | } |
124 | if (info->map.map_priv_1) | 117 | if (info->map.virt) |
125 | iounmap((void *) info->map.map_priv_1); | 118 | iounmap(info->map.virt); |
126 | 119 | ||
127 | kfree(info->partitions); | 120 | kfree(info->partitions); |
128 | 121 | ||
@@ -134,9 +127,6 @@ static int ixp4xx_flash_remove(struct device *_dev) | |||
134 | if (plat->exit) | 127 | if (plat->exit) |
135 | plat->exit(); | 128 | plat->exit(); |
136 | 129 | ||
137 | /* Disable flash write */ | ||
138 | *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE; | ||
139 | |||
140 | return 0; | 130 | return 0; |
141 | } | 131 | } |
142 | 132 | ||
@@ -160,17 +150,11 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
160 | if(!info) { | 150 | if(!info) { |
161 | err = -ENOMEM; | 151 | err = -ENOMEM; |
162 | goto Error; | 152 | goto Error; |
163 | } | 153 | } |
164 | memzero(info, sizeof(struct ixp4xx_flash_info)); | 154 | memzero(info, sizeof(struct ixp4xx_flash_info)); |
165 | 155 | ||
166 | dev_set_drvdata(&dev->dev, info); | 156 | dev_set_drvdata(&dev->dev, info); |
167 | 157 | ||
168 | /* | ||
169 | * Enable flash write | ||
170 | * TODO: Move this out to board specific code | ||
171 | */ | ||
172 | *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; | ||
173 | |||
174 | /* | 158 | /* |
175 | * Tell the MTD layer we're not 1:1 mapped so that it does | 159 | * Tell the MTD layer we're not 1:1 mapped so that it does |
176 | * not attempt to do a direct access on us. | 160 | * not attempt to do a direct access on us. |
@@ -189,8 +173,8 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
189 | info->map.write = ixp4xx_probe_write16, | 173 | info->map.write = ixp4xx_probe_write16, |
190 | info->map.copy_from = ixp4xx_copy_from, | 174 | info->map.copy_from = ixp4xx_copy_from, |
191 | 175 | ||
192 | info->res = request_mem_region(dev->resource->start, | 176 | info->res = request_mem_region(dev->resource->start, |
193 | dev->resource->end - dev->resource->start + 1, | 177 | dev->resource->end - dev->resource->start + 1, |
194 | "IXP4XXFlash"); | 178 | "IXP4XXFlash"); |
195 | if (!info->res) { | 179 | if (!info->res) { |
196 | printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); | 180 | printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); |
@@ -198,9 +182,9 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
198 | goto Error; | 182 | goto Error; |
199 | } | 183 | } |
200 | 184 | ||
201 | info->map.map_priv_1 = ioremap(dev->resource->start, | 185 | info->map.virt = ioremap(dev->resource->start, |
202 | dev->resource->end - dev->resource->start + 1); | 186 | dev->resource->end - dev->resource->start + 1); |
203 | if (!info->map.map_priv_1) { | 187 | if (!info->map.virt) { |
204 | printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); | 188 | printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); |
205 | err = -EIO; | 189 | err = -EIO; |
206 | goto Error; | 190 | goto Error; |
@@ -213,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
213 | goto Error; | 197 | goto Error; |
214 | } | 198 | } |
215 | info->mtd->owner = THIS_MODULE; | 199 | info->mtd->owner = THIS_MODULE; |
216 | 200 | ||
217 | /* Use the fast version */ | 201 | /* Use the fast version */ |
218 | info->map.write = ixp4xx_write16, | 202 | info->map.write = ixp4xx_write16, |
219 | 203 | ||
@@ -258,4 +242,3 @@ module_exit(ixp4xx_flash_exit); | |||
258 | MODULE_LICENSE("GPL"); | 242 | MODULE_LICENSE("GPL"); |
259 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); | 243 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); |
260 | MODULE_AUTHOR("Deepak Saxena"); | 244 | MODULE_AUTHOR("Deepak Saxena"); |
261 | |||
diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index b08668212ab7..851bf9576052 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ | 2 | * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * BIOS Flash chip on Intel 440GX board. | 4 | * BIOS Flash chip on Intel 440GX board. |
5 | * | 5 | * |
@@ -49,7 +49,7 @@ static struct map_info l440gx_map = { | |||
49 | .bankwidth = BUSWIDTH, | 49 | .bankwidth = BUSWIDTH, |
50 | .phys = WINDOW_ADDR, | 50 | .phys = WINDOW_ADDR, |
51 | #if 0 | 51 | #if 0 |
52 | /* FIXME verify that this is the | 52 | /* FIXME verify that this is the |
53 | * appripriate code for vpp enable/disable | 53 | * appripriate code for vpp enable/disable |
54 | */ | 54 | */ |
55 | .set_vpp = l440gx_set_vpp | 55 | .set_vpp = l440gx_set_vpp |
@@ -62,10 +62,10 @@ static int __init init_l440gx(void) | |||
62 | struct resource *pm_iobase; | 62 | struct resource *pm_iobase; |
63 | __u16 word; | 63 | __u16 word; |
64 | 64 | ||
65 | dev = pci_find_device(PCI_VENDOR_ID_INTEL, | 65 | dev = pci_find_device(PCI_VENDOR_ID_INTEL, |
66 | PCI_DEVICE_ID_INTEL_82371AB_0, NULL); | 66 | PCI_DEVICE_ID_INTEL_82371AB_0, NULL); |
67 | 67 | ||
68 | pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, | 68 | pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, |
69 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); | 69 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); |
70 | 70 | ||
71 | if (!dev || !pm_dev) { | 71 | if (!dev || !pm_dev) { |
@@ -82,10 +82,10 @@ static int __init init_l440gx(void) | |||
82 | simple_map_init(&l440gx_map); | 82 | simple_map_init(&l440gx_map); |
83 | printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); | 83 | printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); |
84 | 84 | ||
85 | /* Setup the pm iobase resource | 85 | /* Setup the pm iobase resource |
86 | * This code should move into some kind of generic bridge | 86 | * This code should move into some kind of generic bridge |
87 | * driver but for the moment I'm content with getting the | 87 | * driver but for the moment I'm content with getting the |
88 | * allocation correct. | 88 | * allocation correct. |
89 | */ | 89 | */ |
90 | pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; | 90 | pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; |
91 | if (!(pm_iobase->flags & IORESOURCE_IO)) { | 91 | if (!(pm_iobase->flags & IORESOURCE_IO)) { |
@@ -110,7 +110,7 @@ static int __init init_l440gx(void) | |||
110 | /* Set the iobase */ | 110 | /* Set the iobase */ |
111 | iobase = pm_iobase->start; | 111 | iobase = pm_iobase->start; |
112 | pci_write_config_dword(pm_dev, 0x40, iobase | 1); | 112 | pci_write_config_dword(pm_dev, 0x40, iobase | 1); |
113 | 113 | ||
114 | 114 | ||
115 | /* Set XBCS# */ | 115 | /* Set XBCS# */ |
116 | pci_read_config_word(dev, 0x4e, &word); | 116 | pci_read_config_word(dev, 0x4e, &word); |
@@ -122,7 +122,7 @@ static int __init init_l440gx(void) | |||
122 | 122 | ||
123 | /* Enable the gate on the WE line */ | 123 | /* Enable the gate on the WE line */ |
124 | outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); | 124 | outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); |
125 | 125 | ||
126 | printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); | 126 | printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); |
127 | 127 | ||
128 | mymtd = do_map_probe("jedec_probe", &l440gx_map); | 128 | mymtd = do_map_probe("jedec_probe", &l440gx_map); |
@@ -145,7 +145,7 @@ static void __exit cleanup_l440gx(void) | |||
145 | { | 145 | { |
146 | del_mtd_device(mymtd); | 146 | del_mtd_device(mymtd); |
147 | map_destroy(mymtd); | 147 | map_destroy(mymtd); |
148 | 148 | ||
149 | iounmap(l440gx_map.virt); | 149 | iounmap(l440gx_map.virt); |
150 | } | 150 | } |
151 | 151 | ||
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index 2b4c5058787d..1aa0447c5e66 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Map driver for the Lubbock developer platform. | 4 | * Map driver for the Lubbock developer platform. |
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -76,7 +76,7 @@ static int __init init_lubbock(void) | |||
76 | int flashboot = (LUB_CONF_SWITCHES & 1); | 76 | int flashboot = (LUB_CONF_SWITCHES & 1); |
77 | int ret = 0, i; | 77 | int ret = 0, i; |
78 | 78 | ||
79 | lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = | 79 | lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = |
80 | (BOOT_DEF & 1) ? 2 : 4; | 80 | (BOOT_DEF & 1) ? 2 : 4; |
81 | 81 | ||
82 | /* Compensate for the nROMBT switch which swaps the flash banks */ | 82 | /* Compensate for the nROMBT switch which swaps the flash banks */ |
@@ -100,11 +100,11 @@ static int __init init_lubbock(void) | |||
100 | simple_map_init(&lubbock_maps[i]); | 100 | simple_map_init(&lubbock_maps[i]); |
101 | 101 | ||
102 | printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", | 102 | printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", |
103 | lubbock_maps[i].name, lubbock_maps[i].phys, | 103 | lubbock_maps[i].name, lubbock_maps[i].phys, |
104 | lubbock_maps[i].bankwidth * 8); | 104 | lubbock_maps[i].bankwidth * 8); |
105 | 105 | ||
106 | mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); | 106 | mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); |
107 | 107 | ||
108 | if (!mymtds[i]) { | 108 | if (!mymtds[i]) { |
109 | iounmap((void *)lubbock_maps[i].virt); | 109 | iounmap((void *)lubbock_maps[i].virt); |
110 | if (lubbock_maps[i].cached) | 110 | if (lubbock_maps[i].cached) |
@@ -124,7 +124,7 @@ static int __init init_lubbock(void) | |||
124 | 124 | ||
125 | if (!mymtds[0] && !mymtds[1]) | 125 | if (!mymtds[0] && !mymtds[1]) |
126 | return ret; | 126 | return ret; |
127 | 127 | ||
128 | for (i = 0; i < 2; i++) { | 128 | for (i = 0; i < 2; i++) { |
129 | if (!mymtds[i]) { | 129 | if (!mymtds[i]) { |
130 | printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); | 130 | printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); |
@@ -151,7 +151,7 @@ static void __exit cleanup_lubbock(void) | |||
151 | if (nr_parsed_parts[i] || !i) | 151 | if (nr_parsed_parts[i] || !i) |
152 | del_mtd_partitions(mymtds[i]); | 152 | del_mtd_partitions(mymtds[i]); |
153 | else | 153 | else |
154 | del_mtd_device(mymtds[i]); | 154 | del_mtd_device(mymtds[i]); |
155 | 155 | ||
156 | map_destroy(mymtds[i]); | 156 | map_destroy(mymtds[i]); |
157 | iounmap((void *)lubbock_maps[i].virt); | 157 | iounmap((void *)lubbock_maps[i].virt); |
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c index da0f8a692628..eaa4bbb868a3 100644 --- a/drivers/mtd/maps/mainstone-flash.c +++ b/drivers/mtd/maps/mainstone-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -91,27 +91,27 @@ static int __init init_mainstone(void) | |||
91 | mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, | 91 | mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, |
92 | WINDOW_SIZE); | 92 | WINDOW_SIZE); |
93 | if (!mainstone_maps[i].virt) { | 93 | if (!mainstone_maps[i].virt) { |
94 | printk(KERN_WARNING "Failed to ioremap %s\n", | 94 | printk(KERN_WARNING "Failed to ioremap %s\n", |
95 | mainstone_maps[i].name); | 95 | mainstone_maps[i].name); |
96 | if (!ret) | 96 | if (!ret) |
97 | ret = -ENOMEM; | 97 | ret = -ENOMEM; |
98 | continue; | 98 | continue; |
99 | } | 99 | } |
100 | mainstone_maps[i].cached = | 100 | mainstone_maps[i].cached = |
101 | ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); | 101 | ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); |
102 | if (!mainstone_maps[i].cached) | 102 | if (!mainstone_maps[i].cached) |
103 | printk(KERN_WARNING "Failed to ioremap cached %s\n", | 103 | printk(KERN_WARNING "Failed to ioremap cached %s\n", |
104 | mainstone_maps[i].name); | 104 | mainstone_maps[i].name); |
105 | simple_map_init(&mainstone_maps[i]); | 105 | simple_map_init(&mainstone_maps[i]); |
106 | 106 | ||
107 | printk(KERN_NOTICE | 107 | printk(KERN_NOTICE |
108 | "Probing %s at physical address 0x%08lx" | 108 | "Probing %s at physical address 0x%08lx" |
109 | " (%d-bit bankwidth)\n", | 109 | " (%d-bit bankwidth)\n", |
110 | mainstone_maps[i].name, mainstone_maps[i].phys, | 110 | mainstone_maps[i].name, mainstone_maps[i].phys, |
111 | mainstone_maps[i].bankwidth * 8); | 111 | mainstone_maps[i].bankwidth * 8); |
112 | 112 | ||
113 | mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); | 113 | mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); |
114 | 114 | ||
115 | if (!mymtds[i]) { | 115 | if (!mymtds[i]) { |
116 | iounmap((void *)mainstone_maps[i].virt); | 116 | iounmap((void *)mainstone_maps[i].virt); |
117 | if (mainstone_maps[i].cached) | 117 | if (mainstone_maps[i].cached) |
@@ -131,21 +131,21 @@ static int __init init_mainstone(void) | |||
131 | 131 | ||
132 | if (!mymtds[0] && !mymtds[1]) | 132 | if (!mymtds[0] && !mymtds[1]) |
133 | return ret; | 133 | return ret; |
134 | 134 | ||
135 | for (i = 0; i < 2; i++) { | 135 | for (i = 0; i < 2; i++) { |
136 | if (!mymtds[i]) { | 136 | if (!mymtds[i]) { |
137 | printk(KERN_WARNING "%s is absent. Skipping\n", | 137 | printk(KERN_WARNING "%s is absent. Skipping\n", |
138 | mainstone_maps[i].name); | 138 | mainstone_maps[i].name); |
139 | } else if (nr_parsed_parts[i]) { | 139 | } else if (nr_parsed_parts[i]) { |
140 | add_mtd_partitions(mymtds[i], parsed_parts[i], | 140 | add_mtd_partitions(mymtds[i], parsed_parts[i], |
141 | nr_parsed_parts[i]); | 141 | nr_parsed_parts[i]); |
142 | } else if (!i) { | 142 | } else if (!i) { |
143 | printk("Using static partitions on %s\n", | 143 | printk("Using static partitions on %s\n", |
144 | mainstone_maps[i].name); | 144 | mainstone_maps[i].name); |
145 | add_mtd_partitions(mymtds[i], mainstone_partitions, | 145 | add_mtd_partitions(mymtds[i], mainstone_partitions, |
146 | ARRAY_SIZE(mainstone_partitions)); | 146 | ARRAY_SIZE(mainstone_partitions)); |
147 | } else { | 147 | } else { |
148 | printk("Registering %s as whole device\n", | 148 | printk("Registering %s as whole device\n", |
149 | mainstone_maps[i].name); | 149 | mainstone_maps[i].name); |
150 | add_mtd_device(mymtds[i]); | 150 | add_mtd_device(mymtds[i]); |
151 | } | 151 | } |
diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index c5c6901a4763..06b118727846 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mbx860.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the flash on MBX860 boards | 4 | * Handle mapping of the flash on MBX860 boards |
5 | * | 5 | * |
6 | * Author: Anton Todorov | 6 | * Author: Anton Todorov |
7 | * Copyright: (C) 2001 Emness Technology | 7 | * Copyright: (C) 2001 Emness Technology |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -46,7 +46,7 @@ static struct mtd_partition partition_info[]={ | |||
46 | { .name = "MBX flash APPLICATION partition", | 46 | { .name = "MBX flash APPLICATION partition", |
47 | .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } | 47 | .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } |
48 | }; | 48 | }; |
49 | 49 | ||
50 | 50 | ||
51 | static struct mtd_info *mymtd; | 51 | static struct mtd_info *mymtd; |
52 | 52 | ||
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c new file mode 100644 index 000000000000..d1e66e186746 --- /dev/null +++ b/drivers/mtd/maps/mtx-1_flash.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Flash memory access on 4G Systems MTX-1 boards | ||
3 | * | ||
4 | * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $ | ||
5 | * | ||
6 | * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz> | ||
7 | * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de> | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | #include <linux/mtd/mtd.h> | ||
18 | #include <linux/mtd/map.h> | ||
19 | #include <linux/mtd/partitions.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | |||
23 | static struct map_info mtx1_map = { | ||
24 | .name = "MTX-1 flash", | ||
25 | .bankwidth = 4, | ||
26 | .size = 0x2000000, | ||
27 | .phys = 0x1E000000, | ||
28 | }; | ||
29 | |||
30 | static struct mtd_partition mtx1_partitions[] = { | ||
31 | { | ||
32 | .name = "filesystem", | ||
33 | .size = 0x01C00000, | ||
34 | .offset = 0, | ||
35 | },{ | ||
36 | .name = "yamon", | ||
37 | .size = 0x00100000, | ||
38 | .offset = MTDPART_OFS_APPEND, | ||
39 | .mask_flags = MTD_WRITEABLE, | ||
40 | },{ | ||
41 | .name = "kernel", | ||
42 | .size = 0x002c0000, | ||
43 | .offset = MTDPART_OFS_APPEND, | ||
44 | },{ | ||
45 | .name = "yamon env", | ||
46 | .size = 0x00040000, | ||
47 | .offset = MTDPART_OFS_APPEND, | ||
48 | } | ||
49 | }; | ||
50 | |||
51 | static struct mtd_info *mtx1_mtd; | ||
52 | |||
53 | int __init mtx1_mtd_init(void) | ||
54 | { | ||
55 | int ret = -ENXIO; | ||
56 | |||
57 | simple_map_init(&mtx1_map); | ||
58 | |||
59 | mtx1_map.virt = ioremap(mtx1_map.phys, mtx1_map.size); | ||
60 | if (!mtx1_map.virt) | ||
61 | return -EIO; | ||
62 | |||
63 | mtx1_mtd = do_map_probe("cfi_probe", &mtx1_map); | ||
64 | if (!mtx1_mtd) | ||
65 | goto err; | ||
66 | |||
67 | mtx1_mtd->owner = THIS_MODULE; | ||
68 | |||
69 | ret = add_mtd_partitions(mtx1_mtd, mtx1_partitions, | ||
70 | ARRAY_SIZE(mtx1_partitions)); | ||
71 | if (ret) | ||
72 | goto err; | ||
73 | |||
74 | return 0; | ||
75 | |||
76 | err: | ||
77 | iounmap(mtx1_map.virt); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static void __exit mtx1_mtd_cleanup(void) | ||
82 | { | ||
83 | if (mtx1_mtd) { | ||
84 | del_mtd_partitions(mtx1_mtd); | ||
85 | map_destroy(mtx1_mtd); | ||
86 | } | ||
87 | if (mtx1_map.virt) | ||
88 | iounmap(mtx1_map.virt); | ||
89 | } | ||
90 | |||
91 | module_init(mtx1_mtd_init); | ||
92 | module_exit(mtx1_mtd_cleanup); | ||
93 | |||
94 | MODULE_AUTHOR("Bruno Randolf <bruno.randolf@4g-systems.biz>"); | ||
95 | MODULE_DESCRIPTION("MTX-1 flash map"); | ||
96 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index ab7e6358d281..33060a315722 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) | 3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) |
4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH | 4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH |
5 | * | 5 | * |
6 | * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $ | 6 | * $Id: netsc520.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -38,7 +38,7 @@ | |||
38 | ** The single, 16 megabyte flash bank is divided into four virtual | 38 | ** The single, 16 megabyte flash bank is divided into four virtual |
39 | ** partitions. The first partition is 768 KiB and is intended to | 39 | ** partitions. The first partition is 768 KiB and is intended to |
40 | ** store the kernel image loaded by the bootstrap loader. The second | 40 | ** store the kernel image loaded by the bootstrap loader. The second |
41 | ** partition is 256 KiB and holds the BIOS image. The third | 41 | ** partition is 256 KiB and holds the BIOS image. The third |
42 | ** partition is 14.5 MiB and is intended for the flash file system | 42 | ** partition is 14.5 MiB and is intended for the flash file system |
43 | ** image. The last partition is 512 KiB and contains another copy | 43 | ** image. The last partition is 512 KiB and contains another copy |
44 | ** of the BIOS image and the reset vector. | 44 | ** of the BIOS image and the reset vector. |
@@ -51,28 +51,28 @@ | |||
51 | ** recoverable afterwards. | 51 | ** recoverable afterwards. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | /* partition_info gives details on the logical partitions that the split the | 54 | /* partition_info gives details on the logical partitions that the split the |
55 | * single flash device into. If the size if zero we use up to the end of the | 55 | * single flash device into. If the size if zero we use up to the end of the |
56 | * device. */ | 56 | * device. */ |
57 | static struct mtd_partition partition_info[]={ | 57 | static struct mtd_partition partition_info[]={ |
58 | { | 58 | { |
59 | .name = "NetSc520 boot kernel", | 59 | .name = "NetSc520 boot kernel", |
60 | .offset = 0, | 60 | .offset = 0, |
61 | .size = 0xc0000 | 61 | .size = 0xc0000 |
62 | }, | 62 | }, |
63 | { | 63 | { |
64 | .name = "NetSc520 Low BIOS", | 64 | .name = "NetSc520 Low BIOS", |
65 | .offset = 0xc0000, | 65 | .offset = 0xc0000, |
66 | .size = 0x40000 | 66 | .size = 0x40000 |
67 | }, | 67 | }, |
68 | { | 68 | { |
69 | .name = "NetSc520 file system", | 69 | .name = "NetSc520 file system", |
70 | .offset = 0x100000, | 70 | .offset = 0x100000, |
71 | .size = 0xe80000 | 71 | .size = 0xe80000 |
72 | }, | 72 | }, |
73 | { | 73 | { |
74 | .name = "NetSc520 High BIOS", | 74 | .name = "NetSc520 High BIOS", |
75 | .offset = 0xf80000, | 75 | .offset = 0xf80000, |
76 | .size = 0x80000 | 76 | .size = 0x80000 |
77 | }, | 77 | }, |
78 | }; | 78 | }; |
@@ -114,7 +114,7 @@ static int __init init_netsc520(void) | |||
114 | iounmap(netsc520_map.virt); | 114 | iounmap(netsc520_map.virt); |
115 | return -ENXIO; | 115 | return -ENXIO; |
116 | } | 116 | } |
117 | 117 | ||
118 | mymtd->owner = THIS_MODULE; | 118 | mymtd->owner = THIS_MODULE; |
119 | add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); | 119 | add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); |
120 | return 0; | 120 | return 0; |
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 61be5a4148c9..f00ee7e54dba 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) |
7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) | 7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) |
8 | * | 8 | * |
9 | * $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $ | 9 | * $Id: nettel.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /****************************************************************************/ | 12 | /****************************************************************************/ |
@@ -143,7 +143,7 @@ static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, | |||
143 | { | 143 | { |
144 | struct cfi_private *cfi = nettel_intel_map.fldrv_priv; | 144 | struct cfi_private *cfi = nettel_intel_map.fldrv_priv; |
145 | unsigned long b; | 145 | unsigned long b; |
146 | 146 | ||
147 | /* Make sure all FLASH chips are put back into read mode */ | 147 | /* Make sure all FLASH chips are put back into read mode */ |
148 | for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { | 148 | for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { |
149 | cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, | 149 | cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, |
@@ -199,7 +199,7 @@ int nettel_eraseconfig(void) | |||
199 | 199 | ||
200 | schedule(); /* Wait for erase to finish. */ | 200 | schedule(); /* Wait for erase to finish. */ |
201 | remove_wait_queue(&wait_q, &wait); | 201 | remove_wait_queue(&wait_q, &wait); |
202 | 202 | ||
203 | put_mtd_device(mtd); | 203 | put_mtd_device(mtd); |
204 | } | 204 | } |
205 | 205 | ||
@@ -430,7 +430,7 @@ int __init nettel_init(void) | |||
430 | nettel_intel_partitions[1].size = (intel0size + intel1size) - | 430 | nettel_intel_partitions[1].size = (intel0size + intel1size) - |
431 | (1024*1024 + intel_mtd->erasesize); | 431 | (1024*1024 + intel_mtd->erasesize); |
432 | nettel_intel_partitions[3].size = intel0size + intel1size; | 432 | nettel_intel_partitions[3].size = intel0size + intel1size; |
433 | nettel_intel_partitions[4].offset = | 433 | nettel_intel_partitions[4].offset = |
434 | (intel0size + intel1size) - intel_mtd->erasesize; | 434 | (intel0size + intel1size) - intel_mtd->erasesize; |
435 | nettel_intel_partitions[4].size = intel_mtd->erasesize; | 435 | nettel_intel_partitions[4].size = intel_mtd->erasesize; |
436 | nettel_intel_partitions[5].offset = | 436 | nettel_intel_partitions[5].offset = |
diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c index 82c3070678c5..6977963d7897 100644 --- a/drivers/mtd/maps/ocelot.c +++ b/drivers/mtd/maps/ocelot.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $ | 2 | * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Flash on Momenco Ocelot | 4 | * Flash on Momenco Ocelot |
5 | */ | 5 | */ |
@@ -31,7 +31,7 @@ static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t | |||
31 | struct map_info *map = mtd->priv; | 31 | struct map_info *map = mtd->priv; |
32 | size_t done = 0; | 32 | size_t done = 0; |
33 | 33 | ||
34 | /* If we use memcpy, it does word-wide writes. Even though we told the | 34 | /* If we use memcpy, it does word-wide writes. Even though we told the |
35 | GT64120A that it's an 8-bit wide region, word-wide writes don't work. | 35 | GT64120A that it's an 8-bit wide region, word-wide writes don't work. |
36 | We end up just writing the first byte of the four to all four bytes. | 36 | We end up just writing the first byte of the four to all four bytes. |
37 | So we have this loop instead */ | 37 | So we have this loop instead */ |
@@ -68,7 +68,7 @@ static int __init init_ocelot_maps(void) | |||
68 | int nr_parts; | 68 | int nr_parts; |
69 | unsigned char brd_status; | 69 | unsigned char brd_status; |
70 | 70 | ||
71 | printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", | 71 | printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", |
72 | FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); | 72 | FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); |
73 | 73 | ||
74 | /* First check whether the flash jumper is present */ | 74 | /* First check whether the flash jumper is present */ |
@@ -138,8 +138,8 @@ static int __init init_ocelot_maps(void) | |||
138 | add_mtd_device(flash_mtd); | 138 | add_mtd_device(flash_mtd); |
139 | 139 | ||
140 | return 0; | 140 | return 0; |
141 | 141 | ||
142 | fail3: | 142 | fail3: |
143 | iounmap((void *)ocelot_flash_map.virt); | 143 | iounmap((void *)ocelot_flash_map.virt); |
144 | if (ocelot_flash_map.cached) | 144 | if (ocelot_flash_map.cached) |
145 | iounmap((void *)ocelot_flash_map.cached); | 145 | iounmap((void *)ocelot_flash_map.cached); |
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index e5ff83de420e..a6642db3d325 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c | |||
@@ -1,12 +1,12 @@ | |||
1 | // $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $ | 1 | // $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $ |
2 | /* ###################################################################### | 2 | /* ###################################################################### |
3 | 3 | ||
4 | Octagon 5066 MTD Driver. | 4 | Octagon 5066 MTD Driver. |
5 | 5 | ||
6 | The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It | 6 | The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It |
7 | comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that | 7 | comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that |
8 | is replacable by flash. Both units are mapped through a multiplexer | 8 | is replacable by flash. Both units are mapped through a multiplexer |
9 | into a 32k memory window at 0xe8000. The control register for the | 9 | into a 32k memory window at 0xe8000. The control register for the |
10 | multiplexing unit is located at IO 0x208 with a bit map of | 10 | multiplexing unit is located at IO 0x208 with a bit map of |
11 | 0-5 Page Selection in 32k increments | 11 | 0-5 Page Selection in 32k increments |
12 | 6-7 Device selection: | 12 | 6-7 Device selection: |
@@ -14,14 +14,14 @@ | |||
14 | 01 SSD 0 (Socket) | 14 | 01 SSD 0 (Socket) |
15 | 10 SSD 1 (Flash chip) | 15 | 10 SSD 1 (Flash chip) |
16 | 11 undefined | 16 | 11 undefined |
17 | 17 | ||
18 | On each SSD, the first 128k is reserved for use by the bios | 18 | On each SSD, the first 128k is reserved for use by the bios |
19 | (actually it IS the bios..) This only matters if you are booting off the | 19 | (actually it IS the bios..) This only matters if you are booting off the |
20 | flash, you must not put a file system starting there. | 20 | flash, you must not put a file system starting there. |
21 | 21 | ||
22 | The driver tries to do a detection algorithm to guess what sort of devices | 22 | The driver tries to do a detection algorithm to guess what sort of devices |
23 | are plugged into the sockets. | 23 | are plugged into the sockets. |
24 | 24 | ||
25 | ##################################################################### */ | 25 | ##################################################################### */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
@@ -56,7 +56,7 @@ static void __oct5066_page(struct map_info *map, __u8 byte) | |||
56 | static inline void oct5066_page(struct map_info *map, unsigned long ofs) | 56 | static inline void oct5066_page(struct map_info *map, unsigned long ofs) |
57 | { | 57 | { |
58 | __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); | 58 | __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); |
59 | 59 | ||
60 | if (page_n_dev != byte) | 60 | if (page_n_dev != byte) |
61 | __oct5066_page(map, byte); | 61 | __oct5066_page(map, byte); |
62 | } | 62 | } |
@@ -78,7 +78,7 @@ static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from | |||
78 | unsigned long thislen = len; | 78 | unsigned long thislen = len; |
79 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) | 79 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) |
80 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); | 80 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); |
81 | 81 | ||
82 | spin_lock(&oct5066_spin); | 82 | spin_lock(&oct5066_spin); |
83 | oct5066_page(map, from); | 83 | oct5066_page(map, from); |
84 | memcpy_fromio(to, iomapadr + from, thislen); | 84 | memcpy_fromio(to, iomapadr + from, thislen); |
@@ -103,7 +103,7 @@ static void oct5066_copy_to(struct map_info *map, unsigned long to, const void * | |||
103 | unsigned long thislen = len; | 103 | unsigned long thislen = len; |
104 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) | 104 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) |
105 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); | 105 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); |
106 | 106 | ||
107 | spin_lock(&oct5066_spin); | 107 | spin_lock(&oct5066_spin); |
108 | oct5066_page(map, to); | 108 | oct5066_page(map, to); |
109 | memcpy_toio(iomapadr + to, from, thislen); | 109 | memcpy_toio(iomapadr + to, from, thislen); |
@@ -144,7 +144,7 @@ static struct mtd_info *oct5066_mtd[2] = {NULL, NULL}; | |||
144 | // OctProbe - Sense if this is an octagon card | 144 | // OctProbe - Sense if this is an octagon card |
145 | // --------------------------------------------------------------------- | 145 | // --------------------------------------------------------------------- |
146 | /* Perform a simple validity test, we map the window select SSD0 and | 146 | /* Perform a simple validity test, we map the window select SSD0 and |
147 | change pages while monitoring the window. A change in the window, | 147 | change pages while monitoring the window. A change in the window, |
148 | controlled by the PAGE_IO port is a functioning 5066 board. This will | 148 | controlled by the PAGE_IO port is a functioning 5066 board. This will |
149 | fail if the thing in the socket is set to a uniform value. */ | 149 | fail if the thing in the socket is set to a uniform value. */ |
150 | static int __init OctProbe(void) | 150 | static int __init OctProbe(void) |
@@ -161,13 +161,13 @@ static int __init OctProbe(void) | |||
161 | Values[I%10] = readl(iomapadr); | 161 | Values[I%10] = readl(iomapadr); |
162 | if (I > 0 && Values[I%10] == Values[0]) | 162 | if (I > 0 && Values[I%10] == Values[0]) |
163 | return -EAGAIN; | 163 | return -EAGAIN; |
164 | } | 164 | } |
165 | else | 165 | else |
166 | { | 166 | { |
167 | // Make sure we get the same values on the second pass | 167 | // Make sure we get the same values on the second pass |
168 | if (Values[I%10] != readl(iomapadr)) | 168 | if (Values[I%10] != readl(iomapadr)) |
169 | return -EAGAIN; | 169 | return -EAGAIN; |
170 | } | 170 | } |
171 | } | 171 | } |
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
@@ -207,11 +207,11 @@ int __init init_oct5066(void) | |||
207 | ret = -EAGAIN; | 207 | ret = -EAGAIN; |
208 | goto out_unmap; | 208 | goto out_unmap; |
209 | } | 209 | } |
210 | 210 | ||
211 | // Print out our little header.. | 211 | // Print out our little header.. |
212 | printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, | 212 | printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, |
213 | WINDOW_START+WINDOW_LENGTH); | 213 | WINDOW_START+WINDOW_LENGTH); |
214 | 214 | ||
215 | for (i=0; i<2; i++) { | 215 | for (i=0; i<2; i++) { |
216 | oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); | 216 | oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); |
217 | if (!oct5066_mtd[i]) | 217 | if (!oct5066_mtd[i]) |
@@ -225,11 +225,11 @@ int __init init_oct5066(void) | |||
225 | add_mtd_device(oct5066_mtd[i]); | 225 | add_mtd_device(oct5066_mtd[i]); |
226 | } | 226 | } |
227 | } | 227 | } |
228 | 228 | ||
229 | if (!oct5066_mtd[0] && !oct5066_mtd[1]) { | 229 | if (!oct5066_mtd[0] && !oct5066_mtd[1]) { |
230 | cleanup_oct5066(); | 230 | cleanup_oct5066(); |
231 | return -ENXIO; | 231 | return -ENXIO; |
232 | } | 232 | } |
233 | 233 | ||
234 | return 0; | 234 | return 0; |
235 | 235 | ||
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index 763304154a92..dc3765270057 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * (C) 2002 MontVista Software, Inc. | 6 | * (C) 2002 MontVista Software, Inc. |
7 | * | 7 | * |
8 | * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $ | 8 | * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -38,7 +38,7 @@ static struct map_info omap_toto_map_flash = { | |||
38 | .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, | 38 | .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | 41 | ||
42 | static struct mtd_partition toto_flash_partitions[] = { | 42 | static struct mtd_partition toto_flash_partitions[] = { |
43 | { | 43 | { |
44 | .name = "BootLoader", | 44 | .name = "BootLoader", |
@@ -54,21 +54,21 @@ static struct mtd_partition toto_flash_partitions[] = { | |||
54 | .name = "EnvArea", /* bottom 64KiB for env vars */ | 54 | .name = "EnvArea", /* bottom 64KiB for env vars */ |
55 | .size = MTDPART_SIZ_FULL, | 55 | .size = MTDPART_SIZ_FULL, |
56 | .offset = MTDPART_OFS_APPEND, | 56 | .offset = MTDPART_OFS_APPEND, |
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static struct mtd_partition *parsed_parts; | 60 | static struct mtd_partition *parsed_parts; |
61 | 61 | ||
62 | static struct mtd_info *flash_mtd; | 62 | static struct mtd_info *flash_mtd; |
63 | 63 | ||
64 | static int __init init_flash (void) | 64 | static int __init init_flash (void) |
65 | { | 65 | { |
66 | 66 | ||
67 | struct mtd_partition *parts; | 67 | struct mtd_partition *parts; |
68 | int nb_parts = 0; | 68 | int nb_parts = 0; |
69 | int parsed_nr_parts = 0; | 69 | int parsed_nr_parts = 0; |
70 | const char *part_type; | 70 | const char *part_type; |
71 | 71 | ||
72 | /* | 72 | /* |
73 | * Static partition definition selection | 73 | * Static partition definition selection |
74 | */ | 74 | */ |
@@ -89,7 +89,7 @@ static int __init init_flash (void) | |||
89 | flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); | 89 | flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); |
90 | if (!flash_mtd) | 90 | if (!flash_mtd) |
91 | return -ENXIO; | 91 | return -ENXIO; |
92 | 92 | ||
93 | if (parsed_nr_parts > 0) { | 93 | if (parsed_nr_parts > 0) { |
94 | parts = parsed_parts; | 94 | parts = parsed_parts; |
95 | nb_parts = parsed_nr_parts; | 95 | nb_parts = parsed_nr_parts; |
@@ -108,8 +108,8 @@ static int __init init_flash (void) | |||
108 | } | 108 | } |
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | int __init omap_toto_mtd_init(void) | 112 | int __init omap_toto_mtd_init(void) |
113 | { | 113 | { |
114 | int status; | 114 | int status; |
115 | 115 | ||
@@ -119,7 +119,7 @@ int __init omap_toto_mtd_init(void) | |||
119 | return status; | 119 | return status; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void __exit omap_toto_mtd_cleanup(void) | 122 | static void __exit omap_toto_mtd_cleanup(void) |
123 | { | 123 | { |
124 | if (flash_mtd) { | 124 | if (flash_mtd) { |
125 | del_mtd_partitions(flash_mtd); | 125 | del_mtd_partitions(flash_mtd); |
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index 7f370bb794fe..fd3b4a5fc207 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | 4 | * Copyright (C) 2001-2002 MontaVista Software Inc. |
5 | * Copyright (C) 2003-2004 Texas Instruments | 5 | * Copyright (C) 2003-2004 Texas Instruments |
6 | * Copyright (C) 2004 Nokia Corporation | 6 | * Copyright (C) 2004 Nokia Corporation |
7 | * | 7 | * |
8 | * Assembled using driver code copyright the companies above | 8 | * Assembled using driver code copyright the companies above |
9 | * and written by David Brownell, Jian Zhang <jzhang@ti.com>, | 9 | * and written by David Brownell, Jian Zhang <jzhang@ti.com>, |
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index d9c64e99ee32..8b3570b09095 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c | |||
@@ -7,8 +7,8 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $ | 10 | * $Id: pci.c,v 1.13 2005/11/07 11:14:27 gleixner Exp $ |
11 | * | 11 | * |
12 | * Generic PCI memory map driver. We support the following boards: | 12 | * Generic PCI memory map driver. We support the following boards: |
13 | * - Intel IQ80310 ATU. | 13 | * - Intel IQ80310 ATU. |
14 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 | 14 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 |
@@ -38,7 +38,7 @@ struct map_pci_info { | |||
38 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); | 38 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); |
39 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); | 39 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); |
40 | struct pci_dev *dev; | 40 | struct pci_dev *dev; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) | 43 | static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) |
44 | { | 44 | { |
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index ff7c50d10180..af24216a0626 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $ | 2 | * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards | 4 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards |
5 | * | 5 | * |
@@ -48,7 +48,7 @@ static const int debug = 0; | |||
48 | 48 | ||
49 | 49 | ||
50 | #define DRIVER_DESC "PCMCIA Flash memory card driver" | 50 | #define DRIVER_DESC "PCMCIA Flash memory card driver" |
51 | #define DRIVER_VERSION "$Revision: 1.51 $" | 51 | #define DRIVER_VERSION "$Revision: 1.55 $" |
52 | 52 | ||
53 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ | 53 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ |
54 | #define MAX_PCMCIA_ADDR 0x4000000 | 54 | #define MAX_PCMCIA_ADDR 0x4000000 |
@@ -176,7 +176,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long | |||
176 | 176 | ||
177 | if(toread > len) | 177 | if(toread > len) |
178 | toread = len; | 178 | toread = len; |
179 | 179 | ||
180 | addr = remap_window(map, from); | 180 | addr = remap_window(map, from); |
181 | if(!addr) | 181 | if(!addr) |
182 | return; | 182 | return; |
@@ -386,7 +386,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
386 | cs_error(link->handle, ParseTuple, rc); | 386 | cs_error(link->handle, ParseTuple, rc); |
387 | break; | 387 | break; |
388 | } | 388 | } |
389 | 389 | ||
390 | switch(tuple.TupleCode) { | 390 | switch(tuple.TupleCode) { |
391 | case CISTPL_FORMAT: { | 391 | case CISTPL_FORMAT: { |
392 | cistpl_format_t *t = &parse.format; | 392 | cistpl_format_t *t = &parse.format; |
@@ -394,9 +394,9 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
394 | DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", | 394 | DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", |
395 | t->type, t->edc, t->offset, t->length); | 395 | t->type, t->edc, t->offset, t->length); |
396 | break; | 396 | break; |
397 | 397 | ||
398 | } | 398 | } |
399 | 399 | ||
400 | case CISTPL_DEVICE: { | 400 | case CISTPL_DEVICE: { |
401 | cistpl_device_t *t = &parse.device; | 401 | cistpl_device_t *t = &parse.device; |
402 | int i; | 402 | int i; |
@@ -410,7 +410,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
410 | } | 410 | } |
411 | break; | 411 | break; |
412 | } | 412 | } |
413 | 413 | ||
414 | case CISTPL_VERS_1: { | 414 | case CISTPL_VERS_1: { |
415 | cistpl_vers_1_t *t = &parse.version_1; | 415 | cistpl_vers_1_t *t = &parse.version_1; |
416 | int i; | 416 | int i; |
@@ -425,7 +425,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
425 | DEBUG(2, "Found name: %s", dev->mtd_name); | 425 | DEBUG(2, "Found name: %s", dev->mtd_name); |
426 | break; | 426 | break; |
427 | } | 427 | } |
428 | 428 | ||
429 | case CISTPL_JEDEC_C: { | 429 | case CISTPL_JEDEC_C: { |
430 | cistpl_jedec_t *t = &parse.jedec; | 430 | cistpl_jedec_t *t = &parse.jedec; |
431 | int i; | 431 | int i; |
@@ -434,7 +434,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
434 | } | 434 | } |
435 | break; | 435 | break; |
436 | } | 436 | } |
437 | 437 | ||
438 | case CISTPL_DEVICE_GEO: { | 438 | case CISTPL_DEVICE_GEO: { |
439 | cistpl_device_geo_t *t = &parse.device_geo; | 439 | cistpl_device_geo_t *t = &parse.device_geo; |
440 | int i; | 440 | int i; |
@@ -449,11 +449,11 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
449 | } | 449 | } |
450 | break; | 450 | break; |
451 | } | 451 | } |
452 | 452 | ||
453 | default: | 453 | default: |
454 | DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); | 454 | DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); |
455 | } | 455 | } |
456 | 456 | ||
457 | rc = pcmcia_get_next_tuple(link->handle, &tuple); | 457 | rc = pcmcia_get_next_tuple(link->handle, &tuple); |
458 | } | 458 | } |
459 | if(!dev->pcmcia_map.size) | 459 | if(!dev->pcmcia_map.size) |
@@ -470,7 +470,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
470 | if(bankwidth) { | 470 | if(bankwidth) { |
471 | dev->pcmcia_map.bankwidth = bankwidth; | 471 | dev->pcmcia_map.bankwidth = bankwidth; |
472 | DEBUG(2, "bankwidth forced to %d", bankwidth); | 472 | DEBUG(2, "bankwidth forced to %d", bankwidth); |
473 | } | 473 | } |
474 | 474 | ||
475 | dev->pcmcia_map.name = dev->mtd_name; | 475 | dev->pcmcia_map.name = dev->mtd_name; |
476 | if(!dev->mtd_name[0]) { | 476 | if(!dev->mtd_name[0]) { |
@@ -568,7 +568,7 @@ static void pcmciamtd_config(dev_link_t *link) | |||
568 | return; | 568 | return; |
569 | } | 569 | } |
570 | DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); | 570 | DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); |
571 | 571 | ||
572 | /* Get write protect status */ | 572 | /* Get write protect status */ |
573 | CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); | 573 | CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); |
574 | DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", | 574 | DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", |
@@ -624,11 +624,11 @@ static void pcmciamtd_config(dev_link_t *link) | |||
624 | mtd = do_map_probe(probes[i], &dev->pcmcia_map); | 624 | mtd = do_map_probe(probes[i], &dev->pcmcia_map); |
625 | if(mtd) | 625 | if(mtd) |
626 | break; | 626 | break; |
627 | 627 | ||
628 | DEBUG(1, "FAILED: %s", probes[i]); | 628 | DEBUG(1, "FAILED: %s", probes[i]); |
629 | } | 629 | } |
630 | } | 630 | } |
631 | 631 | ||
632 | if(!mtd) { | 632 | if(!mtd) { |
633 | DEBUG(1, "Cant find an MTD"); | 633 | DEBUG(1, "Cant find an MTD"); |
634 | pcmciamtd_release(link); | 634 | pcmciamtd_release(link); |
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index b853670bfb81..9ee760f97bc6 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $ | 2 | * $Id: physmap.c,v 1.38 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * | 5 | * |
@@ -69,7 +69,7 @@ static int __init init_physmap(void) | |||
69 | mymtd->owner = THIS_MODULE; | 69 | mymtd->owner = THIS_MODULE; |
70 | 70 | ||
71 | #ifdef CONFIG_MTD_PARTITIONS | 71 | #ifdef CONFIG_MTD_PARTITIONS |
72 | mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, | 72 | mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, |
73 | &mtd_parts, 0); | 73 | &mtd_parts, 0); |
74 | 74 | ||
75 | if (mtd_parts_nb > 0) | 75 | if (mtd_parts_nb > 0) |
@@ -78,9 +78,9 @@ static int __init init_physmap(void) | |||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | if (num_physmap_partitions != 0) | 81 | if (num_physmap_partitions != 0) |
82 | { | 82 | { |
83 | printk(KERN_NOTICE | 83 | printk(KERN_NOTICE |
84 | "Using physmap partition definition\n"); | 84 | "Using physmap partition definition\n"); |
85 | add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); | 85 | add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); |
86 | return 0; | 86 | return 0; |
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 104576b5be34..a02eed94a231 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Generic platfrom device based RAM map | 7 | * Generic platfrom device based RAM map |
8 | * | 8 | * |
9 | * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $ | 9 | * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -91,7 +91,7 @@ static int platram_remove(struct device *dev) | |||
91 | 91 | ||
92 | dev_dbg(dev, "removing device\n"); | 92 | dev_dbg(dev, "removing device\n"); |
93 | 93 | ||
94 | if (info == NULL) | 94 | if (info == NULL) |
95 | return 0; | 95 | return 0; |
96 | 96 | ||
97 | if (info->mtd) { | 97 | if (info->mtd) { |
@@ -118,7 +118,7 @@ static int platram_remove(struct device *dev) | |||
118 | 118 | ||
119 | if (info->map.virt != NULL) | 119 | if (info->map.virt != NULL) |
120 | iounmap(info->map.virt); | 120 | iounmap(info->map.virt); |
121 | 121 | ||
122 | kfree(info); | 122 | kfree(info); |
123 | 123 | ||
124 | return 0; | 124 | return 0; |
@@ -139,7 +139,7 @@ static int platram_probe(struct device *dev) | |||
139 | int err = 0; | 139 | int err = 0; |
140 | 140 | ||
141 | dev_dbg(dev, "probe entered\n"); | 141 | dev_dbg(dev, "probe entered\n"); |
142 | 142 | ||
143 | if (dev->platform_data == NULL) { | 143 | if (dev->platform_data == NULL) { |
144 | dev_err(dev, "no platform data supplied\n"); | 144 | dev_err(dev, "no platform data supplied\n"); |
145 | err = -ENOENT; | 145 | err = -ENOENT; |
@@ -177,7 +177,7 @@ static int platram_probe(struct device *dev) | |||
177 | 177 | ||
178 | info->map.phys = res->start; | 178 | info->map.phys = res->start; |
179 | info->map.size = (res->end - res->start) + 1; | 179 | info->map.size = (res->end - res->start) + 1; |
180 | info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; | 180 | info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pd->name; |
181 | info->map.bankwidth = pdata->bankwidth; | 181 | info->map.bankwidth = pdata->bankwidth; |
182 | 182 | ||
183 | /* register our usage of the memory area */ | 183 | /* register our usage of the memory area */ |
@@ -240,7 +240,7 @@ static int platram_probe(struct device *dev) | |||
240 | dev_err(dev, "add_mtd_device() failed\n"); | 240 | dev_err(dev, "add_mtd_device() failed\n"); |
241 | err = -ENOMEM; | 241 | err = -ENOMEM; |
242 | } | 242 | } |
243 | 243 | ||
244 | dev_info(dev, "registered mtd device\n"); | 244 | dev_info(dev, "registered mtd device\n"); |
245 | return err; | 245 | return err; |
246 | 246 | ||
@@ -254,6 +254,7 @@ static int platram_probe(struct device *dev) | |||
254 | 254 | ||
255 | static struct device_driver platram_driver = { | 255 | static struct device_driver platram_driver = { |
256 | .name = "mtd-ram", | 256 | .name = "mtd-ram", |
257 | .owner = THIS_MODULE, | ||
257 | .bus = &platform_bus_type, | 258 | .bus = &platform_bus_type, |
258 | .probe = platram_probe, | 259 | .probe = platram_probe, |
259 | .remove = platram_remove, | 260 | .remove = platram_remove, |
diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c index a0f43dad8985..d7e16c2d5c44 100644 --- a/drivers/mtd/maps/pnc2000.c +++ b/drivers/mtd/maps/pnc2000.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: pnc2000.c,v 1.17 2004/11/16 18:29:02 dwmw2 Exp $ | 8 | * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
@@ -21,7 +21,7 @@ | |||
21 | #define WINDOW_ADDR 0xbf000000 | 21 | #define WINDOW_ADDR 0xbf000000 |
22 | #define WINDOW_SIZE 0x00400000 | 22 | #define WINDOW_SIZE 0x00400000 |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * MAP DRIVER STUFF | 25 | * MAP DRIVER STUFF |
26 | */ | 26 | */ |
27 | 27 | ||
@@ -36,7 +36,7 @@ static struct map_info pnc_map = { | |||
36 | 36 | ||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * MTD 'PARTITIONING' STUFF | 39 | * MTD 'PARTITIONING' STUFF |
40 | */ | 40 | */ |
41 | static struct mtd_partition pnc_partitions[3] = { | 41 | static struct mtd_partition pnc_partitions[3] = { |
42 | { | 42 | { |
@@ -56,7 +56,7 @@ static struct mtd_partition pnc_partitions[3] = { | |||
56 | } | 56 | } |
57 | }; | 57 | }; |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * This is the master MTD device for which all the others are just | 60 | * This is the master MTD device for which all the others are just |
61 | * auto-relocating aliases. | 61 | * auto-relocating aliases. |
62 | */ | 62 | */ |
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c new file mode 100644 index 000000000000..fb78d87cc130 --- /dev/null +++ b/drivers/mtd/maps/pq2fads.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * drivers/mtd/maps/pq2fads.c | ||
3 | * | ||
4 | * Mapping for the flash SIMM on 8272ADS and PQ2FADS board | ||
5 | * | ||
6 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> | ||
7 | * | ||
8 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
9 | * the terms of the GNU General Public License version 2. This program | ||
10 | * is licensed "as is" without any warranty of any kind, whether express | ||
11 | * or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/ppcboot.h> | ||
20 | #include <linux/mtd/mtd.h> | ||
21 | #include <linux/mtd/map.h> | ||
22 | #include <linux/mtd/partitions.h> | ||
23 | #include <linux/mtd/physmap.h> | ||
24 | |||
25 | /* | ||
26 | NOTE: bank width and interleave relative to the installed flash | ||
27 | should have been chosen within MTD_CFI_GEOMETRY options. | ||
28 | */ | ||
29 | #define PQ2FADS_BANK_WIDTH 4 | ||
30 | |||
31 | static struct mtd_partition pq2fads_partitions[] = { | ||
32 | { | ||
33 | #ifdef CONFIG_ADS8272 | ||
34 | .name = "HRCW", | ||
35 | .size = 0x40000, | ||
36 | .offset = 0, | ||
37 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
38 | }, { | ||
39 | .name = "User FS", | ||
40 | .size = 0x5c0000, | ||
41 | .offset = 0x40000, | ||
42 | #else | ||
43 | .name = "User FS", | ||
44 | .size = 0x600000, | ||
45 | .offset = 0, | ||
46 | #endif | ||
47 | }, { | ||
48 | .name = "uImage", | ||
49 | .size = 0x100000, | ||
50 | .offset = 0x600000, | ||
51 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
52 | }, { | ||
53 | .name = "bootloader", | ||
54 | .size = 0x40000, | ||
55 | .offset = 0x700000, | ||
56 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
57 | }, { | ||
58 | .name = "bootloader env", | ||
59 | .size = 0x40000, | ||
60 | .offset = 0x740000, | ||
61 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | |||
66 | /* pointer to MPC885ADS board info data */ | ||
67 | extern unsigned char __res[]; | ||
68 | |||
69 | static int __init init_pq2fads_mtd(void) | ||
70 | { | ||
71 | bd_t *bd = (bd_t *)__res; | ||
72 | physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL); | ||
73 | |||
74 | physmap_set_partitions(pq2fads_partitions, | ||
75 | sizeof (pq2fads_partitions) / | ||
76 | sizeof (pq2fads_partitions[0])); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void __exit cleanup_pq2fads_mtd(void) | ||
81 | { | ||
82 | } | ||
83 | |||
84 | module_init(init_pq2fads_mtd); | ||
85 | module_exit(cleanup_pq2fads_mtd); | ||
86 | |||
87 | MODULE_LICENSE("GPL"); | ||
88 | MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards"); | ||
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index edd01ee4f90b..5b76ed886185 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: redwood.c,v 1.10 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/redwood.c | 4 | * drivers/mtd/maps/redwood.c |
5 | * | 5 | * |
@@ -79,7 +79,7 @@ static struct mtd_partition redwood_flash_partitions[] = { | |||
79 | 79 | ||
80 | #define RW_PART0_OF 0 | 80 | #define RW_PART0_OF 0 |
81 | #define RW_PART0_SZ 0x400000 /* 4 MiB data */ | 81 | #define RW_PART0_SZ 0x400000 /* 4 MiB data */ |
82 | #define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ | 82 | #define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ |
83 | #define RW_PART1_SZ 0x10000 /* 64K VPD */ | 83 | #define RW_PART1_SZ 0x10000 /* 64K VPD */ |
84 | #define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ | 84 | #define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ |
85 | #define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) | 85 | #define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a31f6ee8a4be..9e8bb1782be0 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on SA11x0 based devices | 2 | * Flash memory access on SA11x0 based devices |
3 | * | 3 | * |
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * | 5 | * |
6 | * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $ | 6 | * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $ |
7 | */ | 7 | */ |
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index da684d3384e9..225cdd9ba5b2 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This code is GPLed | 6 | * This code is GPLed |
7 | * | 7 | * |
8 | * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $ | 8 | * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
@@ -205,7 +205,7 @@ int __init init_sbc8240_mtd (void) | |||
205 | } else { | 205 | } else { |
206 | printk (KERN_NOTICE MSG_PREFIX | 206 | printk (KERN_NOTICE MSG_PREFIX |
207 | "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); | 207 | "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); |
208 | add_mtd_partitions (sbc8240_mtd[i], | 208 | add_mtd_partitions (sbc8240_mtd[i], |
209 | sbc8240_part_banks[i].mtd_part, | 209 | sbc8240_part_banks[i].mtd_part, |
210 | sbc8240_part_banks[i].nums); | 210 | sbc8240_part_banks[i].nums); |
211 | } | 211 | } |
diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 65add28bde14..7cc4041d096d 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c | |||
@@ -1,35 +1,35 @@ | |||
1 | /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, | 1 | /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, |
2 | SBC-GXm and SBC-GX1 series boards. | 2 | SBC-GXm and SBC-GX1 series boards. |
3 | 3 | ||
4 | Copyright (C) 2001 Arcom Control System Ltd | 4 | Copyright (C) 2001 Arcom Control System Ltd |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | 9 | (at your option) any later version. |
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful, | 11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
15 | 15 | ||
16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
19 | 19 | ||
20 | $Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $ | 20 | $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $ |
21 | 21 | ||
22 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of | 22 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of |
23 | Intel StrataFlash (28F320/28F640) in x8 mode. | 23 | Intel StrataFlash (28F320/28F640) in x8 mode. |
24 | 24 | ||
25 | This driver uses the CFI probe and Intel Extended Command Set drivers. | 25 | This driver uses the CFI probe and Intel Extended Command Set drivers. |
26 | 26 | ||
27 | The flash is accessed as follows: | 27 | The flash is accessed as follows: |
28 | 28 | ||
29 | 16 KiB memory window at 0xdc000-0xdffff | 29 | 16 KiB memory window at 0xdc000-0xdffff |
30 | 30 | ||
31 | Two IO address locations for paging | 31 | Two IO address locations for paging |
32 | 32 | ||
33 | 0x258 | 33 | 0x258 |
34 | bit 0-7: address bit 14-21 | 34 | bit 0-7: address bit 14-21 |
35 | 0x259 | 35 | 0x259 |
@@ -37,7 +37,7 @@ The flash is accessed as follows: | |||
37 | bit 7: 0 - reset/powered down | 37 | bit 7: 0 - reset/powered down |
38 | 1 - device enabled | 38 | 1 - device enabled |
39 | 39 | ||
40 | The single flash device is divided into 3 partition which appear as | 40 | The single flash device is divided into 3 partition which appear as |
41 | separate MTD devices. | 41 | separate MTD devices. |
42 | 42 | ||
43 | 25/04/2001 AJL (Arcom) Modified signon strings and partition sizes | 43 | 25/04/2001 AJL (Arcom) Modified signon strings and partition sizes |
@@ -87,17 +87,17 @@ static volatile int page_in_window = -1; // Current page in window. | |||
87 | static void __iomem *iomapadr; | 87 | static void __iomem *iomapadr; |
88 | static DEFINE_SPINLOCK(sbc_gxx_spin); | 88 | static DEFINE_SPINLOCK(sbc_gxx_spin); |
89 | 89 | ||
90 | /* partition_info gives details on the logical partitions that the split the | 90 | /* partition_info gives details on the logical partitions that the split the |
91 | * single flash device into. If the size if zero we use up to the end of the | 91 | * single flash device into. If the size if zero we use up to the end of the |
92 | * device. */ | 92 | * device. */ |
93 | static struct mtd_partition partition_info[]={ | 93 | static struct mtd_partition partition_info[]={ |
94 | { .name = "SBC-GXx flash boot partition", | 94 | { .name = "SBC-GXx flash boot partition", |
95 | .offset = 0, | 95 | .offset = 0, |
96 | .size = BOOT_PARTITION_SIZE_KiB*1024 }, | 96 | .size = BOOT_PARTITION_SIZE_KiB*1024 }, |
97 | { .name = "SBC-GXx flash data partition", | 97 | { .name = "SBC-GXx flash data partition", |
98 | .offset = BOOT_PARTITION_SIZE_KiB*1024, | 98 | .offset = BOOT_PARTITION_SIZE_KiB*1024, |
99 | .size = (DATA_PARTITION_SIZE_KiB)*1024 }, | 99 | .size = (DATA_PARTITION_SIZE_KiB)*1024 }, |
100 | { .name = "SBC-GXx flash application partition", | 100 | { .name = "SBC-GXx flash application partition", |
101 | .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } | 101 | .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } |
102 | }; | 102 | }; |
103 | 103 | ||
@@ -130,7 +130,7 @@ static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from | |||
130 | unsigned long thislen = len; | 130 | unsigned long thislen = len; |
131 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) | 131 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) |
132 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); | 132 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); |
133 | 133 | ||
134 | spin_lock(&sbc_gxx_spin); | 134 | spin_lock(&sbc_gxx_spin); |
135 | sbc_gxx_page(map, from); | 135 | sbc_gxx_page(map, from); |
136 | memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); | 136 | memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); |
@@ -150,12 +150,12 @@ static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr) | |||
150 | } | 150 | } |
151 | 151 | ||
152 | static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) | 152 | static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
153 | { | 153 | { |
154 | while(len) { | 154 | while(len) { |
155 | unsigned long thislen = len; | 155 | unsigned long thislen = len; |
156 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) | 156 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) |
157 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); | 157 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); |
158 | 158 | ||
159 | spin_lock(&sbc_gxx_spin); | 159 | spin_lock(&sbc_gxx_spin); |
160 | sbc_gxx_page(map, to); | 160 | sbc_gxx_page(map, to); |
161 | memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); | 161 | memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); |
@@ -201,7 +201,7 @@ static int __init init_sbc_gxx(void) | |||
201 | sbc_gxx_map.name ); | 201 | sbc_gxx_map.name ); |
202 | return -EIO; | 202 | return -EIO; |
203 | } | 203 | } |
204 | 204 | ||
205 | if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { | 205 | if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { |
206 | printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", | 206 | printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", |
207 | sbc_gxx_map.name, | 207 | sbc_gxx_map.name, |
@@ -209,8 +209,8 @@ static int __init init_sbc_gxx(void) | |||
209 | iounmap(iomapadr); | 209 | iounmap(iomapadr); |
210 | return -EAGAIN; | 210 | return -EAGAIN; |
211 | } | 211 | } |
212 | 212 | ||
213 | 213 | ||
214 | printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", | 214 | printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", |
215 | sbc_gxx_map.name, | 215 | sbc_gxx_map.name, |
216 | PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, | 216 | PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, |
@@ -222,7 +222,7 @@ static int __init init_sbc_gxx(void) | |||
222 | cleanup_sbc_gxx(); | 222 | cleanup_sbc_gxx(); |
223 | return -ENXIO; | 223 | return -ENXIO; |
224 | } | 224 | } |
225 | 225 | ||
226 | all_mtd->owner = THIS_MODULE; | 226 | all_mtd->owner = THIS_MODULE; |
227 | 227 | ||
228 | /* Create MTD devices for each partition. */ | 228 | /* Create MTD devices for each partition. */ |
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index a06ed21e7ed1..6fb9f3c57aab 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
18 | * | 18 | * |
19 | * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $ | 19 | * $Id: sc520cdp.c,v 1.22 2005/11/07 11:14:28 gleixner Exp $ |
20 | * | 20 | * |
21 | * | 21 | * |
22 | * The SC520CDP is an evaluation board for the Elan SC520 processor available | 22 | * The SC520CDP is an evaluation board for the Elan SC520 processor available |
@@ -231,7 +231,7 @@ static void sc520cdp_setup_par(void) | |||
231 | static int __init init_sc520cdp(void) | 231 | static int __init init_sc520cdp(void) |
232 | { | 232 | { |
233 | int i, devices_found = 0; | 233 | int i, devices_found = 0; |
234 | 234 | ||
235 | #ifdef REPROGRAM_PAR | 235 | #ifdef REPROGRAM_PAR |
236 | /* reprogram PAR registers so flash appears at the desired addresses */ | 236 | /* reprogram PAR registers so flash appears at the desired addresses */ |
237 | sc520cdp_setup_par(); | 237 | sc520cdp_setup_par(); |
@@ -278,7 +278,7 @@ static int __init init_sc520cdp(void) | |||
278 | static void __exit cleanup_sc520cdp(void) | 278 | static void __exit cleanup_sc520cdp(void) |
279 | { | 279 | { |
280 | int i; | 280 | int i; |
281 | 281 | ||
282 | if (merged_mtd) { | 282 | if (merged_mtd) { |
283 | del_mtd_device(merged_mtd); | 283 | del_mtd_device(merged_mtd); |
284 | mtd_concat_destroy(merged_mtd); | 284 | mtd_concat_destroy(merged_mtd); |
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 0ece3786d6ea..2c91dff8bb60 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* linux/drivers/mtd/maps/scx200_docflash.c | 1 | /* linux/drivers/mtd/maps/scx200_docflash.c |
2 | 2 | ||
3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> | 3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
4 | 4 | ||
5 | $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ | 5 | $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $ |
6 | 6 | ||
7 | National Semiconductor SCx200 flash mapped with DOCCS | 7 | National Semiconductor SCx200 flash mapped with DOCCS |
8 | */ | 8 | */ |
@@ -49,23 +49,23 @@ static struct mtd_info *mymtd; | |||
49 | 49 | ||
50 | #ifdef CONFIG_MTD_PARTITIONS | 50 | #ifdef CONFIG_MTD_PARTITIONS |
51 | static struct mtd_partition partition_info[] = { | 51 | static struct mtd_partition partition_info[] = { |
52 | { | 52 | { |
53 | .name = "DOCCS Boot kernel", | 53 | .name = "DOCCS Boot kernel", |
54 | .offset = 0, | 54 | .offset = 0, |
55 | .size = 0xc0000 | 55 | .size = 0xc0000 |
56 | }, | 56 | }, |
57 | { | 57 | { |
58 | .name = "DOCCS Low BIOS", | 58 | .name = "DOCCS Low BIOS", |
59 | .offset = 0xc0000, | 59 | .offset = 0xc0000, |
60 | .size = 0x40000 | 60 | .size = 0x40000 |
61 | }, | 61 | }, |
62 | { | 62 | { |
63 | .name = "DOCCS File system", | 63 | .name = "DOCCS File system", |
64 | .offset = 0x100000, | 64 | .offset = 0x100000, |
65 | .size = ~0 /* calculate from flash size */ | 65 | .size = ~0 /* calculate from flash size */ |
66 | }, | 66 | }, |
67 | { | 67 | { |
68 | .name = "DOCCS High BIOS", | 68 | .name = "DOCCS High BIOS", |
69 | .offset = ~0, /* calculate from flash size */ | 69 | .offset = ~0, /* calculate from flash size */ |
70 | .size = 0x80000 | 70 | .size = 0x80000 |
71 | }, | 71 | }, |
@@ -88,7 +88,7 @@ static int __init init_scx200_docflash(void) | |||
88 | 88 | ||
89 | printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n"); | 89 | printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n"); |
90 | 90 | ||
91 | if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, | 91 | if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, |
92 | PCI_DEVICE_ID_NS_SCx200_BRIDGE, | 92 | PCI_DEVICE_ID_NS_SCx200_BRIDGE, |
93 | NULL)) == NULL) | 93 | NULL)) == NULL) |
94 | return -ENODEV; | 94 | return -ENODEV; |
@@ -134,28 +134,28 @@ static int __init init_scx200_docflash(void) | |||
134 | printk(KERN_ERR NAME ": invalid size for flash mapping\n"); | 134 | printk(KERN_ERR NAME ": invalid size for flash mapping\n"); |
135 | return -EINVAL; | 135 | return -EINVAL; |
136 | } | 136 | } |
137 | 137 | ||
138 | if (width != 8 && width != 16) { | 138 | if (width != 8 && width != 16) { |
139 | printk(KERN_ERR NAME ": invalid bus width for flash mapping\n"); | 139 | printk(KERN_ERR NAME ": invalid bus width for flash mapping\n"); |
140 | return -EINVAL; | 140 | return -EINVAL; |
141 | } | 141 | } |
142 | 142 | ||
143 | if (allocate_resource(&iomem_resource, &docmem, | 143 | if (allocate_resource(&iomem_resource, &docmem, |
144 | size, | 144 | size, |
145 | 0xc0000000, 0xffffffff, | 145 | 0xc0000000, 0xffffffff, |
146 | size, NULL, NULL)) { | 146 | size, NULL, NULL)) { |
147 | printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n"); | 147 | printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n"); |
148 | return -ENOMEM; | 148 | return -ENOMEM; |
149 | } | 149 | } |
150 | 150 | ||
151 | ctrl = 0x07000000 | ((size-1) >> 13); | 151 | ctrl = 0x07000000 | ((size-1) >> 13); |
152 | 152 | ||
153 | printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl); | 153 | printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl); |
154 | 154 | ||
155 | pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); | 155 | pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); |
156 | pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); | 156 | pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); |
157 | pmr = inl(scx200_cb_base + SCx200_PMR); | 157 | pmr = inl(scx200_cb_base + SCx200_PMR); |
158 | 158 | ||
159 | if (width == 8) { | 159 | if (width == 8) { |
160 | pmr &= ~(1<<6); | 160 | pmr &= ~(1<<6); |
161 | } else { | 161 | } else { |
@@ -163,8 +163,8 @@ static int __init init_scx200_docflash(void) | |||
163 | } | 163 | } |
164 | outl(pmr, scx200_cb_base + SCx200_PMR); | 164 | outl(pmr, scx200_cb_base + SCx200_PMR); |
165 | } | 165 | } |
166 | 166 | ||
167 | printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", | 167 | printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", |
168 | docmem.start, docmem.end, width); | 168 | docmem.start, docmem.end, width); |
169 | 169 | ||
170 | scx200_docflash_map.size = size; | 170 | scx200_docflash_map.size = size; |
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index b7f093fbf9b0..999f4bb3d845 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * sharpsl-flash.c | 2 | * sharpsl-flash.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Lineo Japan, Inc. | 4 | * Copyright (C) 2001 Lineo Japan, Inc. |
5 | * Copyright (C) 2002 SHARP | 5 | * Copyright (C) 2002 SHARP |
6 | * | 6 | * |
7 | * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $ | 7 | * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ |
8 | * | 8 | * |
9 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp | 9 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp |
10 | * Handle mapping of the flash on the RPX Lite and CLLF boards | 10 | * Handle mapping of the flash on the RPX Lite and CLLF boards |
@@ -57,7 +57,7 @@ int __init init_sharpsl(void) | |||
57 | int nb_parts = 0; | 57 | int nb_parts = 0; |
58 | char *part_type = "static"; | 58 | char *part_type = "static"; |
59 | 59 | ||
60 | printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", | 60 | printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", |
61 | WINDOW_SIZE, WINDOW_ADDR); | 61 | WINDOW_SIZE, WINDOW_ADDR); |
62 | sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); | 62 | sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); |
63 | if (!sharpsl_map.virt) { | 63 | if (!sharpsl_map.virt) { |
@@ -75,7 +75,7 @@ int __init init_sharpsl(void) | |||
75 | 75 | ||
76 | mymtd->owner = THIS_MODULE; | 76 | mymtd->owner = THIS_MODULE; |
77 | 77 | ||
78 | if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() | 78 | if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() |
79 | || machine_is_poodle()) { | 79 | || machine_is_poodle()) { |
80 | sharpsl_partitions[0].size=0x006d0000; | 80 | sharpsl_partitions[0].size=0x006d0000; |
81 | sharpsl_partitions[0].offset=0x00120000; | 81 | sharpsl_partitions[0].offset=0x00120000; |
@@ -87,10 +87,10 @@ int __init init_sharpsl(void) | |||
87 | sharpsl_partitions[0].offset=0x00140000; | 87 | sharpsl_partitions[0].offset=0x00140000; |
88 | } else { | 88 | } else { |
89 | map_destroy(mymtd); | 89 | map_destroy(mymtd); |
90 | iounmap(sharpsl_map.virt); | 90 | iounmap(sharpsl_map.virt); |
91 | return -ENODEV; | 91 | return -ENODEV; |
92 | } | 92 | } |
93 | 93 | ||
94 | parts = sharpsl_partitions; | 94 | parts = sharpsl_partitions; |
95 | nb_parts = NB_OF(sharpsl_partitions); | 95 | nb_parts = NB_OF(sharpsl_partitions); |
96 | 96 | ||
diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index 8ce5d897645c..c53c2c369c9d 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $ | 2 | * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * Flash and EPROM on Hitachi Solution Engine and similar boards. | 4 | * Flash and EPROM on Hitachi Solution Engine and similar boards. |
5 | * | 5 | * |
@@ -67,7 +67,7 @@ static int __init init_soleng_maps(void) | |||
67 | soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); | 67 | soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); |
68 | simple_map_init(&soleng_eprom_map); | 68 | simple_map_init(&soleng_eprom_map); |
69 | simple_map_init(&soleng_flash_map); | 69 | simple_map_init(&soleng_flash_map); |
70 | 70 | ||
71 | printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); | 71 | printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); |
72 | flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); | 72 | flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); |
73 | if (!flash_mtd) { | 73 | if (!flash_mtd) { |
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 1355c28f90a4..0758cb1d0105 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $ | 1 | /* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $ |
2 | * | 2 | * |
3 | * sun_uflash - Driver implementation for user-programmable flash | 3 | * sun_uflash - Driver implementation for user-programmable flash |
4 | * present on many Sun Microsystems SME boardsets. | 4 | * present on many Sun Microsystems SME boardsets. |
@@ -63,7 +63,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
63 | iTmp = prom_getproperty( | 63 | iTmp = prom_getproperty( |
64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); | 64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); |
65 | if ((iTmp % sizeof(regs[0])) != 0) { | 65 | if ((iTmp % sizeof(regs[0])) != 0) { |
66 | printk("%s: Strange reg property size %d\n", | 66 | printk("%s: Strange reg property size %d\n", |
67 | UFLASH_DEVNAME, iTmp); | 67 | UFLASH_DEVNAME, iTmp); |
68 | return -ENODEV; | 68 | return -ENODEV; |
69 | } | 69 | } |
@@ -75,7 +75,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
75 | * can work on supporting it. | 75 | * can work on supporting it. |
76 | */ | 76 | */ |
77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ | 77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ |
78 | "email ebrower@usa.net\n", | 78 | "email ebrower@usa.net\n", |
79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); | 79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); |
80 | return -ENODEV; | 80 | return -ENODEV; |
81 | } | 81 | } |
@@ -84,7 +84,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); | 84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); |
85 | return(-ENOMEM); | 85 | return(-ENOMEM); |
86 | } | 86 | } |
87 | 87 | ||
88 | /* copy defaults and tweak parameters */ | 88 | /* copy defaults and tweak parameters */ |
89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); | 89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); |
90 | pdev->map.size = regs[0].reg_size; | 90 | pdev->map.size = regs[0].reg_size; |
@@ -155,7 +155,7 @@ static void __exit uflash_cleanup(void) | |||
155 | 155 | ||
156 | list_for_each(udevlist, &device_list) { | 156 | list_for_each(udevlist, &device_list) { |
157 | udev = list_entry(udevlist, struct uflash_dev, list); | 157 | udev = list_entry(udevlist, struct uflash_dev, list); |
158 | DEBUG(2, "%s: removing device %s\n", | 158 | DEBUG(2, "%s: removing device %s\n", |
159 | UFLASH_DEVNAME, udev->name); | 159 | UFLASH_DEVNAME, udev->name); |
160 | 160 | ||
161 | if(0 != udev->mtd) { | 161 | if(0 != udev->mtd) { |
@@ -168,7 +168,7 @@ static void __exit uflash_cleanup(void) | |||
168 | } | 168 | } |
169 | kfree(udev->name); | 169 | kfree(udev->name); |
170 | kfree(udev); | 170 | kfree(udev); |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | module_init(uflash_init); | 174 | module_init(uflash_init); |
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c new file mode 100644 index 000000000000..c7ae9a515c1a --- /dev/null +++ b/drivers/mtd/maps/tqm834x.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * drivers/mtd/maps/tqm834x.c | ||
3 | * | ||
4 | * MTD mapping driver for TQM834x boards | ||
5 | * | ||
6 | * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/ppcboot.h> | ||
22 | |||
23 | #include <linux/mtd/mtd.h> | ||
24 | #include <linux/mtd/map.h> | ||
25 | #include <linux/mtd/partitions.h> | ||
26 | |||
27 | #define FLASH_BANK_MAX 2 | ||
28 | |||
29 | extern unsigned char __res[]; | ||
30 | |||
31 | /* trivial struct to describe partition information */ | ||
32 | struct mtd_part_def | ||
33 | { | ||
34 | int nums; | ||
35 | unsigned char *type; | ||
36 | struct mtd_partition* mtd_part; | ||
37 | }; | ||
38 | |||
39 | static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; | ||
40 | static struct map_info* map_banks[FLASH_BANK_MAX]; | ||
41 | static struct mtd_part_def part_banks[FLASH_BANK_MAX]; | ||
42 | |||
43 | static unsigned long num_banks; | ||
44 | static unsigned long start_scan_addr; | ||
45 | |||
46 | #ifdef CONFIG_MTD_PARTITIONS | ||
47 | /* | ||
48 | * The following defines the partition layout of TQM834x boards. | ||
49 | * | ||
50 | * See include/linux/mtd/partitions.h for definition of the | ||
51 | * mtd_partition structure. | ||
52 | * | ||
53 | * Assume minimal initial size of 4 MiB per bank, will be updated | ||
54 | * later in init_tqm834x_mtd() routine. | ||
55 | */ | ||
56 | |||
57 | /* Partition definition for the first flash bank which is always present. */ | ||
58 | static struct mtd_partition tqm834x_partitions_bank1[] = { | ||
59 | { | ||
60 | .name = "u-boot", /* u-boot firmware */ | ||
61 | .offset = 0x00000000, | ||
62 | .size = 0x00040000, /* 256 KiB */ | ||
63 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
64 | }, | ||
65 | { | ||
66 | .name = "env", /* u-boot environment */ | ||
67 | .offset = 0x00040000, | ||
68 | .size = 0x00020000, /* 128 KiB */ | ||
69 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
70 | }, | ||
71 | { | ||
72 | .name = "kernel", /* linux kernel image */ | ||
73 | .offset = 0x00060000, | ||
74 | .size = 0x00100000, /* 1 MiB */ | ||
75 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
76 | }, | ||
77 | { | ||
78 | .name = "initrd", /* ramdisk image */ | ||
79 | .offset = 0x00160000, | ||
80 | .size = 0x00200000, /* 2 MiB */ | ||
81 | }, | ||
82 | { | ||
83 | .name = "user", /* user data */ | ||
84 | .offset = 0x00360000, | ||
85 | .size = 0x000a0000, /* remaining space */ | ||
86 | /* NOTE: this parttion size is re-calcated in */ | ||
87 | /* init_tqm834x_mtd() to cover actual remaining space. */ | ||
88 | }, | ||
89 | }; | ||
90 | |||
91 | /* Partition definition for the second flash bank which may be present on some | ||
92 | * TQM834x boards. | ||
93 | */ | ||
94 | static struct mtd_partition tqm834x_partitions_bank2[] = { | ||
95 | { | ||
96 | .name = "jffs2", /* jffs2 filesystem */ | ||
97 | .offset = 0x00000000, | ||
98 | .size = 0x00400000, /* whole device */ | ||
99 | /* NOTE: this parttion size is re-calcated in */ | ||
100 | /* init_tqm834x_mtd() to cover actual device size. */ | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | #endif /* CONFIG_MTD_PARTITIONS */ | ||
105 | |||
106 | static int __init init_tqm834x_mtd(void) | ||
107 | { | ||
108 | int idx = 0, ret = 0; | ||
109 | unsigned long flash_addr, flash_size, mtd_size = 0; | ||
110 | |||
111 | /* pointer to TQM834x board info data */ | ||
112 | bd_t *bd = (bd_t *)__res; | ||
113 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
114 | int n; | ||
115 | char mtdid[4]; | ||
116 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
117 | #endif | ||
118 | |||
119 | flash_addr = bd->bi_flashstart; | ||
120 | flash_size = bd->bi_flashsize; | ||
121 | |||
122 | /* request maximum flash size address space */ | ||
123 | start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); | ||
124 | if (!start_scan_addr) { | ||
125 | printk("%s: Failed to ioremap address: 0x%lx\n", | ||
126 | __FUNCTION__, flash_addr); | ||
127 | return -EIO; | ||
128 | } | ||
129 | |||
130 | for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | ||
131 | if (mtd_size >= flash_size) | ||
132 | break; | ||
133 | |||
134 | pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); | ||
135 | |||
136 | map_banks[idx] = | ||
137 | (struct map_info *)kmalloc(sizeof(struct map_info), | ||
138 | GFP_KERNEL); | ||
139 | if (map_banks[idx] == NULL) { | ||
140 | ret = -ENOMEM; | ||
141 | goto error_mem; | ||
142 | } | ||
143 | memset((void *)map_banks[idx], 0, sizeof(struct map_info)); | ||
144 | map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); | ||
145 | if (map_banks[idx]->name == NULL) { | ||
146 | ret = -ENOMEM; | ||
147 | goto error_mem; | ||
148 | } | ||
149 | memset((void *)map_banks[idx]->name, 0, 16); | ||
150 | |||
151 | sprintf(map_banks[idx]->name, "TQM834x-%d", idx); | ||
152 | map_banks[idx]->size = flash_size; | ||
153 | map_banks[idx]->bankwidth = 4; | ||
154 | |||
155 | simple_map_init(map_banks[idx]); | ||
156 | |||
157 | map_banks[idx]->virt = (void __iomem *) | ||
158 | (start_scan_addr + ((idx > 0) ? | ||
159 | (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0)); | ||
160 | map_banks[idx]->phys = | ||
161 | flash_addr + ((idx > 0) ? | ||
162 | (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); | ||
163 | |||
164 | /* start to probe flash chips */ | ||
165 | mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); | ||
166 | if (mtd_banks[idx]) { | ||
167 | mtd_banks[idx]->owner = THIS_MODULE; | ||
168 | mtd_size += mtd_banks[idx]->size; | ||
169 | num_banks++; | ||
170 | pr_debug("%s: bank %ld, name: %s, size: %d bytes \n", | ||
171 | __FUNCTION__, num_banks, | ||
172 | mtd_banks[idx]->name, mtd_banks[idx]->size); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /* no supported flash chips found */ | ||
177 | if (!num_banks) { | ||
178 | printk("TQM834x: No supported flash chips found!\n"); | ||
179 | ret = -ENXIO; | ||
180 | goto error_mem; | ||
181 | } | ||
182 | |||
183 | #ifdef CONFIG_MTD_PARTITIONS | ||
184 | /* | ||
185 | * Select static partition definitions | ||
186 | */ | ||
187 | n = ARRAY_SIZE(tqm834x_partitions_bank1); | ||
188 | part_banks[0].mtd_part = tqm834x_partitions_bank1; | ||
189 | part_banks[0].type = "static image bank1"; | ||
190 | part_banks[0].nums = n; | ||
191 | |||
192 | /* update last partition size to cover actual remaining space */ | ||
193 | tqm834x_partitions_bank1[n - 1].size = | ||
194 | mtd_banks[0]->size - | ||
195 | tqm834x_partitions_bank1[n - 1].offset; | ||
196 | |||
197 | /* check if we have second bank? */ | ||
198 | if (num_banks == 2) { | ||
199 | n = ARRAY_SIZE(tqm834x_partitions_bank2); | ||
200 | part_banks[1].mtd_part = tqm834x_partitions_bank2; | ||
201 | part_banks[1].type = "static image bank2"; | ||
202 | part_banks[1].nums = n; | ||
203 | |||
204 | /* update last partition size to cover actual remaining space */ | ||
205 | tqm834x_partitions_bank2[n - 1].size = | ||
206 | mtd_banks[1]->size - | ||
207 | tqm834x_partitions_bank2[n - 1].offset; | ||
208 | } | ||
209 | |||
210 | for(idx = 0; idx < num_banks ; idx++) { | ||
211 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
212 | sprintf(mtdid, "%d", idx); | ||
213 | n = parse_mtd_partitions(mtd_banks[idx], | ||
214 | part_probes, | ||
215 | &part_banks[idx].mtd_part, | ||
216 | 0); | ||
217 | pr_debug("%s: %d command line partitions on bank %s\n", | ||
218 | __FUNCTION__, n, mtdid); | ||
219 | if (n > 0) { | ||
220 | part_banks[idx].type = "command line"; | ||
221 | part_banks[idx].nums = n; | ||
222 | } | ||
223 | #endif /* CONFIG_MTD_CMDLINE_PARTS */ | ||
224 | if (part_banks[idx].nums == 0) { | ||
225 | printk(KERN_NOTICE | ||
226 | "TQM834x flash bank %d: no partition info " | ||
227 | "available, registering whole device\n", idx); | ||
228 | add_mtd_device(mtd_banks[idx]); | ||
229 | } else { | ||
230 | printk(KERN_NOTICE | ||
231 | "TQM834x flash bank %d: Using %s partition " | ||
232 | "definition\n", idx, part_banks[idx].type); | ||
233 | add_mtd_partitions(mtd_banks[idx], | ||
234 | part_banks[idx].mtd_part, | ||
235 | part_banks[idx].nums); | ||
236 | } | ||
237 | } | ||
238 | #else /* ! CONFIG_MTD_PARTITIONS */ | ||
239 | printk(KERN_NOTICE "TQM834x flash: registering %d flash banks " | ||
240 | "at once\n", num_banks); | ||
241 | |||
242 | for(idx = 0 ; idx < num_banks ; idx++) | ||
243 | add_mtd_device(mtd_banks[idx]); | ||
244 | |||
245 | #endif /* CONFIG_MTD_PARTITIONS */ | ||
246 | |||
247 | return 0; | ||
248 | error_mem: | ||
249 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | ||
250 | if (map_banks[idx] != NULL) { | ||
251 | if (map_banks[idx]->name != NULL) { | ||
252 | kfree(map_banks[idx]->name); | ||
253 | map_banks[idx]->name = NULL; | ||
254 | } | ||
255 | kfree(map_banks[idx]); | ||
256 | map_banks[idx] = NULL; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | iounmap((void *)start_scan_addr); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static void __exit cleanup_tqm834x_mtd(void) | ||
266 | { | ||
267 | unsigned int idx = 0; | ||
268 | for(idx = 0 ; idx < num_banks ; idx++) { | ||
269 | /* destroy mtd_info previously allocated */ | ||
270 | if (mtd_banks[idx]) { | ||
271 | del_mtd_partitions(mtd_banks[idx]); | ||
272 | map_destroy(mtd_banks[idx]); | ||
273 | } | ||
274 | |||
275 | /* release map_info not used anymore */ | ||
276 | kfree(map_banks[idx]->name); | ||
277 | kfree(map_banks[idx]); | ||
278 | } | ||
279 | |||
280 | if (start_scan_addr) { | ||
281 | iounmap((void *)start_scan_addr); | ||
282 | start_scan_addr = 0; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | module_init(init_tqm834x_mtd); | ||
287 | module_exit(cleanup_tqm834x_mtd); | ||
288 | |||
289 | MODULE_LICENSE("GPL"); | ||
290 | MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>"); | ||
291 | MODULE_DESCRIPTION("MTD map driver for TQM834x boards"); | ||
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 0aca8179f27f..a43517053e7c 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c | |||
@@ -1,15 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * Handle mapping of the flash memory access routines | 2 | * Handle mapping of the flash memory access routines |
3 | * on TQM8xxL based devices. | 3 | * on TQM8xxL based devices. |
4 | * | 4 | * |
5 | * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $ | 5 | * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ |
6 | * | 6 | * |
7 | * based on rpxlite.c | 7 | * based on rpxlite.c |
8 | * | 8 | * |
9 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> | 9 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> |
10 | * | 10 | * |
11 | * This code is GPLed | 11 | * This code is GPLed |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* | 15 | /* |
@@ -19,7 +19,7 @@ | |||
19 | * 2MiB 512Kx16 2MiB 0 | 19 | * 2MiB 512Kx16 2MiB 0 |
20 | * 4MiB 1Mx16 4MiB 0 | 20 | * 4MiB 1Mx16 4MiB 0 |
21 | * 8MiB 1Mx16 4MiB 4MiB | 21 | * 8MiB 1Mx16 4MiB 4MiB |
22 | * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at | 22 | * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at |
23 | * kernel configuration. | 23 | * kernel configuration. |
24 | */ | 24 | */ |
25 | #include <linux/config.h> | 25 | #include <linux/config.h> |
@@ -58,9 +58,9 @@ static void __iomem *start_scan_addr; | |||
58 | * Here are partition information for all known TQM8xxL series devices. | 58 | * Here are partition information for all known TQM8xxL series devices. |
59 | * See include/linux/mtd/partitions.h for definition of the mtd_partition | 59 | * See include/linux/mtd/partitions.h for definition of the mtd_partition |
60 | * structure. | 60 | * structure. |
61 | * | 61 | * |
62 | * The *_max_flash_size is the maximum possible mapped flash size which | 62 | * The *_max_flash_size is the maximum possible mapped flash size which |
63 | * is not necessarily the actual flash size. It must correspond to the | 63 | * is not necessarily the actual flash size. It must correspond to the |
64 | * value specified in the mapping definition defined by the | 64 | * value specified in the mapping definition defined by the |
65 | * "struct map_desc *_io_desc" for the corresponding machine. | 65 | * "struct map_desc *_io_desc" for the corresponding machine. |
66 | */ | 66 | */ |
@@ -132,9 +132,9 @@ int __init init_tqm_mtd(void) | |||
132 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | 132 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { |
133 | if(mtd_size >= flash_size) | 133 | if(mtd_size >= flash_size) |
134 | break; | 134 | break; |
135 | 135 | ||
136 | printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); | 136 | printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); |
137 | 137 | ||
138 | map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); | 138 | map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); |
139 | if(map_banks[idx] == NULL) { | 139 | if(map_banks[idx] == NULL) { |
140 | ret = -ENOMEM; | 140 | ret = -ENOMEM; |
@@ -180,7 +180,7 @@ int __init init_tqm_mtd(void) | |||
180 | mtd_size += mtd_banks[idx]->size; | 180 | mtd_size += mtd_banks[idx]->size; |
181 | num_banks++; | 181 | num_banks++; |
182 | 182 | ||
183 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, | 183 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, |
184 | mtd_banks[idx]->name, mtd_banks[idx]->size); | 184 | mtd_banks[idx]->name, mtd_banks[idx]->size); |
185 | } | 185 | } |
186 | } | 186 | } |
@@ -211,7 +211,7 @@ int __init init_tqm_mtd(void) | |||
211 | } else { | 211 | } else { |
212 | printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", | 212 | printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", |
213 | idx, part_banks[idx].type); | 213 | idx, part_banks[idx].type); |
214 | add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, | 214 | add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, |
215 | part_banks[idx].nums); | 215 | part_banks[idx].nums); |
216 | } | 216 | } |
217 | } | 217 | } |
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index 3ebd90f56503..4b372bcb17f1 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c | |||
@@ -19,26 +19,22 @@ | |||
19 | * | 19 | * |
20 | * Note: | 20 | * Note: |
21 | * - In order for detection to work, jumper 3 must be set. | 21 | * - In order for detection to work, jumper 3 must be set. |
22 | * - Drive A and B use a proprietary FTL from General Software which isn't | 22 | * - Drive A and B use the resident flash disk (RFD) flash translation layer. |
23 | * supported as of yet so standard drives can't be mounted; you can create | 23 | * - If you have created your own jffs file system and the bios overwrites |
24 | * your own (e.g. jffs) file system. | ||
25 | * - If you have created your own jffs file system and the bios overwrites | ||
26 | * it during boot, try disabling Drive A: and B: in the boot order. | 24 | * it during boot, try disabling Drive A: and B: in the boot order. |
27 | * | 25 | * |
28 | * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $ | 26 | * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ |
29 | */ | 27 | */ |
30 | 28 | ||
31 | #include <linux/config.h> | 29 | #include <linux/config.h> |
30 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
33 | #include <linux/types.h> | ||
34 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
35 | #include <linux/init.h> | ||
36 | #include <linux/mtd/mtd.h> | ||
37 | #include <linux/mtd/map.h> | 33 | #include <linux/mtd/map.h> |
38 | 34 | #include <linux/mtd/mtd.h> | |
39 | #ifdef CONFIG_MTD_PARTITIONS | ||
40 | #include <linux/mtd/partitions.h> | 35 | #include <linux/mtd/partitions.h> |
41 | #endif | 36 | #include <linux/types.h> |
37 | |||
42 | 38 | ||
43 | #define WINDOW_ADDR 0x09400000 | 39 | #define WINDOW_ADDR 0x09400000 |
44 | #define WINDOW_SIZE 0x00200000 | 40 | #define WINDOW_SIZE 0x00200000 |
@@ -50,7 +46,6 @@ static struct map_info ts5500_map = { | |||
50 | .phys = WINDOW_ADDR | 46 | .phys = WINDOW_ADDR |
51 | }; | 47 | }; |
52 | 48 | ||
53 | #ifdef CONFIG_MTD_PARTITIONS | ||
54 | static struct mtd_partition ts5500_partitions[] = { | 49 | static struct mtd_partition ts5500_partitions[] = { |
55 | { | 50 | { |
56 | .name = "Drive A", | 51 | .name = "Drive A", |
@@ -71,8 +66,6 @@ static struct mtd_partition ts5500_partitions[] = { | |||
71 | 66 | ||
72 | #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) | 67 | #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) |
73 | 68 | ||
74 | #endif | ||
75 | |||
76 | static struct mtd_info *mymtd; | 69 | static struct mtd_info *mymtd; |
77 | 70 | ||
78 | static int __init init_ts5500_map(void) | 71 | static int __init init_ts5500_map(void) |
@@ -81,48 +74,39 @@ static int __init init_ts5500_map(void) | |||
81 | 74 | ||
82 | ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size); | 75 | ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size); |
83 | 76 | ||
84 | if(!ts5500_map.virt) { | 77 | if (!ts5500_map.virt) { |
85 | printk(KERN_ERR "Failed to ioremap_nocache\n"); | 78 | printk(KERN_ERR "Failed to ioremap_nocache\n"); |
86 | rc = -EIO; | 79 | rc = -EIO; |
87 | goto err_out_ioremap; | 80 | goto err2; |
88 | } | 81 | } |
89 | 82 | ||
90 | simple_map_init(&ts5500_map); | 83 | simple_map_init(&ts5500_map); |
91 | 84 | ||
92 | mymtd = do_map_probe("jedec_probe", &ts5500_map); | 85 | mymtd = do_map_probe("jedec_probe", &ts5500_map); |
93 | if(!mymtd) | 86 | if (!mymtd) |
94 | mymtd = do_map_probe("map_rom", &ts5500_map); | 87 | mymtd = do_map_probe("map_rom", &ts5500_map); |
95 | 88 | ||
96 | if(!mymtd) { | 89 | if (!mymtd) { |
97 | rc = -ENXIO; | 90 | rc = -ENXIO; |
98 | goto err_out_map; | 91 | goto err1; |
99 | } | 92 | } |
100 | 93 | ||
101 | mymtd->owner = THIS_MODULE; | 94 | mymtd->owner = THIS_MODULE; |
102 | #ifdef CONFIG_MTD_PARTITIONS | ||
103 | add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS); | 95 | add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS); |
104 | #else | ||
105 | add_mtd_device(mymtd); | ||
106 | #endif | ||
107 | 96 | ||
108 | return 0; | 97 | return 0; |
109 | 98 | ||
110 | err_out_map: | 99 | err1: |
111 | map_destroy(mymtd); | 100 | map_destroy(mymtd); |
112 | err_out_ioremap: | ||
113 | iounmap(ts5500_map.virt); | 101 | iounmap(ts5500_map.virt); |
114 | 102 | err2: | |
115 | return rc; | 103 | return rc; |
116 | } | 104 | } |
117 | 105 | ||
118 | static void __exit cleanup_ts5500_map(void) | 106 | static void __exit cleanup_ts5500_map(void) |
119 | { | 107 | { |
120 | if (mymtd) { | 108 | if (mymtd) { |
121 | #ifdef CONFIG_MTD_PARTITIONS | ||
122 | del_mtd_partitions(mymtd); | 109 | del_mtd_partitions(mymtd); |
123 | #else | ||
124 | del_mtd_device(mymtd); | ||
125 | #endif | ||
126 | map_destroy(mymtd); | 110 | map_destroy(mymtd); |
127 | } | 111 | } |
128 | 112 | ||
diff --git a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c index 170d71239e5e..9e21e6c02f80 100644 --- a/drivers/mtd/maps/tsunami_flash.c +++ b/drivers/mtd/maps/tsunami_flash.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * tsunami_flash.c | 2 | * tsunami_flash.c |
3 | * | 3 | * |
4 | * flash chip on alpha ds10... | 4 | * flash chip on alpha ds10... |
5 | * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $ | 5 | * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $ |
6 | */ | 6 | */ |
7 | #include <asm/io.h> | 7 | #include <asm/io.h> |
8 | #include <asm/core_tsunami.h> | 8 | #include <asm/core_tsunami.h> |
@@ -41,7 +41,7 @@ static void tsunami_flash_copy_from( | |||
41 | } | 41 | } |
42 | 42 | ||
43 | static void tsunami_flash_copy_to( | 43 | static void tsunami_flash_copy_to( |
44 | struct map_info *map, unsigned long offset, | 44 | struct map_info *map, unsigned long offset, |
45 | const void *addr, ssize_t len) | 45 | const void *addr, ssize_t len) |
46 | { | 46 | { |
47 | const unsigned char *src; | 47 | const unsigned char *src; |
@@ -90,7 +90,7 @@ static int __init init_tsunami_flash(void) | |||
90 | char **type; | 90 | char **type; |
91 | 91 | ||
92 | tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); | 92 | tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); |
93 | 93 | ||
94 | tsunami_flash_mtd = 0; | 94 | tsunami_flash_mtd = 0; |
95 | type = rom_probe_types; | 95 | type = rom_probe_types; |
96 | for(; !tsunami_flash_mtd && *type; type++) { | 96 | for(; !tsunami_flash_mtd && *type; type++) { |
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index cc372136e852..79d92808b766 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
7 | * | 7 | * |
8 | * $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $ | 8 | * $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | /****************************************************************************/ | 11 | /****************************************************************************/ |
@@ -82,7 +82,7 @@ int __init uclinux_mtd_init(void) | |||
82 | iounmap(mapp->virt); | 82 | iounmap(mapp->virt); |
83 | return(-ENXIO); | 83 | return(-ENXIO); |
84 | } | 84 | } |
85 | 85 | ||
86 | mtd->owner = THIS_MODULE; | 86 | mtd->owner = THIS_MODULE; |
87 | mtd->point = uclinux_point; | 87 | mtd->point = uclinux_point; |
88 | mtd->priv = mapp; | 88 | mtd->priv = mapp; |
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index c8c74110ed1b..e0063941c0df 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c | |||
@@ -1,19 +1,19 @@ | |||
1 | // $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $ | 1 | // $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $ |
2 | /* ###################################################################### | 2 | /* ###################################################################### |
3 | 3 | ||
4 | Tempustech VMAX SBC301 MTD Driver. | 4 | Tempustech VMAX SBC301 MTD Driver. |
5 | 5 | ||
6 | The VMAx 301 is a SBC based on . It | 6 | The VMAx 301 is a SBC based on . It |
7 | comes with three builtin AMD 29F016B flash chips and a socket for SRAM or | 7 | comes with three builtin AMD 29F016B flash chips and a socket for SRAM or |
8 | more flash. Each unit has it's own 8k mapping into a settable region | 8 | more flash. Each unit has it's own 8k mapping into a settable region |
9 | (0xD8000). There are two 8k mappings for each MTD, the first is always set | 9 | (0xD8000). There are two 8k mappings for each MTD, the first is always set |
10 | to the lower 8k of the device the second is paged. Writing a 16 bit page | 10 | to the lower 8k of the device the second is paged. Writing a 16 bit page |
11 | value to anywhere in the first 8k will cause the second 8k to page around. | 11 | value to anywhere in the first 8k will cause the second 8k to page around. |
12 | 12 | ||
13 | To boot the device a bios extension must be installed into the first 8k | 13 | To boot the device a bios extension must be installed into the first 8k |
14 | of flash that is smart enough to copy itself down, page in the rest of | 14 | of flash that is smart enough to copy itself down, page in the rest of |
15 | itself and begin executing. | 15 | itself and begin executing. |
16 | 16 | ||
17 | ##################################################################### */ | 17 | ##################################################################### */ |
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -35,7 +35,7 @@ | |||
35 | /* Actually we could use two spinlocks, but we'd have to have | 35 | /* Actually we could use two spinlocks, but we'd have to have |
36 | more private space in the struct map_info. We lose a little | 36 | more private space in the struct map_info. We lose a little |
37 | performance like this, but we'd probably lose more by having | 37 | performance like this, but we'd probably lose more by having |
38 | the extra indirection from having one of the map->map_priv | 38 | the extra indirection from having one of the map->map_priv |
39 | fields pointing to yet another private struct. | 39 | fields pointing to yet another private struct. |
40 | */ | 40 | */ |
41 | static DEFINE_SPINLOCK(vmax301_spin); | 41 | static DEFINE_SPINLOCK(vmax301_spin); |
@@ -98,7 +98,7 @@ static void vmax301_copy_to(struct map_info *map, unsigned long to, const void * | |||
98 | spin_lock(&vmax301_spin); | 98 | spin_lock(&vmax301_spin); |
99 | vmax301_page(map, to); | 99 | vmax301_page(map, to); |
100 | memcpy_toio(map->map_priv_2 + to, from, thislen); | 100 | memcpy_toio(map->map_priv_2 + to, from, thislen); |
101 | spin_unlock(&vmax301_spin); | 101 | spin_unlock(&vmax301_spin); |
102 | to += thislen; | 102 | to += thislen; |
103 | from += thislen; | 103 | from += thislen; |
104 | len -= thislen; | 104 | len -= thislen; |
@@ -137,7 +137,7 @@ static struct mtd_info *vmax_mtd[2] = {NULL, NULL}; | |||
137 | static void __exit cleanup_vmax301(void) | 137 | static void __exit cleanup_vmax301(void) |
138 | { | 138 | { |
139 | int i; | 139 | int i; |
140 | 140 | ||
141 | for (i=0; i<2; i++) { | 141 | for (i=0; i<2; i++) { |
142 | if (vmax_mtd[i]) { | 142 | if (vmax_mtd[i]) { |
143 | del_mtd_device(vmax_mtd[i]); | 143 | del_mtd_device(vmax_mtd[i]); |
@@ -161,13 +161,13 @@ int __init init_vmax301(void) | |||
161 | return -EIO; | 161 | return -EIO; |
162 | } | 162 | } |
163 | /* Put the address in the map's private data area. | 163 | /* Put the address in the map's private data area. |
164 | We store the actual MTD IO address rather than the | 164 | We store the actual MTD IO address rather than the |
165 | address of the first half, because it's used more | 165 | address of the first half, because it's used more |
166 | often. | 166 | often. |
167 | */ | 167 | */ |
168 | vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; | 168 | vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; |
169 | vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); | 169 | vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); |
170 | 170 | ||
171 | for (i=0; i<2; i++) { | 171 | for (i=0; i<2; i++) { |
172 | vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); | 172 | vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); |
173 | if (!vmax_mtd[i]) | 173 | if (!vmax_mtd[i]) |
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c index d6137b1b5670..5c17bca3a37e 100644 --- a/drivers/mtd/maps/walnut.c +++ b/drivers/mtd/maps/walnut.c | |||
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $ | 2 | * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for Walnut flash | 4 | * Mapping for Walnut flash |
5 | * (used ebony.c as a "framework") | 5 | * (used ebony.c as a "framework") |
6 | * | 6 | * |
7 | * Heikki Lindholm <holindho@infradead.org> | 7 | * Heikki Lindholm <holindho@infradead.org> |
8 | * | 8 | * |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -48,7 +48,7 @@ static struct mtd_partition walnut_partitions[] = { | |||
48 | .name = "OpenBIOS", | 48 | .name = "OpenBIOS", |
49 | .offset = 0x0, | 49 | .offset = 0x0, |
50 | .size = WALNUT_FLASH_SIZE, | 50 | .size = WALNUT_FLASH_SIZE, |
51 | /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ | 51 | /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ |
52 | } | 52 | } |
53 | }; | 53 | }; |
54 | 54 | ||
@@ -72,11 +72,11 @@ int __init init_walnut(void) | |||
72 | printk("The on-board flash is disabled (U79 sw 5)!"); | 72 | printk("The on-board flash is disabled (U79 sw 5)!"); |
73 | return -EIO; | 73 | return -EIO; |
74 | } | 74 | } |
75 | if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) | 75 | if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) |
76 | flash_base = WALNUT_FLASH_LOW; | 76 | flash_base = WALNUT_FLASH_LOW; |
77 | else | 77 | else |
78 | flash_base = WALNUT_FLASH_HIGH; | 78 | flash_base = WALNUT_FLASH_HIGH; |
79 | 79 | ||
80 | walnut_map.phys = flash_base; | 80 | walnut_map.phys = flash_base; |
81 | walnut_map.virt = | 81 | walnut_map.virt = |
82 | (void __iomem *)ioremap(flash_base, walnut_map.size); | 82 | (void __iomem *)ioremap(flash_base, walnut_map.size); |
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 82b887b05707..60c197ec455b 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: wr_sbc82xx_flash.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $ |
3 | * | 3 | * |
4 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. | 4 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. |
5 | * | 5 | * |
@@ -163,10 +163,10 @@ static void __exit cleanup_sbc82xx_flash(void) | |||
163 | del_mtd_partitions(sbcmtd[i]); | 163 | del_mtd_partitions(sbcmtd[i]); |
164 | else | 164 | else |
165 | del_mtd_device(sbcmtd[i]); | 165 | del_mtd_device(sbcmtd[i]); |
166 | 166 | ||
167 | kfree(sbcmtd_parts[i]); | 167 | kfree(sbcmtd_parts[i]); |
168 | map_destroy(sbcmtd[i]); | 168 | map_destroy(sbcmtd[i]); |
169 | 169 | ||
170 | iounmap((void *)sbc82xx_flash_map[i].virt); | 170 | iounmap((void *)sbc82xx_flash_map[i].virt); |
171 | sbc82xx_flash_map[i].virt = 0; | 171 | sbc82xx_flash_map[i].virt = 0; |
172 | } | 172 | } |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index f8d2185819e7..339cb1218eaa 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtd_blkdevs.c,v 1.24 2004/11/16 18:28:59 dwmw2 Exp $ | 2 | * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> | 4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> |
5 | * | 5 | * |
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <asm/semaphore.h> | 22 | #include <asm/semaphore.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <linux/devfs_fs_kernel.h> | ||
25 | 24 | ||
26 | static LIST_HEAD(blktrans_majors); | 25 | static LIST_HEAD(blktrans_majors); |
27 | 26 | ||
@@ -86,7 +85,7 @@ static int mtd_blktrans_thread(void *arg) | |||
86 | daemonize("%sd", tr->name); | 85 | daemonize("%sd", tr->name); |
87 | 86 | ||
88 | /* daemonize() doesn't do this for us since some kernel threads | 87 | /* daemonize() doesn't do this for us since some kernel threads |
89 | actually want to deal with signals. We can't just call | 88 | actually want to deal with signals. We can't just call |
90 | exit_sighand() since that'll cause an oops when we finally | 89 | exit_sighand() since that'll cause an oops when we finally |
91 | do exit. */ | 90 | do exit. */ |
92 | spin_lock_irq(¤t->sighand->siglock); | 91 | spin_lock_irq(¤t->sighand->siglock); |
@@ -95,7 +94,7 @@ static int mtd_blktrans_thread(void *arg) | |||
95 | spin_unlock_irq(¤t->sighand->siglock); | 94 | spin_unlock_irq(¤t->sighand->siglock); |
96 | 95 | ||
97 | spin_lock_irq(rq->queue_lock); | 96 | spin_lock_irq(rq->queue_lock); |
98 | 97 | ||
99 | while (!tr->blkcore_priv->exiting) { | 98 | while (!tr->blkcore_priv->exiting) { |
100 | struct request *req; | 99 | struct request *req; |
101 | struct mtd_blktrans_dev *dev; | 100 | struct mtd_blktrans_dev *dev; |
@@ -158,7 +157,7 @@ static int blktrans_open(struct inode *i, struct file *f) | |||
158 | if (!try_module_get(tr->owner)) | 157 | if (!try_module_get(tr->owner)) |
159 | goto out_tr; | 158 | goto out_tr; |
160 | 159 | ||
161 | /* FIXME: Locking. A hot pluggable device can go away | 160 | /* FIXME: Locking. A hot pluggable device can go away |
162 | (del_mtd_device can be called for it) without its module | 161 | (del_mtd_device can be called for it) without its module |
163 | being unloaded. */ | 162 | being unloaded. */ |
164 | dev->mtd->usecount++; | 163 | dev->mtd->usecount++; |
@@ -196,7 +195,7 @@ static int blktrans_release(struct inode *i, struct file *f) | |||
196 | } | 195 | } |
197 | 196 | ||
198 | 197 | ||
199 | static int blktrans_ioctl(struct inode *inode, struct file *file, | 198 | static int blktrans_ioctl(struct inode *inode, struct file *file, |
200 | unsigned int cmd, unsigned long arg) | 199 | unsigned int cmd, unsigned long arg) |
201 | { | 200 | { |
202 | struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; | 201 | struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; |
@@ -265,7 +264,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
265 | /* Required number was free */ | 264 | /* Required number was free */ |
266 | list_add_tail(&new->list, &d->list); | 265 | list_add_tail(&new->list, &d->list); |
267 | goto added; | 266 | goto added; |
268 | } | 267 | } |
269 | last_devnum = d->devnum; | 268 | last_devnum = d->devnum; |
270 | } | 269 | } |
271 | if (new->devnum == -1) | 270 | if (new->devnum == -1) |
@@ -289,11 +288,19 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
289 | gd->major = tr->major; | 288 | gd->major = tr->major; |
290 | gd->first_minor = (new->devnum) << tr->part_bits; | 289 | gd->first_minor = (new->devnum) << tr->part_bits; |
291 | gd->fops = &mtd_blktrans_ops; | 290 | gd->fops = &mtd_blktrans_ops; |
292 | 291 | ||
293 | snprintf(gd->disk_name, sizeof(gd->disk_name), | 292 | if (tr->part_bits) |
294 | "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); | 293 | if (new->devnum < 26) |
295 | snprintf(gd->devfs_name, sizeof(gd->devfs_name), | 294 | snprintf(gd->disk_name, sizeof(gd->disk_name), |
296 | "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); | 295 | "%s%c", tr->name, 'a' + new->devnum); |
296 | else | ||
297 | snprintf(gd->disk_name, sizeof(gd->disk_name), | ||
298 | "%s%c%c", tr->name, | ||
299 | 'a' - 1 + new->devnum / 26, | ||
300 | 'a' + new->devnum % 26); | ||
301 | else | ||
302 | snprintf(gd->disk_name, sizeof(gd->disk_name), | ||
303 | "%s%d", tr->name, new->devnum); | ||
297 | 304 | ||
298 | /* 2.5 has capacity in units of 512 bytes while still | 305 | /* 2.5 has capacity in units of 512 bytes while still |
299 | having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ | 306 | having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ |
@@ -307,7 +314,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
307 | set_disk_ro(gd, 1); | 314 | set_disk_ro(gd, 1); |
308 | 315 | ||
309 | add_disk(gd); | 316 | add_disk(gd); |
310 | 317 | ||
311 | return 0; | 318 | return 0; |
312 | } | 319 | } |
313 | 320 | ||
@@ -322,7 +329,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
322 | 329 | ||
323 | del_gendisk(old->blkcore_priv); | 330 | del_gendisk(old->blkcore_priv); |
324 | put_disk(old->blkcore_priv); | 331 | put_disk(old->blkcore_priv); |
325 | 332 | ||
326 | return 0; | 333 | return 0; |
327 | } | 334 | } |
328 | 335 | ||
@@ -361,12 +368,12 @@ static struct mtd_notifier blktrans_notifier = { | |||
361 | .add = blktrans_notify_add, | 368 | .add = blktrans_notify_add, |
362 | .remove = blktrans_notify_remove, | 369 | .remove = blktrans_notify_remove, |
363 | }; | 370 | }; |
364 | 371 | ||
365 | int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | 372 | int register_mtd_blktrans(struct mtd_blktrans_ops *tr) |
366 | { | 373 | { |
367 | int ret, i; | 374 | int ret, i; |
368 | 375 | ||
369 | /* Register the notifier if/when the first device type is | 376 | /* Register the notifier if/when the first device type is |
370 | registered, to prevent the link/init ordering from fucking | 377 | registered, to prevent the link/init ordering from fucking |
371 | us over. */ | 378 | us over. */ |
372 | if (!blktrans_notifier.list.next) | 379 | if (!blktrans_notifier.list.next) |
@@ -409,9 +416,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
409 | kfree(tr->blkcore_priv); | 416 | kfree(tr->blkcore_priv); |
410 | up(&mtd_table_mutex); | 417 | up(&mtd_table_mutex); |
411 | return ret; | 418 | return ret; |
412 | } | 419 | } |
413 | |||
414 | devfs_mk_dir(tr->name); | ||
415 | 420 | ||
416 | INIT_LIST_HEAD(&tr->devs); | 421 | INIT_LIST_HEAD(&tr->devs); |
417 | list_add(&tr->list, &blktrans_majors); | 422 | list_add(&tr->list, &blktrans_majors); |
@@ -445,7 +450,6 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
445 | tr->remove_dev(dev); | 450 | tr->remove_dev(dev); |
446 | } | 451 | } |
447 | 452 | ||
448 | devfs_remove(tr->name); | ||
449 | blk_cleanup_queue(tr->blkcore_priv->rq); | 453 | blk_cleanup_queue(tr->blkcore_priv->rq); |
450 | unregister_blkdev(tr->major, tr->name); | 454 | unregister_blkdev(tr->major, tr->name); |
451 | 455 | ||
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 400dd9c89883..e84756644fd1 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c | |||
@@ -1,21 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * Direct MTD block device access | 2 | * Direct MTD block device access |
3 | * | 3 | * |
4 | * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $ | 4 | * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ |
5 | * | 5 | * |
6 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> | 6 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> |
7 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> | 7 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/types.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
15 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/types.h> | ||
17 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
18 | #include <linux/sched.h> /* TASK_* */ | 19 | |
19 | #include <linux/mtd/mtd.h> | 20 | #include <linux/mtd/mtd.h> |
20 | #include <linux/mtd/blktrans.h> | 21 | #include <linux/mtd/blktrans.h> |
21 | 22 | ||
@@ -31,7 +32,7 @@ static struct mtdblk_dev { | |||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Cache stuff... | 34 | * Cache stuff... |
34 | * | 35 | * |
35 | * Since typical flash erasable sectors are much larger than what Linux's | 36 | * Since typical flash erasable sectors are much larger than what Linux's |
36 | * buffer cache can handle, we must implement read-modify-write on flash | 37 | * buffer cache can handle, we must implement read-modify-write on flash |
37 | * sectors for each block write requests. To avoid over-erasing flash sectors | 38 | * sectors for each block write requests. To avoid over-erasing flash sectors |
@@ -45,7 +46,7 @@ static void erase_callback(struct erase_info *done) | |||
45 | wake_up(wait_q); | 46 | wake_up(wait_q); |
46 | } | 47 | } |
47 | 48 | ||
48 | static int erase_write (struct mtd_info *mtd, unsigned long pos, | 49 | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
49 | int len, const char *buf) | 50 | int len, const char *buf) |
50 | { | 51 | { |
51 | struct erase_info erase; | 52 | struct erase_info erase; |
@@ -103,18 +104,18 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) | |||
103 | return 0; | 104 | return 0; |
104 | 105 | ||
105 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " | 106 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " |
106 | "at 0x%lx, size 0x%x\n", mtd->name, | 107 | "at 0x%lx, size 0x%x\n", mtd->name, |
107 | mtdblk->cache_offset, mtdblk->cache_size); | 108 | mtdblk->cache_offset, mtdblk->cache_size); |
108 | 109 | ||
109 | ret = erase_write (mtd, mtdblk->cache_offset, | 110 | ret = erase_write (mtd, mtdblk->cache_offset, |
110 | mtdblk->cache_size, mtdblk->cache_data); | 111 | mtdblk->cache_size, mtdblk->cache_data); |
111 | if (ret) | 112 | if (ret) |
112 | return ret; | 113 | return ret; |
113 | 114 | ||
114 | /* | 115 | /* |
115 | * Here we could argubly set the cache state to STATE_CLEAN. | 116 | * Here we could argubly set the cache state to STATE_CLEAN. |
116 | * However this could lead to inconsistency since we will not | 117 | * However this could lead to inconsistency since we will not |
117 | * be notified if this content is altered on the flash by other | 118 | * be notified if this content is altered on the flash by other |
118 | * means. Let's declare it empty and leave buffering tasks to | 119 | * means. Let's declare it empty and leave buffering tasks to |
119 | * the buffer cache instead. | 120 | * the buffer cache instead. |
120 | */ | 121 | */ |
@@ -123,7 +124,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | 126 | ||
126 | static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | 127 | static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, |
127 | int len, const char *buf) | 128 | int len, const char *buf) |
128 | { | 129 | { |
129 | struct mtd_info *mtd = mtdblk->mtd; | 130 | struct mtd_info *mtd = mtdblk->mtd; |
@@ -133,7 +134,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
133 | 134 | ||
134 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", | 135 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", |
135 | mtd->name, pos, len); | 136 | mtd->name, pos, len); |
136 | 137 | ||
137 | if (!sect_size) | 138 | if (!sect_size) |
138 | return MTD_WRITE (mtd, pos, len, &retlen, buf); | 139 | return MTD_WRITE (mtd, pos, len, &retlen, buf); |
139 | 140 | ||
@@ -141,11 +142,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
141 | unsigned long sect_start = (pos/sect_size)*sect_size; | 142 | unsigned long sect_start = (pos/sect_size)*sect_size; |
142 | unsigned int offset = pos - sect_start; | 143 | unsigned int offset = pos - sect_start; |
143 | unsigned int size = sect_size - offset; | 144 | unsigned int size = sect_size - offset; |
144 | if( size > len ) | 145 | if( size > len ) |
145 | size = len; | 146 | size = len; |
146 | 147 | ||
147 | if (size == sect_size) { | 148 | if (size == sect_size) { |
148 | /* | 149 | /* |
149 | * We are covering a whole sector. Thus there is no | 150 | * We are covering a whole sector. Thus there is no |
150 | * need to bother with the cache while it may still be | 151 | * need to bother with the cache while it may still be |
151 | * useful for other partial writes. | 152 | * useful for other partial writes. |
@@ -159,7 +160,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
159 | if (mtdblk->cache_state == STATE_DIRTY && | 160 | if (mtdblk->cache_state == STATE_DIRTY && |
160 | mtdblk->cache_offset != sect_start) { | 161 | mtdblk->cache_offset != sect_start) { |
161 | ret = write_cached_data(mtdblk); | 162 | ret = write_cached_data(mtdblk); |
162 | if (ret) | 163 | if (ret) |
163 | return ret; | 164 | return ret; |
164 | } | 165 | } |
165 | 166 | ||
@@ -192,7 +193,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
192 | } | 193 | } |
193 | 194 | ||
194 | 195 | ||
195 | static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | 196 | static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, |
196 | int len, char *buf) | 197 | int len, char *buf) |
197 | { | 198 | { |
198 | struct mtd_info *mtd = mtdblk->mtd; | 199 | struct mtd_info *mtd = mtdblk->mtd; |
@@ -200,9 +201,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
200 | size_t retlen; | 201 | size_t retlen; |
201 | int ret; | 202 | int ret; |
202 | 203 | ||
203 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", | 204 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", |
204 | mtd->name, pos, len); | 205 | mtd->name, pos, len); |
205 | 206 | ||
206 | if (!sect_size) | 207 | if (!sect_size) |
207 | return MTD_READ (mtd, pos, len, &retlen, buf); | 208 | return MTD_READ (mtd, pos, len, &retlen, buf); |
208 | 209 | ||
@@ -210,7 +211,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
210 | unsigned long sect_start = (pos/sect_size)*sect_size; | 211 | unsigned long sect_start = (pos/sect_size)*sect_size; |
211 | unsigned int offset = pos - sect_start; | 212 | unsigned int offset = pos - sect_start; |
212 | unsigned int size = sect_size - offset; | 213 | unsigned int size = sect_size - offset; |
213 | if (size > len) | 214 | if (size > len) |
214 | size = len; | 215 | size = len; |
215 | 216 | ||
216 | /* | 217 | /* |
@@ -268,12 +269,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) | |||
268 | int dev = mbd->devnum; | 269 | int dev = mbd->devnum; |
269 | 270 | ||
270 | DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); | 271 | DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); |
271 | 272 | ||
272 | if (mtdblks[dev]) { | 273 | if (mtdblks[dev]) { |
273 | mtdblks[dev]->count++; | 274 | mtdblks[dev]->count++; |
274 | return 0; | 275 | return 0; |
275 | } | 276 | } |
276 | 277 | ||
277 | /* OK, it's not open. Create cache info for it */ | 278 | /* OK, it's not open. Create cache info for it */ |
278 | mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); | 279 | mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); |
279 | if (!mtdblk) | 280 | if (!mtdblk) |
@@ -292,7 +293,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) | |||
292 | } | 293 | } |
293 | 294 | ||
294 | mtdblks[dev] = mtdblk; | 295 | mtdblks[dev] = mtdblk; |
295 | 296 | ||
296 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); | 297 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); |
297 | 298 | ||
298 | return 0; | 299 | return 0; |
@@ -320,7 +321,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) | |||
320 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); | 321 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); |
321 | 322 | ||
322 | return 0; | 323 | return 0; |
323 | } | 324 | } |
324 | 325 | ||
325 | static int mtdblock_flush(struct mtd_blktrans_dev *dev) | 326 | static int mtdblock_flush(struct mtd_blktrans_dev *dev) |
326 | { | 327 | { |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 16df1e4fb0e9..6f044584bdc6 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -1,22 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $ | 2 | * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * Character-device access to raw MTD devices. | 4 | * Character-device access to raw MTD devices. |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/device.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/slab.h> | ||
15 | #include <linux/sched.h> | ||
16 | |||
11 | #include <linux/mtd/mtd.h> | 17 | #include <linux/mtd/mtd.h> |
12 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/sched.h> /* TASK_* */ | ||
17 | #include <asm/uaccess.h> | ||
18 | 19 | ||
19 | #include <linux/device.h> | 20 | #include <asm/uaccess.h> |
20 | 21 | ||
21 | static struct class *mtd_class; | 22 | static struct class *mtd_class; |
22 | 23 | ||
@@ -27,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd) | |||
27 | 28 | ||
28 | class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), | 29 | class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), |
29 | NULL, "mtd%d", mtd->index); | 30 | NULL, "mtd%d", mtd->index); |
30 | 31 | ||
31 | class_device_create(mtd_class, NULL, | 32 | class_device_create(mtd_class, NULL, |
32 | MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), | 33 | MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), |
33 | NULL, "mtd%dro", mtd->index); | 34 | NULL, "mtd%dro", mtd->index); |
@@ -70,26 +71,23 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) | |||
70 | switch (orig) { | 71 | switch (orig) { |
71 | case 0: | 72 | case 0: |
72 | /* SEEK_SET */ | 73 | /* SEEK_SET */ |
73 | file->f_pos = offset; | ||
74 | break; | 74 | break; |
75 | case 1: | 75 | case 1: |
76 | /* SEEK_CUR */ | 76 | /* SEEK_CUR */ |
77 | file->f_pos += offset; | 77 | offset += file->f_pos; |
78 | break; | 78 | break; |
79 | case 2: | 79 | case 2: |
80 | /* SEEK_END */ | 80 | /* SEEK_END */ |
81 | file->f_pos =mtd->size + offset; | 81 | offset += mtd->size; |
82 | break; | 82 | break; |
83 | default: | 83 | default: |
84 | return -EINVAL; | 84 | return -EINVAL; |
85 | } | 85 | } |
86 | 86 | ||
87 | if (file->f_pos < 0) | 87 | if (offset >= 0 && offset < mtd->size) |
88 | file->f_pos = 0; | 88 | return file->f_pos = offset; |
89 | else if (file->f_pos >= mtd->size) | ||
90 | file->f_pos = mtd->size - 1; | ||
91 | 89 | ||
92 | return file->f_pos; | 90 | return -EINVAL; |
93 | } | 91 | } |
94 | 92 | ||
95 | 93 | ||
@@ -110,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file) | |||
110 | return -EACCES; | 108 | return -EACCES; |
111 | 109 | ||
112 | mtd = get_mtd_device(NULL, devnum); | 110 | mtd = get_mtd_device(NULL, devnum); |
113 | 111 | ||
114 | if (!mtd) | 112 | if (!mtd) |
115 | return -ENODEV; | 113 | return -ENODEV; |
116 | 114 | ||
117 | if (MTD_ABSENT == mtd->type) { | 115 | if (MTD_ABSENT == mtd->type) { |
118 | put_mtd_device(mtd); | 116 | put_mtd_device(mtd); |
119 | return -ENODEV; | 117 | return -ENODEV; |
120 | } | 118 | } |
121 | 119 | ||
122 | file->private_data = mtd; | 120 | file->private_data = mtd; |
123 | 121 | ||
124 | /* You can't open it RW if it's not a writeable device */ | 122 | /* You can't open it RW if it's not a writeable device */ |
125 | if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { | 123 | if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { |
126 | put_mtd_device(mtd); | 124 | put_mtd_device(mtd); |
127 | return -EACCES; | 125 | return -EACCES; |
128 | } | 126 | } |
129 | 127 | ||
130 | return 0; | 128 | return 0; |
131 | } /* mtd_open */ | 129 | } /* mtd_open */ |
132 | 130 | ||
@@ -139,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file) | |||
139 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); | 137 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); |
140 | 138 | ||
141 | mtd = TO_MTD(file); | 139 | mtd = TO_MTD(file); |
142 | 140 | ||
143 | if (mtd->sync) | 141 | if (mtd->sync) |
144 | mtd->sync(mtd); | 142 | mtd->sync(mtd); |
145 | 143 | ||
146 | put_mtd_device(mtd); | 144 | put_mtd_device(mtd); |
147 | 145 | ||
148 | return 0; | 146 | return 0; |
@@ -161,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
161 | int ret=0; | 159 | int ret=0; |
162 | int len; | 160 | int len; |
163 | char *kbuf; | 161 | char *kbuf; |
164 | 162 | ||
165 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); | 163 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); |
166 | 164 | ||
167 | if (*ppos + count > mtd->size) | 165 | if (*ppos + count > mtd->size) |
@@ -169,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
169 | 167 | ||
170 | if (!count) | 168 | if (!count) |
171 | return 0; | 169 | return 0; |
172 | 170 | ||
173 | /* FIXME: Use kiovec in 2.5 to lock down the user's buffers | 171 | /* FIXME: Use kiovec in 2.5 to lock down the user's buffers |
174 | and pass them directly to the MTD functions */ | 172 | and pass them directly to the MTD functions */ |
175 | while (count) { | 173 | while (count) { |
176 | if (count > MAX_KMALLOC_SIZE) | 174 | if (count > MAX_KMALLOC_SIZE) |
177 | len = MAX_KMALLOC_SIZE; | 175 | len = MAX_KMALLOC_SIZE; |
178 | else | 176 | else |
179 | len = count; | 177 | len = count; |
@@ -181,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
181 | kbuf=kmalloc(len,GFP_KERNEL); | 179 | kbuf=kmalloc(len,GFP_KERNEL); |
182 | if (!kbuf) | 180 | if (!kbuf) |
183 | return -ENOMEM; | 181 | return -ENOMEM; |
184 | 182 | ||
185 | switch (MTD_MODE(file)) { | 183 | switch (MTD_MODE(file)) { |
186 | case MTD_MODE_OTP_FACT: | 184 | case MTD_MODE_OTP_FACT: |
187 | ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); | 185 | ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); |
@@ -194,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
194 | } | 192 | } |
195 | /* Nand returns -EBADMSG on ecc errors, but it returns | 193 | /* Nand returns -EBADMSG on ecc errors, but it returns |
196 | * the data. For our userspace tools it is important | 194 | * the data. For our userspace tools it is important |
197 | * to dump areas with ecc errors ! | 195 | * to dump areas with ecc errors ! |
198 | * Userspace software which accesses NAND this way | 196 | * Userspace software which accesses NAND this way |
199 | * must be aware of the fact that it deals with NAND | 197 | * must be aware of the fact that it deals with NAND |
200 | */ | 198 | */ |
@@ -216,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
216 | kfree(kbuf); | 214 | kfree(kbuf); |
217 | return ret; | 215 | return ret; |
218 | } | 216 | } |
219 | 217 | ||
220 | kfree(kbuf); | 218 | kfree(kbuf); |
221 | } | 219 | } |
222 | 220 | ||
@@ -233,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
233 | int len; | 231 | int len; |
234 | 232 | ||
235 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); | 233 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); |
236 | 234 | ||
237 | if (*ppos == mtd->size) | 235 | if (*ppos == mtd->size) |
238 | return -ENOSPC; | 236 | return -ENOSPC; |
239 | 237 | ||
240 | if (*ppos + count > mtd->size) | 238 | if (*ppos + count > mtd->size) |
241 | count = mtd->size - *ppos; | 239 | count = mtd->size - *ppos; |
242 | 240 | ||
@@ -244,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
244 | return 0; | 242 | return 0; |
245 | 243 | ||
246 | while (count) { | 244 | while (count) { |
247 | if (count > MAX_KMALLOC_SIZE) | 245 | if (count > MAX_KMALLOC_SIZE) |
248 | len = MAX_KMALLOC_SIZE; | 246 | len = MAX_KMALLOC_SIZE; |
249 | else | 247 | else |
250 | len = count; | 248 | len = count; |
@@ -259,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
259 | kfree(kbuf); | 257 | kfree(kbuf); |
260 | return -EFAULT; | 258 | return -EFAULT; |
261 | } | 259 | } |
262 | 260 | ||
263 | switch (MTD_MODE(file)) { | 261 | switch (MTD_MODE(file)) { |
264 | case MTD_MODE_OTP_FACT: | 262 | case MTD_MODE_OTP_FACT: |
265 | ret = -EROFS; | 263 | ret = -EROFS; |
@@ -284,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
284 | kfree(kbuf); | 282 | kfree(kbuf); |
285 | return ret; | 283 | return ret; |
286 | } | 284 | } |
287 | 285 | ||
288 | kfree(kbuf); | 286 | kfree(kbuf); |
289 | } | 287 | } |
290 | 288 | ||
@@ -308,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
308 | void __user *argp = (void __user *)arg; | 306 | void __user *argp = (void __user *)arg; |
309 | int ret = 0; | 307 | int ret = 0; |
310 | u_long size; | 308 | u_long size; |
311 | 309 | ||
312 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); | 310 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); |
313 | 311 | ||
314 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; | 312 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; |
@@ -320,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
320 | if (!access_ok(VERIFY_WRITE, argp, size)) | 318 | if (!access_ok(VERIFY_WRITE, argp, size)) |
321 | return -EFAULT; | 319 | return -EFAULT; |
322 | } | 320 | } |
323 | 321 | ||
324 | switch (cmd) { | 322 | switch (cmd) { |
325 | case MEMGETREGIONCOUNT: | 323 | case MEMGETREGIONCOUNT: |
326 | if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) | 324 | if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) |
@@ -372,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
372 | erase->mtd = mtd; | 370 | erase->mtd = mtd; |
373 | erase->callback = mtdchar_erase_callback; | 371 | erase->callback = mtdchar_erase_callback; |
374 | erase->priv = (unsigned long)&waitq; | 372 | erase->priv = (unsigned long)&waitq; |
375 | 373 | ||
376 | /* | 374 | /* |
377 | FIXME: Allow INTERRUPTIBLE. Which means | 375 | FIXME: Allow INTERRUPTIBLE. Which means |
378 | not having the wait_queue head on the stack. | 376 | not having the wait_queue head on the stack. |
379 | 377 | ||
380 | If the wq_head is on the stack, and we | 378 | If the wq_head is on the stack, and we |
381 | leave because we got interrupted, then the | 379 | leave because we got interrupted, then the |
382 | wq_head is no longer there when the | 380 | wq_head is no longer there when the |
@@ -404,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
404 | struct mtd_oob_buf buf; | 402 | struct mtd_oob_buf buf; |
405 | void *databuf; | 403 | void *databuf; |
406 | ssize_t retlen; | 404 | ssize_t retlen; |
407 | 405 | ||
408 | if(!(file->f_mode & 2)) | 406 | if(!(file->f_mode & 2)) |
409 | return -EPERM; | 407 | return -EPERM; |
410 | 408 | ||
411 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 409 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
412 | return -EFAULT; | 410 | return -EFAULT; |
413 | 411 | ||
414 | if (buf.length > 0x4096) | 412 | if (buf.length > 0x4096) |
415 | return -EINVAL; | 413 | return -EINVAL; |
416 | 414 | ||
@@ -426,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
426 | databuf = kmalloc(buf.length, GFP_KERNEL); | 424 | databuf = kmalloc(buf.length, GFP_KERNEL); |
427 | if (!databuf) | 425 | if (!databuf) |
428 | return -ENOMEM; | 426 | return -ENOMEM; |
429 | 427 | ||
430 | if (copy_from_user(databuf, buf.ptr, buf.length)) { | 428 | if (copy_from_user(databuf, buf.ptr, buf.length)) { |
431 | kfree(databuf); | 429 | kfree(databuf); |
432 | return -EFAULT; | 430 | return -EFAULT; |
@@ -450,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
450 | 448 | ||
451 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 449 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
452 | return -EFAULT; | 450 | return -EFAULT; |
453 | 451 | ||
454 | if (buf.length > 0x4096) | 452 | if (buf.length > 0x4096) |
455 | return -EINVAL; | 453 | return -EINVAL; |
456 | 454 | ||
@@ -466,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
466 | databuf = kmalloc(buf.length, GFP_KERNEL); | 464 | databuf = kmalloc(buf.length, GFP_KERNEL); |
467 | if (!databuf) | 465 | if (!databuf) |
468 | return -ENOMEM; | 466 | return -ENOMEM; |
469 | 467 | ||
470 | ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); | 468 | ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); |
471 | 469 | ||
472 | if (put_user(retlen, (uint32_t __user *)argp)) | 470 | if (put_user(retlen, (uint32_t __user *)argp)) |
473 | ret = -EFAULT; | 471 | ret = -EFAULT; |
474 | else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) | 472 | else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) |
475 | ret = -EFAULT; | 473 | ret = -EFAULT; |
476 | 474 | ||
477 | kfree(databuf); | 475 | kfree(databuf); |
478 | break; | 476 | break; |
479 | } | 477 | } |
@@ -523,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
523 | case MEMGETBADBLOCK: | 521 | case MEMGETBADBLOCK: |
524 | { | 522 | { |
525 | loff_t offs; | 523 | loff_t offs; |
526 | 524 | ||
527 | if (copy_from_user(&offs, argp, sizeof(loff_t))) | 525 | if (copy_from_user(&offs, argp, sizeof(loff_t))) |
528 | return -EFAULT; | 526 | return -EFAULT; |
529 | if (!mtd->block_isbad) | 527 | if (!mtd->block_isbad) |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index f3e65af33a9c..b1bf8c411de7 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -7,14 +7,15 @@ | |||
7 | * | 7 | * |
8 | * This code is GPL | 8 | * This code is GPL |
9 | * | 9 | * |
10 | * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $ | 10 | * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
17 | #include <linux/sched.h> /* TASK_* */ | 16 | #include <linux/sched.h> |
17 | #include <linux/types.h> | ||
18 | |||
18 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
19 | #include <linux/mtd/concat.h> | 20 | #include <linux/mtd/concat.h> |
20 | 21 | ||
@@ -43,7 +44,7 @@ struct mtd_concat { | |||
43 | */ | 44 | */ |
44 | #define CONCAT(x) ((struct mtd_concat *)(x)) | 45 | #define CONCAT(x) ((struct mtd_concat *)(x)) |
45 | 46 | ||
46 | /* | 47 | /* |
47 | * MTD methods which look up the relevant subdevice, translate the | 48 | * MTD methods which look up the relevant subdevice, translate the |
48 | * effective address and pass through to the subdevice. | 49 | * effective address and pass through to the subdevice. |
49 | */ | 50 | */ |
@@ -877,7 +878,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
877 | return &concat->mtd; | 878 | return &concat->mtd; |
878 | } | 879 | } |
879 | 880 | ||
880 | /* | 881 | /* |
881 | * This function destroys an MTD object obtained from concat_mtd_devs() | 882 | * This function destroys an MTD object obtained from concat_mtd_devs() |
882 | */ | 883 | */ |
883 | 884 | ||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index dc86df18e94b..dade02ab0687 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $ | 2 | * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * Core registration and callback routines for MTD | 4 | * Core registration and callback routines for MTD |
5 | * drivers and users. | 5 | * drivers and users. |
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/mtd/mtd.h> | 26 | #include <linux/mtd/mtd.h> |
27 | 27 | ||
28 | /* These are exported solely for the purpose of mtd_blkdevs.c. You | 28 | /* These are exported solely for the purpose of mtd_blkdevs.c. You |
29 | should not use them for _anything_ else */ | 29 | should not use them for _anything_ else */ |
30 | DECLARE_MUTEX(mtd_table_mutex); | 30 | DECLARE_MUTEX(mtd_table_mutex); |
31 | struct mtd_info *mtd_table[MAX_MTD_DEVICES]; | 31 | struct mtd_info *mtd_table[MAX_MTD_DEVICES]; |
@@ -66,7 +66,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
66 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); | 66 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); |
67 | not->add(mtd); | 67 | not->add(mtd); |
68 | } | 68 | } |
69 | 69 | ||
70 | up(&mtd_table_mutex); | 70 | up(&mtd_table_mutex); |
71 | /* We _know_ we aren't being removed, because | 71 | /* We _know_ we aren't being removed, because |
72 | our caller is still holding us here. So none | 72 | our caller is still holding us here. So none |
@@ -75,7 +75,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
75 | __module_get(THIS_MODULE); | 75 | __module_get(THIS_MODULE); |
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | up(&mtd_table_mutex); | 79 | up(&mtd_table_mutex); |
80 | return 1; | 80 | return 1; |
81 | } | 81 | } |
@@ -93,13 +93,13 @@ int add_mtd_device(struct mtd_info *mtd) | |||
93 | int del_mtd_device (struct mtd_info *mtd) | 93 | int del_mtd_device (struct mtd_info *mtd) |
94 | { | 94 | { |
95 | int ret; | 95 | int ret; |
96 | 96 | ||
97 | down(&mtd_table_mutex); | 97 | down(&mtd_table_mutex); |
98 | 98 | ||
99 | if (mtd_table[mtd->index] != mtd) { | 99 | if (mtd_table[mtd->index] != mtd) { |
100 | ret = -ENODEV; | 100 | ret = -ENODEV; |
101 | } else if (mtd->usecount) { | 101 | } else if (mtd->usecount) { |
102 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", | 102 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", |
103 | mtd->index, mtd->name, mtd->usecount); | 103 | mtd->index, mtd->name, mtd->usecount); |
104 | ret = -EBUSY; | 104 | ret = -EBUSY; |
105 | } else { | 105 | } else { |
@@ -140,7 +140,7 @@ void register_mtd_user (struct mtd_notifier *new) | |||
140 | list_add(&new->list, &mtd_notifiers); | 140 | list_add(&new->list, &mtd_notifiers); |
141 | 141 | ||
142 | __module_get(THIS_MODULE); | 142 | __module_get(THIS_MODULE); |
143 | 143 | ||
144 | for (i=0; i< MAX_MTD_DEVICES; i++) | 144 | for (i=0; i< MAX_MTD_DEVICES; i++) |
145 | if (mtd_table[i]) | 145 | if (mtd_table[i]) |
146 | new->add(mtd_table[i]); | 146 | new->add(mtd_table[i]); |
@@ -169,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old) | |||
169 | for (i=0; i< MAX_MTD_DEVICES; i++) | 169 | for (i=0; i< MAX_MTD_DEVICES; i++) |
170 | if (mtd_table[i]) | 170 | if (mtd_table[i]) |
171 | old->remove(mtd_table[i]); | 171 | old->remove(mtd_table[i]); |
172 | 172 | ||
173 | list_del(&old->list); | 173 | list_del(&old->list); |
174 | up(&mtd_table_mutex); | 174 | up(&mtd_table_mutex); |
175 | return 0; | 175 | return 0; |
@@ -187,7 +187,7 @@ int unregister_mtd_user (struct mtd_notifier *old) | |||
187 | * both, return the num'th driver only if its address matches. Return NULL | 187 | * both, return the num'th driver only if its address matches. Return NULL |
188 | * if not. | 188 | * if not. |
189 | */ | 189 | */ |
190 | 190 | ||
191 | struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) | 191 | struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) |
192 | { | 192 | { |
193 | struct mtd_info *ret = NULL; | 193 | struct mtd_info *ret = NULL; |
@@ -297,39 +297,6 @@ EXPORT_SYMBOL(default_mtd_writev); | |||
297 | EXPORT_SYMBOL(default_mtd_readv); | 297 | EXPORT_SYMBOL(default_mtd_readv); |
298 | 298 | ||
299 | /*====================================================================*/ | 299 | /*====================================================================*/ |
300 | /* Power management code */ | ||
301 | |||
302 | #ifdef CONFIG_PM | ||
303 | |||
304 | #include <linux/pm.h> | ||
305 | |||
306 | static struct pm_dev *mtd_pm_dev = NULL; | ||
307 | |||
308 | static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) | ||
309 | { | ||
310 | int ret = 0, i; | ||
311 | |||
312 | if (down_trylock(&mtd_table_mutex)) | ||
313 | return -EAGAIN; | ||
314 | if (rqst == PM_SUSPEND) { | ||
315 | for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) { | ||
316 | if (mtd_table[i] && mtd_table[i]->suspend) | ||
317 | ret = mtd_table[i]->suspend(mtd_table[i]); | ||
318 | } | ||
319 | } else i = MAX_MTD_DEVICES-1; | ||
320 | |||
321 | if (rqst == PM_RESUME || ret) { | ||
322 | for ( ; i >= 0; i--) { | ||
323 | if (mtd_table[i] && mtd_table[i]->resume) | ||
324 | mtd_table[i]->resume(mtd_table[i]); | ||
325 | } | ||
326 | } | ||
327 | up(&mtd_table_mutex); | ||
328 | return ret; | ||
329 | } | ||
330 | #endif | ||
331 | |||
332 | /*====================================================================*/ | ||
333 | /* Support for /proc/mtd */ | 300 | /* Support for /proc/mtd */ |
334 | 301 | ||
335 | #ifdef CONFIG_PROC_FS | 302 | #ifdef CONFIG_PROC_FS |
@@ -388,22 +355,11 @@ static int __init init_mtd(void) | |||
388 | if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) | 355 | if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) |
389 | proc_mtd->read_proc = mtd_read_proc; | 356 | proc_mtd->read_proc = mtd_read_proc; |
390 | #endif | 357 | #endif |
391 | |||
392 | #ifdef CONFIG_PM | ||
393 | mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback); | ||
394 | #endif | ||
395 | return 0; | 358 | return 0; |
396 | } | 359 | } |
397 | 360 | ||
398 | static void __exit cleanup_mtd(void) | 361 | static void __exit cleanup_mtd(void) |
399 | { | 362 | { |
400 | #ifdef CONFIG_PM | ||
401 | if (mtd_pm_dev) { | ||
402 | pm_unregister(mtd_pm_dev); | ||
403 | mtd_pm_dev = NULL; | ||
404 | } | ||
405 | #endif | ||
406 | |||
407 | #ifdef CONFIG_PROC_FS | 363 | #ifdef CONFIG_PROC_FS |
408 | if (proc_mtd) | 364 | if (proc_mtd) |
409 | remove_proc_entry( "mtd", NULL); | 365 | remove_proc_entry( "mtd", NULL); |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b92e6bfffaf2..99395911d26f 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -5,11 +5,11 @@ | |||
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ | 8 | * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ |
9 | * | 9 | * |
10 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> | 10 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> |
11 | * added support for read_oob, write_oob | 11 | * added support for read_oob, write_oob |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
@@ -41,13 +41,13 @@ struct mtd_part { | |||
41 | */ | 41 | */ |
42 | #define PART(x) ((struct mtd_part *)(x)) | 42 | #define PART(x) ((struct mtd_part *)(x)) |
43 | 43 | ||
44 | 44 | ||
45 | /* | 45 | /* |
46 | * MTD methods which simply translate the effective address and pass through | 46 | * MTD methods which simply translate the effective address and pass through |
47 | * to the _real_ device. | 47 | * to the _real_ device. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | 50 | static int part_read (struct mtd_info *mtd, loff_t from, size_t len, |
51 | size_t *retlen, u_char *buf) | 51 | size_t *retlen, u_char *buf) |
52 | { | 52 | { |
53 | struct mtd_part *part = PART(mtd); | 53 | struct mtd_part *part = PART(mtd); |
@@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
55 | len = 0; | 55 | len = 0; |
56 | else if (from + len > mtd->size) | 56 | else if (from + len > mtd->size) |
57 | len = mtd->size - from; | 57 | len = mtd->size - from; |
58 | if (part->master->read_ecc == NULL) | 58 | if (part->master->read_ecc == NULL) |
59 | return part->master->read (part->master, from + part->offset, | 59 | return part->master->read (part->master, from + part->offset, |
60 | len, retlen, buf); | 60 | len, retlen, buf); |
61 | else | 61 | else |
62 | return part->master->read_ecc (part->master, from + part->offset, | 62 | return part->master->read_ecc (part->master, from + part->offset, |
63 | len, retlen, buf, NULL, &mtd->oobinfo); | 63 | len, retlen, buf, NULL, &mtd->oobinfo); |
64 | } | 64 | } |
65 | 65 | ||
66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | 66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, |
67 | size_t *retlen, u_char **buf) | 67 | size_t *retlen, u_char **buf) |
68 | { | 68 | { |
69 | struct mtd_part *part = PART(mtd); | 69 | struct mtd_part *part = PART(mtd); |
@@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | |||
71 | len = 0; | 71 | len = 0; |
72 | else if (from + len > mtd->size) | 72 | else if (from + len > mtd->size) |
73 | len = mtd->size - from; | 73 | len = mtd->size - from; |
74 | return part->master->point (part->master, from + part->offset, | 74 | return part->master->point (part->master, from + part->offset, |
75 | len, retlen, buf); | 75 | len, retlen, buf); |
76 | } | 76 | } |
77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) | 77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) |
@@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_ | |||
82 | } | 82 | } |
83 | 83 | ||
84 | 84 | ||
85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) | 86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) |
87 | { | 87 | { |
88 | struct mtd_part *part = PART(mtd); | 88 | struct mtd_part *part = PART(mtd); |
@@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
92 | len = 0; | 92 | len = 0; |
93 | else if (from + len > mtd->size) | 93 | else if (from + len > mtd->size) |
94 | len = mtd->size - from; | 94 | len = mtd->size - from; |
95 | return part->master->read_ecc (part->master, from + part->offset, | 95 | return part->master->read_ecc (part->master, from + part->offset, |
96 | len, retlen, buf, eccbuf, oobsel); | 96 | len, retlen, buf, eccbuf, oobsel); |
97 | } | 97 | } |
98 | 98 | ||
99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | 99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, |
100 | size_t *retlen, u_char *buf) | 100 | size_t *retlen, u_char *buf) |
101 | { | 101 | { |
102 | struct mtd_part *part = PART(mtd); | 102 | struct mtd_part *part = PART(mtd); |
@@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | |||
104 | len = 0; | 104 | len = 0; |
105 | else if (from + len > mtd->size) | 105 | else if (from + len > mtd->size) |
106 | len = mtd->size - from; | 106 | len = mtd->size - from; |
107 | return part->master->read_oob (part->master, from + part->offset, | 107 | return part->master->read_oob (part->master, from + part->offset, |
108 | len, retlen, buf); | 108 | len, retlen, buf); |
109 | } | 109 | } |
110 | 110 | ||
111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
112 | size_t *retlen, u_char *buf) | 112 | size_t *retlen, u_char *buf) |
113 | { | 113 | { |
114 | struct mtd_part *part = PART(mtd); | 114 | struct mtd_part *part = PART(mtd); |
115 | return part->master->read_user_prot_reg (part->master, from, | 115 | return part->master->read_user_prot_reg (part->master, from, |
116 | len, retlen, buf); | 116 | len, retlen, buf); |
117 | } | 117 | } |
118 | 118 | ||
@@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd, | |||
123 | return part->master->get_user_prot_info (part->master, buf, len); | 123 | return part->master->get_user_prot_info (part->master, buf, len); |
124 | } | 124 | } |
125 | 125 | ||
126 | static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 126 | static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
127 | size_t *retlen, u_char *buf) | 127 | size_t *retlen, u_char *buf) |
128 | { | 128 | { |
129 | struct mtd_part *part = PART(mtd); | 129 | struct mtd_part *part = PART(mtd); |
130 | return part->master->read_fact_prot_reg (part->master, from, | 130 | return part->master->read_fact_prot_reg (part->master, from, |
131 | len, retlen, buf); | 131 | len, retlen, buf); |
132 | } | 132 | } |
133 | 133 | ||
@@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
148 | len = 0; | 148 | len = 0; |
149 | else if (to + len > mtd->size) | 149 | else if (to + len > mtd->size) |
150 | len = mtd->size - to; | 150 | len = mtd->size - to; |
151 | if (part->master->write_ecc == NULL) | 151 | if (part->master->write_ecc == NULL) |
152 | return part->master->write (part->master, to + part->offset, | 152 | return part->master->write (part->master, to + part->offset, |
153 | len, retlen, buf); | 153 | len, retlen, buf); |
154 | else | 154 | else |
155 | return part->master->write_ecc (part->master, to + part->offset, | 155 | return part->master->write_ecc (part->master, to + part->offset, |
156 | len, retlen, buf, NULL, &mtd->oobinfo); | 156 | len, retlen, buf, NULL, &mtd->oobinfo); |
157 | 157 | ||
158 | } | 158 | } |
159 | 159 | ||
160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | 160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, |
@@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
170 | len = 0; | 170 | len = 0; |
171 | else if (to + len > mtd->size) | 171 | else if (to + len > mtd->size) |
172 | len = mtd->size - to; | 172 | len = mtd->size - to; |
173 | return part->master->write_ecc (part->master, to + part->offset, | 173 | return part->master->write_ecc (part->master, to + part->offset, |
174 | len, retlen, buf, eccbuf, oobsel); | 174 | len, retlen, buf, eccbuf, oobsel); |
175 | } | 175 | } |
176 | 176 | ||
@@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, | |||
184 | len = 0; | 184 | len = 0; |
185 | else if (to + len > mtd->size) | 185 | else if (to + len > mtd->size) |
186 | len = mtd->size - to; | 186 | len = mtd->size - to; |
187 | return part->master->write_oob (part->master, to + part->offset, | 187 | return part->master->write_oob (part->master, to + part->offset, |
188 | len, retlen, buf); | 188 | len, retlen, buf); |
189 | } | 189 | } |
190 | 190 | ||
191 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 191 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
192 | size_t *retlen, u_char *buf) | 192 | size_t *retlen, u_char *buf) |
193 | { | 193 | { |
194 | struct mtd_part *part = PART(mtd); | 194 | struct mtd_part *part = PART(mtd); |
195 | return part->master->write_user_prot_reg (part->master, from, | 195 | return part->master->write_user_prot_reg (part->master, from, |
196 | len, retlen, buf); | 196 | len, retlen, buf); |
197 | } | 197 | } |
198 | 198 | ||
199 | static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) | 199 | static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) |
200 | { | 200 | { |
201 | struct mtd_part *part = PART(mtd); | 201 | struct mtd_part *part = PART(mtd); |
202 | return part->master->lock_user_prot_reg (part->master, from, len); | 202 | return part->master->lock_user_prot_reg (part->master, from, len); |
@@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, | |||
208 | struct mtd_part *part = PART(mtd); | 208 | struct mtd_part *part = PART(mtd); |
209 | if (!(mtd->flags & MTD_WRITEABLE)) | 209 | if (!(mtd->flags & MTD_WRITEABLE)) |
210 | return -EROFS; | 210 | return -EROFS; |
211 | if (part->master->writev_ecc == NULL) | 211 | if (part->master->writev_ecc == NULL) |
212 | return part->master->writev (part->master, vecs, count, | 212 | return part->master->writev (part->master, vecs, count, |
213 | to + part->offset, retlen); | 213 | to + part->offset, retlen); |
214 | else | 214 | else |
@@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd, struct kvec *vecs, | |||
221 | unsigned long count, loff_t from, size_t *retlen) | 221 | unsigned long count, loff_t from, size_t *retlen) |
222 | { | 222 | { |
223 | struct mtd_part *part = PART(mtd); | 223 | struct mtd_part *part = PART(mtd); |
224 | if (part->master->readv_ecc == NULL) | 224 | if (part->master->readv_ecc == NULL) |
225 | return part->master->readv (part->master, vecs, count, | 225 | return part->master->readv (part->master, vecs, count, |
226 | from + part->offset, retlen); | 226 | from + part->offset, retlen); |
227 | else | 227 | else |
228 | return part->master->readv_ecc (part->master, vecs, count, | 228 | return part->master->readv_ecc (part->master, vecs, count, |
229 | from + part->offset, retlen, | 229 | from + part->offset, retlen, |
230 | NULL, &mtd->oobinfo); | 230 | NULL, &mtd->oobinfo); |
231 | } | 231 | } |
232 | 232 | ||
@@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs, | |||
252 | if (oobsel == NULL) | 252 | if (oobsel == NULL) |
253 | oobsel = &mtd->oobinfo; | 253 | oobsel = &mtd->oobinfo; |
254 | return part->master->readv_ecc (part->master, vecs, count, | 254 | return part->master->readv_ecc (part->master, vecs, count, |
255 | from + part->offset, retlen, | 255 | from + part->offset, retlen, |
256 | eccbuf, oobsel); | 256 | eccbuf, oobsel); |
257 | } | 257 | } |
258 | 258 | ||
@@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback); | |||
286 | static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | 286 | static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) |
287 | { | 287 | { |
288 | struct mtd_part *part = PART(mtd); | 288 | struct mtd_part *part = PART(mtd); |
289 | if ((len + ofs) > mtd->size) | 289 | if ((len + ofs) > mtd->size) |
290 | return -EINVAL; | 290 | return -EINVAL; |
291 | return part->master->lock(part->master, ofs + part->offset, len); | 291 | return part->master->lock(part->master, ofs + part->offset, len); |
292 | } | 292 | } |
@@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | |||
294 | static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) | 294 | static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) |
295 | { | 295 | { |
296 | struct mtd_part *part = PART(mtd); | 296 | struct mtd_part *part = PART(mtd); |
297 | if ((len + ofs) > mtd->size) | 297 | if ((len + ofs) > mtd->size) |
298 | return -EINVAL; | 298 | return -EINVAL; |
299 | return part->master->unlock(part->master, ofs + part->offset, len); | 299 | return part->master->unlock(part->master, ofs + part->offset, len); |
300 | } | 300 | } |
@@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
337 | return part->master->block_markbad(part->master, ofs); | 337 | return part->master->block_markbad(part->master, ofs); |
338 | } | 338 | } |
339 | 339 | ||
340 | /* | 340 | /* |
341 | * This function unregisters and destroy all slave MTD objects which are | 341 | * This function unregisters and destroy all slave MTD objects which are |
342 | * attached to the given master MTD object. | 342 | * attached to the given master MTD object. |
343 | */ | 343 | */ |
344 | 344 | ||
@@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master) | |||
371 | * (Q: should we register the master MTD object as well?) | 371 | * (Q: should we register the master MTD object as well?) |
372 | */ | 372 | */ |
373 | 373 | ||
374 | int add_mtd_partitions(struct mtd_info *master, | 374 | int add_mtd_partitions(struct mtd_info *master, |
375 | const struct mtd_partition *parts, | 375 | const struct mtd_partition *parts, |
376 | int nbparts) | 376 | int nbparts) |
377 | { | 377 | { |
@@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
414 | slave->mtd.point = part_point; | 414 | slave->mtd.point = part_point; |
415 | slave->mtd.unpoint = part_unpoint; | 415 | slave->mtd.unpoint = part_unpoint; |
416 | } | 416 | } |
417 | 417 | ||
418 | if (master->read_ecc) | 418 | if (master->read_ecc) |
419 | slave->mtd.read_ecc = part_read_ecc; | 419 | slave->mtd.read_ecc = part_read_ecc; |
420 | if (master->write_ecc) | 420 | if (master->write_ecc) |
@@ -465,9 +465,10 @@ int add_mtd_partitions(struct mtd_info *master, | |||
465 | if (slave->offset == MTDPART_OFS_APPEND) | 465 | if (slave->offset == MTDPART_OFS_APPEND) |
466 | slave->offset = cur_offset; | 466 | slave->offset = cur_offset; |
467 | if (slave->offset == MTDPART_OFS_NXTBLK) { | 467 | if (slave->offset == MTDPART_OFS_NXTBLK) { |
468 | u_int32_t emask = master->erasesize-1; | 468 | slave->offset = cur_offset; |
469 | slave->offset = (cur_offset + emask) & ~emask; | 469 | if ((cur_offset % master->erasesize) != 0) { |
470 | if (slave->offset != cur_offset) { | 470 | /* Round up to next erasesize */ |
471 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | ||
471 | printk(KERN_NOTICE "Moving partition %d: " | 472 | printk(KERN_NOTICE "Moving partition %d: " |
472 | "0x%08x -> 0x%08x\n", i, | 473 | "0x%08x -> 0x%08x\n", i, |
473 | cur_offset, slave->offset); | 474 | cur_offset, slave->offset); |
@@ -476,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master, | |||
476 | if (slave->mtd.size == MTDPART_SIZ_FULL) | 477 | if (slave->mtd.size == MTDPART_SIZ_FULL) |
477 | slave->mtd.size = master->size - slave->offset; | 478 | slave->mtd.size = master->size - slave->offset; |
478 | cur_offset = slave->offset + slave->mtd.size; | 479 | cur_offset = slave->offset + slave->mtd.size; |
479 | 480 | ||
480 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, | 481 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, |
481 | slave->offset + slave->mtd.size, slave->mtd.name); | 482 | slave->offset + slave->mtd.size, slave->mtd.name); |
482 | 483 | ||
483 | /* let's do some sanity checks */ | 484 | /* let's do some sanity checks */ |
@@ -497,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
497 | /* Deal with variable erase size stuff */ | 498 | /* Deal with variable erase size stuff */ |
498 | int i; | 499 | int i; |
499 | struct mtd_erase_region_info *regions = master->eraseregions; | 500 | struct mtd_erase_region_info *regions = master->eraseregions; |
500 | 501 | ||
501 | /* Find the first erase regions which is part of this partition. */ | 502 | /* Find the first erase regions which is part of this partition. */ |
502 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) | 503 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) |
503 | ; | 504 | ; |
@@ -512,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
512 | slave->mtd.erasesize = master->erasesize; | 513 | slave->mtd.erasesize = master->erasesize; |
513 | } | 514 | } |
514 | 515 | ||
515 | if ((slave->mtd.flags & MTD_WRITEABLE) && | 516 | if ((slave->mtd.flags & MTD_WRITEABLE) && |
516 | (slave->offset % slave->mtd.erasesize)) { | 517 | (slave->offset % slave->mtd.erasesize)) { |
517 | /* Doesn't start on a boundary of major erase size */ | 518 | /* Doesn't start on a boundary of major erase size */ |
518 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ | 519 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ |
@@ -520,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master, | |||
520 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | 521 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", |
521 | parts[i].name); | 522 | parts[i].name); |
522 | } | 523 | } |
523 | if ((slave->mtd.flags & MTD_WRITEABLE) && | 524 | if ((slave->mtd.flags & MTD_WRITEABLE) && |
524 | (slave->mtd.size % slave->mtd.erasesize)) { | 525 | (slave->mtd.size % slave->mtd.erasesize)) { |
525 | slave->mtd.flags &= ~MTD_WRITEABLE; | 526 | slave->mtd.flags &= ~MTD_WRITEABLE; |
526 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | 527 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", |
527 | parts[i].name); | 528 | parts[i].name); |
528 | } | 529 | } |
529 | 530 | ||
530 | /* copy oobinfo from master */ | 531 | /* copy oobinfo from master */ |
531 | memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); | 532 | memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); |
532 | 533 | ||
533 | if(parts[i].mtdp) | 534 | if(parts[i].mtdp) |
@@ -588,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p) | |||
588 | return 0; | 589 | return 0; |
589 | } | 590 | } |
590 | 591 | ||
591 | int parse_mtd_partitions(struct mtd_info *master, const char **types, | 592 | int parse_mtd_partitions(struct mtd_info *master, const char **types, |
592 | struct mtd_partition **pparts, unsigned long origin) | 593 | struct mtd_partition **pparts, unsigned long origin) |
593 | { | 594 | { |
594 | struct mtd_part_parser *parser; | 595 | struct mtd_part_parser *parser; |
595 | int ret = 0; | 596 | int ret = 0; |
596 | 597 | ||
597 | for ( ; ret <= 0 && *types; types++) { | 598 | for ( ; ret <= 0 && *types; types++) { |
598 | parser = get_partition_parser(*types); | 599 | parser = get_partition_parser(*types); |
599 | #ifdef CONFIG_KMOD | 600 | #ifdef CONFIG_KMOD |
@@ -607,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
607 | } | 608 | } |
608 | ret = (*parser->parse_fn)(master, pparts, origin); | 609 | ret = (*parser->parse_fn)(master, pparts, origin); |
609 | if (ret > 0) { | 610 | if (ret > 0) { |
610 | printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", | 611 | printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", |
611 | ret, parser->name, master->name); | 612 | ret, parser->name, master->name); |
612 | } | 613 | } |
613 | put_partition_parser(parser); | 614 | put_partition_parser(parser); |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 36d34e5e5a5a..1fc4c134d939 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
2 | # $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $ | 2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ |
3 | 3 | ||
4 | menu "NAND Flash Device Drivers" | 4 | menu "NAND Flash Device Drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -25,33 +25,33 @@ config MTD_NAND_VERIFY_WRITE | |||
25 | 25 | ||
26 | config MTD_NAND_AUTCPU12 | 26 | config MTD_NAND_AUTCPU12 |
27 | tristate "SmartMediaCard on autronix autcpu12 board" | 27 | tristate "SmartMediaCard on autronix autcpu12 board" |
28 | depends on ARM && MTD_NAND && ARCH_AUTCPU12 | 28 | depends on MTD_NAND && ARCH_AUTCPU12 |
29 | help | 29 | help |
30 | This enables the driver for the autronix autcpu12 board to | 30 | This enables the driver for the autronix autcpu12 board to |
31 | access the SmartMediaCard. | 31 | access the SmartMediaCard. |
32 | 32 | ||
33 | config MTD_NAND_EDB7312 | 33 | config MTD_NAND_EDB7312 |
34 | tristate "Support for Cirrus Logic EBD7312 evaluation board" | 34 | tristate "Support for Cirrus Logic EBD7312 evaluation board" |
35 | depends on ARM && MTD_NAND && ARCH_EDB7312 | 35 | depends on MTD_NAND && ARCH_EDB7312 |
36 | help | 36 | help |
37 | This enables the driver for the Cirrus Logic EBD7312 evaluation | 37 | This enables the driver for the Cirrus Logic EBD7312 evaluation |
38 | board to access the onboard NAND Flash. | 38 | board to access the onboard NAND Flash. |
39 | 39 | ||
40 | config MTD_NAND_H1900 | 40 | config MTD_NAND_H1900 |
41 | tristate "iPAQ H1900 flash" | 41 | tristate "iPAQ H1900 flash" |
42 | depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS | 42 | depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS |
43 | help | 43 | help |
44 | This enables the driver for the iPAQ h1900 flash. | 44 | This enables the driver for the iPAQ h1900 flash. |
45 | 45 | ||
46 | config MTD_NAND_SPIA | 46 | config MTD_NAND_SPIA |
47 | tristate "NAND Flash device on SPIA board" | 47 | tristate "NAND Flash device on SPIA board" |
48 | depends on ARM && ARCH_P720T && MTD_NAND | 48 | depends on ARCH_P720T && MTD_NAND |
49 | help | 49 | help |
50 | If you had to ask, you don't have one. Say 'N'. | 50 | If you had to ask, you don't have one. Say 'N'. |
51 | 51 | ||
52 | config MTD_NAND_TOTO | 52 | config MTD_NAND_TOTO |
53 | tristate "NAND Flash device on TOTO board" | 53 | tristate "NAND Flash device on TOTO board" |
54 | depends on ARM && ARCH_OMAP && MTD_NAND | 54 | depends on ARCH_OMAP && MTD_NAND |
55 | help | 55 | help |
56 | Support for NAND flash on Texas Instruments Toto platform. | 56 | Support for NAND flash on Texas Instruments Toto platform. |
57 | 57 | ||
@@ -59,8 +59,8 @@ config MTD_NAND_IDS | |||
59 | tristate | 59 | tristate |
60 | 60 | ||
61 | config MTD_NAND_AU1550 | 61 | config MTD_NAND_AU1550 |
62 | tristate "Au1550 NAND support" | 62 | tristate "Au1550/1200 NAND support" |
63 | depends on SOC_AU1550 && MTD_NAND | 63 | depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND |
64 | help | 64 | help |
65 | This enables the driver for the NAND flash controller on the | 65 | This enables the driver for the NAND flash controller on the |
66 | AMD/Alchemy 1550 SOC. | 66 | AMD/Alchemy 1550 SOC. |
@@ -71,7 +71,7 @@ config MTD_NAND_RTC_FROM4 | |||
71 | select REED_SOLOMON | 71 | select REED_SOLOMON |
72 | select REED_SOLOMON_DEC8 | 72 | select REED_SOLOMON_DEC8 |
73 | help | 73 | help |
74 | This enables the driver for the Renesas Technology AG-AND | 74 | This enables the driver for the Renesas Technology AG-AND |
75 | flash interface board (FROM_BOARD4) | 75 | flash interface board (FROM_BOARD4) |
76 | 76 | ||
77 | config MTD_NAND_PPCHAMELEONEVB | 77 | config MTD_NAND_PPCHAMELEONEVB |
@@ -88,7 +88,7 @@ config MTD_NAND_S3C2410 | |||
88 | SoCs | 88 | SoCs |
89 | 89 | ||
90 | No board specfic support is done by this driver, each board | 90 | No board specfic support is done by this driver, each board |
91 | must advertise a platform_device for the driver to attach. | 91 | must advertise a platform_device for the driver to attach. |
92 | 92 | ||
93 | config MTD_NAND_S3C2410_DEBUG | 93 | config MTD_NAND_S3C2410_DEBUG |
94 | bool "S3C2410 NAND driver debug" | 94 | bool "S3C2410 NAND driver debug" |
@@ -181,7 +181,7 @@ config MTD_NAND_DISKONCHIP_BBTWRITE | |||
181 | 181 | ||
182 | config MTD_NAND_SHARPSL | 182 | config MTD_NAND_SHARPSL |
183 | bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" | 183 | bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" |
184 | depends on MTD_NAND && ARCH_PXA | 184 | depends on MTD_NAND && ARCH_PXA |
185 | 185 | ||
186 | config MTD_NAND_NANDSIM | 186 | config MTD_NAND_NANDSIM |
187 | bool "Support for NAND Flash Simulator" | 187 | bool "Support for NAND Flash Simulator" |
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 4c7719ce3f48..3cafcdf28aed 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Embedded Edge, LLC | 4 | * Copyright (C) 2004 Embedded Edge, LLC |
5 | * | 5 | * |
6 | * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ | 6 | * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -21,20 +21,14 @@ | |||
21 | 21 | ||
22 | /* fixme: this is ugly */ | 22 | /* fixme: this is ugly */ |
23 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) | 23 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) |
24 | #include <asm/mach-au1x00/au1000.h> | 24 | #include <asm/mach-au1x00/au1xxx.h> |
25 | #ifdef CONFIG_MIPS_PB1550 | ||
26 | #include <asm/mach-pb1x00/pb1550.h> | ||
27 | #endif | ||
28 | #ifdef CONFIG_MIPS_DB1550 | ||
29 | #include <asm/mach-db1x00/db1x00.h> | ||
30 | #endif | ||
31 | #else | 25 | #else |
32 | #include <asm/au1000.h> | 26 | #include <asm/au1000.h> |
33 | #ifdef CONFIG_MIPS_PB1550 | 27 | #ifdef CONFIG_MIPS_PB1550 |
34 | #include <asm/pb1550.h> | 28 | #include <asm/pb1550.h> |
35 | #endif | 29 | #endif |
36 | #ifdef CONFIG_MIPS_DB1550 | 30 | #ifdef CONFIG_MIPS_DB1550 |
37 | #include <asm/db1x00.h> | 31 | #include <asm/db1x00.h> |
38 | #endif | 32 | #endif |
39 | #endif | 33 | #endif |
40 | 34 | ||
@@ -45,39 +39,22 @@ static struct mtd_info *au1550_mtd = NULL; | |||
45 | static void __iomem *p_nand; | 39 | static void __iomem *p_nand; |
46 | static int nand_width = 1; /* default x8*/ | 40 | static int nand_width = 1; /* default x8*/ |
47 | 41 | ||
48 | #define NAND_CS 1 | ||
49 | |||
50 | /* | 42 | /* |
51 | * Define partitions for flash device | 43 | * Define partitions for flash device |
52 | */ | 44 | */ |
53 | const static struct mtd_partition partition_info[] = { | 45 | const static struct mtd_partition partition_info[] = { |
54 | #ifdef CONFIG_MIPS_PB1550 | 46 | { |
55 | #define NUM_PARTITIONS 2 | 47 | .name = "NAND FS 0", |
56 | { | ||
57 | .name = "Pb1550 NAND FS 0", | ||
58 | .offset = 0, | 48 | .offset = 0, |
59 | .size = 8*1024*1024 | 49 | .size = 8*1024*1024 |
60 | }, | 50 | }, |
61 | { | 51 | { |
62 | .name = "Pb1550 NAND FS 1", | 52 | .name = "NAND FS 1", |
63 | .offset = MTDPART_OFS_APPEND, | 53 | .offset = MTDPART_OFS_APPEND, |
64 | .size = MTDPART_SIZ_FULL | 54 | .size = MTDPART_SIZ_FULL |
65 | } | 55 | } |
66 | #endif | ||
67 | #ifdef CONFIG_MIPS_DB1550 | ||
68 | #define NUM_PARTITIONS 2 | ||
69 | { | ||
70 | .name = "Db1550 NAND FS 0", | ||
71 | .offset = 0, | ||
72 | .size = 8*1024*1024 | ||
73 | }, | ||
74 | { | ||
75 | .name = "Db1550 NAND FS 1", | ||
76 | .offset = MTDPART_OFS_APPEND, | ||
77 | .size = MTDPART_SIZ_FULL | ||
78 | } | ||
79 | #endif | ||
80 | }; | 56 | }; |
57 | #define NB_OF(x) (sizeof(x)/sizeof(x[0])) | ||
81 | 58 | ||
82 | 59 | ||
83 | /** | 60 | /** |
@@ -112,7 +89,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) | |||
112 | * au_read_byte16 - read one byte endianess aware from the chip | 89 | * au_read_byte16 - read one byte endianess aware from the chip |
113 | * @mtd: MTD device structure | 90 | * @mtd: MTD device structure |
114 | * | 91 | * |
115 | * read function for 16bit buswith with | 92 | * read function for 16bit buswith with |
116 | * endianess conversion | 93 | * endianess conversion |
117 | */ | 94 | */ |
118 | static u_char au_read_byte16(struct mtd_info *mtd) | 95 | static u_char au_read_byte16(struct mtd_info *mtd) |
@@ -142,7 +119,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) | |||
142 | * au_read_word - read one word from the chip | 119 | * au_read_word - read one word from the chip |
143 | * @mtd: MTD device structure | 120 | * @mtd: MTD device structure |
144 | * | 121 | * |
145 | * read function for 16bit buswith without | 122 | * read function for 16bit buswith without |
146 | * endianess conversion | 123 | * endianess conversion |
147 | */ | 124 | */ |
148 | static u16 au_read_word(struct mtd_info *mtd) | 125 | static u16 au_read_word(struct mtd_info *mtd) |
@@ -158,7 +135,7 @@ static u16 au_read_word(struct mtd_info *mtd) | |||
158 | * @mtd: MTD device structure | 135 | * @mtd: MTD device structure |
159 | * @word: data word to write | 136 | * @word: data word to write |
160 | * | 137 | * |
161 | * write function for 16bit buswith without | 138 | * write function for 16bit buswith without |
162 | * endianess conversion | 139 | * endianess conversion |
163 | */ | 140 | */ |
164 | static void au_write_word(struct mtd_info *mtd, u16 word) | 141 | static void au_write_word(struct mtd_info *mtd, u16 word) |
@@ -188,7 +165,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
188 | } | 165 | } |
189 | 166 | ||
190 | /** | 167 | /** |
191 | * au_read_buf - read chip data into buffer | 168 | * au_read_buf - read chip data into buffer |
192 | * @mtd: MTD device structure | 169 | * @mtd: MTD device structure |
193 | * @buf: buffer to store date | 170 | * @buf: buffer to store date |
194 | * @len: number of bytes to read | 171 | * @len: number of bytes to read |
@@ -202,12 +179,12 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
202 | 179 | ||
203 | for (i=0; i<len; i++) { | 180 | for (i=0; i<len; i++) { |
204 | buf[i] = readb(this->IO_ADDR_R); | 181 | buf[i] = readb(this->IO_ADDR_R); |
205 | au_sync(); | 182 | au_sync(); |
206 | } | 183 | } |
207 | } | 184 | } |
208 | 185 | ||
209 | /** | 186 | /** |
210 | * au_verify_buf - Verify chip data against buffer | 187 | * au_verify_buf - Verify chip data against buffer |
211 | * @mtd: MTD device structure | 188 | * @mtd: MTD device structure |
212 | * @buf: buffer containing the data to compare | 189 | * @buf: buffer containing the data to compare |
213 | * @len: number of bytes to compare | 190 | * @len: number of bytes to compare |
@@ -242,16 +219,16 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
242 | struct nand_chip *this = mtd->priv; | 219 | struct nand_chip *this = mtd->priv; |
243 | u16 *p = (u16 *) buf; | 220 | u16 *p = (u16 *) buf; |
244 | len >>= 1; | 221 | len >>= 1; |
245 | 222 | ||
246 | for (i=0; i<len; i++) { | 223 | for (i=0; i<len; i++) { |
247 | writew(p[i], this->IO_ADDR_W); | 224 | writew(p[i], this->IO_ADDR_W); |
248 | au_sync(); | 225 | au_sync(); |
249 | } | 226 | } |
250 | 227 | ||
251 | } | 228 | } |
252 | 229 | ||
253 | /** | 230 | /** |
254 | * au_read_buf16 - read chip data into buffer | 231 | * au_read_buf16 - read chip data into buffer |
255 | * @mtd: MTD device structure | 232 | * @mtd: MTD device structure |
256 | * @buf: buffer to store date | 233 | * @buf: buffer to store date |
257 | * @len: number of bytes to read | 234 | * @len: number of bytes to read |
@@ -272,7 +249,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) | |||
272 | } | 249 | } |
273 | 250 | ||
274 | /** | 251 | /** |
275 | * au_verify_buf16 - Verify chip data against buffer | 252 | * au_verify_buf16 - Verify chip data against buffer |
276 | * @mtd: MTD device structure | 253 | * @mtd: MTD device structure |
277 | * @buf: buffer containing the data to compare | 254 | * @buf: buffer containing the data to compare |
278 | * @len: number of bytes to compare | 255 | * @len: number of bytes to compare |
@@ -305,26 +282,26 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) | |||
305 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; | 282 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; |
306 | 283 | ||
307 | case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; | 284 | case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; |
308 | case NAND_CTL_CLRALE: | 285 | case NAND_CTL_CLRALE: |
309 | this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; | 286 | this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; |
310 | /* FIXME: Nobody knows why this is neccecary, | 287 | /* FIXME: Nobody knows why this is neccecary, |
311 | * but it works only that way */ | 288 | * but it works only that way */ |
312 | udelay(1); | 289 | udelay(1); |
313 | break; | 290 | break; |
314 | 291 | ||
315 | case NAND_CTL_SETNCE: | 292 | case NAND_CTL_SETNCE: |
316 | /* assert (force assert) chip enable */ | 293 | /* assert (force assert) chip enable */ |
317 | au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; | 294 | au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; |
318 | break; | 295 | break; |
319 | 296 | ||
320 | case NAND_CTL_CLRNCE: | 297 | case NAND_CTL_CLRNCE: |
321 | /* deassert chip enable */ | 298 | /* deassert chip enable */ |
322 | au_writel(0, MEM_STNDCTL); break; | 299 | au_writel(0, MEM_STNDCTL); break; |
323 | break; | 300 | break; |
324 | } | 301 | } |
325 | 302 | ||
326 | this->IO_ADDR_R = this->IO_ADDR_W; | 303 | this->IO_ADDR_R = this->IO_ADDR_W; |
327 | 304 | ||
328 | /* Drain the writebuffer */ | 305 | /* Drain the writebuffer */ |
329 | au_sync(); | 306 | au_sync(); |
330 | } | 307 | } |
@@ -339,14 +316,16 @@ int au1550_device_ready(struct mtd_info *mtd) | |||
339 | /* | 316 | /* |
340 | * Main initialization routine | 317 | * Main initialization routine |
341 | */ | 318 | */ |
342 | int __init au1550_init (void) | 319 | int __init au1xxx_nand_init (void) |
343 | { | 320 | { |
344 | struct nand_chip *this; | 321 | struct nand_chip *this; |
345 | u16 boot_swapboot = 0; /* default value */ | 322 | u16 boot_swapboot = 0; /* default value */ |
346 | int retval; | 323 | int retval; |
324 | u32 mem_staddr; | ||
325 | u32 nand_phys; | ||
347 | 326 | ||
348 | /* Allocate memory for MTD device structure and private data */ | 327 | /* Allocate memory for MTD device structure and private data */ |
349 | au1550_mtd = kmalloc (sizeof(struct mtd_info) + | 328 | au1550_mtd = kmalloc (sizeof(struct mtd_info) + |
350 | sizeof (struct nand_chip), GFP_KERNEL); | 329 | sizeof (struct nand_chip), GFP_KERNEL); |
351 | if (!au1550_mtd) { | 330 | if (!au1550_mtd) { |
352 | printk ("Unable to allocate NAND MTD dev structure.\n"); | 331 | printk ("Unable to allocate NAND MTD dev structure.\n"); |
@@ -364,14 +343,17 @@ int __init au1550_init (void) | |||
364 | au1550_mtd->priv = this; | 343 | au1550_mtd->priv = this; |
365 | 344 | ||
366 | 345 | ||
367 | /* MEM_STNDCTL: disable ints, disable nand boot */ | 346 | /* disable interrupts */ |
368 | au_writel(0, MEM_STNDCTL); | 347 | au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); |
348 | |||
349 | /* disable NAND boot */ | ||
350 | au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); | ||
369 | 351 | ||
370 | #ifdef CONFIG_MIPS_PB1550 | 352 | #ifdef CONFIG_MIPS_PB1550 |
371 | /* set gpio206 high */ | 353 | /* set gpio206 high */ |
372 | au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); | 354 | au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); |
373 | 355 | ||
374 | boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | | 356 | boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | |
375 | ((bcsr->status >> 6) & 0x1); | 357 | ((bcsr->status >> 6) & 0x1); |
376 | switch (boot_swapboot) { | 358 | switch (boot_swapboot) { |
377 | case 0: | 359 | case 0: |
@@ -397,25 +379,66 @@ int __init au1550_init (void) | |||
397 | } | 379 | } |
398 | #endif | 380 | #endif |
399 | 381 | ||
400 | /* Configure RCE1 - should be done by YAMON */ | 382 | /* Configure chip-select; normally done by boot code, e.g. YAMON */ |
401 | au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */ | 383 | #ifdef NAND_STCFG |
402 | au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */ | 384 | if (NAND_CS == 0) { |
403 | au_sync(); | 385 | au_writel(NAND_STCFG, MEM_STCFG0); |
386 | au_writel(NAND_STTIME, MEM_STTIME0); | ||
387 | au_writel(NAND_STADDR, MEM_STADDR0); | ||
388 | } | ||
389 | if (NAND_CS == 1) { | ||
390 | au_writel(NAND_STCFG, MEM_STCFG1); | ||
391 | au_writel(NAND_STTIME, MEM_STTIME1); | ||
392 | au_writel(NAND_STADDR, MEM_STADDR1); | ||
393 | } | ||
394 | if (NAND_CS == 2) { | ||
395 | au_writel(NAND_STCFG, MEM_STCFG2); | ||
396 | au_writel(NAND_STTIME, MEM_STTIME2); | ||
397 | au_writel(NAND_STADDR, MEM_STADDR2); | ||
398 | } | ||
399 | if (NAND_CS == 3) { | ||
400 | au_writel(NAND_STCFG, MEM_STCFG3); | ||
401 | au_writel(NAND_STTIME, MEM_STTIME3); | ||
402 | au_writel(NAND_STADDR, MEM_STADDR3); | ||
403 | } | ||
404 | #endif | ||
404 | 405 | ||
405 | /* setup and enable chip select, MEM_STADDR1 */ | 406 | /* Locate NAND chip-select in order to determine NAND phys address */ |
406 | /* we really need to decode offsets only up till 0x20 */ | 407 | mem_staddr = 0x00000000; |
407 | au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | | 408 | if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) |
408 | (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), | 409 | mem_staddr = au_readl(MEM_STADDR0); |
409 | MEM_STADDR1); | 410 | else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) |
410 | au_sync(); | 411 | mem_staddr = au_readl(MEM_STADDR1); |
412 | else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) | ||
413 | mem_staddr = au_readl(MEM_STADDR2); | ||
414 | else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) | ||
415 | mem_staddr = au_readl(MEM_STADDR3); | ||
416 | |||
417 | if (mem_staddr == 0x00000000) { | ||
418 | printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n"); | ||
419 | kfree(au1550_mtd); | ||
420 | return 1; | ||
421 | } | ||
422 | nand_phys = (mem_staddr << 4) & 0xFFFC0000; | ||
423 | |||
424 | p_nand = (void __iomem *)ioremap(nand_phys, 0x1000); | ||
425 | |||
426 | /* make controller and MTD agree */ | ||
427 | if (NAND_CS == 0) | ||
428 | nand_width = au_readl(MEM_STCFG0) & (1<<22); | ||
429 | if (NAND_CS == 1) | ||
430 | nand_width = au_readl(MEM_STCFG1) & (1<<22); | ||
431 | if (NAND_CS == 2) | ||
432 | nand_width = au_readl(MEM_STCFG2) & (1<<22); | ||
433 | if (NAND_CS == 3) | ||
434 | nand_width = au_readl(MEM_STCFG3) & (1<<22); | ||
411 | 435 | ||
412 | p_nand = ioremap(NAND_PHYS_ADDR, 0x1000); | ||
413 | 436 | ||
414 | /* Set address of hardware control function */ | 437 | /* Set address of hardware control function */ |
415 | this->hwcontrol = au1550_hwcontrol; | 438 | this->hwcontrol = au1550_hwcontrol; |
416 | this->dev_ready = au1550_device_ready; | 439 | this->dev_ready = au1550_device_ready; |
417 | /* 30 us command delay time */ | 440 | /* 30 us command delay time */ |
418 | this->chip_delay = 30; | 441 | this->chip_delay = 30; |
419 | this->eccmode = NAND_ECC_SOFT; | 442 | this->eccmode = NAND_ECC_SOFT; |
420 | 443 | ||
421 | this->options = NAND_NO_AUTOINCR; | 444 | this->options = NAND_NO_AUTOINCR; |
@@ -438,19 +461,19 @@ int __init au1550_init (void) | |||
438 | } | 461 | } |
439 | 462 | ||
440 | /* Register the partitions */ | 463 | /* Register the partitions */ |
441 | add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS); | 464 | add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info)); |
442 | 465 | ||
443 | return 0; | 466 | return 0; |
444 | 467 | ||
445 | outio: | 468 | outio: |
446 | iounmap ((void *)p_nand); | 469 | iounmap ((void *)p_nand); |
447 | 470 | ||
448 | outmem: | 471 | outmem: |
449 | kfree (au1550_mtd); | 472 | kfree (au1550_mtd); |
450 | return retval; | 473 | return retval; |
451 | } | 474 | } |
452 | 475 | ||
453 | module_init(au1550_init); | 476 | module_init(au1xxx_nand_init); |
454 | 477 | ||
455 | /* | 478 | /* |
456 | * Clean up routine | 479 | * Clean up routine |
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 4afa8ced05ad..056dfc17a075 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
@@ -5,8 +5,8 @@ | |||
5 | * | 5 | * |
6 | * Derived from drivers/mtd/spia.c | 6 | * Derived from drivers/mtd/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,7 +14,7 @@ | |||
14 | * | 14 | * |
15 | * Overview: | 15 | * Overview: |
16 | * This is a device driver for the NAND flash device found on the | 16 | * This is a device driver for the NAND flash device found on the |
17 | * autronix autcpu12 board, which is a SmartMediaCard. It supports | 17 | * autronix autcpu12 board, which is a SmartMediaCard. It supports |
18 | * 16MiB, 32MiB and 64MiB cards. | 18 | * 16MiB, 32MiB and 64MiB cards. |
19 | * | 19 | * |
20 | * | 20 | * |
@@ -93,7 +93,7 @@ static struct mtd_partition partition_info128k[] = { | |||
93 | #define NUM_PARTITIONS32K 2 | 93 | #define NUM_PARTITIONS32K 2 |
94 | #define NUM_PARTITIONS64K 2 | 94 | #define NUM_PARTITIONS64K 2 |
95 | #define NUM_PARTITIONS128K 2 | 95 | #define NUM_PARTITIONS128K 2 |
96 | /* | 96 | /* |
97 | * hardware specific access to control-lines | 97 | * hardware specific access to control-lines |
98 | */ | 98 | */ |
99 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) | 99 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) |
@@ -163,7 +163,7 @@ int __init autcpu12_init (void) | |||
163 | this->hwcontrol = autcpu12_hwcontrol; | 163 | this->hwcontrol = autcpu12_hwcontrol; |
164 | this->dev_ready = autcpu12_device_ready; | 164 | this->dev_ready = autcpu12_device_ready; |
165 | /* 20 us command delay time */ | 165 | /* 20 us command delay time */ |
166 | this->chip_delay = 20; | 166 | this->chip_delay = 20; |
167 | this->eccmode = NAND_ECC_SOFT; | 167 | this->eccmode = NAND_ECC_SOFT; |
168 | 168 | ||
169 | /* Enable the following for a flash based bad block table */ | 169 | /* Enable the following for a flash based bad block table */ |
@@ -171,21 +171,21 @@ int __init autcpu12_init (void) | |||
171 | this->options = NAND_USE_FLASH_BBT; | 171 | this->options = NAND_USE_FLASH_BBT; |
172 | */ | 172 | */ |
173 | this->options = NAND_USE_FLASH_BBT; | 173 | this->options = NAND_USE_FLASH_BBT; |
174 | 174 | ||
175 | /* Scan to find existance of the device */ | 175 | /* Scan to find existance of the device */ |
176 | if (nand_scan (autcpu12_mtd, 1)) { | 176 | if (nand_scan (autcpu12_mtd, 1)) { |
177 | err = -ENXIO; | 177 | err = -ENXIO; |
178 | goto out_ior; | 178 | goto out_ior; |
179 | } | 179 | } |
180 | 180 | ||
181 | /* Register the partitions */ | 181 | /* Register the partitions */ |
182 | switch(autcpu12_mtd->size){ | 182 | switch(autcpu12_mtd->size){ |
183 | case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; | 183 | case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; |
184 | case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; | 184 | case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; |
185 | case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; | 185 | case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; |
186 | case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; | 186 | case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; |
187 | default: { | 187 | default: { |
188 | printk ("Unsupported SmartMedia device\n"); | 188 | printk ("Unsupported SmartMedia device\n"); |
189 | err = -ENXIO; | 189 | err = -ENXIO; |
190 | goto out_ior; | 190 | goto out_ior; |
191 | } | 191 | } |
@@ -213,7 +213,7 @@ static void __exit autcpu12_cleanup (void) | |||
213 | 213 | ||
214 | /* unmap physical adress */ | 214 | /* unmap physical adress */ |
215 | iounmap((void *)autcpu12_fio_base); | 215 | iounmap((void *)autcpu12_fio_base); |
216 | 216 | ||
217 | /* Free the MTD device structure */ | 217 | /* Free the MTD device structure */ |
218 | kfree (autcpu12_mtd); | 218 | kfree (autcpu12_mtd); |
219 | } | 219 | } |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fdb5d4ad3d52..21d4e8f4b7af 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/mtd/nand/diskonchip.c | 2 | * drivers/mtd/nand/diskonchip.c |
3 | * | 3 | * |
4 | * (C) 2003 Red Hat, Inc. | 4 | * (C) 2003 Red Hat, Inc. |
@@ -8,15 +8,15 @@ | |||
8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
9 | * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org> | 9 | * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org> |
10 | * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee> | 10 | * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee> |
11 | * | 11 | * |
12 | * Error correction code lifted from the old docecc code | 12 | * Error correction code lifted from the old docecc code |
13 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 13 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
14 | * Copyright (C) 2000 Netgem S.A. | 14 | * Copyright (C) 2000 Netgem S.A. |
15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> | 15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> |
16 | * | 16 | * |
17 | * Interface to generic NAND code for M-Systems DiskOnChip devices | 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices |
18 | * | 18 | * |
19 | * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $ | 19 | * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
@@ -42,16 +42,16 @@ | |||
42 | static unsigned long __initdata doc_locations[] = { | 42 | static unsigned long __initdata doc_locations[] = { |
43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) | 43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) |
44 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH | 44 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH |
45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, | 45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, |
46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, | 46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, |
47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, | 47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, |
48 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, | 48 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, |
49 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, | 49 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, |
50 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ | 50 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ |
51 | 0xc8000, 0xca000, 0xcc000, 0xce000, | 51 | 0xc8000, 0xca000, 0xcc000, 0xce000, |
52 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, | 52 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, |
53 | 0xd8000, 0xda000, 0xdc000, 0xde000, | 53 | 0xd8000, 0xda000, 0xdc000, 0xde000, |
54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
55 | 0xe8000, 0xea000, 0xec000, 0xee000, | 55 | 0xe8000, 0xea000, 0xec000, 0xee000, |
56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
57 | #elif defined(__PPC__) | 57 | #elif defined(__PPC__) |
@@ -138,7 +138,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe | |||
138 | /* the Reed Solomon control structure */ | 138 | /* the Reed Solomon control structure */ |
139 | static struct rs_control *rs_decoder; | 139 | static struct rs_control *rs_decoder; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * The HW decoder in the DoC ASIC's provides us a error syndrome, | 142 | * The HW decoder in the DoC ASIC's provides us a error syndrome, |
143 | * which we must convert to a standard syndrom usable by the generic | 143 | * which we must convert to a standard syndrom usable by the generic |
144 | * Reed-Solomon library code. | 144 | * Reed-Solomon library code. |
@@ -163,8 +163,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
163 | /* Initialize the syndrom buffer */ | 163 | /* Initialize the syndrom buffer */ |
164 | for (i = 0; i < NROOTS; i++) | 164 | for (i = 0; i < NROOTS; i++) |
165 | s[i] = ds[0]; | 165 | s[i] = ds[0]; |
166 | /* | 166 | /* |
167 | * Evaluate | 167 | * Evaluate |
168 | * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] | 168 | * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] |
169 | * where x = alpha^(FCR + i) | 169 | * where x = alpha^(FCR + i) |
170 | */ | 170 | */ |
@@ -188,7 +188,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
188 | if (nerr < 0) | 188 | if (nerr < 0) |
189 | return nerr; | 189 | return nerr; |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * Correct the errors. The bitpositions are a bit of magic, | 192 | * Correct the errors. The bitpositions are a bit of magic, |
193 | * but they are given by the design of the de/encoder circuit | 193 | * but they are given by the design of the de/encoder circuit |
194 | * in the DoC ASIC's. | 194 | * in the DoC ASIC's. |
@@ -205,7 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
205 | can be modified since pos is even */ | 205 | can be modified since pos is even */ |
206 | index = (pos >> 3) ^ 1; | 206 | index = (pos >> 3) ^ 1; |
207 | bitpos = pos & 7; | 207 | bitpos = pos & 7; |
208 | if ((index >= 0 && index < SECTOR_SIZE) || | 208 | if ((index >= 0 && index < SECTOR_SIZE) || |
209 | index == (SECTOR_SIZE + 1)) { | 209 | index == (SECTOR_SIZE + 1)) { |
210 | val = (uint8_t) (errval[i] >> (2 + bitpos)); | 210 | val = (uint8_t) (errval[i] >> (2 + bitpos)); |
211 | parity ^= val; | 211 | parity ^= val; |
@@ -216,7 +216,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
216 | bitpos = (bitpos + 10) & 7; | 216 | bitpos = (bitpos + 10) & 7; |
217 | if (bitpos == 0) | 217 | if (bitpos == 0) |
218 | bitpos = 8; | 218 | bitpos = 8; |
219 | if ((index >= 0 && index < SECTOR_SIZE) || | 219 | if ((index >= 0 && index < SECTOR_SIZE) || |
220 | index == (SECTOR_SIZE + 1)) { | 220 | index == (SECTOR_SIZE + 1)) { |
221 | val = (uint8_t)(errval[i] << (8 - bitpos)); | 221 | val = (uint8_t)(errval[i] << (8 - bitpos)); |
222 | parity ^= val; | 222 | parity ^= val; |
@@ -233,7 +233,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) | |||
233 | { | 233 | { |
234 | volatile char dummy; | 234 | volatile char dummy; |
235 | int i; | 235 | int i; |
236 | 236 | ||
237 | for (i = 0; i < cycles; i++) { | 237 | for (i = 0; i < cycles; i++) { |
238 | if (DoC_is_Millennium(doc)) | 238 | if (DoC_is_Millennium(doc)) |
239 | dummy = ReadDOC(doc->virtadr, NOP); | 239 | dummy = ReadDOC(doc->virtadr, NOP); |
@@ -242,7 +242,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) | |||
242 | else | 242 | else |
243 | dummy = ReadDOC(doc->virtadr, DOCStatus); | 243 | dummy = ReadDOC(doc->virtadr, DOCStatus); |
244 | } | 244 | } |
245 | 245 | ||
246 | } | 246 | } |
247 | 247 | ||
248 | #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) | 248 | #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) |
@@ -327,7 +327,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) | |||
327 | return ret; | 327 | return ret; |
328 | } | 328 | } |
329 | 329 | ||
330 | static void doc2000_writebuf(struct mtd_info *mtd, | 330 | static void doc2000_writebuf(struct mtd_info *mtd, |
331 | const u_char *buf, int len) | 331 | const u_char *buf, int len) |
332 | { | 332 | { |
333 | struct nand_chip *this = mtd->priv; | 333 | struct nand_chip *this = mtd->priv; |
@@ -343,7 +343,7 @@ static void doc2000_writebuf(struct mtd_info *mtd, | |||
343 | if (debug) printk("\n"); | 343 | if (debug) printk("\n"); |
344 | } | 344 | } |
345 | 345 | ||
346 | static void doc2000_readbuf(struct mtd_info *mtd, | 346 | static void doc2000_readbuf(struct mtd_info *mtd, |
347 | u_char *buf, int len) | 347 | u_char *buf, int len) |
348 | { | 348 | { |
349 | struct nand_chip *this = mtd->priv; | 349 | struct nand_chip *this = mtd->priv; |
@@ -358,7 +358,7 @@ static void doc2000_readbuf(struct mtd_info *mtd, | |||
358 | } | 358 | } |
359 | } | 359 | } |
360 | 360 | ||
361 | static void doc2000_readbuf_dword(struct mtd_info *mtd, | 361 | static void doc2000_readbuf_dword(struct mtd_info *mtd, |
362 | u_char *buf, int len) | 362 | u_char *buf, int len) |
363 | { | 363 | { |
364 | struct nand_chip *this = mtd->priv; | 364 | struct nand_chip *this = mtd->priv; |
@@ -379,7 +379,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, | |||
379 | } | 379 | } |
380 | } | 380 | } |
381 | 381 | ||
382 | static int doc2000_verifybuf(struct mtd_info *mtd, | 382 | static int doc2000_verifybuf(struct mtd_info *mtd, |
383 | const u_char *buf, int len) | 383 | const u_char *buf, int len) |
384 | { | 384 | { |
385 | struct nand_chip *this = mtd->priv; | 385 | struct nand_chip *this = mtd->priv; |
@@ -406,12 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
406 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); | 406 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); |
407 | this->write_byte(mtd, 0); | 407 | this->write_byte(mtd, 0); |
408 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | 408 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); |
409 | 409 | ||
410 | /* We cant' use dev_ready here, but at least we wait for the | 410 | /* We cant' use dev_ready here, but at least we wait for the |
411 | * command to complete | 411 | * command to complete |
412 | */ | 412 | */ |
413 | udelay(50); | 413 | udelay(50); |
414 | 414 | ||
415 | ret = this->read_byte(mtd) << 8; | 415 | ret = this->read_byte(mtd) << 8; |
416 | ret |= this->read_byte(mtd); | 416 | ret |= this->read_byte(mtd); |
417 | 417 | ||
@@ -438,7 +438,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
438 | this->read_buf = &doc2000_readbuf_dword; | 438 | this->read_buf = &doc2000_readbuf_dword; |
439 | } | 439 | } |
440 | } | 440 | } |
441 | 441 | ||
442 | return ret; | 442 | return ret; |
443 | } | 443 | } |
444 | 444 | ||
@@ -469,7 +469,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
469 | struct doc_priv *doc = this->priv; | 469 | struct doc_priv *doc = this->priv; |
470 | 470 | ||
471 | int status; | 471 | int status; |
472 | 472 | ||
473 | DoC_WaitReady(doc); | 473 | DoC_WaitReady(doc); |
474 | this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 474 | this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
475 | DoC_WaitReady(doc); | 475 | DoC_WaitReady(doc); |
@@ -503,7 +503,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) | |||
503 | return ReadDOC(docptr, LastDataRead); | 503 | return ReadDOC(docptr, LastDataRead); |
504 | } | 504 | } |
505 | 505 | ||
506 | static void doc2001_writebuf(struct mtd_info *mtd, | 506 | static void doc2001_writebuf(struct mtd_info *mtd, |
507 | const u_char *buf, int len) | 507 | const u_char *buf, int len) |
508 | { | 508 | { |
509 | struct nand_chip *this = mtd->priv; | 509 | struct nand_chip *this = mtd->priv; |
@@ -517,7 +517,7 @@ static void doc2001_writebuf(struct mtd_info *mtd, | |||
517 | WriteDOC(0x00, docptr, WritePipeTerm); | 517 | WriteDOC(0x00, docptr, WritePipeTerm); |
518 | } | 518 | } |
519 | 519 | ||
520 | static void doc2001_readbuf(struct mtd_info *mtd, | 520 | static void doc2001_readbuf(struct mtd_info *mtd, |
521 | u_char *buf, int len) | 521 | u_char *buf, int len) |
522 | { | 522 | { |
523 | struct nand_chip *this = mtd->priv; | 523 | struct nand_chip *this = mtd->priv; |
@@ -535,7 +535,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, | |||
535 | buf[i] = ReadDOC(docptr, LastDataRead); | 535 | buf[i] = ReadDOC(docptr, LastDataRead); |
536 | } | 536 | } |
537 | 537 | ||
538 | static int doc2001_verifybuf(struct mtd_info *mtd, | 538 | static int doc2001_verifybuf(struct mtd_info *mtd, |
539 | const u_char *buf, int len) | 539 | const u_char *buf, int len) |
540 | { | 540 | { |
541 | struct nand_chip *this = mtd->priv; | 541 | struct nand_chip *this = mtd->priv; |
@@ -570,7 +570,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) | |||
570 | return ret; | 570 | return ret; |
571 | } | 571 | } |
572 | 572 | ||
573 | static void doc2001plus_writebuf(struct mtd_info *mtd, | 573 | static void doc2001plus_writebuf(struct mtd_info *mtd, |
574 | const u_char *buf, int len) | 574 | const u_char *buf, int len) |
575 | { | 575 | { |
576 | struct nand_chip *this = mtd->priv; | 576 | struct nand_chip *this = mtd->priv; |
@@ -587,7 +587,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, | |||
587 | if (debug) printk("\n"); | 587 | if (debug) printk("\n"); |
588 | } | 588 | } |
589 | 589 | ||
590 | static void doc2001plus_readbuf(struct mtd_info *mtd, | 590 | static void doc2001plus_readbuf(struct mtd_info *mtd, |
591 | u_char *buf, int len) | 591 | u_char *buf, int len) |
592 | { | 592 | { |
593 | struct nand_chip *this = mtd->priv; | 593 | struct nand_chip *this = mtd->priv; |
@@ -617,7 +617,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, | |||
617 | if (debug) printk("\n"); | 617 | if (debug) printk("\n"); |
618 | } | 618 | } |
619 | 619 | ||
620 | static int doc2001plus_verifybuf(struct mtd_info *mtd, | 620 | static int doc2001plus_verifybuf(struct mtd_info *mtd, |
621 | const u_char *buf, int len) | 621 | const u_char *buf, int len) |
622 | { | 622 | { |
623 | struct nand_chip *this = mtd->priv; | 623 | struct nand_chip *this = mtd->priv; |
@@ -797,7 +797,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col | |||
797 | WriteDOC(0, docptr, Mplus_FlashControl); | 797 | WriteDOC(0, docptr, Mplus_FlashControl); |
798 | } | 798 | } |
799 | 799 | ||
800 | /* | 800 | /* |
801 | * program and erase have their own busy handlers | 801 | * program and erase have their own busy handlers |
802 | * status and sequential in needs no delay | 802 | * status and sequential in needs no delay |
803 | */ | 803 | */ |
@@ -822,7 +822,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col | |||
822 | 822 | ||
823 | /* This applies to read commands */ | 823 | /* This applies to read commands */ |
824 | default: | 824 | default: |
825 | /* | 825 | /* |
826 | * If we don't have access to the busy pin, we apply the given | 826 | * If we don't have access to the busy pin, we apply the given |
827 | * command delay | 827 | * command delay |
828 | */ | 828 | */ |
@@ -945,7 +945,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | |||
945 | for (i = 0; i < 6; i++) { | 945 | for (i = 0; i < 6; i++) { |
946 | if (DoC_is_MillenniumPlus(doc)) | 946 | if (DoC_is_MillenniumPlus(doc)) |
947 | ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); | 947 | ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); |
948 | else | 948 | else |
949 | ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); | 949 | ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); |
950 | if (ecc_code[i] != empty_write_ecc[i]) | 950 | if (ecc_code[i] != empty_write_ecc[i]) |
951 | emptymatch = 0; | 951 | emptymatch = 0; |
@@ -982,7 +982,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
982 | void __iomem *docptr = doc->virtadr; | 982 | void __iomem *docptr = doc->virtadr; |
983 | volatile u_char dummy; | 983 | volatile u_char dummy; |
984 | int emptymatch = 1; | 984 | int emptymatch = 1; |
985 | 985 | ||
986 | /* flush the pipeline */ | 986 | /* flush the pipeline */ |
987 | if (DoC_is_2000(doc)) { | 987 | if (DoC_is_2000(doc)) { |
988 | dummy = ReadDOC(docptr, 2k_ECCStatus); | 988 | dummy = ReadDOC(docptr, 2k_ECCStatus); |
@@ -997,7 +997,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
997 | dummy = ReadDOC(docptr, ECCConf); | 997 | dummy = ReadDOC(docptr, ECCConf); |
998 | dummy = ReadDOC(docptr, ECCConf); | 998 | dummy = ReadDOC(docptr, ECCConf); |
999 | } | 999 | } |
1000 | 1000 | ||
1001 | /* Error occured ? */ | 1001 | /* Error occured ? */ |
1002 | if (dummy & 0x80) { | 1002 | if (dummy & 0x80) { |
1003 | for (i = 0; i < 6; i++) { | 1003 | for (i = 0; i < 6; i++) { |
@@ -1035,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
1035 | if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); | 1035 | if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); |
1036 | if (ret > 0) | 1036 | if (ret > 0) |
1037 | printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); | 1037 | printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); |
1038 | } | 1038 | } |
1039 | if (DoC_is_MillenniumPlus(doc)) | 1039 | if (DoC_is_MillenniumPlus(doc)) |
1040 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); | 1040 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); |
1041 | else | 1041 | else |
@@ -1046,7 +1046,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
1046 | } | 1046 | } |
1047 | return ret; | 1047 | return ret; |
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | //u_char mydatabuf[528]; | 1050 | //u_char mydatabuf[528]; |
1051 | 1051 | ||
1052 | /* The strange out-of-order .oobfree list below is a (possibly unneeded) | 1052 | /* The strange out-of-order .oobfree list below is a (possibly unneeded) |
@@ -1065,7 +1065,7 @@ static struct nand_oobinfo doc200x_oobinfo = { | |||
1065 | .eccpos = {0, 1, 2, 3, 4, 5}, | 1065 | .eccpos = {0, 1, 2, 3, 4, 5}, |
1066 | .oobfree = { {8, 8}, {6, 2} } | 1066 | .oobfree = { {8, 8}, {6, 2} } |
1067 | }; | 1067 | }; |
1068 | 1068 | ||
1069 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. | 1069 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. |
1070 | On sucessful return, buf will contain a copy of the media header for | 1070 | On sucessful return, buf will contain a copy of the media header for |
1071 | further processing. id is the string to scan for, and will presumably be | 1071 | further processing. id is the string to scan for, and will presumably be |
@@ -1251,7 +1251,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1251 | mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); | 1251 | mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); |
1252 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); | 1252 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); |
1253 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); | 1253 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); |
1254 | 1254 | ||
1255 | printk(KERN_INFO " bootRecordID = %s\n" | 1255 | printk(KERN_INFO " bootRecordID = %s\n" |
1256 | " NoOfBootImageBlocks = %d\n" | 1256 | " NoOfBootImageBlocks = %d\n" |
1257 | " NoOfBinaryPartitions = %d\n" | 1257 | " NoOfBinaryPartitions = %d\n" |
@@ -1468,7 +1468,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd) | |||
1468 | ReadDOC(doc->virtadr, ChipID); | 1468 | ReadDOC(doc->virtadr, ChipID); |
1469 | if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { | 1469 | if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { |
1470 | /* It's not a Millennium; it's one of the newer | 1470 | /* It's not a Millennium; it's one of the newer |
1471 | DiskOnChip 2000 units with a similar ASIC. | 1471 | DiskOnChip 2000 units with a similar ASIC. |
1472 | Treat it like a Millennium, except that it | 1472 | Treat it like a Millennium, except that it |
1473 | can have multiple chips. */ | 1473 | can have multiple chips. */ |
1474 | doc2000_count_chips(mtd); | 1474 | doc2000_count_chips(mtd); |
@@ -1530,20 +1530,20 @@ static inline int __init doc_probe(unsigned long physadr) | |||
1530 | * to the DOCControl register. So we store the current contents | 1530 | * to the DOCControl register. So we store the current contents |
1531 | * of the DOCControl register's location, in case we later decide | 1531 | * of the DOCControl register's location, in case we later decide |
1532 | * that it's not a DiskOnChip, and want to put it back how we | 1532 | * that it's not a DiskOnChip, and want to put it back how we |
1533 | * found it. | 1533 | * found it. |
1534 | */ | 1534 | */ |
1535 | save_control = ReadDOC(virtadr, DOCControl); | 1535 | save_control = ReadDOC(virtadr, DOCControl); |
1536 | 1536 | ||
1537 | /* Reset the DiskOnChip ASIC */ | 1537 | /* Reset the DiskOnChip ASIC */ |
1538 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 1538 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
1539 | virtadr, DOCControl); | 1539 | virtadr, DOCControl); |
1540 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 1540 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
1541 | virtadr, DOCControl); | 1541 | virtadr, DOCControl); |
1542 | 1542 | ||
1543 | /* Enable the DiskOnChip ASIC */ | 1543 | /* Enable the DiskOnChip ASIC */ |
1544 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 1544 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
1545 | virtadr, DOCControl); | 1545 | virtadr, DOCControl); |
1546 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 1546 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
1547 | virtadr, DOCControl); | 1547 | virtadr, DOCControl); |
1548 | 1548 | ||
1549 | ChipID = ReadDOC(virtadr, ChipID); | 1549 | ChipID = ReadDOC(virtadr, ChipID); |
@@ -1738,7 +1738,7 @@ static int __init init_nanddoc(void) | |||
1738 | int i, ret = 0; | 1738 | int i, ret = 0; |
1739 | 1739 | ||
1740 | /* We could create the decoder on demand, if memory is a concern. | 1740 | /* We could create the decoder on demand, if memory is a concern. |
1741 | * This way we have it handy, if an error happens | 1741 | * This way we have it handy, if an error happens |
1742 | * | 1742 | * |
1743 | * Symbolsize is 10 (bits) | 1743 | * Symbolsize is 10 (bits) |
1744 | * Primitve polynomial is x^10+x^3+1 | 1744 | * Primitve polynomial is x^10+x^3+1 |
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 5549681ccdce..9b1fd2f387fa 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/autcpu12.c | 6 | * Derived from drivers/mtd/nand/autcpu12.c |
7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
8 | * | 8 | * |
9 | * $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -71,27 +71,27 @@ static struct mtd_partition partition_info[] = { | |||
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | 73 | ||
74 | /* | 74 | /* |
75 | * hardware specific access to control-lines | 75 | * hardware specific access to control-lines |
76 | */ | 76 | */ |
77 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) | 77 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) |
78 | { | 78 | { |
79 | switch(cmd) { | 79 | switch(cmd) { |
80 | 80 | ||
81 | case NAND_CTL_SETCLE: | 81 | case NAND_CTL_SETCLE: |
82 | clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); | 82 | clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); |
83 | break; | 83 | break; |
84 | case NAND_CTL_CLRCLE: | 84 | case NAND_CTL_CLRCLE: |
85 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); | 85 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); |
86 | break; | 86 | break; |
87 | 87 | ||
88 | case NAND_CTL_SETALE: | 88 | case NAND_CTL_SETALE: |
89 | clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); | 89 | clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); |
90 | break; | 90 | break; |
91 | case NAND_CTL_CLRALE: | 91 | case NAND_CTL_CLRALE: |
92 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); | 92 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); |
93 | break; | 93 | break; |
94 | 94 | ||
95 | case NAND_CTL_SETNCE: | 95 | case NAND_CTL_SETNCE: |
96 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); | 96 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); |
97 | break; | 97 | break; |
@@ -122,16 +122,16 @@ static int __init ep7312_init (void) | |||
122 | int mtd_parts_nb = 0; | 122 | int mtd_parts_nb = 0; |
123 | struct mtd_partition *mtd_parts = 0; | 123 | struct mtd_partition *mtd_parts = 0; |
124 | void __iomem * ep7312_fio_base; | 124 | void __iomem * ep7312_fio_base; |
125 | 125 | ||
126 | /* Allocate memory for MTD device structure and private data */ | 126 | /* Allocate memory for MTD device structure and private data */ |
127 | ep7312_mtd = kmalloc(sizeof(struct mtd_info) + | 127 | ep7312_mtd = kmalloc(sizeof(struct mtd_info) + |
128 | sizeof(struct nand_chip), | 128 | sizeof(struct nand_chip), |
129 | GFP_KERNEL); | 129 | GFP_KERNEL); |
130 | if (!ep7312_mtd) { | 130 | if (!ep7312_mtd) { |
131 | printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); | 131 | printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | } | 133 | } |
134 | 134 | ||
135 | /* map physical adress */ | 135 | /* map physical adress */ |
136 | ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); | 136 | ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); |
137 | if(!ep7312_fio_base) { | 137 | if(!ep7312_fio_base) { |
@@ -139,23 +139,23 @@ static int __init ep7312_init (void) | |||
139 | kfree(ep7312_mtd); | 139 | kfree(ep7312_mtd); |
140 | return -EIO; | 140 | return -EIO; |
141 | } | 141 | } |
142 | 142 | ||
143 | /* Get pointer to private data */ | 143 | /* Get pointer to private data */ |
144 | this = (struct nand_chip *) (&ep7312_mtd[1]); | 144 | this = (struct nand_chip *) (&ep7312_mtd[1]); |
145 | 145 | ||
146 | /* Initialize structures */ | 146 | /* Initialize structures */ |
147 | memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); | 147 | memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); |
148 | memset((char *) this, 0, sizeof(struct nand_chip)); | 148 | memset((char *) this, 0, sizeof(struct nand_chip)); |
149 | 149 | ||
150 | /* Link the private data with the MTD structure */ | 150 | /* Link the private data with the MTD structure */ |
151 | ep7312_mtd->priv = this; | 151 | ep7312_mtd->priv = this; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Set GPIO Port B control register so that the pins are configured | 154 | * Set GPIO Port B control register so that the pins are configured |
155 | * to be outputs for controlling the NAND flash. | 155 | * to be outputs for controlling the NAND flash. |
156 | */ | 156 | */ |
157 | clps_writeb(0xf0, ep7312_pxddr); | 157 | clps_writeb(0xf0, ep7312_pxddr); |
158 | 158 | ||
159 | /* insert callbacks */ | 159 | /* insert callbacks */ |
160 | this->IO_ADDR_R = ep7312_fio_base; | 160 | this->IO_ADDR_R = ep7312_fio_base; |
161 | this->IO_ADDR_W = ep7312_fio_base; | 161 | this->IO_ADDR_W = ep7312_fio_base; |
@@ -163,14 +163,14 @@ static int __init ep7312_init (void) | |||
163 | this->dev_ready = ep7312_device_ready; | 163 | this->dev_ready = ep7312_device_ready; |
164 | /* 15 us command delay time */ | 164 | /* 15 us command delay time */ |
165 | this->chip_delay = 15; | 165 | this->chip_delay = 15; |
166 | 166 | ||
167 | /* Scan to find existence of the device */ | 167 | /* Scan to find existence of the device */ |
168 | if (nand_scan (ep7312_mtd, 1)) { | 168 | if (nand_scan (ep7312_mtd, 1)) { |
169 | iounmap((void *)ep7312_fio_base); | 169 | iounmap((void *)ep7312_fio_base); |
170 | kfree (ep7312_mtd); | 170 | kfree (ep7312_mtd); |
171 | return -ENXIO; | 171 | return -ENXIO; |
172 | } | 172 | } |
173 | 173 | ||
174 | #ifdef CONFIG_MTD_PARTITIONS | 174 | #ifdef CONFIG_MTD_PARTITIONS |
175 | ep7312_mtd->name = "edb7312-nand"; | 175 | ep7312_mtd->name = "edb7312-nand"; |
176 | mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, | 176 | mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, |
@@ -185,11 +185,11 @@ static int __init ep7312_init (void) | |||
185 | mtd_parts_nb = NUM_PARTITIONS; | 185 | mtd_parts_nb = NUM_PARTITIONS; |
186 | part_type = "static"; | 186 | part_type = "static"; |
187 | } | 187 | } |
188 | 188 | ||
189 | /* Register the partitions */ | 189 | /* Register the partitions */ |
190 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); | 190 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); |
191 | add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); | 191 | add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); |
192 | 192 | ||
193 | /* Return happy */ | 193 | /* Return happy */ |
194 | return 0; | 194 | return 0; |
195 | } | 195 | } |
@@ -201,13 +201,13 @@ module_init(ep7312_init); | |||
201 | static void __exit ep7312_cleanup (void) | 201 | static void __exit ep7312_cleanup (void) |
202 | { | 202 | { |
203 | struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; | 203 | struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; |
204 | 204 | ||
205 | /* Release resources, unregister device */ | 205 | /* Release resources, unregister device */ |
206 | nand_release (ap7312_mtd); | 206 | nand_release (ap7312_mtd); |
207 | 207 | ||
208 | /* Free internal data buffer */ | 208 | /* Free internal data buffer */ |
209 | kfree (this->data_buf); | 209 | kfree (this->data_buf); |
210 | 210 | ||
211 | /* Free the MTD device structure */ | 211 | /* Free the MTD device structure */ |
212 | kfree (ep7312_mtd); | 212 | kfree (ep7312_mtd); |
213 | } | 213 | } |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 3825a7a0900c..041e4b3358fb 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) | 7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) |
8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
9 | * | 9 | * |
10 | * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $ | 10 | * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
@@ -54,24 +54,24 @@ static struct mtd_partition partition_info[] = { | |||
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | 56 | ||
57 | /* | 57 | /* |
58 | * hardware specific access to control-lines | 58 | * hardware specific access to control-lines |
59 | */ | 59 | */ |
60 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) | 60 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) |
61 | { | 61 | { |
62 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); | 62 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); |
63 | 63 | ||
64 | switch(cmd) { | 64 | switch(cmd) { |
65 | 65 | ||
66 | case NAND_CTL_SETCLE: | 66 | case NAND_CTL_SETCLE: |
67 | this->IO_ADDR_R |= (1 << 2); | 67 | this->IO_ADDR_R |= (1 << 2); |
68 | this->IO_ADDR_W |= (1 << 2); | 68 | this->IO_ADDR_W |= (1 << 2); |
69 | break; | 69 | break; |
70 | case NAND_CTL_CLRCLE: | 70 | case NAND_CTL_CLRCLE: |
71 | this->IO_ADDR_R &= ~(1 << 2); | 71 | this->IO_ADDR_R &= ~(1 << 2); |
72 | this->IO_ADDR_W &= ~(1 << 2); | 72 | this->IO_ADDR_W &= ~(1 << 2); |
73 | break; | 73 | break; |
74 | 74 | ||
75 | case NAND_CTL_SETALE: | 75 | case NAND_CTL_SETALE: |
76 | this->IO_ADDR_R |= (1 << 3); | 76 | this->IO_ADDR_R |= (1 << 3); |
77 | this->IO_ADDR_W |= (1 << 3); | 77 | this->IO_ADDR_W |= (1 << 3); |
@@ -80,7 +80,7 @@ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) | |||
80 | this->IO_ADDR_R &= ~(1 << 3); | 80 | this->IO_ADDR_R &= ~(1 << 3); |
81 | this->IO_ADDR_W &= ~(1 << 3); | 81 | this->IO_ADDR_W &= ~(1 << 3); |
82 | break; | 82 | break; |
83 | 83 | ||
84 | case NAND_CTL_SETNCE: | 84 | case NAND_CTL_SETNCE: |
85 | break; | 85 | break; |
86 | case NAND_CTL_CLRNCE: | 86 | case NAND_CTL_CLRNCE: |
@@ -108,18 +108,18 @@ static int __init h1910_init (void) | |||
108 | int mtd_parts_nb = 0; | 108 | int mtd_parts_nb = 0; |
109 | struct mtd_partition *mtd_parts = 0; | 109 | struct mtd_partition *mtd_parts = 0; |
110 | void __iomem *nandaddr; | 110 | void __iomem *nandaddr; |
111 | 111 | ||
112 | if (!machine_is_h1900()) | 112 | if (!machine_is_h1900()) |
113 | return -ENODEV; | 113 | return -ENODEV; |
114 | 114 | ||
115 | nandaddr = __ioremap(0x08000000, 0x1000, 0, 1); | 115 | nandaddr = __ioremap(0x08000000, 0x1000, 0, 1); |
116 | if (!nandaddr) { | 116 | if (!nandaddr) { |
117 | printk("Failed to ioremap nand flash.\n"); | 117 | printk("Failed to ioremap nand flash.\n"); |
118 | return -ENOMEM; | 118 | return -ENOMEM; |
119 | } | 119 | } |
120 | 120 | ||
121 | /* Allocate memory for MTD device structure and private data */ | 121 | /* Allocate memory for MTD device structure and private data */ |
122 | h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + | 122 | h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + |
123 | sizeof(struct nand_chip), | 123 | sizeof(struct nand_chip), |
124 | GFP_KERNEL); | 124 | GFP_KERNEL); |
125 | if (!h1910_nand_mtd) { | 125 | if (!h1910_nand_mtd) { |
@@ -127,22 +127,22 @@ static int __init h1910_init (void) | |||
127 | iounmap ((void *) nandaddr); | 127 | iounmap ((void *) nandaddr); |
128 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | } | 129 | } |
130 | 130 | ||
131 | /* Get pointer to private data */ | 131 | /* Get pointer to private data */ |
132 | this = (struct nand_chip *) (&h1910_nand_mtd[1]); | 132 | this = (struct nand_chip *) (&h1910_nand_mtd[1]); |
133 | 133 | ||
134 | /* Initialize structures */ | 134 | /* Initialize structures */ |
135 | memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); | 135 | memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); |
136 | memset((char *) this, 0, sizeof(struct nand_chip)); | 136 | memset((char *) this, 0, sizeof(struct nand_chip)); |
137 | 137 | ||
138 | /* Link the private data with the MTD structure */ | 138 | /* Link the private data with the MTD structure */ |
139 | h1910_nand_mtd->priv = this; | 139 | h1910_nand_mtd->priv = this; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Enable VPEN | 142 | * Enable VPEN |
143 | */ | 143 | */ |
144 | GPSR(37) = GPIO_bit(37); | 144 | GPSR(37) = GPIO_bit(37); |
145 | 145 | ||
146 | /* insert callbacks */ | 146 | /* insert callbacks */ |
147 | this->IO_ADDR_R = nandaddr; | 147 | this->IO_ADDR_R = nandaddr; |
148 | this->IO_ADDR_W = nandaddr; | 148 | this->IO_ADDR_W = nandaddr; |
@@ -152,7 +152,7 @@ static int __init h1910_init (void) | |||
152 | this->chip_delay = 50; | 152 | this->chip_delay = 50; |
153 | this->eccmode = NAND_ECC_SOFT; | 153 | this->eccmode = NAND_ECC_SOFT; |
154 | this->options = NAND_NO_AUTOINCR; | 154 | this->options = NAND_NO_AUTOINCR; |
155 | 155 | ||
156 | /* Scan to find existence of the device */ | 156 | /* Scan to find existence of the device */ |
157 | if (nand_scan (h1910_nand_mtd, 1)) { | 157 | if (nand_scan (h1910_nand_mtd, 1)) { |
158 | printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); | 158 | printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); |
@@ -160,9 +160,9 @@ static int __init h1910_init (void) | |||
160 | iounmap ((void *) nandaddr); | 160 | iounmap ((void *) nandaddr); |
161 | return -ENXIO; | 161 | return -ENXIO; |
162 | } | 162 | } |
163 | 163 | ||
164 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 164 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
165 | mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, | 165 | mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, |
166 | "h1910-nand"); | 166 | "h1910-nand"); |
167 | if (mtd_parts_nb > 0) | 167 | if (mtd_parts_nb > 0) |
168 | part_type = "command line"; | 168 | part_type = "command line"; |
@@ -175,11 +175,11 @@ static int __init h1910_init (void) | |||
175 | mtd_parts_nb = NUM_PARTITIONS; | 175 | mtd_parts_nb = NUM_PARTITIONS; |
176 | part_type = "static"; | 176 | part_type = "static"; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* Register the partitions */ | 179 | /* Register the partitions */ |
180 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); | 180 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); |
181 | add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); | 181 | add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); |
182 | 182 | ||
183 | /* Return happy */ | 183 | /* Return happy */ |
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
@@ -191,7 +191,7 @@ module_init(h1910_init); | |||
191 | static void __exit h1910_cleanup (void) | 191 | static void __exit h1910_cleanup (void) |
192 | { | 192 | { |
193 | struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; | 193 | struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; |
194 | 194 | ||
195 | /* Release resources, unregister device */ | 195 | /* Release resources, unregister device */ |
196 | nand_release (h1910_nand_mtd); | 196 | nand_release (h1910_nand_mtd); |
197 | 197 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8e78d7b96a56..5d222460b42a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -5,14 +5,14 @@ | |||
5 | * This is the generic MTD driver for NAND flash devices. It should be | 5 | * This is the generic MTD driver for NAND flash devices. It should be |
6 | * capable of working with almost all NAND chips currently available. | 6 | * capable of working with almost all NAND chips currently available. |
7 | * Basic support for AG-AND chips is provided. | 7 | * Basic support for AG-AND chips is provided. |
8 | * | 8 | * |
9 | * Additional technical information is available on | 9 | * Additional technical information is available on |
10 | * http://www.linux-mtd.infradead.org/tech/nand.html | 10 | * http://www.linux-mtd.infradead.org/tech/nand.html |
11 | * | 11 | * |
12 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 12 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
13 | * 2002 Thomas Gleixner (tglx@linutronix.de) | 13 | * 2002 Thomas Gleixner (tglx@linutronix.de) |
14 | * | 14 | * |
15 | * 02-08-2004 tglx: support for strange chips, which cannot auto increment | 15 | * 02-08-2004 tglx: support for strange chips, which cannot auto increment |
16 | * pages on read / read_oob | 16 | * pages on read / read_oob |
17 | * | 17 | * |
18 | * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes | 18 | * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes |
@@ -21,7 +21,7 @@ | |||
21 | * Make reads over block boundaries work too | 21 | * Make reads over block boundaries work too |
22 | * | 22 | * |
23 | * 04-14-2004 tglx: first working version for 2k page size chips | 23 | * 04-14-2004 tglx: first working version for 2k page size chips |
24 | * | 24 | * |
25 | * 05-19-2004 tglx: Basic support for Renesas AG-AND chips | 25 | * 05-19-2004 tglx: Basic support for Renesas AG-AND chips |
26 | * | 26 | * |
27 | * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared | 27 | * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared |
@@ -30,25 +30,27 @@ | |||
30 | * | 30 | * |
31 | * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. | 31 | * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. |
32 | * Basically, any block not rewritten may lose data when surrounding blocks | 32 | * Basically, any block not rewritten may lose data when surrounding blocks |
33 | * are rewritten many times. JFFS2 ensures this doesn't happen for blocks | 33 | * are rewritten many times. JFFS2 ensures this doesn't happen for blocks |
34 | * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they | 34 | * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they |
35 | * do not lose data, force them to be rewritten when some of the surrounding | 35 | * do not lose data, force them to be rewritten when some of the surrounding |
36 | * blocks are erased. Rather than tracking a specific nearby block (which | 36 | * blocks are erased. Rather than tracking a specific nearby block (which |
37 | * could itself go bad), use a page address 'mask' to select several blocks | 37 | * could itself go bad), use a page address 'mask' to select several blocks |
38 | * in the same area, and rewrite the BBT when any of them are erased. | 38 | * in the same area, and rewrite the BBT when any of them are erased. |
39 | * | 39 | * |
40 | * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas | 40 | * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas |
41 | * AG-AND chips. If there was a sudden loss of power during an erase operation, | 41 | * AG-AND chips. If there was a sudden loss of power during an erase operation, |
42 | * a "device recovery" operation must be performed when power is restored | 42 | * a "device recovery" operation must be performed when power is restored |
43 | * to ensure correct operation. | 43 | * to ensure correct operation. |
44 | * | 44 | * |
45 | * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to | 45 | * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to |
46 | * perform extra error status checks on erase and write failures. This required | 46 | * perform extra error status checks on erase and write failures. This required |
47 | * adding a wrapper function for nand_read_ecc. | 47 | * adding a wrapper function for nand_read_ecc. |
48 | * | 48 | * |
49 | * 08-20-2005 vwool: suspend/resume added | ||
50 | * | ||
49 | * Credits: | 51 | * Credits: |
50 | * David Woodhouse for adding multichip support | 52 | * David Woodhouse for adding multichip support |
51 | * | 53 | * |
52 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the | 54 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the |
53 | * rework for 2K page size chips | 55 | * rework for 2K page size chips |
54 | * | 56 | * |
@@ -59,7 +61,7 @@ | |||
59 | * The AG-AND chips have nice features for speed improvement, | 61 | * The AG-AND chips have nice features for speed improvement, |
60 | * which are not supported yet. Read / program 4 pages in one go. | 62 | * which are not supported yet. Read / program 4 pages in one go. |
61 | * | 63 | * |
62 | * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $ | 64 | * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $ |
63 | * | 65 | * |
64 | * This program is free software; you can redistribute it and/or modify | 66 | * This program is free software; you can redistribute it and/or modify |
65 | * it under the terms of the GNU General Public License version 2 as | 67 | * it under the terms of the GNU General Public License version 2 as |
@@ -103,8 +105,8 @@ static struct nand_oobinfo nand_oob_64 = { | |||
103 | .useecc = MTD_NANDECC_AUTOPLACE, | 105 | .useecc = MTD_NANDECC_AUTOPLACE, |
104 | .eccbytes = 24, | 106 | .eccbytes = 24, |
105 | .eccpos = { | 107 | .eccpos = { |
106 | 40, 41, 42, 43, 44, 45, 46, 47, | 108 | 40, 41, 42, 43, 44, 45, 46, 47, |
107 | 48, 49, 50, 51, 52, 53, 54, 55, | 109 | 48, 49, 50, 51, 52, 53, 54, 55, |
108 | 56, 57, 58, 59, 60, 61, 62, 63}, | 110 | 56, 57, 58, 59, 60, 61, 62, 63}, |
109 | .oobfree = { {2, 38} } | 111 | .oobfree = { {2, 38} } |
110 | }; | 112 | }; |
@@ -147,19 +149,19 @@ static void nand_sync (struct mtd_info *mtd); | |||
147 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, | 149 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, |
148 | struct nand_oobinfo *oobsel, int mode); | 150 | struct nand_oobinfo *oobsel, int mode); |
149 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 151 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
150 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, | 152 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, |
151 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); | 153 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); |
152 | #else | 154 | #else |
153 | #define nand_verify_pages(...) (0) | 155 | #define nand_verify_pages(...) (0) |
154 | #endif | 156 | #endif |
155 | 157 | ||
156 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); | 158 | static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); |
157 | 159 | ||
158 | /** | 160 | /** |
159 | * nand_release_device - [GENERIC] release chip | 161 | * nand_release_device - [GENERIC] release chip |
160 | * @mtd: MTD device structure | 162 | * @mtd: MTD device structure |
161 | * | 163 | * |
162 | * Deselect, release chip lock and wake up anyone waiting on the device | 164 | * Deselect, release chip lock and wake up anyone waiting on the device |
163 | */ | 165 | */ |
164 | static void nand_release_device (struct mtd_info *mtd) | 166 | static void nand_release_device (struct mtd_info *mtd) |
165 | { | 167 | { |
@@ -213,7 +215,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
213 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip | 215 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip |
214 | * @mtd: MTD device structure | 216 | * @mtd: MTD device structure |
215 | * | 217 | * |
216 | * Default read function for 16bit buswith with | 218 | * Default read function for 16bit buswith with |
217 | * endianess conversion | 219 | * endianess conversion |
218 | */ | 220 | */ |
219 | static u_char nand_read_byte16(struct mtd_info *mtd) | 221 | static u_char nand_read_byte16(struct mtd_info *mtd) |
@@ -240,7 +242,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) | |||
240 | * nand_read_word - [DEFAULT] read one word from the chip | 242 | * nand_read_word - [DEFAULT] read one word from the chip |
241 | * @mtd: MTD device structure | 243 | * @mtd: MTD device structure |
242 | * | 244 | * |
243 | * Default read function for 16bit buswith without | 245 | * Default read function for 16bit buswith without |
244 | * endianess conversion | 246 | * endianess conversion |
245 | */ | 247 | */ |
246 | static u16 nand_read_word(struct mtd_info *mtd) | 248 | static u16 nand_read_word(struct mtd_info *mtd) |
@@ -254,7 +256,7 @@ static u16 nand_read_word(struct mtd_info *mtd) | |||
254 | * @mtd: MTD device structure | 256 | * @mtd: MTD device structure |
255 | * @word: data word to write | 257 | * @word: data word to write |
256 | * | 258 | * |
257 | * Default write function for 16bit buswith without | 259 | * Default write function for 16bit buswith without |
258 | * endianess conversion | 260 | * endianess conversion |
259 | */ | 261 | */ |
260 | static void nand_write_word(struct mtd_info *mtd, u16 word) | 262 | static void nand_write_word(struct mtd_info *mtd, u16 word) |
@@ -275,7 +277,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) | |||
275 | struct nand_chip *this = mtd->priv; | 277 | struct nand_chip *this = mtd->priv; |
276 | switch(chip) { | 278 | switch(chip) { |
277 | case -1: | 279 | case -1: |
278 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | 280 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); |
279 | break; | 281 | break; |
280 | case 0: | 282 | case 0: |
281 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | 283 | this->hwcontrol(mtd, NAND_CTL_SETNCE); |
@@ -304,7 +306,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
304 | } | 306 | } |
305 | 307 | ||
306 | /** | 308 | /** |
307 | * nand_read_buf - [DEFAULT] read chip data into buffer | 309 | * nand_read_buf - [DEFAULT] read chip data into buffer |
308 | * @mtd: MTD device structure | 310 | * @mtd: MTD device structure |
309 | * @buf: buffer to store date | 311 | * @buf: buffer to store date |
310 | * @len: number of bytes to read | 312 | * @len: number of bytes to read |
@@ -321,7 +323,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
321 | } | 323 | } |
322 | 324 | ||
323 | /** | 325 | /** |
324 | * nand_verify_buf - [DEFAULT] Verify chip data against buffer | 326 | * nand_verify_buf - [DEFAULT] Verify chip data against buffer |
325 | * @mtd: MTD device structure | 327 | * @mtd: MTD device structure |
326 | * @buf: buffer containing the data to compare | 328 | * @buf: buffer containing the data to compare |
327 | * @len: number of bytes to compare | 329 | * @len: number of bytes to compare |
@@ -354,14 +356,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
354 | struct nand_chip *this = mtd->priv; | 356 | struct nand_chip *this = mtd->priv; |
355 | u16 *p = (u16 *) buf; | 357 | u16 *p = (u16 *) buf; |
356 | len >>= 1; | 358 | len >>= 1; |
357 | 359 | ||
358 | for (i=0; i<len; i++) | 360 | for (i=0; i<len; i++) |
359 | writew(p[i], this->IO_ADDR_W); | 361 | writew(p[i], this->IO_ADDR_W); |
360 | 362 | ||
361 | } | 363 | } |
362 | 364 | ||
363 | /** | 365 | /** |
364 | * nand_read_buf16 - [DEFAULT] read chip data into buffer | 366 | * nand_read_buf16 - [DEFAULT] read chip data into buffer |
365 | * @mtd: MTD device structure | 367 | * @mtd: MTD device structure |
366 | * @buf: buffer to store date | 368 | * @buf: buffer to store date |
367 | * @len: number of bytes to read | 369 | * @len: number of bytes to read |
@@ -380,7 +382,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) | |||
380 | } | 382 | } |
381 | 383 | ||
382 | /** | 384 | /** |
383 | * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer | 385 | * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer |
384 | * @mtd: MTD device structure | 386 | * @mtd: MTD device structure |
385 | * @buf: buffer containing the data to compare | 387 | * @buf: buffer containing the data to compare |
386 | * @len: number of bytes to compare | 388 | * @len: number of bytes to compare |
@@ -407,7 +409,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
407 | * @ofs: offset from device start | 409 | * @ofs: offset from device start |
408 | * @getchip: 0, if the chip is already selected | 410 | * @getchip: 0, if the chip is already selected |
409 | * | 411 | * |
410 | * Check, if the block is bad. | 412 | * Check, if the block is bad. |
411 | */ | 413 | */ |
412 | static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | 414 | static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) |
413 | { | 415 | { |
@@ -424,14 +426,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
424 | 426 | ||
425 | /* Select the NAND device */ | 427 | /* Select the NAND device */ |
426 | this->select_chip(mtd, chipnr); | 428 | this->select_chip(mtd, chipnr); |
427 | } else | 429 | } else |
428 | page = (int) ofs; | 430 | page = (int) ofs; |
429 | 431 | ||
430 | if (this->options & NAND_BUSWIDTH_16) { | 432 | if (this->options & NAND_BUSWIDTH_16) { |
431 | this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); | 433 | this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); |
432 | bad = cpu_to_le16(this->read_word(mtd)); | 434 | bad = cpu_to_le16(this->read_word(mtd)); |
433 | if (this->badblockpos & 0x1) | 435 | if (this->badblockpos & 0x1) |
434 | bad >>= 1; | 436 | bad >>= 8; |
435 | if ((bad & 0xFF) != 0xff) | 437 | if ((bad & 0xFF) != 0xff) |
436 | res = 1; | 438 | res = 1; |
437 | } else { | 439 | } else { |
@@ -439,12 +441,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
439 | if (this->read_byte(mtd) != 0xff) | 441 | if (this->read_byte(mtd) != 0xff) |
440 | res = 1; | 442 | res = 1; |
441 | } | 443 | } |
442 | 444 | ||
443 | if (getchip) { | 445 | if (getchip) { |
444 | /* Deselect and wake up anyone waiting on the device */ | 446 | /* Deselect and wake up anyone waiting on the device */ |
445 | nand_release_device(mtd); | 447 | nand_release_device(mtd); |
446 | } | 448 | } |
447 | 449 | ||
448 | return res; | 450 | return res; |
449 | } | 451 | } |
450 | 452 | ||
@@ -462,7 +464,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
462 | u_char buf[2] = {0, 0}; | 464 | u_char buf[2] = {0, 0}; |
463 | size_t retlen; | 465 | size_t retlen; |
464 | int block; | 466 | int block; |
465 | 467 | ||
466 | /* Get block number */ | 468 | /* Get block number */ |
467 | block = ((int) ofs) >> this->bbt_erase_shift; | 469 | block = ((int) ofs) >> this->bbt_erase_shift; |
468 | if (this->bbt) | 470 | if (this->bbt) |
@@ -471,25 +473,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
471 | /* Do we have a flash based bad block table ? */ | 473 | /* Do we have a flash based bad block table ? */ |
472 | if (this->options & NAND_USE_FLASH_BBT) | 474 | if (this->options & NAND_USE_FLASH_BBT) |
473 | return nand_update_bbt (mtd, ofs); | 475 | return nand_update_bbt (mtd, ofs); |
474 | 476 | ||
475 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 477 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
476 | ofs += mtd->oobsize + (this->badblockpos & ~0x01); | 478 | ofs += mtd->oobsize + (this->badblockpos & ~0x01); |
477 | return nand_write_oob (mtd, ofs , 2, &retlen, buf); | 479 | return nand_write_oob (mtd, ofs , 2, &retlen, buf); |
478 | } | 480 | } |
479 | 481 | ||
480 | /** | 482 | /** |
481 | * nand_check_wp - [GENERIC] check if the chip is write protected | 483 | * nand_check_wp - [GENERIC] check if the chip is write protected |
482 | * @mtd: MTD device structure | 484 | * @mtd: MTD device structure |
483 | * Check, if the device is write protected | 485 | * Check, if the device is write protected |
484 | * | 486 | * |
485 | * The function expects, that the device is already selected | 487 | * The function expects, that the device is already selected |
486 | */ | 488 | */ |
487 | static int nand_check_wp (struct mtd_info *mtd) | 489 | static int nand_check_wp (struct mtd_info *mtd) |
488 | { | 490 | { |
489 | struct nand_chip *this = mtd->priv; | 491 | struct nand_chip *this = mtd->priv; |
490 | /* Check the WP bit */ | 492 | /* Check the WP bit */ |
491 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); | 493 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); |
492 | return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; | 494 | return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; |
493 | } | 495 | } |
494 | 496 | ||
495 | /** | 497 | /** |
@@ -505,15 +507,15 @@ static int nand_check_wp (struct mtd_info *mtd) | |||
505 | static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) | 507 | static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) |
506 | { | 508 | { |
507 | struct nand_chip *this = mtd->priv; | 509 | struct nand_chip *this = mtd->priv; |
508 | 510 | ||
509 | if (!this->bbt) | 511 | if (!this->bbt) |
510 | return this->block_bad(mtd, ofs, getchip); | 512 | return this->block_bad(mtd, ofs, getchip); |
511 | 513 | ||
512 | /* Return info from the table */ | 514 | /* Return info from the table */ |
513 | return nand_isbad_bbt (mtd, ofs, allowbbt); | 515 | return nand_isbad_bbt (mtd, ofs, allowbbt); |
514 | } | 516 | } |
515 | 517 | ||
516 | /* | 518 | /* |
517 | * Wait for the ready pin, after a command | 519 | * Wait for the ready pin, after a command |
518 | * The timeout is catched later. | 520 | * The timeout is catched later. |
519 | */ | 521 | */ |
@@ -527,7 +529,7 @@ static void nand_wait_ready(struct mtd_info *mtd) | |||
527 | if (this->dev_ready(mtd)) | 529 | if (this->dev_ready(mtd)) |
528 | return; | 530 | return; |
529 | touch_softlockup_watchdog(); | 531 | touch_softlockup_watchdog(); |
530 | } while (time_before(jiffies, timeo)); | 532 | } while (time_before(jiffies, timeo)); |
531 | } | 533 | } |
532 | 534 | ||
533 | /** | 535 | /** |
@@ -590,13 +592,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
590 | /* Latch in address */ | 592 | /* Latch in address */ |
591 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 593 | this->hwcontrol(mtd, NAND_CTL_CLRALE); |
592 | } | 594 | } |
593 | 595 | ||
594 | /* | 596 | /* |
595 | * program and erase have their own busy handlers | 597 | * program and erase have their own busy handlers |
596 | * status and sequential in needs no delay | 598 | * status and sequential in needs no delay |
597 | */ | 599 | */ |
598 | switch (command) { | 600 | switch (command) { |
599 | 601 | ||
600 | case NAND_CMD_PAGEPROG: | 602 | case NAND_CMD_PAGEPROG: |
601 | case NAND_CMD_ERASE1: | 603 | case NAND_CMD_ERASE1: |
602 | case NAND_CMD_ERASE2: | 604 | case NAND_CMD_ERASE2: |
@@ -605,7 +607,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
605 | return; | 607 | return; |
606 | 608 | ||
607 | case NAND_CMD_RESET: | 609 | case NAND_CMD_RESET: |
608 | if (this->dev_ready) | 610 | if (this->dev_ready) |
609 | break; | 611 | break; |
610 | udelay(this->chip_delay); | 612 | udelay(this->chip_delay); |
611 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 613 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
@@ -614,16 +616,16 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
614 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); | 616 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); |
615 | return; | 617 | return; |
616 | 618 | ||
617 | /* This applies to read commands */ | 619 | /* This applies to read commands */ |
618 | default: | 620 | default: |
619 | /* | 621 | /* |
620 | * If we don't have access to the busy pin, we apply the given | 622 | * If we don't have access to the busy pin, we apply the given |
621 | * command delay | 623 | * command delay |
622 | */ | 624 | */ |
623 | if (!this->dev_ready) { | 625 | if (!this->dev_ready) { |
624 | udelay (this->chip_delay); | 626 | udelay (this->chip_delay); |
625 | return; | 627 | return; |
626 | } | 628 | } |
627 | } | 629 | } |
628 | /* Apply this short delay always to ensure that we do wait tWB in | 630 | /* Apply this short delay always to ensure that we do wait tWB in |
629 | * any case on any machine. */ | 631 | * any case on any machine. */ |
@@ -653,8 +655,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
653 | column += mtd->oobblock; | 655 | column += mtd->oobblock; |
654 | command = NAND_CMD_READ0; | 656 | command = NAND_CMD_READ0; |
655 | } | 657 | } |
656 | 658 | ||
657 | 659 | ||
658 | /* Begin command latch cycle */ | 660 | /* Begin command latch cycle */ |
659 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 661 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
660 | /* Write out the command to the device. */ | 662 | /* Write out the command to the device. */ |
@@ -672,7 +674,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
672 | column >>= 1; | 674 | column >>= 1; |
673 | this->write_byte(mtd, column & 0xff); | 675 | this->write_byte(mtd, column & 0xff); |
674 | this->write_byte(mtd, column >> 8); | 676 | this->write_byte(mtd, column >> 8); |
675 | } | 677 | } |
676 | if (page_addr != -1) { | 678 | if (page_addr != -1) { |
677 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); | 679 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); |
678 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); | 680 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); |
@@ -683,13 +685,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
683 | /* Latch in address */ | 685 | /* Latch in address */ |
684 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 686 | this->hwcontrol(mtd, NAND_CTL_CLRALE); |
685 | } | 687 | } |
686 | 688 | ||
687 | /* | 689 | /* |
688 | * program and erase have their own busy handlers | 690 | * program and erase have their own busy handlers |
689 | * status, sequential in, and deplete1 need no delay | 691 | * status, sequential in, and deplete1 need no delay |
690 | */ | 692 | */ |
691 | switch (command) { | 693 | switch (command) { |
692 | 694 | ||
693 | case NAND_CMD_CACHEDPROG: | 695 | case NAND_CMD_CACHEDPROG: |
694 | case NAND_CMD_PAGEPROG: | 696 | case NAND_CMD_PAGEPROG: |
695 | case NAND_CMD_ERASE1: | 697 | case NAND_CMD_ERASE1: |
@@ -699,7 +701,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
699 | case NAND_CMD_DEPLETE1: | 701 | case NAND_CMD_DEPLETE1: |
700 | return; | 702 | return; |
701 | 703 | ||
702 | /* | 704 | /* |
703 | * read error status commands require only a short delay | 705 | * read error status commands require only a short delay |
704 | */ | 706 | */ |
705 | case NAND_CMD_STATUS_ERROR: | 707 | case NAND_CMD_STATUS_ERROR: |
@@ -711,7 +713,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
711 | return; | 713 | return; |
712 | 714 | ||
713 | case NAND_CMD_RESET: | 715 | case NAND_CMD_RESET: |
714 | if (this->dev_ready) | 716 | if (this->dev_ready) |
715 | break; | 717 | break; |
716 | udelay(this->chip_delay); | 718 | udelay(this->chip_delay); |
717 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 719 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
@@ -728,17 +730,17 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
728 | /* End command latch cycle */ | 730 | /* End command latch cycle */ |
729 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 731 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); |
730 | /* Fall through into ready check */ | 732 | /* Fall through into ready check */ |
731 | 733 | ||
732 | /* This applies to read commands */ | 734 | /* This applies to read commands */ |
733 | default: | 735 | default: |
734 | /* | 736 | /* |
735 | * If we don't have access to the busy pin, we apply the given | 737 | * If we don't have access to the busy pin, we apply the given |
736 | * command delay | 738 | * command delay |
737 | */ | 739 | */ |
738 | if (!this->dev_ready) { | 740 | if (!this->dev_ready) { |
739 | udelay (this->chip_delay); | 741 | udelay (this->chip_delay); |
740 | return; | 742 | return; |
741 | } | 743 | } |
742 | } | 744 | } |
743 | 745 | ||
744 | /* Apply this short delay always to ensure that we do wait tWB in | 746 | /* Apply this short delay always to ensure that we do wait tWB in |
@@ -752,11 +754,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
752 | * nand_get_device - [GENERIC] Get chip for selected access | 754 | * nand_get_device - [GENERIC] Get chip for selected access |
753 | * @this: the nand chip descriptor | 755 | * @this: the nand chip descriptor |
754 | * @mtd: MTD device structure | 756 | * @mtd: MTD device structure |
755 | * @new_state: the state which is requested | 757 | * @new_state: the state which is requested |
756 | * | 758 | * |
757 | * Get the device and lock it for exclusive access | 759 | * Get the device and lock it for exclusive access |
758 | */ | 760 | */ |
759 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) | 761 | static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) |
760 | { | 762 | { |
761 | struct nand_chip *active; | 763 | struct nand_chip *active; |
762 | spinlock_t *lock; | 764 | spinlock_t *lock; |
@@ -779,7 +781,11 @@ retry: | |||
779 | if (active == this && this->state == FL_READY) { | 781 | if (active == this && this->state == FL_READY) { |
780 | this->state = new_state; | 782 | this->state = new_state; |
781 | spin_unlock(lock); | 783 | spin_unlock(lock); |
782 | return; | 784 | return 0; |
785 | } | ||
786 | if (new_state == FL_PM_SUSPENDED) { | ||
787 | spin_unlock(lock); | ||
788 | return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; | ||
783 | } | 789 | } |
784 | set_current_state(TASK_UNINTERRUPTIBLE); | 790 | set_current_state(TASK_UNINTERRUPTIBLE); |
785 | add_wait_queue(wq, &wait); | 791 | add_wait_queue(wq, &wait); |
@@ -796,7 +802,7 @@ retry: | |||
796 | * @state: state to select the max. timeout value | 802 | * @state: state to select the max. timeout value |
797 | * | 803 | * |
798 | * Wait for command done. This applies to erase and program only | 804 | * Wait for command done. This applies to erase and program only |
799 | * Erase can take up to 400ms and program up to 20ms according to | 805 | * Erase can take up to 400ms and program up to 20ms according to |
800 | * general NAND and SmartMedia specs | 806 | * general NAND and SmartMedia specs |
801 | * | 807 | * |
802 | */ | 808 | */ |
@@ -805,7 +811,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
805 | 811 | ||
806 | unsigned long timeo = jiffies; | 812 | unsigned long timeo = jiffies; |
807 | int status; | 813 | int status; |
808 | 814 | ||
809 | if (state == FL_ERASING) | 815 | if (state == FL_ERASING) |
810 | timeo += (HZ * 400) / 1000; | 816 | timeo += (HZ * 400) / 1000; |
811 | else | 817 | else |
@@ -817,17 +823,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
817 | 823 | ||
818 | if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) | 824 | if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) |
819 | this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); | 825 | this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); |
820 | else | 826 | else |
821 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); | 827 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); |
822 | 828 | ||
823 | while (time_before(jiffies, timeo)) { | 829 | while (time_before(jiffies, timeo)) { |
824 | /* Check, if we were interrupted */ | 830 | /* Check, if we were interrupted */ |
825 | if (this->state != state) | 831 | if (this->state != state) |
826 | return 0; | 832 | return 0; |
827 | 833 | ||
828 | if (this->dev_ready) { | 834 | if (this->dev_ready) { |
829 | if (this->dev_ready(mtd)) | 835 | if (this->dev_ready(mtd)) |
830 | break; | 836 | break; |
831 | } else { | 837 | } else { |
832 | if (this->read_byte(mtd) & NAND_STATUS_READY) | 838 | if (this->read_byte(mtd) & NAND_STATUS_READY) |
833 | break; | 839 | break; |
@@ -853,7 +859,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
853 | * | 859 | * |
854 | * Cached programming is not supported yet. | 860 | * Cached programming is not supported yet. |
855 | */ | 861 | */ |
856 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, | 862 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, |
857 | u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) | 863 | u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) |
858 | { | 864 | { |
859 | int i, status; | 865 | int i, status; |
@@ -862,10 +868,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
862 | int *oob_config = oobsel->eccpos; | 868 | int *oob_config = oobsel->eccpos; |
863 | int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; | 869 | int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; |
864 | int eccbytes = 0; | 870 | int eccbytes = 0; |
865 | 871 | ||
866 | /* FIXME: Enable cached programming */ | 872 | /* FIXME: Enable cached programming */ |
867 | cached = 0; | 873 | cached = 0; |
868 | 874 | ||
869 | /* Send command to begin auto page programming */ | 875 | /* Send command to begin auto page programming */ |
870 | this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); | 876 | this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); |
871 | 877 | ||
@@ -876,7 +882,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
876 | printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); | 882 | printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); |
877 | this->write_buf(mtd, this->data_poi, mtd->oobblock); | 883 | this->write_buf(mtd, this->data_poi, mtd->oobblock); |
878 | break; | 884 | break; |
879 | 885 | ||
880 | /* Software ecc 3/256, write all */ | 886 | /* Software ecc 3/256, write all */ |
881 | case NAND_ECC_SOFT: | 887 | case NAND_ECC_SOFT: |
882 | for (; eccsteps; eccsteps--) { | 888 | for (; eccsteps; eccsteps--) { |
@@ -905,11 +911,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
905 | } | 911 | } |
906 | break; | 912 | break; |
907 | } | 913 | } |
908 | 914 | ||
909 | /* Write out OOB data */ | 915 | /* Write out OOB data */ |
910 | if (this->options & NAND_HWECC_SYNDROME) | 916 | if (this->options & NAND_HWECC_SYNDROME) |
911 | this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); | 917 | this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); |
912 | else | 918 | else |
913 | this->write_buf(mtd, oob_buf, mtd->oobsize); | 919 | this->write_buf(mtd, oob_buf, mtd->oobsize); |
914 | 920 | ||
915 | /* Send command to actually program the data */ | 921 | /* Send command to actually program the data */ |
@@ -934,7 +940,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
934 | /* wait until cache is ready*/ | 940 | /* wait until cache is ready*/ |
935 | // status = this->waitfunc (mtd, this, FL_CACHEDRPG); | 941 | // status = this->waitfunc (mtd, this, FL_CACHEDRPG); |
936 | } | 942 | } |
937 | return 0; | 943 | return 0; |
938 | } | 944 | } |
939 | 945 | ||
940 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 946 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
@@ -950,19 +956,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
950 | * @oobmode: 1 = full buffer verify, 0 = ecc only | 956 | * @oobmode: 1 = full buffer verify, 0 = ecc only |
951 | * | 957 | * |
952 | * The NAND device assumes that it is always writing to a cleanly erased page. | 958 | * The NAND device assumes that it is always writing to a cleanly erased page. |
953 | * Hence, it performs its internal write verification only on bits that | 959 | * Hence, it performs its internal write verification only on bits that |
954 | * transitioned from 1 to 0. The device does NOT verify the whole page on a | 960 | * transitioned from 1 to 0. The device does NOT verify the whole page on a |
955 | * byte by byte basis. It is possible that the page was not completely erased | 961 | * byte by byte basis. It is possible that the page was not completely erased |
956 | * or the page is becoming unusable due to wear. The read with ECC would catch | 962 | * or the page is becoming unusable due to wear. The read with ECC would catch |
957 | * the error later when the ECC page check fails, but we would rather catch | 963 | * the error later when the ECC page check fails, but we would rather catch |
958 | * it early in the page write stage. Better to write no data than invalid data. | 964 | * it early in the page write stage. Better to write no data than invalid data. |
959 | */ | 965 | */ |
960 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, | 966 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, |
961 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) | 967 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) |
962 | { | 968 | { |
963 | int i, j, datidx = 0, oobofs = 0, res = -EIO; | 969 | int i, j, datidx = 0, oobofs = 0, res = -EIO; |
964 | int eccsteps = this->eccsteps; | 970 | int eccsteps = this->eccsteps; |
965 | int hweccbytes; | 971 | int hweccbytes; |
966 | u_char oobdata[64]; | 972 | u_char oobdata[64]; |
967 | 973 | ||
968 | hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; | 974 | hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; |
@@ -1002,7 +1008,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1002 | 1008 | ||
1003 | if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { | 1009 | if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { |
1004 | int ecccnt = oobsel->eccbytes; | 1010 | int ecccnt = oobsel->eccbytes; |
1005 | 1011 | ||
1006 | for (i = 0; i < ecccnt; i++) { | 1012 | for (i = 0; i < ecccnt; i++) { |
1007 | int idx = oobsel->eccpos[i]; | 1013 | int idx = oobsel->eccpos[i]; |
1008 | if (oobdata[idx] != oob_buf[oobofs + idx] ) { | 1014 | if (oobdata[idx] != oob_buf[oobofs + idx] ) { |
@@ -1012,20 +1018,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1012 | goto out; | 1018 | goto out; |
1013 | } | 1019 | } |
1014 | } | 1020 | } |
1015 | } | 1021 | } |
1016 | } | 1022 | } |
1017 | oobofs += mtd->oobsize - hweccbytes * eccsteps; | 1023 | oobofs += mtd->oobsize - hweccbytes * eccsteps; |
1018 | page++; | 1024 | page++; |
1019 | numpages--; | 1025 | numpages--; |
1020 | 1026 | ||
1021 | /* Apply delay or wait for ready/busy pin | 1027 | /* Apply delay or wait for ready/busy pin |
1022 | * Do this before the AUTOINCR check, so no problems | 1028 | * Do this before the AUTOINCR check, so no problems |
1023 | * arise if a chip which does auto increment | 1029 | * arise if a chip which does auto increment |
1024 | * is marked as NOAUTOINCR by the board driver. | 1030 | * is marked as NOAUTOINCR by the board driver. |
1025 | * Do this also before returning, so the chip is | 1031 | * Do this also before returning, so the chip is |
1026 | * ready for the next command. | 1032 | * ready for the next command. |
1027 | */ | 1033 | */ |
1028 | if (!this->dev_ready) | 1034 | if (!this->dev_ready) |
1029 | udelay (this->chip_delay); | 1035 | udelay (this->chip_delay); |
1030 | else | 1036 | else |
1031 | nand_wait_ready(mtd); | 1037 | nand_wait_ready(mtd); |
@@ -1033,17 +1039,17 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1033 | /* All done, return happy */ | 1039 | /* All done, return happy */ |
1034 | if (!numpages) | 1040 | if (!numpages) |
1035 | return 0; | 1041 | return 0; |
1036 | 1042 | ||
1037 | 1043 | ||
1038 | /* Check, if the chip supports auto page increment */ | 1044 | /* Check, if the chip supports auto page increment */ |
1039 | if (!NAND_CANAUTOINCR(this)) | 1045 | if (!NAND_CANAUTOINCR(this)) |
1040 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); | 1046 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); |
1041 | } | 1047 | } |
1042 | /* | 1048 | /* |
1043 | * Terminate the read command. We come here in case of an error | 1049 | * Terminate the read command. We come here in case of an error |
1044 | * So we must issue a reset command. | 1050 | * So we must issue a reset command. |
1045 | */ | 1051 | */ |
1046 | out: | 1052 | out: |
1047 | this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); | 1053 | this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); |
1048 | return res; | 1054 | return res; |
1049 | } | 1055 | } |
@@ -1105,7 +1111,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1105 | * NAND read with ECC | 1111 | * NAND read with ECC |
1106 | */ | 1112 | */ |
1107 | int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 1113 | int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
1108 | size_t * retlen, u_char * buf, u_char * oob_buf, | 1114 | size_t * retlen, u_char * buf, u_char * oob_buf, |
1109 | struct nand_oobinfo *oobsel, int flags) | 1115 | struct nand_oobinfo *oobsel, int flags) |
1110 | { | 1116 | { |
1111 | 1117 | ||
@@ -1139,7 +1145,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1139 | /* Autoplace of oob data ? Use the default placement scheme */ | 1145 | /* Autoplace of oob data ? Use the default placement scheme */ |
1140 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) | 1146 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) |
1141 | oobsel = this->autooob; | 1147 | oobsel = this->autooob; |
1142 | 1148 | ||
1143 | eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; | 1149 | eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; |
1144 | oob_config = oobsel->eccpos; | 1150 | oob_config = oobsel->eccpos; |
1145 | 1151 | ||
@@ -1157,28 +1163,28 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1157 | end = mtd->oobblock; | 1163 | end = mtd->oobblock; |
1158 | ecc = this->eccsize; | 1164 | ecc = this->eccsize; |
1159 | eccbytes = this->eccbytes; | 1165 | eccbytes = this->eccbytes; |
1160 | 1166 | ||
1161 | if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) | 1167 | if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) |
1162 | compareecc = 0; | 1168 | compareecc = 0; |
1163 | 1169 | ||
1164 | oobreadlen = mtd->oobsize; | 1170 | oobreadlen = mtd->oobsize; |
1165 | if (this->options & NAND_HWECC_SYNDROME) | 1171 | if (this->options & NAND_HWECC_SYNDROME) |
1166 | oobreadlen -= oobsel->eccbytes; | 1172 | oobreadlen -= oobsel->eccbytes; |
1167 | 1173 | ||
1168 | /* Loop until all data read */ | 1174 | /* Loop until all data read */ |
1169 | while (read < len) { | 1175 | while (read < len) { |
1170 | 1176 | ||
1171 | int aligned = (!col && (len - read) >= end); | 1177 | int aligned = (!col && (len - read) >= end); |
1172 | /* | 1178 | /* |
1173 | * If the read is not page aligned, we have to read into data buffer | 1179 | * If the read is not page aligned, we have to read into data buffer |
1174 | * due to ecc, else we read into return buffer direct | 1180 | * due to ecc, else we read into return buffer direct |
1175 | */ | 1181 | */ |
1176 | if (aligned) | 1182 | if (aligned) |
1177 | data_poi = &buf[read]; | 1183 | data_poi = &buf[read]; |
1178 | else | 1184 | else |
1179 | data_poi = this->data_buf; | 1185 | data_poi = this->data_buf; |
1180 | 1186 | ||
1181 | /* Check, if we have this page in the buffer | 1187 | /* Check, if we have this page in the buffer |
1182 | * | 1188 | * |
1183 | * FIXME: Make it work when we must provide oob data too, | 1189 | * FIXME: Make it work when we must provide oob data too, |
1184 | * check the usage of data_buf oob field | 1190 | * check the usage of data_buf oob field |
@@ -1194,7 +1200,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1194 | if (sndcmd) { | 1200 | if (sndcmd) { |
1195 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); | 1201 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); |
1196 | sndcmd = 0; | 1202 | sndcmd = 0; |
1197 | } | 1203 | } |
1198 | 1204 | ||
1199 | /* get oob area, if we have no oob buffer from fs-driver */ | 1205 | /* get oob area, if we have no oob buffer from fs-driver */ |
1200 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || | 1206 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || |
@@ -1202,7 +1208,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1202 | oob_data = &this->data_buf[end]; | 1208 | oob_data = &this->data_buf[end]; |
1203 | 1209 | ||
1204 | eccsteps = this->eccsteps; | 1210 | eccsteps = this->eccsteps; |
1205 | 1211 | ||
1206 | switch (eccmode) { | 1212 | switch (eccmode) { |
1207 | case NAND_ECC_NONE: { /* No ECC, Read in a page */ | 1213 | case NAND_ECC_NONE: { /* No ECC, Read in a page */ |
1208 | static unsigned long lastwhinge = 0; | 1214 | static unsigned long lastwhinge = 0; |
@@ -1213,12 +1219,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1213 | this->read_buf(mtd, data_poi, end); | 1219 | this->read_buf(mtd, data_poi, end); |
1214 | break; | 1220 | break; |
1215 | } | 1221 | } |
1216 | 1222 | ||
1217 | case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ | 1223 | case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ |
1218 | this->read_buf(mtd, data_poi, end); | 1224 | this->read_buf(mtd, data_poi, end); |
1219 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) | 1225 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) |
1220 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); | 1226 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); |
1221 | break; | 1227 | break; |
1222 | 1228 | ||
1223 | default: | 1229 | default: |
1224 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { | 1230 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { |
@@ -1237,15 +1243,15 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1237 | * does the error correction on the fly */ | 1243 | * does the error correction on the fly */ |
1238 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); | 1244 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); |
1239 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { | 1245 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { |
1240 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " | 1246 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
1241 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); | 1247 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); |
1242 | ecc_failed++; | 1248 | ecc_failed++; |
1243 | } | 1249 | } |
1244 | } else { | 1250 | } else { |
1245 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); | 1251 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); |
1246 | } | 1252 | } |
1247 | } | 1253 | } |
1248 | break; | 1254 | break; |
1249 | } | 1255 | } |
1250 | 1256 | ||
1251 | /* read oobdata */ | 1257 | /* read oobdata */ |
@@ -1253,8 +1259,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1253 | 1259 | ||
1254 | /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ | 1260 | /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ |
1255 | if (!compareecc) | 1261 | if (!compareecc) |
1256 | goto readoob; | 1262 | goto readoob; |
1257 | 1263 | ||
1258 | /* Pick the ECC bytes out of the oob data */ | 1264 | /* Pick the ECC bytes out of the oob data */ |
1259 | for (j = 0; j < oobsel->eccbytes; j++) | 1265 | for (j = 0; j < oobsel->eccbytes; j++) |
1260 | ecc_code[j] = oob_data[oob_config[j]]; | 1266 | ecc_code[j] = oob_data[oob_config[j]]; |
@@ -1262,24 +1268,24 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1262 | /* correct data, if neccecary */ | 1268 | /* correct data, if neccecary */ |
1263 | for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { | 1269 | for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { |
1264 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); | 1270 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); |
1265 | 1271 | ||
1266 | /* Get next chunk of ecc bytes */ | 1272 | /* Get next chunk of ecc bytes */ |
1267 | j += eccbytes; | 1273 | j += eccbytes; |
1268 | 1274 | ||
1269 | /* Check, if we have a fs supplied oob-buffer, | 1275 | /* Check, if we have a fs supplied oob-buffer, |
1270 | * This is the legacy mode. Used by YAFFS1 | 1276 | * This is the legacy mode. Used by YAFFS1 |
1271 | * Should go away some day | 1277 | * Should go away some day |
1272 | */ | 1278 | */ |
1273 | if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { | 1279 | if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { |
1274 | int *p = (int *)(&oob_data[mtd->oobsize]); | 1280 | int *p = (int *)(&oob_data[mtd->oobsize]); |
1275 | p[i] = ecc_status; | 1281 | p[i] = ecc_status; |
1276 | } | 1282 | } |
1277 | 1283 | ||
1278 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { | 1284 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { |
1279 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); | 1285 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); |
1280 | ecc_failed++; | 1286 | ecc_failed++; |
1281 | } | 1287 | } |
1282 | } | 1288 | } |
1283 | 1289 | ||
1284 | readoob: | 1290 | readoob: |
1285 | /* check, if we have a fs supplied oob-buffer */ | 1291 | /* check, if we have a fs supplied oob-buffer */ |
@@ -1305,25 +1311,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1305 | } | 1311 | } |
1306 | readdata: | 1312 | readdata: |
1307 | /* Partial page read, transfer data into fs buffer */ | 1313 | /* Partial page read, transfer data into fs buffer */ |
1308 | if (!aligned) { | 1314 | if (!aligned) { |
1309 | for (j = col; j < end && read < len; j++) | 1315 | for (j = col; j < end && read < len; j++) |
1310 | buf[read++] = data_poi[j]; | 1316 | buf[read++] = data_poi[j]; |
1311 | this->pagebuf = realpage; | 1317 | this->pagebuf = realpage; |
1312 | } else | 1318 | } else |
1313 | read += mtd->oobblock; | 1319 | read += mtd->oobblock; |
1314 | 1320 | ||
1315 | /* Apply delay or wait for ready/busy pin | 1321 | /* Apply delay or wait for ready/busy pin |
1316 | * Do this before the AUTOINCR check, so no problems | 1322 | * Do this before the AUTOINCR check, so no problems |
1317 | * arise if a chip which does auto increment | 1323 | * arise if a chip which does auto increment |
1318 | * is marked as NOAUTOINCR by the board driver. | 1324 | * is marked as NOAUTOINCR by the board driver. |
1319 | */ | 1325 | */ |
1320 | if (!this->dev_ready) | 1326 | if (!this->dev_ready) |
1321 | udelay (this->chip_delay); | 1327 | udelay (this->chip_delay); |
1322 | else | 1328 | else |
1323 | nand_wait_ready(mtd); | 1329 | nand_wait_ready(mtd); |
1324 | 1330 | ||
1325 | if (read == len) | 1331 | if (read == len) |
1326 | break; | 1332 | break; |
1327 | 1333 | ||
1328 | /* For subsequent reads align to page boundary. */ | 1334 | /* For subsequent reads align to page boundary. */ |
1329 | col = 0; | 1335 | col = 0; |
@@ -1337,11 +1343,11 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1337 | this->select_chip(mtd, -1); | 1343 | this->select_chip(mtd, -1); |
1338 | this->select_chip(mtd, chipnr); | 1344 | this->select_chip(mtd, chipnr); |
1339 | } | 1345 | } |
1340 | /* Check, if the chip supports auto page increment | 1346 | /* Check, if the chip supports auto page increment |
1341 | * or if we have hit a block boundary. | 1347 | * or if we have hit a block boundary. |
1342 | */ | 1348 | */ |
1343 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) | 1349 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) |
1344 | sndcmd = 1; | 1350 | sndcmd = 1; |
1345 | } | 1351 | } |
1346 | 1352 | ||
1347 | /* Deselect and wake up anyone waiting on the device */ | 1353 | /* Deselect and wake up anyone waiting on the device */ |
@@ -1378,7 +1384,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1378 | /* Shift to get page */ | 1384 | /* Shift to get page */ |
1379 | page = (int)(from >> this->page_shift); | 1385 | page = (int)(from >> this->page_shift); |
1380 | chipnr = (int)(from >> this->chip_shift); | 1386 | chipnr = (int)(from >> this->chip_shift); |
1381 | 1387 | ||
1382 | /* Mask to get column */ | 1388 | /* Mask to get column */ |
1383 | col = from & (mtd->oobsize - 1); | 1389 | col = from & (mtd->oobsize - 1); |
1384 | 1390 | ||
@@ -1400,7 +1406,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1400 | 1406 | ||
1401 | /* Send the read command */ | 1407 | /* Send the read command */ |
1402 | this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); | 1408 | this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); |
1403 | /* | 1409 | /* |
1404 | * Read the data, if we read more than one page | 1410 | * Read the data, if we read more than one page |
1405 | * oob data, let the device transfer the data ! | 1411 | * oob data, let the device transfer the data ! |
1406 | */ | 1412 | */ |
@@ -1422,20 +1428,20 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1422 | this->select_chip(mtd, -1); | 1428 | this->select_chip(mtd, -1); |
1423 | this->select_chip(mtd, chipnr); | 1429 | this->select_chip(mtd, chipnr); |
1424 | } | 1430 | } |
1425 | 1431 | ||
1426 | /* Apply delay or wait for ready/busy pin | 1432 | /* Apply delay or wait for ready/busy pin |
1427 | * Do this before the AUTOINCR check, so no problems | 1433 | * Do this before the AUTOINCR check, so no problems |
1428 | * arise if a chip which does auto increment | 1434 | * arise if a chip which does auto increment |
1429 | * is marked as NOAUTOINCR by the board driver. | 1435 | * is marked as NOAUTOINCR by the board driver. |
1430 | */ | 1436 | */ |
1431 | if (!this->dev_ready) | 1437 | if (!this->dev_ready) |
1432 | udelay (this->chip_delay); | 1438 | udelay (this->chip_delay); |
1433 | else | 1439 | else |
1434 | nand_wait_ready(mtd); | 1440 | nand_wait_ready(mtd); |
1435 | 1441 | ||
1436 | /* Check, if the chip supports auto page increment | 1442 | /* Check, if the chip supports auto page increment |
1437 | * or if we have hit a block boundary. | 1443 | * or if we have hit a block boundary. |
1438 | */ | 1444 | */ |
1439 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { | 1445 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { |
1440 | /* For subsequent page reads set offset to 0 */ | 1446 | /* For subsequent page reads set offset to 0 */ |
1441 | this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); | 1447 | this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
@@ -1481,27 +1487,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | |||
1481 | nand_get_device (this, mtd , FL_READING); | 1487 | nand_get_device (this, mtd , FL_READING); |
1482 | 1488 | ||
1483 | this->select_chip (mtd, chip); | 1489 | this->select_chip (mtd, chip); |
1484 | 1490 | ||
1485 | /* Add requested oob length */ | 1491 | /* Add requested oob length */ |
1486 | len += ooblen; | 1492 | len += ooblen; |
1487 | 1493 | ||
1488 | while (len) { | 1494 | while (len) { |
1489 | if (sndcmd) | 1495 | if (sndcmd) |
1490 | this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); | 1496 | this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); |
1491 | sndcmd = 0; | 1497 | sndcmd = 0; |
1492 | 1498 | ||
1493 | this->read_buf (mtd, &buf[cnt], pagesize); | 1499 | this->read_buf (mtd, &buf[cnt], pagesize); |
1494 | 1500 | ||
1495 | len -= pagesize; | 1501 | len -= pagesize; |
1496 | cnt += pagesize; | 1502 | cnt += pagesize; |
1497 | page++; | 1503 | page++; |
1498 | 1504 | ||
1499 | if (!this->dev_ready) | 1505 | if (!this->dev_ready) |
1500 | udelay (this->chip_delay); | 1506 | udelay (this->chip_delay); |
1501 | else | 1507 | else |
1502 | nand_wait_ready(mtd); | 1508 | nand_wait_ready(mtd); |
1503 | 1509 | ||
1504 | /* Check, if the chip supports auto page increment */ | 1510 | /* Check, if the chip supports auto page increment */ |
1505 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) | 1511 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) |
1506 | sndcmd = 1; | 1512 | sndcmd = 1; |
1507 | } | 1513 | } |
@@ -1512,8 +1518,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | |||
1512 | } | 1518 | } |
1513 | 1519 | ||
1514 | 1520 | ||
1515 | /** | 1521 | /** |
1516 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer | 1522 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer |
1517 | * @mtd: MTD device structure | 1523 | * @mtd: MTD device structure |
1518 | * @fsbuf: buffer given by fs driver | 1524 | * @fsbuf: buffer given by fs driver |
1519 | * @oobsel: out of band selection structre | 1525 | * @oobsel: out of band selection structre |
@@ -1542,20 +1548,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct | |||
1542 | int i, len, ofs; | 1548 | int i, len, ofs; |
1543 | 1549 | ||
1544 | /* Zero copy fs supplied buffer */ | 1550 | /* Zero copy fs supplied buffer */ |
1545 | if (fsbuf && !autoplace) | 1551 | if (fsbuf && !autoplace) |
1546 | return fsbuf; | 1552 | return fsbuf; |
1547 | 1553 | ||
1548 | /* Check, if the buffer must be filled with ff again */ | 1554 | /* Check, if the buffer must be filled with ff again */ |
1549 | if (this->oobdirty) { | 1555 | if (this->oobdirty) { |
1550 | memset (this->oob_buf, 0xff, | 1556 | memset (this->oob_buf, 0xff, |
1551 | mtd->oobsize << (this->phys_erase_shift - this->page_shift)); | 1557 | mtd->oobsize << (this->phys_erase_shift - this->page_shift)); |
1552 | this->oobdirty = 0; | 1558 | this->oobdirty = 0; |
1553 | } | 1559 | } |
1554 | 1560 | ||
1555 | /* If we have no autoplacement or no fs buffer use the internal one */ | 1561 | /* If we have no autoplacement or no fs buffer use the internal one */ |
1556 | if (!autoplace || !fsbuf) | 1562 | if (!autoplace || !fsbuf) |
1557 | return this->oob_buf; | 1563 | return this->oob_buf; |
1558 | 1564 | ||
1559 | /* Walk through the pages and place the data */ | 1565 | /* Walk through the pages and place the data */ |
1560 | this->oobdirty = 1; | 1566 | this->oobdirty = 1; |
1561 | ofs = 0; | 1567 | ofs = 0; |
@@ -1589,7 +1595,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret | |||
1589 | { | 1595 | { |
1590 | return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); | 1596 | return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); |
1591 | } | 1597 | } |
1592 | 1598 | ||
1593 | /** | 1599 | /** |
1594 | * nand_write_ecc - [MTD Interface] NAND write with ECC | 1600 | * nand_write_ecc - [MTD Interface] NAND write with ECC |
1595 | * @mtd: MTD device structure | 1601 | * @mtd: MTD device structure |
@@ -1622,7 +1628,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1622 | return -EINVAL; | 1628 | return -EINVAL; |
1623 | } | 1629 | } |
1624 | 1630 | ||
1625 | /* reject writes, which are not page aligned */ | 1631 | /* reject writes, which are not page aligned */ |
1626 | if (NOTALIGNED (to) || NOTALIGNED(len)) { | 1632 | if (NOTALIGNED (to) || NOTALIGNED(len)) { |
1627 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | 1633 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); |
1628 | return -EINVAL; | 1634 | return -EINVAL; |
@@ -1641,14 +1647,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1641 | goto out; | 1647 | goto out; |
1642 | 1648 | ||
1643 | /* if oobsel is NULL, use chip defaults */ | 1649 | /* if oobsel is NULL, use chip defaults */ |
1644 | if (oobsel == NULL) | 1650 | if (oobsel == NULL) |
1645 | oobsel = &mtd->oobinfo; | 1651 | oobsel = &mtd->oobinfo; |
1646 | 1652 | ||
1647 | /* Autoplace of oob data ? Use the default placement scheme */ | 1653 | /* Autoplace of oob data ? Use the default placement scheme */ |
1648 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | 1654 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { |
1649 | oobsel = this->autooob; | 1655 | oobsel = this->autooob; |
1650 | autoplace = 1; | 1656 | autoplace = 1; |
1651 | } | 1657 | } |
1652 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | 1658 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) |
1653 | autoplace = 1; | 1659 | autoplace = 1; |
1654 | 1660 | ||
@@ -1656,9 +1662,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1656 | totalpages = len >> this->page_shift; | 1662 | totalpages = len >> this->page_shift; |
1657 | page = (int) (to >> this->page_shift); | 1663 | page = (int) (to >> this->page_shift); |
1658 | /* Invalidate the page cache, if we write to the cached page */ | 1664 | /* Invalidate the page cache, if we write to the cached page */ |
1659 | if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) | 1665 | if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) |
1660 | this->pagebuf = -1; | 1666 | this->pagebuf = -1; |
1661 | 1667 | ||
1662 | /* Set it relative to chip */ | 1668 | /* Set it relative to chip */ |
1663 | page &= this->pagemask; | 1669 | page &= this->pagemask; |
1664 | startpage = page; | 1670 | startpage = page; |
@@ -1680,14 +1686,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1680 | if (ret) { | 1686 | if (ret) { |
1681 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); | 1687 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); |
1682 | goto out; | 1688 | goto out; |
1683 | } | 1689 | } |
1684 | /* Next oob page */ | 1690 | /* Next oob page */ |
1685 | oob += mtd->oobsize; | 1691 | oob += mtd->oobsize; |
1686 | /* Update written bytes count */ | 1692 | /* Update written bytes count */ |
1687 | written += mtd->oobblock; | 1693 | written += mtd->oobblock; |
1688 | if (written == len) | 1694 | if (written == len) |
1689 | goto cmp; | 1695 | goto cmp; |
1690 | 1696 | ||
1691 | /* Increment page address */ | 1697 | /* Increment page address */ |
1692 | page++; | 1698 | page++; |
1693 | 1699 | ||
@@ -1698,13 +1704,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1698 | if (!(page & (ppblock - 1))){ | 1704 | if (!(page & (ppblock - 1))){ |
1699 | int ofs; | 1705 | int ofs; |
1700 | this->data_poi = bufstart; | 1706 | this->data_poi = bufstart; |
1701 | ret = nand_verify_pages (mtd, this, startpage, | 1707 | ret = nand_verify_pages (mtd, this, startpage, |
1702 | page - startpage, | 1708 | page - startpage, |
1703 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); | 1709 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
1704 | if (ret) { | 1710 | if (ret) { |
1705 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1711 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
1706 | goto out; | 1712 | goto out; |
1707 | } | 1713 | } |
1708 | *retlen = written; | 1714 | *retlen = written; |
1709 | 1715 | ||
1710 | ofs = autoplace ? mtd->oobavail : mtd->oobsize; | 1716 | ofs = autoplace ? mtd->oobavail : mtd->oobsize; |
@@ -1714,8 +1720,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1714 | numpages = min (totalpages, ppblock); | 1720 | numpages = min (totalpages, ppblock); |
1715 | page &= this->pagemask; | 1721 | page &= this->pagemask; |
1716 | startpage = page; | 1722 | startpage = page; |
1717 | oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, | 1723 | oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, |
1718 | autoplace, numpages); | 1724 | autoplace, numpages); |
1725 | oob = 0; | ||
1719 | /* Check, if we cross a chip boundary */ | 1726 | /* Check, if we cross a chip boundary */ |
1720 | if (!page) { | 1727 | if (!page) { |
1721 | chipnr++; | 1728 | chipnr++; |
@@ -1731,7 +1738,7 @@ cmp: | |||
1731 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); | 1738 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
1732 | if (!ret) | 1739 | if (!ret) |
1733 | *retlen = written; | 1740 | *retlen = written; |
1734 | else | 1741 | else |
1735 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1742 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
1736 | 1743 | ||
1737 | out: | 1744 | out: |
@@ -1791,7 +1798,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * | |||
1791 | /* Check, if it is write protected */ | 1798 | /* Check, if it is write protected */ |
1792 | if (nand_check_wp(mtd)) | 1799 | if (nand_check_wp(mtd)) |
1793 | goto out; | 1800 | goto out; |
1794 | 1801 | ||
1795 | /* Invalidate the page cache, if we write to the cached page */ | 1802 | /* Invalidate the page cache, if we write to the cached page */ |
1796 | if (page == this->pagebuf) | 1803 | if (page == this->pagebuf) |
1797 | this->pagebuf = -1; | 1804 | this->pagebuf = -1; |
@@ -1854,10 +1861,10 @@ out: | |||
1854 | * | 1861 | * |
1855 | * NAND write with kvec. This just calls the ecc function | 1862 | * NAND write with kvec. This just calls the ecc function |
1856 | */ | 1863 | */ |
1857 | static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | 1864 | static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, |
1858 | loff_t to, size_t * retlen) | 1865 | loff_t to, size_t * retlen) |
1859 | { | 1866 | { |
1860 | return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); | 1867 | return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); |
1861 | } | 1868 | } |
1862 | 1869 | ||
1863 | /** | 1870 | /** |
@@ -1872,7 +1879,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned | |||
1872 | * | 1879 | * |
1873 | * NAND write with iovec with ecc | 1880 | * NAND write with iovec with ecc |
1874 | */ | 1881 | */ |
1875 | static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | 1882 | static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, |
1876 | loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) | 1883 | loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) |
1877 | { | 1884 | { |
1878 | int i, page, len, total_len, ret = -EIO, written = 0, chipnr; | 1885 | int i, page, len, total_len, ret = -EIO, written = 0, chipnr; |
@@ -1898,7 +1905,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1898 | return -EINVAL; | 1905 | return -EINVAL; |
1899 | } | 1906 | } |
1900 | 1907 | ||
1901 | /* reject writes, which are not page aligned */ | 1908 | /* reject writes, which are not page aligned */ |
1902 | if (NOTALIGNED (to) || NOTALIGNED(total_len)) { | 1909 | if (NOTALIGNED (to) || NOTALIGNED(total_len)) { |
1903 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | 1910 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); |
1904 | return -EINVAL; | 1911 | return -EINVAL; |
@@ -1917,21 +1924,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1917 | goto out; | 1924 | goto out; |
1918 | 1925 | ||
1919 | /* if oobsel is NULL, use chip defaults */ | 1926 | /* if oobsel is NULL, use chip defaults */ |
1920 | if (oobsel == NULL) | 1927 | if (oobsel == NULL) |
1921 | oobsel = &mtd->oobinfo; | 1928 | oobsel = &mtd->oobinfo; |
1922 | 1929 | ||
1923 | /* Autoplace of oob data ? Use the default placement scheme */ | 1930 | /* Autoplace of oob data ? Use the default placement scheme */ |
1924 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | 1931 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { |
1925 | oobsel = this->autooob; | 1932 | oobsel = this->autooob; |
1926 | autoplace = 1; | 1933 | autoplace = 1; |
1927 | } | 1934 | } |
1928 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | 1935 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) |
1929 | autoplace = 1; | 1936 | autoplace = 1; |
1930 | 1937 | ||
1931 | /* Setup start page */ | 1938 | /* Setup start page */ |
1932 | page = (int) (to >> this->page_shift); | 1939 | page = (int) (to >> this->page_shift); |
1933 | /* Invalidate the page cache, if we write to the cached page */ | 1940 | /* Invalidate the page cache, if we write to the cached page */ |
1934 | if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) | 1941 | if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) |
1935 | this->pagebuf = -1; | 1942 | this->pagebuf = -1; |
1936 | 1943 | ||
1937 | startpage = page & this->pagemask; | 1944 | startpage = page & this->pagemask; |
@@ -1955,10 +1962,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1955 | oob = 0; | 1962 | oob = 0; |
1956 | for (i = 1; i <= numpages; i++) { | 1963 | for (i = 1; i <= numpages; i++) { |
1957 | /* Write one page. If this is the last page to write | 1964 | /* Write one page. If this is the last page to write |
1958 | * then use the real pageprogram command, else select | 1965 | * then use the real pageprogram command, else select |
1959 | * cached programming if supported by the chip. | 1966 | * cached programming if supported by the chip. |
1960 | */ | 1967 | */ |
1961 | ret = nand_write_page (mtd, this, page & this->pagemask, | 1968 | ret = nand_write_page (mtd, this, page & this->pagemask, |
1962 | &oobbuf[oob], oobsel, i != numpages); | 1969 | &oobbuf[oob], oobsel, i != numpages); |
1963 | if (ret) | 1970 | if (ret) |
1964 | goto out; | 1971 | goto out; |
@@ -1974,12 +1981,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1974 | count--; | 1981 | count--; |
1975 | } | 1982 | } |
1976 | } else { | 1983 | } else { |
1977 | /* We must use the internal buffer, read data out of each | 1984 | /* We must use the internal buffer, read data out of each |
1978 | * tuple until we have a full page to write | 1985 | * tuple until we have a full page to write |
1979 | */ | 1986 | */ |
1980 | int cnt = 0; | 1987 | int cnt = 0; |
1981 | while (cnt < mtd->oobblock) { | 1988 | while (cnt < mtd->oobblock) { |
1982 | if (vecs->iov_base != NULL && vecs->iov_len) | 1989 | if (vecs->iov_base != NULL && vecs->iov_len) |
1983 | this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; | 1990 | this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; |
1984 | /* Check, if we have to switch to the next tuple */ | 1991 | /* Check, if we have to switch to the next tuple */ |
1985 | if (len >= (int) vecs->iov_len) { | 1992 | if (len >= (int) vecs->iov_len) { |
@@ -1988,10 +1995,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1988 | count--; | 1995 | count--; |
1989 | } | 1996 | } |
1990 | } | 1997 | } |
1991 | this->pagebuf = page; | 1998 | this->pagebuf = page; |
1992 | this->data_poi = this->data_buf; | 1999 | this->data_poi = this->data_buf; |
1993 | bufstart = this->data_poi; | 2000 | bufstart = this->data_poi; |
1994 | numpages = 1; | 2001 | numpages = 1; |
1995 | oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); | 2002 | oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); |
1996 | ret = nand_write_page (mtd, this, page & this->pagemask, | 2003 | ret = nand_write_page (mtd, this, page & this->pagemask, |
1997 | oobbuf, oobsel, 0); | 2004 | oobbuf, oobsel, 0); |
@@ -2004,7 +2011,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
2004 | ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); | 2011 | ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); |
2005 | if (ret) | 2012 | if (ret) |
2006 | goto out; | 2013 | goto out; |
2007 | 2014 | ||
2008 | written += mtd->oobblock * numpages; | 2015 | written += mtd->oobblock * numpages; |
2009 | /* All done ? */ | 2016 | /* All done ? */ |
2010 | if (!count) | 2017 | if (!count) |
@@ -2072,7 +2079,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
2072 | { | 2079 | { |
2073 | return nand_erase_nand (mtd, instr, 0); | 2080 | return nand_erase_nand (mtd, instr, 0); |
2074 | } | 2081 | } |
2075 | 2082 | ||
2076 | #define BBT_PAGE_MASK 0xffffff3f | 2083 | #define BBT_PAGE_MASK 0xffffff3f |
2077 | /** | 2084 | /** |
2078 | * nand_erase_intern - [NAND Interface] erase block(s) | 2085 | * nand_erase_intern - [NAND Interface] erase block(s) |
@@ -2154,14 +2161,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2154 | instr->state = MTD_ERASE_FAILED; | 2161 | instr->state = MTD_ERASE_FAILED; |
2155 | goto erase_exit; | 2162 | goto erase_exit; |
2156 | } | 2163 | } |
2157 | 2164 | ||
2158 | /* Invalidate the page cache, if we erase the block which contains | 2165 | /* Invalidate the page cache, if we erase the block which contains |
2159 | the current cached page */ | 2166 | the current cached page */ |
2160 | if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) | 2167 | if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) |
2161 | this->pagebuf = -1; | 2168 | this->pagebuf = -1; |
2162 | 2169 | ||
2163 | this->erase_cmd (mtd, page & this->pagemask); | 2170 | this->erase_cmd (mtd, page & this->pagemask); |
2164 | 2171 | ||
2165 | status = this->waitfunc (mtd, this, FL_ERASING); | 2172 | status = this->waitfunc (mtd, this, FL_ERASING); |
2166 | 2173 | ||
2167 | /* See if operation failed and additional status checks are available */ | 2174 | /* See if operation failed and additional status checks are available */ |
@@ -2179,12 +2186,12 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2179 | 2186 | ||
2180 | /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ | 2187 | /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ |
2181 | if (this->options & BBT_AUTO_REFRESH) { | 2188 | if (this->options & BBT_AUTO_REFRESH) { |
2182 | if (((page & BBT_PAGE_MASK) == bbt_masked_page) && | 2189 | if (((page & BBT_PAGE_MASK) == bbt_masked_page) && |
2183 | (page != this->bbt_td->pages[chipnr])) { | 2190 | (page != this->bbt_td->pages[chipnr])) { |
2184 | rewrite_bbt[chipnr] = (page << this->page_shift); | 2191 | rewrite_bbt[chipnr] = (page << this->page_shift); |
2185 | } | 2192 | } |
2186 | } | 2193 | } |
2187 | 2194 | ||
2188 | /* Increment page address and decrement length */ | 2195 | /* Increment page address and decrement length */ |
2189 | len -= (1 << this->phys_erase_shift); | 2196 | len -= (1 << this->phys_erase_shift); |
2190 | page += pages_per_block; | 2197 | page += pages_per_block; |
@@ -2195,7 +2202,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2195 | this->select_chip(mtd, -1); | 2202 | this->select_chip(mtd, -1); |
2196 | this->select_chip(mtd, chipnr); | 2203 | this->select_chip(mtd, chipnr); |
2197 | 2204 | ||
2198 | /* if BBT requires refresh and BBT-PERCHIP, | 2205 | /* if BBT requires refresh and BBT-PERCHIP, |
2199 | * set the BBT page mask to see if this BBT should be rewritten */ | 2206 | * set the BBT page mask to see if this BBT should be rewritten */ |
2200 | if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { | 2207 | if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { |
2201 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; | 2208 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; |
@@ -2220,7 +2227,7 @@ erase_exit: | |||
2220 | for (chipnr = 0; chipnr < this->numchips; chipnr++) { | 2227 | for (chipnr = 0; chipnr < this->numchips; chipnr++) { |
2221 | if (rewrite_bbt[chipnr]) { | 2228 | if (rewrite_bbt[chipnr]) { |
2222 | /* update the BBT for chip */ | 2229 | /* update the BBT for chip */ |
2223 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", | 2230 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", |
2224 | chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); | 2231 | chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); |
2225 | nand_update_bbt (mtd, rewrite_bbt[chipnr]); | 2232 | nand_update_bbt (mtd, rewrite_bbt[chipnr]); |
2226 | } | 2233 | } |
@@ -2258,9 +2265,9 @@ static void nand_sync (struct mtd_info *mtd) | |||
2258 | static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) | 2265 | static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) |
2259 | { | 2266 | { |
2260 | /* Check for invalid offset */ | 2267 | /* Check for invalid offset */ |
2261 | if (ofs > mtd->size) | 2268 | if (ofs > mtd->size) |
2262 | return -EINVAL; | 2269 | return -EINVAL; |
2263 | 2270 | ||
2264 | return nand_block_checkbad (mtd, ofs, 1, 0); | 2271 | return nand_block_checkbad (mtd, ofs, 1, 0); |
2265 | } | 2272 | } |
2266 | 2273 | ||
@@ -2285,6 +2292,34 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
2285 | } | 2292 | } |
2286 | 2293 | ||
2287 | /** | 2294 | /** |
2295 | * nand_suspend - [MTD Interface] Suspend the NAND flash | ||
2296 | * @mtd: MTD device structure | ||
2297 | */ | ||
2298 | static int nand_suspend(struct mtd_info *mtd) | ||
2299 | { | ||
2300 | struct nand_chip *this = mtd->priv; | ||
2301 | |||
2302 | return nand_get_device (this, mtd, FL_PM_SUSPENDED); | ||
2303 | } | ||
2304 | |||
2305 | /** | ||
2306 | * nand_resume - [MTD Interface] Resume the NAND flash | ||
2307 | * @mtd: MTD device structure | ||
2308 | */ | ||
2309 | static void nand_resume(struct mtd_info *mtd) | ||
2310 | { | ||
2311 | struct nand_chip *this = mtd->priv; | ||
2312 | |||
2313 | if (this->state == FL_PM_SUSPENDED) | ||
2314 | nand_release_device(mtd); | ||
2315 | else | ||
2316 | printk(KERN_ERR "resume() called for the chip which is not " | ||
2317 | "in suspended state\n"); | ||
2318 | |||
2319 | } | ||
2320 | |||
2321 | |||
2322 | /** | ||
2288 | * nand_scan - [NAND Interface] Scan for the NAND device | 2323 | * nand_scan - [NAND Interface] Scan for the NAND device |
2289 | * @mtd: MTD device structure | 2324 | * @mtd: MTD device structure |
2290 | * @maxchips: Number of chips to scan for | 2325 | * @maxchips: Number of chips to scan for |
@@ -2351,13 +2386,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2351 | 2386 | ||
2352 | /* Print and store flash device information */ | 2387 | /* Print and store flash device information */ |
2353 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 2388 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
2354 | 2389 | ||
2355 | if (nand_dev_id != nand_flash_ids[i].id) | 2390 | if (nand_dev_id != nand_flash_ids[i].id) |
2356 | continue; | 2391 | continue; |
2357 | 2392 | ||
2358 | if (!mtd->name) mtd->name = nand_flash_ids[i].name; | 2393 | if (!mtd->name) mtd->name = nand_flash_ids[i].name; |
2359 | this->chipsize = nand_flash_ids[i].chipsize << 20; | 2394 | this->chipsize = nand_flash_ids[i].chipsize << 20; |
2360 | 2395 | ||
2361 | /* New devices have all the information in additional id bytes */ | 2396 | /* New devices have all the information in additional id bytes */ |
2362 | if (!nand_flash_ids[i].pagesize) { | 2397 | if (!nand_flash_ids[i].pagesize) { |
2363 | int extid; | 2398 | int extid; |
@@ -2369,14 +2404,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2369 | mtd->oobblock = 1024 << (extid & 0x3); | 2404 | mtd->oobblock = 1024 << (extid & 0x3); |
2370 | extid >>= 2; | 2405 | extid >>= 2; |
2371 | /* Calc oobsize */ | 2406 | /* Calc oobsize */ |
2372 | mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); | 2407 | mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); |
2373 | extid >>= 2; | 2408 | extid >>= 2; |
2374 | /* Calc blocksize. Blocksize is multiples of 64KiB */ | 2409 | /* Calc blocksize. Blocksize is multiples of 64KiB */ |
2375 | mtd->erasesize = (64 * 1024) << (extid & 0x03); | 2410 | mtd->erasesize = (64 * 1024) << (extid & 0x03); |
2376 | extid >>= 2; | 2411 | extid >>= 2; |
2377 | /* Get buswidth information */ | 2412 | /* Get buswidth information */ |
2378 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | 2413 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; |
2379 | 2414 | ||
2380 | } else { | 2415 | } else { |
2381 | /* Old devices have this data hardcoded in the | 2416 | /* Old devices have this data hardcoded in the |
2382 | * device id table */ | 2417 | * device id table */ |
@@ -2396,23 +2431,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2396 | * this correct ! */ | 2431 | * this correct ! */ |
2397 | if (busw != (this->options & NAND_BUSWIDTH_16)) { | 2432 | if (busw != (this->options & NAND_BUSWIDTH_16)) { |
2398 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2433 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2399 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2434 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2400 | nand_manuf_ids[maf_id].name , mtd->name); | 2435 | nand_manuf_ids[maf_id].name , mtd->name); |
2401 | printk (KERN_WARNING | 2436 | printk (KERN_WARNING |
2402 | "NAND bus width %d instead %d bit\n", | 2437 | "NAND bus width %d instead %d bit\n", |
2403 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, | 2438 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, |
2404 | busw ? 16 : 8); | 2439 | busw ? 16 : 8); |
2405 | this->select_chip(mtd, -1); | 2440 | this->select_chip(mtd, -1); |
2406 | return 1; | 2441 | return 1; |
2407 | } | 2442 | } |
2408 | 2443 | ||
2409 | /* Calculate the address shift from the page size */ | 2444 | /* Calculate the address shift from the page size */ |
2410 | this->page_shift = ffs(mtd->oobblock) - 1; | 2445 | this->page_shift = ffs(mtd->oobblock) - 1; |
2411 | this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; | 2446 | this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; |
2412 | this->chip_shift = ffs(this->chipsize) - 1; | 2447 | this->chip_shift = ffs(this->chipsize) - 1; |
2413 | 2448 | ||
2414 | /* Set the bad block position */ | 2449 | /* Set the bad block position */ |
2415 | this->badblockpos = mtd->oobblock > 512 ? | 2450 | this->badblockpos = mtd->oobblock > 512 ? |
2416 | NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; | 2451 | NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; |
2417 | 2452 | ||
2418 | /* Get chip options, preserve non chip based options */ | 2453 | /* Get chip options, preserve non chip based options */ |
@@ -2422,10 +2457,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2422 | this->options |= NAND_NO_AUTOINCR; | 2457 | this->options |= NAND_NO_AUTOINCR; |
2423 | /* Check if this is a not a samsung device. Do not clear the options | 2458 | /* Check if this is a not a samsung device. Do not clear the options |
2424 | * for chips which are not having an extended id. | 2459 | * for chips which are not having an extended id. |
2425 | */ | 2460 | */ |
2426 | if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) | 2461 | if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) |
2427 | this->options &= ~NAND_SAMSUNG_LP_OPTIONS; | 2462 | this->options &= ~NAND_SAMSUNG_LP_OPTIONS; |
2428 | 2463 | ||
2429 | /* Check for AND chips with 4 page planes */ | 2464 | /* Check for AND chips with 4 page planes */ |
2430 | if (this->options & NAND_4PAGE_ARRAY) | 2465 | if (this->options & NAND_4PAGE_ARRAY) |
2431 | this->erase_cmd = multi_erase_cmd; | 2466 | this->erase_cmd = multi_erase_cmd; |
@@ -2435,9 +2470,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2435 | /* Do not replace user supplied command function ! */ | 2470 | /* Do not replace user supplied command function ! */ |
2436 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) | 2471 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) |
2437 | this->cmdfunc = nand_command_lp; | 2472 | this->cmdfunc = nand_command_lp; |
2438 | 2473 | ||
2439 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2474 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2440 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2475 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2441 | nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); | 2476 | nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); |
2442 | break; | 2477 | break; |
2443 | } | 2478 | } |
@@ -2461,7 +2496,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2461 | } | 2496 | } |
2462 | if (i > 1) | 2497 | if (i > 1) |
2463 | printk(KERN_INFO "%d NAND chips detected\n", i); | 2498 | printk(KERN_INFO "%d NAND chips detected\n", i); |
2464 | 2499 | ||
2465 | /* Allocate buffers, if neccecary */ | 2500 | /* Allocate buffers, if neccecary */ |
2466 | if (!this->oob_buf) { | 2501 | if (!this->oob_buf) { |
2467 | size_t len; | 2502 | size_t len; |
@@ -2473,7 +2508,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2473 | } | 2508 | } |
2474 | this->options |= NAND_OOBBUF_ALLOC; | 2509 | this->options |= NAND_OOBBUF_ALLOC; |
2475 | } | 2510 | } |
2476 | 2511 | ||
2477 | if (!this->data_buf) { | 2512 | if (!this->data_buf) { |
2478 | size_t len; | 2513 | size_t len; |
2479 | len = mtd->oobblock + mtd->oobsize; | 2514 | len = mtd->oobblock + mtd->oobsize; |
@@ -2500,7 +2535,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2500 | if (!this->autooob) { | 2535 | if (!this->autooob) { |
2501 | /* Select the appropriate default oob placement scheme for | 2536 | /* Select the appropriate default oob placement scheme for |
2502 | * placement agnostic filesystems */ | 2537 | * placement agnostic filesystems */ |
2503 | switch (mtd->oobsize) { | 2538 | switch (mtd->oobsize) { |
2504 | case 8: | 2539 | case 8: |
2505 | this->autooob = &nand_oob_8; | 2540 | this->autooob = &nand_oob_8; |
2506 | break; | 2541 | break; |
@@ -2516,19 +2551,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2516 | BUG(); | 2551 | BUG(); |
2517 | } | 2552 | } |
2518 | } | 2553 | } |
2519 | 2554 | ||
2520 | /* The number of bytes available for the filesystem to place fs dependend | 2555 | /* The number of bytes available for the filesystem to place fs dependend |
2521 | * oob data */ | 2556 | * oob data */ |
2522 | mtd->oobavail = 0; | 2557 | mtd->oobavail = 0; |
2523 | for (i = 0; this->autooob->oobfree[i][1]; i++) | 2558 | for (i = 0; this->autooob->oobfree[i][1]; i++) |
2524 | mtd->oobavail += this->autooob->oobfree[i][1]; | 2559 | mtd->oobavail += this->autooob->oobfree[i][1]; |
2525 | 2560 | ||
2526 | /* | 2561 | /* |
2527 | * check ECC mode, default to software | 2562 | * check ECC mode, default to software |
2528 | * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize | 2563 | * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize |
2529 | * fallback to software ECC | 2564 | * fallback to software ECC |
2530 | */ | 2565 | */ |
2531 | this->eccsize = 256; /* set default eccsize */ | 2566 | this->eccsize = 256; /* set default eccsize */ |
2532 | this->eccbytes = 3; | 2567 | this->eccbytes = 3; |
2533 | 2568 | ||
2534 | switch (this->eccmode) { | 2569 | switch (this->eccmode) { |
@@ -2543,56 +2578,56 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2543 | this->eccsize = 2048; | 2578 | this->eccsize = 2048; |
2544 | break; | 2579 | break; |
2545 | 2580 | ||
2546 | case NAND_ECC_HW3_512: | 2581 | case NAND_ECC_HW3_512: |
2547 | case NAND_ECC_HW6_512: | 2582 | case NAND_ECC_HW6_512: |
2548 | case NAND_ECC_HW8_512: | 2583 | case NAND_ECC_HW8_512: |
2549 | if (mtd->oobblock == 256) { | 2584 | if (mtd->oobblock == 256) { |
2550 | printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); | 2585 | printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); |
2551 | this->eccmode = NAND_ECC_SOFT; | 2586 | this->eccmode = NAND_ECC_SOFT; |
2552 | this->calculate_ecc = nand_calculate_ecc; | 2587 | this->calculate_ecc = nand_calculate_ecc; |
2553 | this->correct_data = nand_correct_data; | 2588 | this->correct_data = nand_correct_data; |
2554 | } else | 2589 | } else |
2555 | this->eccsize = 512; /* set eccsize to 512 */ | 2590 | this->eccsize = 512; /* set eccsize to 512 */ |
2556 | break; | 2591 | break; |
2557 | 2592 | ||
2558 | case NAND_ECC_HW3_256: | 2593 | case NAND_ECC_HW3_256: |
2559 | break; | 2594 | break; |
2560 | 2595 | ||
2561 | case NAND_ECC_NONE: | 2596 | case NAND_ECC_NONE: |
2562 | printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); | 2597 | printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); |
2563 | this->eccmode = NAND_ECC_NONE; | 2598 | this->eccmode = NAND_ECC_NONE; |
2564 | break; | 2599 | break; |
2565 | 2600 | ||
2566 | case NAND_ECC_SOFT: | 2601 | case NAND_ECC_SOFT: |
2567 | this->calculate_ecc = nand_calculate_ecc; | 2602 | this->calculate_ecc = nand_calculate_ecc; |
2568 | this->correct_data = nand_correct_data; | 2603 | this->correct_data = nand_correct_data; |
2569 | break; | 2604 | break; |
2570 | 2605 | ||
2571 | default: | 2606 | default: |
2572 | printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); | 2607 | printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); |
2573 | BUG(); | 2608 | BUG(); |
2574 | } | 2609 | } |
2575 | 2610 | ||
2576 | /* Check hardware ecc function availability and adjust number of ecc bytes per | 2611 | /* Check hardware ecc function availability and adjust number of ecc bytes per |
2577 | * calculation step | 2612 | * calculation step |
2578 | */ | 2613 | */ |
2579 | switch (this->eccmode) { | 2614 | switch (this->eccmode) { |
2580 | case NAND_ECC_HW12_2048: | 2615 | case NAND_ECC_HW12_2048: |
2581 | this->eccbytes += 4; | 2616 | this->eccbytes += 4; |
2582 | case NAND_ECC_HW8_512: | 2617 | case NAND_ECC_HW8_512: |
2583 | this->eccbytes += 2; | 2618 | this->eccbytes += 2; |
2584 | case NAND_ECC_HW6_512: | 2619 | case NAND_ECC_HW6_512: |
2585 | this->eccbytes += 3; | 2620 | this->eccbytes += 3; |
2586 | case NAND_ECC_HW3_512: | 2621 | case NAND_ECC_HW3_512: |
2587 | case NAND_ECC_HW3_256: | 2622 | case NAND_ECC_HW3_256: |
2588 | if (this->calculate_ecc && this->correct_data && this->enable_hwecc) | 2623 | if (this->calculate_ecc && this->correct_data && this->enable_hwecc) |
2589 | break; | 2624 | break; |
2590 | printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); | 2625 | printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); |
2591 | BUG(); | 2626 | BUG(); |
2592 | } | 2627 | } |
2593 | 2628 | ||
2594 | mtd->eccsize = this->eccsize; | 2629 | mtd->eccsize = this->eccsize; |
2595 | 2630 | ||
2596 | /* Set the number of read / write steps for one page to ensure ECC generation */ | 2631 | /* Set the number of read / write steps for one page to ensure ECC generation */ |
2597 | switch (this->eccmode) { | 2632 | switch (this->eccmode) { |
2598 | case NAND_ECC_HW12_2048: | 2633 | case NAND_ECC_HW12_2048: |
@@ -2604,15 +2639,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2604 | this->eccsteps = mtd->oobblock / 512; | 2639 | this->eccsteps = mtd->oobblock / 512; |
2605 | break; | 2640 | break; |
2606 | case NAND_ECC_HW3_256: | 2641 | case NAND_ECC_HW3_256: |
2607 | case NAND_ECC_SOFT: | 2642 | case NAND_ECC_SOFT: |
2608 | this->eccsteps = mtd->oobblock / 256; | 2643 | this->eccsteps = mtd->oobblock / 256; |
2609 | break; | 2644 | break; |
2610 | 2645 | ||
2611 | case NAND_ECC_NONE: | 2646 | case NAND_ECC_NONE: |
2612 | this->eccsteps = 1; | 2647 | this->eccsteps = 1; |
2613 | break; | 2648 | break; |
2614 | } | 2649 | } |
2615 | 2650 | ||
2616 | /* Initialize state, waitqueue and spinlock */ | 2651 | /* Initialize state, waitqueue and spinlock */ |
2617 | this->state = FL_READY; | 2652 | this->state = FL_READY; |
2618 | init_waitqueue_head (&this->wq); | 2653 | init_waitqueue_head (&this->wq); |
@@ -2643,8 +2678,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2643 | mtd->sync = nand_sync; | 2678 | mtd->sync = nand_sync; |
2644 | mtd->lock = NULL; | 2679 | mtd->lock = NULL; |
2645 | mtd->unlock = NULL; | 2680 | mtd->unlock = NULL; |
2646 | mtd->suspend = NULL; | 2681 | mtd->suspend = nand_suspend; |
2647 | mtd->resume = NULL; | 2682 | mtd->resume = nand_resume; |
2648 | mtd->block_isbad = nand_block_isbad; | 2683 | mtd->block_isbad = nand_block_isbad; |
2649 | mtd->block_markbad = nand_block_markbad; | 2684 | mtd->block_markbad = nand_block_markbad; |
2650 | 2685 | ||
@@ -2652,7 +2687,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2652 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | 2687 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); |
2653 | 2688 | ||
2654 | mtd->owner = THIS_MODULE; | 2689 | mtd->owner = THIS_MODULE; |
2655 | 2690 | ||
2656 | /* Check, if we should skip the bad block table scan */ | 2691 | /* Check, if we should skip the bad block table scan */ |
2657 | if (this->options & NAND_SKIP_BBTSCAN) | 2692 | if (this->options & NAND_SKIP_BBTSCAN) |
2658 | return 0; | 2693 | return 0; |
@@ -2662,7 +2697,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2662 | } | 2697 | } |
2663 | 2698 | ||
2664 | /** | 2699 | /** |
2665 | * nand_release - [NAND Interface] Free resources held by the NAND device | 2700 | * nand_release - [NAND Interface] Free resources held by the NAND device |
2666 | * @mtd: MTD device structure | 2701 | * @mtd: MTD device structure |
2667 | */ | 2702 | */ |
2668 | void nand_release (struct mtd_info *mtd) | 2703 | void nand_release (struct mtd_info *mtd) |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7535ef53685e..ca286999fe08 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -3,10 +3,10 @@ | |||
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Bad block table support for the NAND driver | 5 | * Bad block table support for the NAND driver |
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 gleixner Exp $ | 9 | * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,23 +14,23 @@ | |||
14 | * | 14 | * |
15 | * Description: | 15 | * Description: |
16 | * | 16 | * |
17 | * When nand_scan_bbt is called, then it tries to find the bad block table | 17 | * When nand_scan_bbt is called, then it tries to find the bad block table |
18 | * depending on the options in the bbt descriptor(s). If a bbt is found | 18 | * depending on the options in the bbt descriptor(s). If a bbt is found |
19 | * then the contents are read and the memory based bbt is created. If a | 19 | * then the contents are read and the memory based bbt is created. If a |
20 | * mirrored bbt is selected then the mirror is searched too and the | 20 | * mirrored bbt is selected then the mirror is searched too and the |
21 | * versions are compared. If the mirror has a greater version number | 21 | * versions are compared. If the mirror has a greater version number |
22 | * than the mirror bbt is used to build the memory based bbt. | 22 | * than the mirror bbt is used to build the memory based bbt. |
23 | * If the tables are not versioned, then we "or" the bad block information. | 23 | * If the tables are not versioned, then we "or" the bad block information. |
24 | * If one of the bbt's is out of date or does not exist it is (re)created. | 24 | * If one of the bbt's is out of date or does not exist it is (re)created. |
25 | * If no bbt exists at all then the device is scanned for factory marked | 25 | * If no bbt exists at all then the device is scanned for factory marked |
26 | * good / bad blocks and the bad block tables are created. | 26 | * good / bad blocks and the bad block tables are created. |
27 | * | 27 | * |
28 | * For manufacturer created bbts like the one found on M-SYS DOC devices | 28 | * For manufacturer created bbts like the one found on M-SYS DOC devices |
29 | * the bbt is searched and read but never created | 29 | * the bbt is searched and read but never created |
30 | * | 30 | * |
31 | * The autogenerated bad block table is located in the last good blocks | 31 | * The autogenerated bad block table is located in the last good blocks |
32 | * of the device. The table is mirrored, so it can be updated eventually. | 32 | * of the device. The table is mirrored, so it can be updated eventually. |
33 | * The table is marked in the oob area with an ident pattern and a version | 33 | * The table is marked in the oob area with an ident pattern and a version |
34 | * number which indicates which of both tables is more up to date. | 34 | * number which indicates which of both tables is more up to date. |
35 | * | 35 | * |
36 | * The table uses 2 bits per block | 36 | * The table uses 2 bits per block |
@@ -43,13 +43,13 @@ | |||
43 | * 01b: block is marked bad due to wear | 43 | * 01b: block is marked bad due to wear |
44 | * 10b: block is reserved (to protect the bbt area) | 44 | * 10b: block is reserved (to protect the bbt area) |
45 | * 11b: block is factory marked bad | 45 | * 11b: block is factory marked bad |
46 | * | 46 | * |
47 | * Multichip devices like DOC store the bad block info per floor. | 47 | * Multichip devices like DOC store the bad block info per floor. |
48 | * | 48 | * |
49 | * Following assumptions are made: | 49 | * Following assumptions are made: |
50 | * - bbts start at a page boundary, if autolocated on a block boundary | 50 | * - bbts start at a page boundary, if autolocated on a block boundary |
51 | * - the space neccecary for a bbt in FLASH does not exceed a block boundary | 51 | * - the space neccecary for a bbt in FLASH does not exceed a block boundary |
52 | * | 52 | * |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #include <linux/slab.h> | 55 | #include <linux/slab.h> |
@@ -62,7 +62,7 @@ | |||
62 | #include <linux/delay.h> | 62 | #include <linux/delay.h> |
63 | 63 | ||
64 | 64 | ||
65 | /** | 65 | /** |
66 | * check_pattern - [GENERIC] check if a pattern is in the buffer | 66 | * check_pattern - [GENERIC] check if a pattern is in the buffer |
67 | * @buf: the buffer to search | 67 | * @buf: the buffer to search |
68 | * @len: the length of buffer to search | 68 | * @len: the length of buffer to search |
@@ -86,9 +86,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
86 | if (p[i] != 0xff) | 86 | if (p[i] != 0xff) |
87 | return -1; | 87 | return -1; |
88 | } | 88 | } |
89 | } | 89 | } |
90 | p += end; | 90 | p += end; |
91 | 91 | ||
92 | /* Compare the pattern */ | 92 | /* Compare the pattern */ |
93 | for (i = 0; i < td->len; i++) { | 93 | for (i = 0; i < td->len; i++) { |
94 | if (p[i] != td->pattern[i]) | 94 | if (p[i] != td->pattern[i]) |
@@ -106,13 +106,13 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | 108 | ||
109 | /** | 109 | /** |
110 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | 110 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer |
111 | * @buf: the buffer to search | 111 | * @buf: the buffer to search |
112 | * @td: search pattern descriptor | 112 | * @td: search pattern descriptor |
113 | * | 113 | * |
114 | * Check for a pattern at the given place. Used to search bad block | 114 | * Check for a pattern at the given place. Used to search bad block |
115 | * tables and good / bad block identifiers. Same as check_pattern, but | 115 | * tables and good / bad block identifiers. Same as check_pattern, but |
116 | * no optional empty check | 116 | * no optional empty check |
117 | * | 117 | * |
118 | */ | 118 | */ |
@@ -142,7 +142,7 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td) | |||
142 | * Read the bad block table starting from page. | 142 | * Read the bad block table starting from page. |
143 | * | 143 | * |
144 | */ | 144 | */ |
145 | static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | 145 | static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, |
146 | int bits, int offs, int reserved_block_code) | 146 | int bits, int offs, int reserved_block_code) |
147 | { | 147 | { |
148 | int res, i, j, act = 0; | 148 | int res, i, j, act = 0; |
@@ -153,7 +153,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
153 | 153 | ||
154 | totlen = (num * bits) >> 3; | 154 | totlen = (num * bits) >> 3; |
155 | from = ((loff_t)page) << this->page_shift; | 155 | from = ((loff_t)page) << this->page_shift; |
156 | 156 | ||
157 | while (totlen) { | 157 | while (totlen) { |
158 | len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); | 158 | len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); |
159 | res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); | 159 | res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); |
@@ -163,7 +163,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
163 | return res; | 163 | return res; |
164 | } | 164 | } |
165 | printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); | 165 | printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); |
166 | } | 166 | } |
167 | 167 | ||
168 | /* Analyse data */ | 168 | /* Analyse data */ |
169 | for (i = 0; i < len; i++) { | 169 | for (i = 0; i < len; i++) { |
@@ -183,12 +183,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
183 | * message to MTD_DEBUG_LEVEL0 */ | 183 | * message to MTD_DEBUG_LEVEL0 */ |
184 | printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", | 184 | printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", |
185 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 185 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
186 | /* Factory marked bad or worn out ? */ | 186 | /* Factory marked bad or worn out ? */ |
187 | if (tmp == 0) | 187 | if (tmp == 0) |
188 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); | 188 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); |
189 | else | 189 | else |
190 | this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); | 190 | this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); |
191 | } | 191 | } |
192 | } | 192 | } |
193 | totlen -= len; | 193 | totlen -= len; |
194 | from += len; | 194 | from += len; |
@@ -200,7 +200,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
200 | * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page | 200 | * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page |
201 | * @mtd: MTD device structure | 201 | * @mtd: MTD device structure |
202 | * @buf: temporary buffer | 202 | * @buf: temporary buffer |
203 | * @td: descriptor for the bad block table | 203 | * @td: descriptor for the bad block table |
204 | * @chip: read the table for a specific chip, -1 read all chips. | 204 | * @chip: read the table for a specific chip, -1 read all chips. |
205 | * Applies only if NAND_BBT_PERCHIP option is set | 205 | * Applies only if NAND_BBT_PERCHIP option is set |
206 | * | 206 | * |
@@ -235,7 +235,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
235 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page | 235 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page |
236 | * @mtd: MTD device structure | 236 | * @mtd: MTD device structure |
237 | * @buf: temporary buffer | 237 | * @buf: temporary buffer |
238 | * @td: descriptor for the bad block table | 238 | * @td: descriptor for the bad block table |
239 | * @md: descriptor for the bad block table mirror | 239 | * @md: descriptor for the bad block table mirror |
240 | * | 240 | * |
241 | * Read the bad block table(s) for all chips starting at a given page | 241 | * Read the bad block table(s) for all chips starting at a given page |
@@ -247,16 +247,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
247 | { | 247 | { |
248 | struct nand_chip *this = mtd->priv; | 248 | struct nand_chip *this = mtd->priv; |
249 | 249 | ||
250 | /* Read the primary version, if available */ | 250 | /* Read the primary version, if available */ |
251 | if (td->options & NAND_BBT_VERSION) { | 251 | if (td->options & NAND_BBT_VERSION) { |
252 | nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); | 252 | nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); |
253 | td->version[0] = buf[mtd->oobblock + td->veroffs]; | 253 | td->version[0] = buf[mtd->oobblock + td->veroffs]; |
254 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); | 254 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); |
255 | } | 255 | } |
256 | 256 | ||
257 | /* Read the mirror version, if available */ | 257 | /* Read the mirror version, if available */ |
258 | if (md && (md->options & NAND_BBT_VERSION)) { | 258 | if (md && (md->options & NAND_BBT_VERSION)) { |
259 | nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); | 259 | nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); |
260 | md->version[0] = buf[mtd->oobblock + md->veroffs]; | 260 | md->version[0] = buf[mtd->oobblock + md->veroffs]; |
261 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); | 261 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); |
262 | } | 262 | } |
@@ -290,7 +290,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
290 | else { | 290 | else { |
291 | if (bd->options & NAND_BBT_SCAN2NDPAGE) | 291 | if (bd->options & NAND_BBT_SCAN2NDPAGE) |
292 | len = 2; | 292 | len = 2; |
293 | else | 293 | else |
294 | len = 1; | 294 | len = 1; |
295 | } | 295 | } |
296 | 296 | ||
@@ -322,10 +322,10 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
322 | numblocks += startblock; | 322 | numblocks += startblock; |
323 | from = startblock << (this->bbt_erase_shift - 1); | 323 | from = startblock << (this->bbt_erase_shift - 1); |
324 | } | 324 | } |
325 | 325 | ||
326 | for (i = startblock; i < numblocks;) { | 326 | for (i = startblock; i < numblocks;) { |
327 | int ret; | 327 | int ret; |
328 | 328 | ||
329 | if (bd->options & NAND_BBT_SCANEMPTY) | 329 | if (bd->options & NAND_BBT_SCANEMPTY) |
330 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) | 330 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) |
331 | return ret; | 331 | return ret; |
@@ -333,8 +333,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
333 | for (j = 0; j < len; j++) { | 333 | for (j = 0; j < len; j++) { |
334 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 334 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
335 | size_t retlen; | 335 | size_t retlen; |
336 | 336 | ||
337 | /* Read the full oob until read_oob is fixed to | 337 | /* Read the full oob until read_oob is fixed to |
338 | * handle single byte reads for 16 bit buswidth */ | 338 | * handle single byte reads for 16 bit buswidth */ |
339 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock, | 339 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock, |
340 | mtd->oobsize, &retlen, buf); | 340 | mtd->oobsize, &retlen, buf); |
@@ -343,14 +343,14 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
343 | 343 | ||
344 | if (check_short_pattern (buf, bd)) { | 344 | if (check_short_pattern (buf, bd)) { |
345 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 345 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
346 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 346 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
347 | i >> 1, (unsigned int) from); | 347 | i >> 1, (unsigned int) from); |
348 | break; | 348 | break; |
349 | } | 349 | } |
350 | } else { | 350 | } else { |
351 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 351 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { |
352 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 352 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
353 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 353 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
354 | i >> 1, (unsigned int) from); | 354 | i >> 1, (unsigned int) from); |
355 | break; | 355 | break; |
356 | } | 356 | } |
@@ -369,15 +369,15 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
369 | * @td: descriptor for the bad block table | 369 | * @td: descriptor for the bad block table |
370 | * | 370 | * |
371 | * Read the bad block table by searching for a given ident pattern. | 371 | * Read the bad block table by searching for a given ident pattern. |
372 | * Search is preformed either from the beginning up or from the end of | 372 | * Search is preformed either from the beginning up or from the end of |
373 | * the device downwards. The search starts always at the start of a | 373 | * the device downwards. The search starts always at the start of a |
374 | * block. | 374 | * block. |
375 | * If the option NAND_BBT_PERCHIP is given, each chip is searched | 375 | * If the option NAND_BBT_PERCHIP is given, each chip is searched |
376 | * for a bbt, which contains the bad block information of this chip. | 376 | * for a bbt, which contains the bad block information of this chip. |
377 | * This is neccecary to provide support for certain DOC devices. | 377 | * This is neccecary to provide support for certain DOC devices. |
378 | * | 378 | * |
379 | * The bbt ident pattern resides in the oob area of the first page | 379 | * The bbt ident pattern resides in the oob area of the first page |
380 | * in a block. | 380 | * in a block. |
381 | */ | 381 | */ |
382 | static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) | 382 | static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) |
383 | { | 383 | { |
@@ -392,10 +392,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
392 | startblock = (mtd->size >> this->bbt_erase_shift) -1; | 392 | startblock = (mtd->size >> this->bbt_erase_shift) -1; |
393 | dir = -1; | 393 | dir = -1; |
394 | } else { | 394 | } else { |
395 | startblock = 0; | 395 | startblock = 0; |
396 | dir = 1; | 396 | dir = 1; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* Do we have a bbt per chip ? */ | 399 | /* Do we have a bbt per chip ? */ |
400 | if (td->options & NAND_BBT_PERCHIP) { | 400 | if (td->options & NAND_BBT_PERCHIP) { |
401 | chips = this->numchips; | 401 | chips = this->numchips; |
@@ -405,19 +405,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
405 | chips = 1; | 405 | chips = 1; |
406 | bbtblocks = mtd->size >> this->bbt_erase_shift; | 406 | bbtblocks = mtd->size >> this->bbt_erase_shift; |
407 | } | 407 | } |
408 | 408 | ||
409 | /* Number of bits for each erase block in the bbt */ | 409 | /* Number of bits for each erase block in the bbt */ |
410 | bits = td->options & NAND_BBT_NRBITS_MSK; | 410 | bits = td->options & NAND_BBT_NRBITS_MSK; |
411 | 411 | ||
412 | for (i = 0; i < chips; i++) { | 412 | for (i = 0; i < chips; i++) { |
413 | /* Reset version information */ | 413 | /* Reset version information */ |
414 | td->version[i] = 0; | 414 | td->version[i] = 0; |
415 | td->pages[i] = -1; | 415 | td->pages[i] = -1; |
416 | /* Scan the maximum number of blocks */ | 416 | /* Scan the maximum number of blocks */ |
417 | for (block = 0; block < td->maxblocks; block++) { | 417 | for (block = 0; block < td->maxblocks; block++) { |
418 | int actblock = startblock + dir * block; | 418 | int actblock = startblock + dir * block; |
419 | /* Read first page */ | 419 | /* Read first page */ |
420 | nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); | 420 | nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); |
421 | if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { | 421 | if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { |
422 | td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); | 422 | td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); |
423 | if (td->options & NAND_BBT_VERSION) { | 423 | if (td->options & NAND_BBT_VERSION) { |
@@ -435,46 +435,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
435 | else | 435 | else |
436 | printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); | 436 | printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); |
437 | } | 437 | } |
438 | return 0; | 438 | return 0; |
439 | } | 439 | } |
440 | 440 | ||
441 | /** | 441 | /** |
442 | * search_read_bbts - [GENERIC] scan the device for bad block table(s) | 442 | * search_read_bbts - [GENERIC] scan the device for bad block table(s) |
443 | * @mtd: MTD device structure | 443 | * @mtd: MTD device structure |
444 | * @buf: temporary buffer | 444 | * @buf: temporary buffer |
445 | * @td: descriptor for the bad block table | 445 | * @td: descriptor for the bad block table |
446 | * @md: descriptor for the bad block table mirror | 446 | * @md: descriptor for the bad block table mirror |
447 | * | 447 | * |
448 | * Search and read the bad block table(s) | 448 | * Search and read the bad block table(s) |
449 | */ | 449 | */ |
450 | static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, | 450 | static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, |
451 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) | 451 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) |
452 | { | 452 | { |
453 | /* Search the primary table */ | 453 | /* Search the primary table */ |
454 | search_bbt (mtd, buf, td); | 454 | search_bbt (mtd, buf, td); |
455 | 455 | ||
456 | /* Search the mirror table */ | 456 | /* Search the mirror table */ |
457 | if (md) | 457 | if (md) |
458 | search_bbt (mtd, buf, md); | 458 | search_bbt (mtd, buf, md); |
459 | 459 | ||
460 | /* Force result check */ | 460 | /* Force result check */ |
461 | return 1; | 461 | return 1; |
462 | } | 462 | } |
463 | |||
464 | 463 | ||
465 | /** | 464 | |
465 | /** | ||
466 | * write_bbt - [GENERIC] (Re)write the bad block table | 466 | * write_bbt - [GENERIC] (Re)write the bad block table |
467 | * | 467 | * |
468 | * @mtd: MTD device structure | 468 | * @mtd: MTD device structure |
469 | * @buf: temporary buffer | 469 | * @buf: temporary buffer |
470 | * @td: descriptor for the bad block table | 470 | * @td: descriptor for the bad block table |
471 | * @md: descriptor for the bad block table mirror | 471 | * @md: descriptor for the bad block table mirror |
472 | * @chipsel: selector for a specific chip, -1 for all | 472 | * @chipsel: selector for a specific chip, -1 for all |
473 | * | 473 | * |
474 | * (Re)write the bad block table | 474 | * (Re)write the bad block table |
475 | * | 475 | * |
476 | */ | 476 | */ |
477 | static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | 477 | static int write_bbt (struct mtd_info *mtd, uint8_t *buf, |
478 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) | 478 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) |
479 | { | 479 | { |
480 | struct nand_chip *this = mtd->priv; | 480 | struct nand_chip *this = mtd->priv; |
@@ -493,7 +493,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
493 | /* Write bad block table per chip rather than per device ? */ | 493 | /* Write bad block table per chip rather than per device ? */ |
494 | if (td->options & NAND_BBT_PERCHIP) { | 494 | if (td->options & NAND_BBT_PERCHIP) { |
495 | numblocks = (int) (this->chipsize >> this->bbt_erase_shift); | 495 | numblocks = (int) (this->chipsize >> this->bbt_erase_shift); |
496 | /* Full device write or specific chip ? */ | 496 | /* Full device write or specific chip ? */ |
497 | if (chipsel == -1) { | 497 | if (chipsel == -1) { |
498 | nrchips = this->numchips; | 498 | nrchips = this->numchips; |
499 | } else { | 499 | } else { |
@@ -503,19 +503,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
503 | } else { | 503 | } else { |
504 | numblocks = (int) (mtd->size >> this->bbt_erase_shift); | 504 | numblocks = (int) (mtd->size >> this->bbt_erase_shift); |
505 | nrchips = 1; | 505 | nrchips = 1; |
506 | } | 506 | } |
507 | 507 | ||
508 | /* Loop through the chips */ | 508 | /* Loop through the chips */ |
509 | for (; chip < nrchips; chip++) { | 509 | for (; chip < nrchips; chip++) { |
510 | 510 | ||
511 | /* There was already a version of the table, reuse the page | 511 | /* There was already a version of the table, reuse the page |
512 | * This applies for absolute placement too, as we have the | 512 | * This applies for absolute placement too, as we have the |
513 | * page nr. in td->pages. | 513 | * page nr. in td->pages. |
514 | */ | 514 | */ |
515 | if (td->pages[chip] != -1) { | 515 | if (td->pages[chip] != -1) { |
516 | page = td->pages[chip]; | 516 | page = td->pages[chip]; |
517 | goto write; | 517 | goto write; |
518 | } | 518 | } |
519 | 519 | ||
520 | /* Automatic placement of the bad block table */ | 520 | /* Automatic placement of the bad block table */ |
521 | /* Search direction top -> down ? */ | 521 | /* Search direction top -> down ? */ |
@@ -525,7 +525,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
525 | } else { | 525 | } else { |
526 | startblock = chip * numblocks; | 526 | startblock = chip * numblocks; |
527 | dir = 1; | 527 | dir = 1; |
528 | } | 528 | } |
529 | 529 | ||
530 | for (i = 0; i < td->maxblocks; i++) { | 530 | for (i = 0; i < td->maxblocks; i++) { |
531 | int block = startblock + dir * i; | 531 | int block = startblock + dir * i; |
@@ -542,7 +542,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
542 | } | 542 | } |
543 | printk (KERN_ERR "No space left to write bad block table\n"); | 543 | printk (KERN_ERR "No space left to write bad block table\n"); |
544 | return -ENOSPC; | 544 | return -ENOSPC; |
545 | write: | 545 | write: |
546 | 546 | ||
547 | /* Set up shift count and masks for the flash table */ | 547 | /* Set up shift count and masks for the flash table */ |
548 | bits = td->options & NAND_BBT_NRBITS_MSK; | 548 | bits = td->options & NAND_BBT_NRBITS_MSK; |
@@ -553,14 +553,14 @@ write: | |||
553 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; | 553 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; |
554 | default: return -EINVAL; | 554 | default: return -EINVAL; |
555 | } | 555 | } |
556 | 556 | ||
557 | bbtoffs = chip * (numblocks >> 2); | 557 | bbtoffs = chip * (numblocks >> 2); |
558 | 558 | ||
559 | to = ((loff_t) page) << this->page_shift; | 559 | to = ((loff_t) page) << this->page_shift; |
560 | 560 | ||
561 | memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); | 561 | memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); |
562 | oobinfo.useecc = MTD_NANDECC_PLACEONLY; | 562 | oobinfo.useecc = MTD_NANDECC_PLACEONLY; |
563 | 563 | ||
564 | /* Must we save the block contents ? */ | 564 | /* Must we save the block contents ? */ |
565 | if (td->options & NAND_BBT_SAVECONTENT) { | 565 | if (td->options & NAND_BBT_SAVECONTENT) { |
566 | /* Make it block aligned */ | 566 | /* Make it block aligned */ |
@@ -599,7 +599,7 @@ write: | |||
599 | buf[len + td->veroffs] = td->version[chip]; | 599 | buf[len + td->veroffs] = td->version[chip]; |
600 | } | 600 | } |
601 | } | 601 | } |
602 | 602 | ||
603 | /* walk through the memory table */ | 603 | /* walk through the memory table */ |
604 | for (i = 0; i < numblocks; ) { | 604 | for (i = 0; i < numblocks; ) { |
605 | uint8_t dat; | 605 | uint8_t dat; |
@@ -611,7 +611,7 @@ write: | |||
611 | dat >>= 2; | 611 | dat >>= 2; |
612 | } | 612 | } |
613 | } | 613 | } |
614 | 614 | ||
615 | memset (&einfo, 0, sizeof (einfo)); | 615 | memset (&einfo, 0, sizeof (einfo)); |
616 | einfo.mtd = mtd; | 616 | einfo.mtd = mtd; |
617 | einfo.addr = (unsigned long) to; | 617 | einfo.addr = (unsigned long) to; |
@@ -621,18 +621,18 @@ write: | |||
621 | printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); | 621 | printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); |
622 | return res; | 622 | return res; |
623 | } | 623 | } |
624 | 624 | ||
625 | res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); | 625 | res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); |
626 | if (res < 0) { | 626 | if (res < 0) { |
627 | printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); | 627 | printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); |
628 | return res; | 628 | return res; |
629 | } | 629 | } |
630 | printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", | 630 | printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", |
631 | (unsigned int) to, td->version[chip]); | 631 | (unsigned int) to, td->version[chip]); |
632 | 632 | ||
633 | /* Mark it as used */ | 633 | /* Mark it as used */ |
634 | td->pages[chip] = page; | 634 | td->pages[chip] = page; |
635 | } | 635 | } |
636 | return 0; | 636 | return 0; |
637 | } | 637 | } |
638 | 638 | ||
@@ -641,7 +641,7 @@ write: | |||
641 | * @mtd: MTD device structure | 641 | * @mtd: MTD device structure |
642 | * @bd: descriptor for the good/bad block search pattern | 642 | * @bd: descriptor for the good/bad block search pattern |
643 | * | 643 | * |
644 | * The function creates a memory based bbt by scanning the device | 644 | * The function creates a memory based bbt by scanning the device |
645 | * for manufacturer / software marked good / bad blocks | 645 | * for manufacturer / software marked good / bad blocks |
646 | */ | 646 | */ |
647 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | 647 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) |
@@ -673,11 +673,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
673 | struct nand_bbt_descr *rd, *rd2; | 673 | struct nand_bbt_descr *rd, *rd2; |
674 | 674 | ||
675 | /* Do we have a bbt per chip ? */ | 675 | /* Do we have a bbt per chip ? */ |
676 | if (td->options & NAND_BBT_PERCHIP) | 676 | if (td->options & NAND_BBT_PERCHIP) |
677 | chips = this->numchips; | 677 | chips = this->numchips; |
678 | else | 678 | else |
679 | chips = 1; | 679 | chips = 1; |
680 | 680 | ||
681 | for (i = 0; i < chips; i++) { | 681 | for (i = 0; i < chips; i++) { |
682 | writeops = 0; | 682 | writeops = 0; |
683 | rd = NULL; | 683 | rd = NULL; |
@@ -692,7 +692,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
692 | } | 692 | } |
693 | 693 | ||
694 | if (td->pages[i] == -1) { | 694 | if (td->pages[i] == -1) { |
695 | rd = md; | 695 | rd = md; |
696 | td->version[i] = md->version[i]; | 696 | td->version[i] = md->version[i]; |
697 | writeops = 1; | 697 | writeops = 1; |
698 | goto writecheck; | 698 | goto writecheck; |
@@ -710,7 +710,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
710 | if (!(td->options & NAND_BBT_VERSION)) | 710 | if (!(td->options & NAND_BBT_VERSION)) |
711 | rd2 = md; | 711 | rd2 = md; |
712 | goto writecheck; | 712 | goto writecheck; |
713 | } | 713 | } |
714 | 714 | ||
715 | if (((int8_t) (td->version[i] - md->version[i])) > 0) { | 715 | if (((int8_t) (td->version[i] - md->version[i])) > 0) { |
716 | rd = td; | 716 | rd = td; |
@@ -735,15 +735,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
735 | create: | 735 | create: |
736 | /* Create the bad block table by scanning the device ? */ | 736 | /* Create the bad block table by scanning the device ? */ |
737 | if (!(td->options & NAND_BBT_CREATE)) | 737 | if (!(td->options & NAND_BBT_CREATE)) |
738 | continue; | 738 | continue; |
739 | 739 | ||
740 | /* Create the table in memory by scanning the chip(s) */ | 740 | /* Create the table in memory by scanning the chip(s) */ |
741 | create_bbt (mtd, buf, bd, chipsel); | 741 | create_bbt (mtd, buf, bd, chipsel); |
742 | 742 | ||
743 | td->version[i] = 1; | 743 | td->version[i] = 1; |
744 | if (md) | 744 | if (md) |
745 | md->version[i] = 1; | 745 | md->version[i] = 1; |
746 | writecheck: | 746 | writecheck: |
747 | /* read back first ? */ | 747 | /* read back first ? */ |
748 | if (rd) | 748 | if (rd) |
749 | read_abs_bbt (mtd, buf, rd, chipsel); | 749 | read_abs_bbt (mtd, buf, rd, chipsel); |
@@ -757,7 +757,7 @@ writecheck: | |||
757 | if (res < 0) | 757 | if (res < 0) |
758 | return res; | 758 | return res; |
759 | } | 759 | } |
760 | 760 | ||
761 | /* Write the mirror bad block table to the device ? */ | 761 | /* Write the mirror bad block table to the device ? */ |
762 | if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { | 762 | if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { |
763 | res = write_bbt (mtd, buf, md, td, chipsel); | 763 | res = write_bbt (mtd, buf, md, td, chipsel); |
@@ -765,11 +765,11 @@ writecheck: | |||
765 | return res; | 765 | return res; |
766 | } | 766 | } |
767 | } | 767 | } |
768 | return 0; | 768 | return 0; |
769 | } | 769 | } |
770 | 770 | ||
771 | /** | 771 | /** |
772 | * mark_bbt_regions - [GENERIC] mark the bad block table regions | 772 | * mark_bbt_regions - [GENERIC] mark the bad block table regions |
773 | * @mtd: MTD device structure | 773 | * @mtd: MTD device structure |
774 | * @td: bad block table descriptor | 774 | * @td: bad block table descriptor |
775 | * | 775 | * |
@@ -790,14 +790,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
790 | } else { | 790 | } else { |
791 | chips = 1; | 791 | chips = 1; |
792 | nrblocks = (int)(mtd->size >> this->bbt_erase_shift); | 792 | nrblocks = (int)(mtd->size >> this->bbt_erase_shift); |
793 | } | 793 | } |
794 | 794 | ||
795 | for (i = 0; i < chips; i++) { | 795 | for (i = 0; i < chips; i++) { |
796 | if ((td->options & NAND_BBT_ABSPAGE) || | 796 | if ((td->options & NAND_BBT_ABSPAGE) || |
797 | !(td->options & NAND_BBT_WRITE)) { | 797 | !(td->options & NAND_BBT_WRITE)) { |
798 | if (td->pages[i] == -1) continue; | 798 | if (td->pages[i] == -1) continue; |
799 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); | 799 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); |
800 | block <<= 1; | 800 | block <<= 1; |
801 | oldval = this->bbt[(block >> 3)]; | 801 | oldval = this->bbt[(block >> 3)]; |
802 | newval = oldval | (0x2 << (block & 0x06)); | 802 | newval = oldval | (0x2 << (block & 0x06)); |
803 | this->bbt[(block >> 3)] = newval; | 803 | this->bbt[(block >> 3)] = newval; |
@@ -808,16 +808,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
808 | update = 0; | 808 | update = 0; |
809 | if (td->options & NAND_BBT_LASTBLOCK) | 809 | if (td->options & NAND_BBT_LASTBLOCK) |
810 | block = ((i + 1) * nrblocks) - td->maxblocks; | 810 | block = ((i + 1) * nrblocks) - td->maxblocks; |
811 | else | 811 | else |
812 | block = i * nrblocks; | 812 | block = i * nrblocks; |
813 | block <<= 1; | 813 | block <<= 1; |
814 | for (j = 0; j < td->maxblocks; j++) { | 814 | for (j = 0; j < td->maxblocks; j++) { |
815 | oldval = this->bbt[(block >> 3)]; | 815 | oldval = this->bbt[(block >> 3)]; |
816 | newval = oldval | (0x2 << (block & 0x06)); | 816 | newval = oldval | (0x2 << (block & 0x06)); |
817 | this->bbt[(block >> 3)] = newval; | 817 | this->bbt[(block >> 3)] = newval; |
818 | if (oldval != newval) update = 1; | 818 | if (oldval != newval) update = 1; |
819 | block += 2; | 819 | block += 2; |
820 | } | 820 | } |
821 | /* If we want reserved blocks to be recorded to flash, and some | 821 | /* If we want reserved blocks to be recorded to flash, and some |
822 | new ones have been marked, then we need to update the stored | 822 | new ones have been marked, then we need to update the stored |
823 | bbts. This should only happen once. */ | 823 | bbts. This should only happen once. */ |
@@ -831,7 +831,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
831 | * @mtd: MTD device structure | 831 | * @mtd: MTD device structure |
832 | * @bd: descriptor for the good/bad block search pattern | 832 | * @bd: descriptor for the good/bad block search pattern |
833 | * | 833 | * |
834 | * The function checks, if a bad block table(s) is/are already | 834 | * The function checks, if a bad block table(s) is/are already |
835 | * available. If not it scans the device for manufacturer | 835 | * available. If not it scans the device for manufacturer |
836 | * marked good / bad blocks and writes the bad block table(s) to | 836 | * marked good / bad blocks and writes the bad block table(s) to |
837 | * the selected place. | 837 | * the selected place. |
@@ -880,30 +880,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
880 | this->bbt = NULL; | 880 | this->bbt = NULL; |
881 | return -ENOMEM; | 881 | return -ENOMEM; |
882 | } | 882 | } |
883 | 883 | ||
884 | /* Is the bbt at a given page ? */ | 884 | /* Is the bbt at a given page ? */ |
885 | if (td->options & NAND_BBT_ABSPAGE) { | 885 | if (td->options & NAND_BBT_ABSPAGE) { |
886 | res = read_abs_bbts (mtd, buf, td, md); | 886 | res = read_abs_bbts (mtd, buf, td, md); |
887 | } else { | 887 | } else { |
888 | /* Search the bad block table using a pattern in oob */ | 888 | /* Search the bad block table using a pattern in oob */ |
889 | res = search_read_bbts (mtd, buf, td, md); | 889 | res = search_read_bbts (mtd, buf, td, md); |
890 | } | 890 | } |
891 | 891 | ||
892 | if (res) | 892 | if (res) |
893 | res = check_create (mtd, buf, bd); | 893 | res = check_create (mtd, buf, bd); |
894 | 894 | ||
895 | /* Prevent the bbt regions from erasing / writing */ | 895 | /* Prevent the bbt regions from erasing / writing */ |
896 | mark_bbt_region (mtd, td); | 896 | mark_bbt_region (mtd, td); |
897 | if (md) | 897 | if (md) |
898 | mark_bbt_region (mtd, md); | 898 | mark_bbt_region (mtd, md); |
899 | 899 | ||
900 | kfree (buf); | 900 | kfree (buf); |
901 | return res; | 901 | return res; |
902 | } | 902 | } |
903 | 903 | ||
904 | 904 | ||
905 | /** | 905 | /** |
906 | * nand_update_bbt - [NAND Interface] update bad block table(s) | 906 | * nand_update_bbt - [NAND Interface] update bad block table(s) |
907 | * @mtd: MTD device structure | 907 | * @mtd: MTD device structure |
908 | * @offs: the offset of the newly marked block | 908 | * @offs: the offset of the newly marked block |
909 | * | 909 | * |
@@ -930,7 +930,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
930 | printk (KERN_ERR "nand_update_bbt: Out of memory\n"); | 930 | printk (KERN_ERR "nand_update_bbt: Out of memory\n"); |
931 | return -ENOMEM; | 931 | return -ENOMEM; |
932 | } | 932 | } |
933 | 933 | ||
934 | writeops = md != NULL ? 0x03 : 0x01; | 934 | writeops = md != NULL ? 0x03 : 0x01; |
935 | 935 | ||
936 | /* Do we have a bbt per chip ? */ | 936 | /* Do we have a bbt per chip ? */ |
@@ -944,7 +944,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
944 | 944 | ||
945 | td->version[chip]++; | 945 | td->version[chip]++; |
946 | if (md) | 946 | if (md) |
947 | md->version[chip]++; | 947 | md->version[chip]++; |
948 | 948 | ||
949 | /* Write the bad block table to the device ? */ | 949 | /* Write the bad block table to the device ? */ |
950 | if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { | 950 | if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { |
@@ -957,12 +957,12 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
957 | res = write_bbt (mtd, buf, md, td, chipsel); | 957 | res = write_bbt (mtd, buf, md, td, chipsel); |
958 | } | 958 | } |
959 | 959 | ||
960 | out: | 960 | out: |
961 | kfree (buf); | 961 | kfree (buf); |
962 | return res; | 962 | return res; |
963 | } | 963 | } |
964 | 964 | ||
965 | /* Define some generic bad / good block scan pattern which are used | 965 | /* Define some generic bad / good block scan pattern which are used |
966 | * while scanning a device for factory marked good / bad blocks. */ | 966 | * while scanning a device for factory marked good / bad blocks. */ |
967 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 967 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
968 | 968 | ||
@@ -1009,7 +1009,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; | |||
1009 | static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; | 1009 | static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; |
1010 | 1010 | ||
1011 | static struct nand_bbt_descr bbt_main_descr = { | 1011 | static struct nand_bbt_descr bbt_main_descr = { |
1012 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | 1012 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
1013 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | 1013 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, |
1014 | .offs = 8, | 1014 | .offs = 8, |
1015 | .len = 4, | 1015 | .len = 4, |
@@ -1019,7 +1019,7 @@ static struct nand_bbt_descr bbt_main_descr = { | |||
1019 | }; | 1019 | }; |
1020 | 1020 | ||
1021 | static struct nand_bbt_descr bbt_mirror_descr = { | 1021 | static struct nand_bbt_descr bbt_mirror_descr = { |
1022 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | 1022 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
1023 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | 1023 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, |
1024 | .offs = 8, | 1024 | .offs = 8, |
1025 | .len = 4, | 1025 | .len = 4, |
@@ -1029,7 +1029,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1029 | }; | 1029 | }; |
1030 | 1030 | ||
1031 | /** | 1031 | /** |
1032 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device | 1032 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device |
1033 | * @mtd: MTD device structure | 1033 | * @mtd: MTD device structure |
1034 | * | 1034 | * |
1035 | * This function selects the default bad block table | 1035 | * This function selects the default bad block table |
@@ -1039,29 +1039,29 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1039 | int nand_default_bbt (struct mtd_info *mtd) | 1039 | int nand_default_bbt (struct mtd_info *mtd) |
1040 | { | 1040 | { |
1041 | struct nand_chip *this = mtd->priv; | 1041 | struct nand_chip *this = mtd->priv; |
1042 | 1042 | ||
1043 | /* Default for AG-AND. We must use a flash based | 1043 | /* Default for AG-AND. We must use a flash based |
1044 | * bad block table as the devices have factory marked | 1044 | * bad block table as the devices have factory marked |
1045 | * _good_ blocks. Erasing those blocks leads to loss | 1045 | * _good_ blocks. Erasing those blocks leads to loss |
1046 | * of the good / bad information, so we _must_ store | 1046 | * of the good / bad information, so we _must_ store |
1047 | * this information in a good / bad table during | 1047 | * this information in a good / bad table during |
1048 | * startup | 1048 | * startup |
1049 | */ | 1049 | */ |
1050 | if (this->options & NAND_IS_AND) { | 1050 | if (this->options & NAND_IS_AND) { |
1051 | /* Use the default pattern descriptors */ | 1051 | /* Use the default pattern descriptors */ |
1052 | if (!this->bbt_td) { | 1052 | if (!this->bbt_td) { |
1053 | this->bbt_td = &bbt_main_descr; | 1053 | this->bbt_td = &bbt_main_descr; |
1054 | this->bbt_md = &bbt_mirror_descr; | 1054 | this->bbt_md = &bbt_mirror_descr; |
1055 | } | 1055 | } |
1056 | this->options |= NAND_USE_FLASH_BBT; | 1056 | this->options |= NAND_USE_FLASH_BBT; |
1057 | return nand_scan_bbt (mtd, &agand_flashbased); | 1057 | return nand_scan_bbt (mtd, &agand_flashbased); |
1058 | } | 1058 | } |
1059 | 1059 | ||
1060 | 1060 | ||
1061 | /* Is a flash based bad block table requested ? */ | 1061 | /* Is a flash based bad block table requested ? */ |
1062 | if (this->options & NAND_USE_FLASH_BBT) { | 1062 | if (this->options & NAND_USE_FLASH_BBT) { |
1063 | /* Use the default pattern descriptors */ | 1063 | /* Use the default pattern descriptors */ |
1064 | if (!this->bbt_td) { | 1064 | if (!this->bbt_td) { |
1065 | this->bbt_td = &bbt_main_descr; | 1065 | this->bbt_td = &bbt_main_descr; |
1066 | this->bbt_md = &bbt_mirror_descr; | 1066 | this->bbt_md = &bbt_mirror_descr; |
1067 | } | 1067 | } |
@@ -1081,7 +1081,7 @@ int nand_default_bbt (struct mtd_info *mtd) | |||
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | /** | 1083 | /** |
1084 | * nand_isbad_bbt - [NAND Interface] Check if a block is bad | 1084 | * nand_isbad_bbt - [NAND Interface] Check if a block is bad |
1085 | * @mtd: MTD device structure | 1085 | * @mtd: MTD device structure |
1086 | * @offs: offset in the device | 1086 | * @offs: offset in the device |
1087 | * @allowbbt: allow access to bad block table region | 1087 | * @allowbbt: allow access to bad block table region |
@@ -1092,12 +1092,12 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1092 | struct nand_chip *this = mtd->priv; | 1092 | struct nand_chip *this = mtd->priv; |
1093 | int block; | 1093 | int block; |
1094 | uint8_t res; | 1094 | uint8_t res; |
1095 | 1095 | ||
1096 | /* Get block number * 2 */ | 1096 | /* Get block number * 2 */ |
1097 | block = (int) (offs >> (this->bbt_erase_shift - 1)); | 1097 | block = (int) (offs >> (this->bbt_erase_shift - 1)); |
1098 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1098 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
1099 | 1099 | ||
1100 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", | 1100 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", |
1101 | (unsigned int)offs, block >> 1, res); | 1101 | (unsigned int)offs, block >> 1, res); |
1102 | 1102 | ||
1103 | switch ((int)res) { | 1103 | switch ((int)res) { |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 2e341b75437a..40ac909150a3 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -7,22 +7,22 @@ | |||
7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * Toshiba America Electronics Components, Inc. | 8 | * Toshiba America Electronics Components, Inc. |
9 | * | 9 | * |
10 | * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $ | 10 | * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ |
11 | * | 11 | * |
12 | * This file is free software; you can redistribute it and/or modify it | 12 | * This file is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
14 | * Free Software Foundation; either version 2 or (at your option) any | 14 | * Free Software Foundation; either version 2 or (at your option) any |
15 | * later version. | 15 | * later version. |
16 | * | 16 | * |
17 | * This file is distributed in the hope that it will be useful, but WITHOUT | 17 | * This file is distributed in the hope that it will be useful, but WITHOUT |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
20 | * for more details. | 20 | * for more details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License along | 22 | * You should have received a copy of the GNU General Public License along |
23 | * with this file; if not, write to the Free Software Foundation, Inc., | 23 | * with this file; if not, write to the Free Software Foundation, Inc., |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
25 | * | 25 | * |
26 | * As a special exception, if other files instantiate templates or use | 26 | * As a special exception, if other files instantiate templates or use |
27 | * macros or inline functions from these files, or you compile these | 27 | * macros or inline functions from these files, or you compile these |
28 | * files and link them with other works to produce a work based on these | 28 | * files and link them with other works to produce a work based on these |
@@ -30,7 +30,7 @@ | |||
30 | * covered by the GNU General Public License. However the source code for | 30 | * covered by the GNU General Public License. However the source code for |
31 | * these files must still be made available in accordance with section (3) | 31 | * these files must still be made available in accordance with section (3) |
32 | * of the GNU General Public License. | 32 | * of the GNU General Public License. |
33 | * | 33 | * |
34 | * This exception does not invalidate any other reasons why a work based on | 34 | * This exception does not invalidate any other reasons why a work based on |
35 | * this file might be covered by the GNU General Public License. | 35 | * this file might be covered by the GNU General Public License. |
36 | */ | 36 | */ |
@@ -67,7 +67,7 @@ static const u_char nand_ecc_precalc_table[] = { | |||
67 | * nand_trans_result - [GENERIC] create non-inverted ECC | 67 | * nand_trans_result - [GENERIC] create non-inverted ECC |
68 | * @reg2: line parity reg 2 | 68 | * @reg2: line parity reg 2 |
69 | * @reg3: line parity reg 3 | 69 | * @reg3: line parity reg 3 |
70 | * @ecc_code: ecc | 70 | * @ecc_code: ecc |
71 | * | 71 | * |
72 | * Creates non-inverted ECC code from line parity | 72 | * Creates non-inverted ECC code from line parity |
73 | */ | 73 | */ |
@@ -75,11 +75,11 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
75 | u_char *ecc_code) | 75 | u_char *ecc_code) |
76 | { | 76 | { |
77 | u_char a, b, i, tmp1, tmp2; | 77 | u_char a, b, i, tmp1, tmp2; |
78 | 78 | ||
79 | /* Initialize variables */ | 79 | /* Initialize variables */ |
80 | a = b = 0x80; | 80 | a = b = 0x80; |
81 | tmp1 = tmp2 = 0; | 81 | tmp1 = tmp2 = 0; |
82 | 82 | ||
83 | /* Calculate first ECC byte */ | 83 | /* Calculate first ECC byte */ |
84 | for (i = 0; i < 4; i++) { | 84 | for (i = 0; i < 4; i++) { |
85 | if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ | 85 | if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ |
@@ -90,7 +90,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
90 | b >>= 1; | 90 | b >>= 1; |
91 | a >>= 1; | 91 | a >>= 1; |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Calculate second ECC byte */ | 94 | /* Calculate second ECC byte */ |
95 | b = 0x80; | 95 | b = 0x80; |
96 | for (i = 0; i < 4; i++) { | 96 | for (i = 0; i < 4; i++) { |
@@ -102,7 +102,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
102 | b >>= 1; | 102 | b >>= 1; |
103 | a >>= 1; | 103 | a >>= 1; |
104 | } | 104 | } |
105 | 105 | ||
106 | /* Store two of the ECC bytes */ | 106 | /* Store two of the ECC bytes */ |
107 | ecc_code[0] = tmp1; | 107 | ecc_code[0] = tmp1; |
108 | ecc_code[1] = tmp2; | 108 | ecc_code[1] = tmp2; |
@@ -118,28 +118,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code | |||
118 | { | 118 | { |
119 | u_char idx, reg1, reg2, reg3; | 119 | u_char idx, reg1, reg2, reg3; |
120 | int j; | 120 | int j; |
121 | 121 | ||
122 | /* Initialize variables */ | 122 | /* Initialize variables */ |
123 | reg1 = reg2 = reg3 = 0; | 123 | reg1 = reg2 = reg3 = 0; |
124 | ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; | 124 | ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; |
125 | 125 | ||
126 | /* Build up column parity */ | 126 | /* Build up column parity */ |
127 | for(j = 0; j < 256; j++) { | 127 | for(j = 0; j < 256; j++) { |
128 | 128 | ||
129 | /* Get CP0 - CP5 from table */ | 129 | /* Get CP0 - CP5 from table */ |
130 | idx = nand_ecc_precalc_table[dat[j]]; | 130 | idx = nand_ecc_precalc_table[dat[j]]; |
131 | reg1 ^= (idx & 0x3f); | 131 | reg1 ^= (idx & 0x3f); |
132 | 132 | ||
133 | /* All bit XOR = 1 ? */ | 133 | /* All bit XOR = 1 ? */ |
134 | if (idx & 0x40) { | 134 | if (idx & 0x40) { |
135 | reg3 ^= (u_char) j; | 135 | reg3 ^= (u_char) j; |
136 | reg2 ^= ~((u_char) j); | 136 | reg2 ^= ~((u_char) j); |
137 | } | 137 | } |
138 | } | 138 | } |
139 | 139 | ||
140 | /* Create non-inverted ECC code from line parity */ | 140 | /* Create non-inverted ECC code from line parity */ |
141 | nand_trans_result(reg2, reg3, ecc_code); | 141 | nand_trans_result(reg2, reg3, ecc_code); |
142 | 142 | ||
143 | /* Calculate final ECC code */ | 143 | /* Calculate final ECC code */ |
144 | ecc_code[0] = ~ecc_code[0]; | 144 | ecc_code[0] = ~ecc_code[0]; |
145 | ecc_code[1] = ~ecc_code[1]; | 145 | ecc_code[1] = ~ecc_code[1]; |
@@ -159,12 +159,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code | |||
159 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) | 159 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) |
160 | { | 160 | { |
161 | u_char a, b, c, d1, d2, d3, add, bit, i; | 161 | u_char a, b, c, d1, d2, d3, add, bit, i; |
162 | 162 | ||
163 | /* Do error detection */ | 163 | /* Do error detection */ |
164 | d1 = calc_ecc[0] ^ read_ecc[0]; | 164 | d1 = calc_ecc[0] ^ read_ecc[0]; |
165 | d2 = calc_ecc[1] ^ read_ecc[1]; | 165 | d2 = calc_ecc[1] ^ read_ecc[1]; |
166 | d3 = calc_ecc[2] ^ read_ecc[2]; | 166 | d3 = calc_ecc[2] ^ read_ecc[2]; |
167 | 167 | ||
168 | if ((d1 | d2 | d3) == 0) { | 168 | if ((d1 | d2 | d3) == 0) { |
169 | /* No errors */ | 169 | /* No errors */ |
170 | return 0; | 170 | return 0; |
@@ -173,7 +173,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha | |||
173 | a = (d1 ^ (d1 >> 1)) & 0x55; | 173 | a = (d1 ^ (d1 >> 1)) & 0x55; |
174 | b = (d2 ^ (d2 >> 1)) & 0x55; | 174 | b = (d2 ^ (d2 >> 1)) & 0x55; |
175 | c = (d3 ^ (d3 >> 1)) & 0x54; | 175 | c = (d3 ^ (d3 >> 1)) & 0x54; |
176 | 176 | ||
177 | /* Found and will correct single bit error in the data */ | 177 | /* Found and will correct single bit error in the data */ |
178 | if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { | 178 | if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { |
179 | c = 0x80; | 179 | c = 0x80; |
@@ -237,7 +237,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha | |||
237 | } | 237 | } |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
241 | /* Should never happen */ | 241 | /* Should never happen */ |
242 | return -1; | 242 | return -1; |
243 | } | 243 | } |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index efe246961b69..dbc7e55a4247 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) | 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) |
5 | * | 5 | * |
6 | * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $ | 6 | * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,14 +14,14 @@ | |||
14 | #include <linux/mtd/nand.h> | 14 | #include <linux/mtd/nand.h> |
15 | /* | 15 | /* |
16 | * Chip ID list | 16 | * Chip ID list |
17 | * | 17 | * |
18 | * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, | 18 | * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, |
19 | * options | 19 | * options |
20 | * | 20 | * |
21 | * Pagesize; 0, 256, 512 | 21 | * Pagesize; 0, 256, 512 |
22 | * 0 get this information from the extended chip ID | 22 | * 0 get this information from the extended chip ID |
23 | + 256 256 Byte page size | 23 | + 256 256 Byte page size |
24 | * 512 512 Byte page size | 24 | * 512 512 Byte page size |
25 | */ | 25 | */ |
26 | struct nand_flash_dev nand_flash_ids[] = { | 26 | struct nand_flash_dev nand_flash_ids[] = { |
27 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, | 27 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, |
@@ -34,27 +34,27 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
34 | {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, | 34 | {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, |
35 | {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, | 35 | {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, |
36 | {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, | 36 | {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, |
37 | 37 | ||
38 | {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, | 38 | {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, |
39 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, | 39 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, |
40 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 40 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
41 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 41 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
42 | 42 | ||
43 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, | 43 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, |
44 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, | 44 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, |
45 | {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, | 45 | {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, |
46 | {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, | 46 | {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, |
47 | 47 | ||
48 | {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, | 48 | {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, |
49 | {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, | 49 | {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, |
50 | {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, | 50 | {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, |
51 | {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, | 51 | {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, |
52 | 52 | ||
53 | {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, | 53 | {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, |
54 | {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, | 54 | {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, |
55 | {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, | 55 | {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, |
56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, | 56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, |
57 | 57 | ||
58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, | 58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, |
59 | {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, | 59 | {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, |
60 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, | 60 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, |
@@ -62,7 +62,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
62 | {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 62 | {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
63 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 63 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
64 | {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 64 | {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
65 | 65 | ||
66 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, | 66 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, |
67 | 67 | ||
68 | /* These are the new chips with large page size. The pagesize | 68 | /* These are the new chips with large page size. The pagesize |
@@ -73,7 +73,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
73 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 73 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
74 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 74 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
75 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 75 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
76 | 76 | ||
77 | /* 1 Gigabit */ | 77 | /* 1 Gigabit */ |
78 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 78 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
79 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 79 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
@@ -85,13 +85,13 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
85 | {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 85 | {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
86 | {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 86 | {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
87 | {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 87 | {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
88 | 88 | ||
89 | /* 4 Gigabit */ | 89 | /* 4 Gigabit */ |
90 | {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 90 | {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
91 | {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 91 | {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
92 | {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 92 | {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
93 | {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 93 | {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
94 | 94 | ||
95 | /* 8 Gigabit */ | 95 | /* 8 Gigabit */ |
96 | {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 96 | {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
97 | {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 97 | {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
@@ -104,11 +104,11 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
104 | {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 104 | {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
105 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 105 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
106 | 106 | ||
107 | /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! | 107 | /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! |
108 | * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes | 108 | * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes |
109 | * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 | 109 | * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 |
110 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go | 110 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go |
111 | * There are more speed improvements for reads and writes possible, but not implemented now | 111 | * There are more speed improvements for reads and writes possible, but not implemented now |
112 | */ | 112 | */ |
113 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, | 113 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, |
114 | 114 | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 754b6ed7ce14..de4500395300 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> | 4 | * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> |
5 | * | 5 | * |
6 | * Copyright (C) 2004 Nokia Corporation | 6 | * Copyright (C) 2004 Nokia Corporation |
7 | * | 7 | * |
8 | * Note: NS means "NAND Simulator". | 8 | * Note: NS means "NAND Simulator". |
9 | * Note: Input means input TO flash chip, output means output FROM chip. | 9 | * Note: Input means input TO flash chip, output means output FROM chip. |
@@ -126,7 +126,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
126 | 126 | ||
127 | /* The largest possible page size */ | 127 | /* The largest possible page size */ |
128 | #define NS_LARGEST_PAGE_SIZE 2048 | 128 | #define NS_LARGEST_PAGE_SIZE 2048 |
129 | 129 | ||
130 | /* The prefix for simulator output */ | 130 | /* The prefix for simulator output */ |
131 | #define NS_OUTPUT_PREFIX "[nandsim]" | 131 | #define NS_OUTPUT_PREFIX "[nandsim]" |
132 | 132 | ||
@@ -145,7 +145,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
145 | do { if (do_delays) udelay(us); } while(0) | 145 | do { if (do_delays) udelay(us); } while(0) |
146 | #define NS_MDELAY(us) \ | 146 | #define NS_MDELAY(us) \ |
147 | do { if (do_delays) mdelay(us); } while(0) | 147 | do { if (do_delays) mdelay(us); } while(0) |
148 | 148 | ||
149 | /* Is the nandsim structure initialized ? */ | 149 | /* Is the nandsim structure initialized ? */ |
150 | #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) | 150 | #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) |
151 | 151 | ||
@@ -153,12 +153,12 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
153 | #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) | 153 | #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) |
154 | 154 | ||
155 | /* Operation failed completion status */ | 155 | /* Operation failed completion status */ |
156 | #define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) | 156 | #define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) |
157 | 157 | ||
158 | /* Calculate the page offset in flash RAM image by (row, column) address */ | 158 | /* Calculate the page offset in flash RAM image by (row, column) address */ |
159 | #define NS_RAW_OFFSET(ns) \ | 159 | #define NS_RAW_OFFSET(ns) \ |
160 | (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) | 160 | (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) |
161 | 161 | ||
162 | /* Calculate the OOB offset in flash RAM image by (row, column) address */ | 162 | /* Calculate the OOB offset in flash RAM image by (row, column) address */ |
163 | #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) | 163 | #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) |
164 | 164 | ||
@@ -223,15 +223,15 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
223 | 223 | ||
224 | /* Remove action bits ftom state */ | 224 | /* Remove action bits ftom state */ |
225 | #define NS_STATE(x) ((x) & ~ACTION_MASK) | 225 | #define NS_STATE(x) ((x) & ~ACTION_MASK) |
226 | 226 | ||
227 | /* | 227 | /* |
228 | * Maximum previous states which need to be saved. Currently saving is | 228 | * Maximum previous states which need to be saved. Currently saving is |
229 | * only needed for page programm operation with preceeded read command | 229 | * only needed for page programm operation with preceeded read command |
230 | * (which is only valid for 512-byte pages). | 230 | * (which is only valid for 512-byte pages). |
231 | */ | 231 | */ |
232 | #define NS_MAX_PREVSTATES 1 | 232 | #define NS_MAX_PREVSTATES 1 |
233 | 233 | ||
234 | /* | 234 | /* |
235 | * The structure which describes all the internal simulator data. | 235 | * The structure which describes all the internal simulator data. |
236 | */ | 236 | */ |
237 | struct nandsim { | 237 | struct nandsim { |
@@ -242,7 +242,7 @@ struct nandsim { | |||
242 | uint32_t options; /* chip's characteristic bits */ | 242 | uint32_t options; /* chip's characteristic bits */ |
243 | uint32_t state; /* current chip state */ | 243 | uint32_t state; /* current chip state */ |
244 | uint32_t nxstate; /* next expected state */ | 244 | uint32_t nxstate; /* next expected state */ |
245 | 245 | ||
246 | uint32_t *op; /* current operation, NULL operations isn't known yet */ | 246 | uint32_t *op; /* current operation, NULL operations isn't known yet */ |
247 | uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ | 247 | uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ |
248 | uint16_t npstates; /* number of previous states saved */ | 248 | uint16_t npstates; /* number of previous states saved */ |
@@ -413,7 +413,7 @@ init_nandsim(struct mtd_info *mtd) | |||
413 | ns->geom.secaddrbytes = 3; | 413 | ns->geom.secaddrbytes = 3; |
414 | } | 414 | } |
415 | } | 415 | } |
416 | 416 | ||
417 | /* Detect how many ID bytes the NAND chip outputs */ | 417 | /* Detect how many ID bytes the NAND chip outputs */ |
418 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 418 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
419 | if (second_id_byte != nand_flash_ids[i].id) | 419 | if (second_id_byte != nand_flash_ids[i].id) |
@@ -444,7 +444,7 @@ init_nandsim(struct mtd_info *mtd) | |||
444 | #ifdef CONFIG_NS_ABS_POS | 444 | #ifdef CONFIG_NS_ABS_POS |
445 | ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); | 445 | ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); |
446 | if (!ns->mem.byte) { | 446 | if (!ns->mem.byte) { |
447 | NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", | 447 | NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", |
448 | (void *)CONFIG_NS_ABS_POS); | 448 | (void *)CONFIG_NS_ABS_POS); |
449 | return -ENOMEM; | 449 | return -ENOMEM; |
450 | } | 450 | } |
@@ -567,7 +567,7 @@ static int | |||
567 | check_command(int cmd) | 567 | check_command(int cmd) |
568 | { | 568 | { |
569 | switch (cmd) { | 569 | switch (cmd) { |
570 | 570 | ||
571 | case NAND_CMD_READ0: | 571 | case NAND_CMD_READ0: |
572 | case NAND_CMD_READSTART: | 572 | case NAND_CMD_READSTART: |
573 | case NAND_CMD_PAGEPROG: | 573 | case NAND_CMD_PAGEPROG: |
@@ -580,7 +580,7 @@ check_command(int cmd) | |||
580 | case NAND_CMD_RESET: | 580 | case NAND_CMD_RESET: |
581 | case NAND_CMD_READ1: | 581 | case NAND_CMD_READ1: |
582 | return 0; | 582 | return 0; |
583 | 583 | ||
584 | case NAND_CMD_STATUS_MULTI: | 584 | case NAND_CMD_STATUS_MULTI: |
585 | default: | 585 | default: |
586 | return 1; | 586 | return 1; |
@@ -631,7 +631,7 @@ static inline void | |||
631 | accept_addr_byte(struct nandsim *ns, u_char bt) | 631 | accept_addr_byte(struct nandsim *ns, u_char bt) |
632 | { | 632 | { |
633 | uint byte = (uint)bt; | 633 | uint byte = (uint)bt; |
634 | 634 | ||
635 | if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | 635 | if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) |
636 | ns->regs.column |= (byte << 8 * ns->regs.count); | 636 | ns->regs.column |= (byte << 8 * ns->regs.count); |
637 | else { | 637 | else { |
@@ -642,11 +642,11 @@ accept_addr_byte(struct nandsim *ns, u_char bt) | |||
642 | 642 | ||
643 | return; | 643 | return; |
644 | } | 644 | } |
645 | 645 | ||
646 | /* | 646 | /* |
647 | * Switch to STATE_READY state. | 647 | * Switch to STATE_READY state. |
648 | */ | 648 | */ |
649 | static inline void | 649 | static inline void |
650 | switch_to_ready_state(struct nandsim *ns, u_char status) | 650 | switch_to_ready_state(struct nandsim *ns, u_char status) |
651 | { | 651 | { |
652 | NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); | 652 | NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); |
@@ -675,7 +675,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
675 | * (for example program from the second half and read from the | 675 | * (for example program from the second half and read from the |
676 | * second half operations both begin with the READ1 command). In this | 676 | * second half operations both begin with the READ1 command). In this |
677 | * case the ns->pstates[] array contains previous states. | 677 | * case the ns->pstates[] array contains previous states. |
678 | * | 678 | * |
679 | * Thus, the function tries to find operation containing the following | 679 | * Thus, the function tries to find operation containing the following |
680 | * states (if the 'flag' parameter is 0): | 680 | * states (if the 'flag' parameter is 0): |
681 | * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state | 681 | * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state |
@@ -683,7 +683,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
683 | * If (one and only one) matching operation is found, it is accepted ( | 683 | * If (one and only one) matching operation is found, it is accepted ( |
684 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is | 684 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is |
685 | * zeroed). | 685 | * zeroed). |
686 | * | 686 | * |
687 | * If there are several maches, the current state is pushed to the | 687 | * If there are several maches, the current state is pushed to the |
688 | * ns->pstates. | 688 | * ns->pstates. |
689 | * | 689 | * |
@@ -692,7 +692,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
692 | * In such situation the function is called with 'flag' != 0, and the | 692 | * In such situation the function is called with 'flag' != 0, and the |
693 | * operation is searched using the following pattern: | 693 | * operation is searched using the following pattern: |
694 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> | 694 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> |
695 | * | 695 | * |
696 | * It is supposed that this pattern must either match one operation on | 696 | * It is supposed that this pattern must either match one operation on |
697 | * none. There can't be ambiguity in that case. | 697 | * none. There can't be ambiguity in that case. |
698 | * | 698 | * |
@@ -711,15 +711,15 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
711 | { | 711 | { |
712 | int opsfound = 0; | 712 | int opsfound = 0; |
713 | int i, j, idx = 0; | 713 | int i, j, idx = 0; |
714 | 714 | ||
715 | for (i = 0; i < NS_OPER_NUM; i++) { | 715 | for (i = 0; i < NS_OPER_NUM; i++) { |
716 | 716 | ||
717 | int found = 1; | 717 | int found = 1; |
718 | 718 | ||
719 | if (!(ns->options & ops[i].reqopts)) | 719 | if (!(ns->options & ops[i].reqopts)) |
720 | /* Ignore operations we can't perform */ | 720 | /* Ignore operations we can't perform */ |
721 | continue; | 721 | continue; |
722 | 722 | ||
723 | if (flag) { | 723 | if (flag) { |
724 | if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) | 724 | if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) |
725 | continue; | 725 | continue; |
@@ -728,7 +728,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
728 | continue; | 728 | continue; |
729 | } | 729 | } |
730 | 730 | ||
731 | for (j = 0; j < ns->npstates; j++) | 731 | for (j = 0; j < ns->npstates; j++) |
732 | if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) | 732 | if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) |
733 | && (ns->options & ops[idx].reqopts)) { | 733 | && (ns->options & ops[idx].reqopts)) { |
734 | found = 0; | 734 | found = 0; |
@@ -745,7 +745,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
745 | /* Exact match */ | 745 | /* Exact match */ |
746 | ns->op = &ops[idx].states[0]; | 746 | ns->op = &ops[idx].states[0]; |
747 | if (flag) { | 747 | if (flag) { |
748 | /* | 748 | /* |
749 | * In this case the find_operation function was | 749 | * In this case the find_operation function was |
750 | * called when address has just began input. But it isn't | 750 | * called when address has just began input. But it isn't |
751 | * yet fully input and the current state must | 751 | * yet fully input and the current state must |
@@ -763,7 +763,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
763 | idx, get_state_name(ns->state), get_state_name(ns->nxstate)); | 763 | idx, get_state_name(ns->state), get_state_name(ns->nxstate)); |
764 | return 0; | 764 | return 0; |
765 | } | 765 | } |
766 | 766 | ||
767 | if (opsfound == 0) { | 767 | if (opsfound == 0) { |
768 | /* Nothing was found. Try to ignore previous commands (if any) and search again */ | 768 | /* Nothing was found. Try to ignore previous commands (if any) and search again */ |
769 | if (ns->npstates != 0) { | 769 | if (ns->npstates != 0) { |
@@ -777,13 +777,13 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
777 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 777 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
778 | return -2; | 778 | return -2; |
779 | } | 779 | } |
780 | 780 | ||
781 | if (flag) { | 781 | if (flag) { |
782 | /* This shouldn't happen */ | 782 | /* This shouldn't happen */ |
783 | NS_DBG("find_operation: BUG, operation must be known if address is input\n"); | 783 | NS_DBG("find_operation: BUG, operation must be known if address is input\n"); |
784 | return -2; | 784 | return -2; |
785 | } | 785 | } |
786 | 786 | ||
787 | NS_DBG("find_operation: there is still ambiguity\n"); | 787 | NS_DBG("find_operation: there is still ambiguity\n"); |
788 | 788 | ||
789 | ns->pstates[ns->npstates++] = ns->state; | 789 | ns->pstates[ns->npstates++] = ns->state; |
@@ -803,7 +803,7 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
803 | int busdiv = ns->busw == 8 ? 1 : 2; | 803 | int busdiv = ns->busw == 8 ? 1 : 2; |
804 | 804 | ||
805 | action &= ACTION_MASK; | 805 | action &= ACTION_MASK; |
806 | 806 | ||
807 | /* Check that page address input is correct */ | 807 | /* Check that page address input is correct */ |
808 | if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { | 808 | if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { |
809 | NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); | 809 | NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); |
@@ -827,14 +827,14 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
827 | 827 | ||
828 | NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", | 828 | NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", |
829 | num, NS_RAW_OFFSET(ns) + ns->regs.off); | 829 | num, NS_RAW_OFFSET(ns) + ns->regs.off); |
830 | 830 | ||
831 | if (ns->regs.off == 0) | 831 | if (ns->regs.off == 0) |
832 | NS_LOG("read page %d\n", ns->regs.row); | 832 | NS_LOG("read page %d\n", ns->regs.row); |
833 | else if (ns->regs.off < ns->geom.pgsz) | 833 | else if (ns->regs.off < ns->geom.pgsz) |
834 | NS_LOG("read page %d (second half)\n", ns->regs.row); | 834 | NS_LOG("read page %d (second half)\n", ns->regs.row); |
835 | else | 835 | else |
836 | NS_LOG("read OOB of page %d\n", ns->regs.row); | 836 | NS_LOG("read OOB of page %d\n", ns->regs.row); |
837 | 837 | ||
838 | NS_UDELAY(access_delay); | 838 | NS_UDELAY(access_delay); |
839 | NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); | 839 | NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); |
840 | 840 | ||
@@ -844,30 +844,30 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
844 | /* | 844 | /* |
845 | * Erase sector. | 845 | * Erase sector. |
846 | */ | 846 | */ |
847 | 847 | ||
848 | if (ns->lines.wp) { | 848 | if (ns->lines.wp) { |
849 | NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); | 849 | NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); |
850 | return -1; | 850 | return -1; |
851 | } | 851 | } |
852 | 852 | ||
853 | if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec | 853 | if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec |
854 | || (ns->regs.row & ~(ns->geom.secsz - 1))) { | 854 | || (ns->regs.row & ~(ns->geom.secsz - 1))) { |
855 | NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); | 855 | NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); |
856 | return -1; | 856 | return -1; |
857 | } | 857 | } |
858 | 858 | ||
859 | ns->regs.row = (ns->regs.row << | 859 | ns->regs.row = (ns->regs.row << |
860 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; | 860 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; |
861 | ns->regs.column = 0; | 861 | ns->regs.column = 0; |
862 | 862 | ||
863 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", | 863 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", |
864 | ns->regs.row, NS_RAW_OFFSET(ns)); | 864 | ns->regs.row, NS_RAW_OFFSET(ns)); |
865 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); | 865 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); |
866 | 866 | ||
867 | memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); | 867 | memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); |
868 | 868 | ||
869 | NS_MDELAY(erase_delay); | 869 | NS_MDELAY(erase_delay); |
870 | 870 | ||
871 | break; | 871 | break; |
872 | 872 | ||
873 | case ACTION_PRGPAGE: | 873 | case ACTION_PRGPAGE: |
@@ -893,12 +893,12 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
893 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", | 893 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", |
894 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); | 894 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); |
895 | NS_LOG("programm page %d\n", ns->regs.row); | 895 | NS_LOG("programm page %d\n", ns->regs.row); |
896 | 896 | ||
897 | NS_UDELAY(programm_delay); | 897 | NS_UDELAY(programm_delay); |
898 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); | 898 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); |
899 | 899 | ||
900 | break; | 900 | break; |
901 | 901 | ||
902 | case ACTION_ZEROOFF: | 902 | case ACTION_ZEROOFF: |
903 | NS_DBG("do_state_action: set internal offset to 0\n"); | 903 | NS_DBG("do_state_action: set internal offset to 0\n"); |
904 | ns->regs.off = 0; | 904 | ns->regs.off = 0; |
@@ -918,7 +918,7 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
918 | NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); | 918 | NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); |
919 | ns->regs.off = ns->geom.pgsz; | 919 | ns->regs.off = ns->geom.pgsz; |
920 | break; | 920 | break; |
921 | 921 | ||
922 | default: | 922 | default: |
923 | NS_DBG("do_state_action: BUG! unknown action\n"); | 923 | NS_DBG("do_state_action: BUG! unknown action\n"); |
924 | } | 924 | } |
@@ -937,7 +937,7 @@ switch_state(struct nandsim *ns) | |||
937 | * The current operation have already been identified. | 937 | * The current operation have already been identified. |
938 | * Just follow the states chain. | 938 | * Just follow the states chain. |
939 | */ | 939 | */ |
940 | 940 | ||
941 | ns->stateidx += 1; | 941 | ns->stateidx += 1; |
942 | ns->state = ns->nxstate; | 942 | ns->state = ns->nxstate; |
943 | ns->nxstate = ns->op[ns->stateidx + 1]; | 943 | ns->nxstate = ns->op[ns->stateidx + 1]; |
@@ -951,14 +951,14 @@ switch_state(struct nandsim *ns) | |||
951 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 951 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
952 | return; | 952 | return; |
953 | } | 953 | } |
954 | 954 | ||
955 | } else { | 955 | } else { |
956 | /* | 956 | /* |
957 | * We don't yet know which operation we perform. | 957 | * We don't yet know which operation we perform. |
958 | * Try to identify it. | 958 | * Try to identify it. |
959 | */ | 959 | */ |
960 | 960 | ||
961 | /* | 961 | /* |
962 | * The only event causing the switch_state function to | 962 | * The only event causing the switch_state function to |
963 | * be called with yet unknown operation is new command. | 963 | * be called with yet unknown operation is new command. |
964 | */ | 964 | */ |
@@ -987,7 +987,7 @@ switch_state(struct nandsim *ns) | |||
987 | */ | 987 | */ |
988 | 988 | ||
989 | u_char status = NS_STATUS_OK(ns); | 989 | u_char status = NS_STATUS_OK(ns); |
990 | 990 | ||
991 | /* In case of data states, see if all bytes were input/output */ | 991 | /* In case of data states, see if all bytes were input/output */ |
992 | if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) | 992 | if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) |
993 | && ns->regs.count != ns->regs.num) { | 993 | && ns->regs.count != ns->regs.num) { |
@@ -995,17 +995,17 @@ switch_state(struct nandsim *ns) | |||
995 | ns->regs.num - ns->regs.count); | 995 | ns->regs.num - ns->regs.count); |
996 | status = NS_STATUS_FAILED(ns); | 996 | status = NS_STATUS_FAILED(ns); |
997 | } | 997 | } |
998 | 998 | ||
999 | NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); | 999 | NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); |
1000 | 1000 | ||
1001 | switch_to_ready_state(ns, status); | 1001 | switch_to_ready_state(ns, status); |
1002 | 1002 | ||
1003 | return; | 1003 | return; |
1004 | } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { | 1004 | } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { |
1005 | /* | 1005 | /* |
1006 | * If the next state is data input/output, switch to it now | 1006 | * If the next state is data input/output, switch to it now |
1007 | */ | 1007 | */ |
1008 | 1008 | ||
1009 | ns->state = ns->nxstate; | 1009 | ns->state = ns->nxstate; |
1010 | ns->nxstate = ns->op[++ns->stateidx + 1]; | 1010 | ns->nxstate = ns->op[++ns->stateidx + 1]; |
1011 | ns->regs.num = ns->regs.count = 0; | 1011 | ns->regs.num = ns->regs.count = 0; |
@@ -1023,16 +1023,16 @@ switch_state(struct nandsim *ns) | |||
1023 | case STATE_DATAOUT: | 1023 | case STATE_DATAOUT: |
1024 | ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; | 1024 | ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; |
1025 | break; | 1025 | break; |
1026 | 1026 | ||
1027 | case STATE_DATAOUT_ID: | 1027 | case STATE_DATAOUT_ID: |
1028 | ns->regs.num = ns->geom.idbytes; | 1028 | ns->regs.num = ns->geom.idbytes; |
1029 | break; | 1029 | break; |
1030 | 1030 | ||
1031 | case STATE_DATAOUT_STATUS: | 1031 | case STATE_DATAOUT_STATUS: |
1032 | case STATE_DATAOUT_STATUS_M: | 1032 | case STATE_DATAOUT_STATUS_M: |
1033 | ns->regs.count = ns->regs.num = 0; | 1033 | ns->regs.count = ns->regs.num = 0; |
1034 | break; | 1034 | break; |
1035 | 1035 | ||
1036 | default: | 1036 | default: |
1037 | NS_ERR("switch_state: BUG! unknown data state\n"); | 1037 | NS_ERR("switch_state: BUG! unknown data state\n"); |
1038 | } | 1038 | } |
@@ -1044,16 +1044,16 @@ switch_state(struct nandsim *ns) | |||
1044 | */ | 1044 | */ |
1045 | 1045 | ||
1046 | ns->regs.count = 0; | 1046 | ns->regs.count = 0; |
1047 | 1047 | ||
1048 | switch (NS_STATE(ns->nxstate)) { | 1048 | switch (NS_STATE(ns->nxstate)) { |
1049 | case STATE_ADDR_PAGE: | 1049 | case STATE_ADDR_PAGE: |
1050 | ns->regs.num = ns->geom.pgaddrbytes; | 1050 | ns->regs.num = ns->geom.pgaddrbytes; |
1051 | 1051 | ||
1052 | break; | 1052 | break; |
1053 | case STATE_ADDR_SEC: | 1053 | case STATE_ADDR_SEC: |
1054 | ns->regs.num = ns->geom.secaddrbytes; | 1054 | ns->regs.num = ns->geom.secaddrbytes; |
1055 | break; | 1055 | break; |
1056 | 1056 | ||
1057 | case STATE_ADDR_ZERO: | 1057 | case STATE_ADDR_ZERO: |
1058 | ns->regs.num = 1; | 1058 | ns->regs.num = 1; |
1059 | break; | 1059 | break; |
@@ -1062,7 +1062,7 @@ switch_state(struct nandsim *ns) | |||
1062 | NS_ERR("switch_state: BUG! unknown address state\n"); | 1062 | NS_ERR("switch_state: BUG! unknown address state\n"); |
1063 | } | 1063 | } |
1064 | } else { | 1064 | } else { |
1065 | /* | 1065 | /* |
1066 | * Just reset internal counters. | 1066 | * Just reset internal counters. |
1067 | */ | 1067 | */ |
1068 | 1068 | ||
@@ -1184,7 +1184,7 @@ ns_nand_read_byte(struct mtd_info *mtd) | |||
1184 | default: | 1184 | default: |
1185 | BUG(); | 1185 | BUG(); |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | if (ns->regs.count == ns->regs.num) { | 1188 | if (ns->regs.count == ns->regs.num) { |
1189 | NS_DBG("read_byte: all bytes were read\n"); | 1189 | NS_DBG("read_byte: all bytes were read\n"); |
1190 | 1190 | ||
@@ -1201,9 +1201,9 @@ ns_nand_read_byte(struct mtd_info *mtd) | |||
1201 | } | 1201 | } |
1202 | else if (NS_STATE(ns->nxstate) == STATE_READY) | 1202 | else if (NS_STATE(ns->nxstate) == STATE_READY) |
1203 | switch_state(ns); | 1203 | switch_state(ns); |
1204 | 1204 | ||
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | return outb; | 1207 | return outb; |
1208 | } | 1208 | } |
1209 | 1209 | ||
@@ -1211,7 +1211,7 @@ static void | |||
1211 | ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | 1211 | ns_nand_write_byte(struct mtd_info *mtd, u_char byte) |
1212 | { | 1212 | { |
1213 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1213 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
1214 | 1214 | ||
1215 | /* Sanity and correctness checks */ | 1215 | /* Sanity and correctness checks */ |
1216 | if (!ns->lines.ce) { | 1216 | if (!ns->lines.ce) { |
1217 | NS_ERR("write_byte: chip is disabled, ignore write\n"); | 1217 | NS_ERR("write_byte: chip is disabled, ignore write\n"); |
@@ -1221,7 +1221,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1221 | NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); | 1221 | NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); |
1222 | return; | 1222 | return; |
1223 | } | 1223 | } |
1224 | 1224 | ||
1225 | if (ns->lines.cle == 1) { | 1225 | if (ns->lines.cle == 1) { |
1226 | /* | 1226 | /* |
1227 | * The byte written is a command. | 1227 | * The byte written is a command. |
@@ -1233,7 +1233,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1233 | return; | 1233 | return; |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | /* | 1236 | /* |
1237 | * Chip might still be in STATE_DATAOUT | 1237 | * Chip might still be in STATE_DATAOUT |
1238 | * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or | 1238 | * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or |
1239 | * STATE_DATAOUT_STATUS_M state. If so, switch state. | 1239 | * STATE_DATAOUT_STATUS_M state. If so, switch state. |
@@ -1254,13 +1254,13 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1254 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | 1254 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); |
1255 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1255 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1256 | } | 1256 | } |
1257 | 1257 | ||
1258 | /* Check that the command byte is correct */ | 1258 | /* Check that the command byte is correct */ |
1259 | if (check_command(byte)) { | 1259 | if (check_command(byte)) { |
1260 | NS_ERR("write_byte: unknown command %#x\n", (uint)byte); | 1260 | NS_ERR("write_byte: unknown command %#x\n", (uint)byte); |
1261 | return; | 1261 | return; |
1262 | } | 1262 | } |
1263 | 1263 | ||
1264 | NS_DBG("command byte corresponding to %s state accepted\n", | 1264 | NS_DBG("command byte corresponding to %s state accepted\n", |
1265 | get_state_name(get_state_by_command(byte))); | 1265 | get_state_name(get_state_by_command(byte))); |
1266 | ns->regs.command = byte; | 1266 | ns->regs.command = byte; |
@@ -1277,12 +1277,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1277 | 1277 | ||
1278 | if (find_operation(ns, 1) < 0) | 1278 | if (find_operation(ns, 1) < 0) |
1279 | return; | 1279 | return; |
1280 | 1280 | ||
1281 | if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { | 1281 | if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { |
1282 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1282 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1283 | return; | 1283 | return; |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | ns->regs.count = 0; | 1286 | ns->regs.count = 0; |
1287 | switch (NS_STATE(ns->nxstate)) { | 1287 | switch (NS_STATE(ns->nxstate)) { |
1288 | case STATE_ADDR_PAGE: | 1288 | case STATE_ADDR_PAGE: |
@@ -1306,7 +1306,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1306 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1306 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1307 | return; | 1307 | return; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | /* Check if this is expected byte */ | 1310 | /* Check if this is expected byte */ |
1311 | if (ns->regs.count == ns->regs.num) { | 1311 | if (ns->regs.count == ns->regs.num) { |
1312 | NS_ERR("write_byte: no more address bytes expected\n"); | 1312 | NS_ERR("write_byte: no more address bytes expected\n"); |
@@ -1325,12 +1325,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1325 | NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); | 1325 | NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); |
1326 | switch_state(ns); | 1326 | switch_state(ns); |
1327 | } | 1327 | } |
1328 | 1328 | ||
1329 | } else { | 1329 | } else { |
1330 | /* | 1330 | /* |
1331 | * The byte written is an input data. | 1331 | * The byte written is an input data. |
1332 | */ | 1332 | */ |
1333 | 1333 | ||
1334 | /* Check that chip is expecting data input */ | 1334 | /* Check that chip is expecting data input */ |
1335 | if (!(ns->state & STATE_DATAIN_MASK)) { | 1335 | if (!(ns->state & STATE_DATAIN_MASK)) { |
1336 | NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " | 1336 | NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " |
@@ -1372,7 +1372,7 @@ ns_nand_read_word(struct mtd_info *mtd) | |||
1372 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 1372 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
1373 | 1373 | ||
1374 | NS_DBG("read_word\n"); | 1374 | NS_DBG("read_word\n"); |
1375 | 1375 | ||
1376 | return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); | 1376 | return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); |
1377 | } | 1377 | } |
1378 | 1378 | ||
@@ -1380,14 +1380,14 @@ static void | |||
1380 | ns_nand_write_word(struct mtd_info *mtd, uint16_t word) | 1380 | ns_nand_write_word(struct mtd_info *mtd, uint16_t word) |
1381 | { | 1381 | { |
1382 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 1382 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
1383 | 1383 | ||
1384 | NS_DBG("write_word\n"); | 1384 | NS_DBG("write_word\n"); |
1385 | 1385 | ||
1386 | chip->write_byte(mtd, word & 0xFF); | 1386 | chip->write_byte(mtd, word & 0xFF); |
1387 | chip->write_byte(mtd, word >> 8); | 1387 | chip->write_byte(mtd, word >> 8); |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static void | 1390 | static void |
1391 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 1391 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
1392 | { | 1392 | { |
1393 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1393 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
@@ -1409,13 +1409,13 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
1409 | 1409 | ||
1410 | memcpy(ns->buf.byte + ns->regs.count, buf, len); | 1410 | memcpy(ns->buf.byte + ns->regs.count, buf, len); |
1411 | ns->regs.count += len; | 1411 | ns->regs.count += len; |
1412 | 1412 | ||
1413 | if (ns->regs.count == ns->regs.num) { | 1413 | if (ns->regs.count == ns->regs.num) { |
1414 | NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); | 1414 | NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); |
1415 | } | 1415 | } |
1416 | } | 1416 | } |
1417 | 1417 | ||
1418 | static void | 1418 | static void |
1419 | ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | 1419 | ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
1420 | { | 1420 | { |
1421 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1421 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
@@ -1453,7 +1453,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
1453 | 1453 | ||
1454 | memcpy(buf, ns->buf.byte + ns->regs.count, len); | 1454 | memcpy(buf, ns->buf.byte + ns->regs.count, len); |
1455 | ns->regs.count += len; | 1455 | ns->regs.count += len; |
1456 | 1456 | ||
1457 | if (ns->regs.count == ns->regs.num) { | 1457 | if (ns->regs.count == ns->regs.num) { |
1458 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { | 1458 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { |
1459 | ns->regs.count = 0; | 1459 | ns->regs.count = 0; |
@@ -1465,11 +1465,11 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
1465 | else if (NS_STATE(ns->nxstate) == STATE_READY) | 1465 | else if (NS_STATE(ns->nxstate) == STATE_READY) |
1466 | switch_state(ns); | 1466 | switch_state(ns); |
1467 | } | 1467 | } |
1468 | 1468 | ||
1469 | return; | 1469 | return; |
1470 | } | 1470 | } |
1471 | 1471 | ||
1472 | static int | 1472 | static int |
1473 | ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | 1473 | ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) |
1474 | { | 1474 | { |
1475 | ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); | 1475 | ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); |
@@ -1496,7 +1496,7 @@ int __init ns_init_module(void) | |||
1496 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); | 1496 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
1497 | return -EINVAL; | 1497 | return -EINVAL; |
1498 | } | 1498 | } |
1499 | 1499 | ||
1500 | /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ | 1500 | /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ |
1501 | nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) | 1501 | nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) |
1502 | + sizeof(struct nandsim), GFP_KERNEL); | 1502 | + sizeof(struct nandsim), GFP_KERNEL); |
@@ -1509,7 +1509,7 @@ int __init ns_init_module(void) | |||
1509 | chip = (struct nand_chip *)(nsmtd + 1); | 1509 | chip = (struct nand_chip *)(nsmtd + 1); |
1510 | nsmtd->priv = (void *)chip; | 1510 | nsmtd->priv = (void *)chip; |
1511 | nand = (struct nandsim *)(chip + 1); | 1511 | nand = (struct nandsim *)(chip + 1); |
1512 | chip->priv = (void *)nand; | 1512 | chip->priv = (void *)nand; |
1513 | 1513 | ||
1514 | /* | 1514 | /* |
1515 | * Register simulator's callbacks. | 1515 | * Register simulator's callbacks. |
@@ -1526,9 +1526,9 @@ int __init ns_init_module(void) | |||
1526 | chip->eccmode = NAND_ECC_SOFT; | 1526 | chip->eccmode = NAND_ECC_SOFT; |
1527 | chip->options |= NAND_SKIP_BBTSCAN; | 1527 | chip->options |= NAND_SKIP_BBTSCAN; |
1528 | 1528 | ||
1529 | /* | 1529 | /* |
1530 | * Perform minimum nandsim structure initialization to handle | 1530 | * Perform minimum nandsim structure initialization to handle |
1531 | * the initial ID read command correctly | 1531 | * the initial ID read command correctly |
1532 | */ | 1532 | */ |
1533 | if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) | 1533 | if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) |
1534 | nand->geom.idbytes = 4; | 1534 | nand->geom.idbytes = 4; |
@@ -1557,7 +1557,7 @@ int __init ns_init_module(void) | |||
1557 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | 1557 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); |
1558 | goto error; | 1558 | goto error; |
1559 | } | 1559 | } |
1560 | 1560 | ||
1561 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | 1561 | if ((retval = nand_default_bbt(nsmtd)) != 0) { |
1562 | free_nandsim(nand); | 1562 | free_nandsim(nand); |
1563 | goto error; | 1563 | goto error; |
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index e510a83d7bdb..91a95f34a6ee 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/edb7312.c | 6 | * Derived from drivers/mtd/nand/edb7312.c |
7 | * | 7 | * |
8 | * | 8 | * |
9 | * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev Exp $ | 9 | * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -338,7 +338,7 @@ nand_evb_init: | |||
338 | out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); | 338 | out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); |
339 | out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); | 339 | out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); |
340 | /* enable output driver */ | 340 | /* enable output driver */ |
341 | out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | | 341 | out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | |
342 | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); | 342 | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); |
343 | #ifdef USE_READY_BUSY_PIN | 343 | #ifdef USE_READY_BUSY_PIN |
344 | /* three-state select */ | 344 | /* three-state select */ |
@@ -402,7 +402,7 @@ static void __exit ppchameleonevb_cleanup (void) | |||
402 | /* Release resources, unregister device(s) */ | 402 | /* Release resources, unregister device(s) */ |
403 | nand_release (ppchameleon_mtd); | 403 | nand_release (ppchameleon_mtd); |
404 | nand_release (ppchameleonevb_mtd); | 404 | nand_release (ppchameleonevb_mtd); |
405 | 405 | ||
406 | /* Release iomaps */ | 406 | /* Release iomaps */ |
407 | this = (struct nand_chip *) &ppchameleon_mtd[1]; | 407 | this = (struct nand_chip *) &ppchameleon_mtd[1]; |
408 | iounmap((void *) this->IO_ADDR_R; | 408 | iounmap((void *) this->IO_ADDR_R; |
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 031051cbde76..3a5841c9d950 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -2,11 +2,11 @@ | |||
2 | * drivers/mtd/nand/rtc_from4.c | 2 | * drivers/mtd/nand/rtc_from4.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Red Hat, Inc. | 4 | * Copyright (C) 2004 Red Hat, Inc. |
5 | * | 5 | * |
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ | 9 | * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,8 +14,8 @@ | |||
14 | * | 14 | * |
15 | * Overview: | 15 | * Overview: |
16 | * This is a device driver for the AG-AND flash device found on the | 16 | * This is a device driver for the AG-AND flash device found on the |
17 | * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), | 17 | * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), |
18 | * which utilizes the Renesas HN29V1G91T-30 part. | 18 | * which utilizes the Renesas HN29V1G91T-30 part. |
19 | * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. | 19 | * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. |
20 | */ | 20 | */ |
21 | 21 | ||
@@ -105,9 +105,9 @@ const static struct mtd_partition partition_info[] = { | |||
105 | }; | 105 | }; |
106 | #define NUM_PARTITIONS 1 | 106 | #define NUM_PARTITIONS 1 |
107 | 107 | ||
108 | /* | 108 | /* |
109 | * hardware specific flash bbt decriptors | 109 | * hardware specific flash bbt decriptors |
110 | * Note: this is to allow debugging by disabling | 110 | * Note: this is to allow debugging by disabling |
111 | * NAND_BBT_CREATE and/or NAND_BBT_WRITE | 111 | * NAND_BBT_CREATE and/or NAND_BBT_WRITE |
112 | * | 112 | * |
113 | */ | 113 | */ |
@@ -141,7 +141,7 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { | |||
141 | /* the Reed Solomon control structure */ | 141 | /* the Reed Solomon control structure */ |
142 | static struct rs_control *rs_decoder; | 142 | static struct rs_control *rs_decoder; |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * hardware specific Out Of Band information | 145 | * hardware specific Out Of Band information |
146 | */ | 146 | */ |
147 | static struct nand_oobinfo rtc_from4_nand_oobinfo = { | 147 | static struct nand_oobinfo rtc_from4_nand_oobinfo = { |
@@ -200,38 +200,38 @@ static uint8_t revbits[256] = { | |||
200 | 200 | ||
201 | 201 | ||
202 | 202 | ||
203 | /* | 203 | /* |
204 | * rtc_from4_hwcontrol - hardware specific access to control-lines | 204 | * rtc_from4_hwcontrol - hardware specific access to control-lines |
205 | * @mtd: MTD device structure | 205 | * @mtd: MTD device structure |
206 | * @cmd: hardware control command | 206 | * @cmd: hardware control command |
207 | * | 207 | * |
208 | * Address lines (A5 and A4) are used to control Command and Address Latch | 208 | * Address lines (A5 and A4) are used to control Command and Address Latch |
209 | * Enable on this board, so set the read/write address appropriately. | 209 | * Enable on this board, so set the read/write address appropriately. |
210 | * | 210 | * |
211 | * Chip Enable is also controlled by the Chip Select (CS5) and | 211 | * Chip Enable is also controlled by the Chip Select (CS5) and |
212 | * Address lines (A24-A22), so no action is required here. | 212 | * Address lines (A24-A22), so no action is required here. |
213 | * | 213 | * |
214 | */ | 214 | */ |
215 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) | 215 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) |
216 | { | 216 | { |
217 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); | 217 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); |
218 | 218 | ||
219 | switch(cmd) { | 219 | switch(cmd) { |
220 | 220 | ||
221 | case NAND_CTL_SETCLE: | 221 | case NAND_CTL_SETCLE: |
222 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); | 222 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); |
223 | break; | 223 | break; |
224 | case NAND_CTL_CLRCLE: | 224 | case NAND_CTL_CLRCLE: |
225 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); | 225 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); |
226 | break; | 226 | break; |
227 | 227 | ||
228 | case NAND_CTL_SETALE: | 228 | case NAND_CTL_SETALE: |
229 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); | 229 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); |
230 | break; | 230 | break; |
231 | case NAND_CTL_CLRALE: | 231 | case NAND_CTL_CLRALE: |
232 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); | 232 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); |
233 | break; | 233 | break; |
234 | 234 | ||
235 | case NAND_CTL_SETNCE: | 235 | case NAND_CTL_SETNCE: |
236 | break; | 236 | break; |
237 | case NAND_CTL_CLRNCE: | 237 | case NAND_CTL_CLRNCE: |
@@ -296,7 +296,7 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) | |||
296 | * @mtd: MTD device structure | 296 | * @mtd: MTD device structure |
297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) | 297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) |
298 | * | 298 | * |
299 | * If there was a sudden loss of power during an erase operation, a | 299 | * If there was a sudden loss of power during an erase operation, a |
300 | * "device recovery" operation must be performed when power is restored | 300 | * "device recovery" operation must be performed when power is restored |
301 | * to ensure correct operation. This routine performs the required steps | 301 | * to ensure correct operation. This routine performs the required steps |
302 | * for the requested chip. | 302 | * for the requested chip. |
@@ -312,7 +312,7 @@ static void deplete(struct mtd_info *mtd, int chip) | |||
312 | while (!this->dev_ready(mtd)); | 312 | while (!this->dev_ready(mtd)); |
313 | 313 | ||
314 | this->select_chip(mtd, chip); | 314 | this->select_chip(mtd, chip); |
315 | 315 | ||
316 | /* Send the commands for device recovery, phase 1 */ | 316 | /* Send the commands for device recovery, phase 1 */ |
317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); | 317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); |
318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | 318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); |
@@ -330,7 +330,7 @@ static void deplete(struct mtd_info *mtd, int chip) | |||
330 | * @mtd: MTD device structure | 330 | * @mtd: MTD device structure |
331 | * @mode: I/O mode; read or write | 331 | * @mode: I/O mode; read or write |
332 | * | 332 | * |
333 | * enable hardware ECC for data read or write | 333 | * enable hardware ECC for data read or write |
334 | * | 334 | * |
335 | */ | 335 | */ |
336 | static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | 336 | static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) |
@@ -340,7 +340,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
340 | 340 | ||
341 | switch (mode) { | 341 | switch (mode) { |
342 | case NAND_ECC_READ : | 342 | case NAND_ECC_READ : |
343 | status = RTC_FROM4_RS_ECC_CTL_CLR | 343 | status = RTC_FROM4_RS_ECC_CTL_CLR |
344 | | RTC_FROM4_RS_ECC_CTL_FD_E; | 344 | | RTC_FROM4_RS_ECC_CTL_FD_E; |
345 | 345 | ||
346 | *rs_ecc_ctl = status; | 346 | *rs_ecc_ctl = status; |
@@ -353,8 +353,8 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
353 | break; | 353 | break; |
354 | 354 | ||
355 | case NAND_ECC_WRITE : | 355 | case NAND_ECC_WRITE : |
356 | status = RTC_FROM4_RS_ECC_CTL_CLR | 356 | status = RTC_FROM4_RS_ECC_CTL_CLR |
357 | | RTC_FROM4_RS_ECC_CTL_GEN | 357 | | RTC_FROM4_RS_ECC_CTL_GEN |
358 | | RTC_FROM4_RS_ECC_CTL_FD_E; | 358 | | RTC_FROM4_RS_ECC_CTL_FD_E; |
359 | 359 | ||
360 | *rs_ecc_ctl = status; | 360 | *rs_ecc_ctl = status; |
@@ -411,7 +411,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) | 411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) |
412 | { | 412 | { |
413 | int i, j, res; | 413 | int i, j, res; |
414 | unsigned short status; | 414 | unsigned short status; |
415 | uint16_t par[6], syn[6]; | 415 | uint16_t par[6], syn[6]; |
416 | uint8_t ecc[8]; | 416 | uint8_t ecc[8]; |
417 | volatile unsigned short *rs_ecc; | 417 | volatile unsigned short *rs_ecc; |
@@ -430,7 +430,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
430 | } | 430 | } |
431 | 431 | ||
432 | /* convert into 6 10bit syndrome fields */ | 432 | /* convert into 6 10bit syndrome fields */ |
433 | par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | | 433 | par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | |
434 | (((uint16_t)ecc[1] << 8) & 0x300)]; | 434 | (((uint16_t)ecc[1] << 8) & 0x300)]; |
435 | par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | | 435 | par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | |
436 | (((uint16_t)ecc[2] << 6) & 0x3c0)]; | 436 | (((uint16_t)ecc[2] << 6) & 0x3c0)]; |
@@ -456,7 +456,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
456 | /* Let the library code do its magic.*/ | 456 | /* Let the library code do its magic.*/ |
457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); | 457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); |
458 | if (res > 0) { | 458 | if (res > 0) { |
459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " | 459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " |
460 | "ECC corrected %d errors on read\n", res); | 460 | "ECC corrected %d errors on read\n", res); |
461 | } | 461 | } |
462 | return res; | 462 | return res; |
@@ -470,9 +470,9 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
470 | * @state: state or the operation | 470 | * @state: state or the operation |
471 | * @status: status code returned from read status | 471 | * @status: status code returned from read status |
472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) | 472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) |
473 | * | 473 | * |
474 | * Perform additional error status checks on erase and write failures | 474 | * Perform additional error status checks on erase and write failures |
475 | * to determine if errors are correctable. For this device, correctable | 475 | * to determine if errors are correctable. For this device, correctable |
476 | * 1-bit errors on erase and write are considered acceptable. | 476 | * 1-bit errors on erase and write are considered acceptable. |
477 | * | 477 | * |
478 | * note: see pages 34..37 of data sheet for details. | 478 | * note: see pages 34..37 of data sheet for details. |
@@ -633,7 +633,7 @@ int __init rtc_from4_init (void) | |||
633 | 633 | ||
634 | #ifdef RTC_FROM4_HWECC | 634 | #ifdef RTC_FROM4_HWECC |
635 | /* We could create the decoder on demand, if memory is a concern. | 635 | /* We could create the decoder on demand, if memory is a concern. |
636 | * This way we have it handy, if an error happens | 636 | * This way we have it handy, if an error happens |
637 | * | 637 | * |
638 | * Symbolsize is 10 (bits) | 638 | * Symbolsize is 10 (bits) |
639 | * Primitve polynomial is x^10+x^3+1 | 639 | * Primitve polynomial is x^10+x^3+1 |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2df5e47d1f5c..97e9b7892d29 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -17,8 +17,9 @@ | |||
17 | * 02-May-2005 BJD Reduced hwcontrol decode | 17 | * 02-May-2005 BJD Reduced hwcontrol decode |
18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | 18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug |
19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | 19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied |
20 | * 20-Oct-2005 BJD Fix timing calculation bug | ||
20 | * | 21 | * |
21 | * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $ | 22 | * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $ |
22 | * | 23 | * |
23 | * This program is free software; you can redistribute it and/or modify | 24 | * This program is free software; you can redistribute it and/or modify |
24 | * it under the terms of the GNU General Public License as published by | 25 | * it under the terms of the GNU General Public License as published by |
@@ -136,13 +137,13 @@ static struct s3c2410_platform_nand *to_nand_plat(struct device *dev) | |||
136 | 137 | ||
137 | /* timing calculations */ | 138 | /* timing calculations */ |
138 | 139 | ||
139 | #define NS_IN_KHZ 10000000 | 140 | #define NS_IN_KHZ 1000000 |
140 | 141 | ||
141 | static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | 142 | static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) |
142 | { | 143 | { |
143 | int result; | 144 | int result; |
144 | 145 | ||
145 | result = (wanted * NS_IN_KHZ) / clk; | 146 | result = (wanted * clk) / NS_IN_KHZ; |
146 | result++; | 147 | result++; |
147 | 148 | ||
148 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); | 149 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); |
@@ -159,20 +160,22 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
159 | return result; | 160 | return result; |
160 | } | 161 | } |
161 | 162 | ||
162 | #define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ) | 163 | #define to_ns(ticks,clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk)) |
163 | 164 | ||
164 | /* controller setup */ | 165 | /* controller setup */ |
165 | 166 | ||
166 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | 167 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, |
167 | struct device *dev) | 168 | struct device *dev) |
168 | { | 169 | { |
169 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); | 170 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); |
170 | unsigned int tacls, twrph0, twrph1; | ||
171 | unsigned long clkrate = clk_get_rate(info->clk); | 171 | unsigned long clkrate = clk_get_rate(info->clk); |
172 | int tacls, twrph0, twrph1; | ||
172 | unsigned long cfg; | 173 | unsigned long cfg; |
173 | 174 | ||
174 | /* calculate the timing information for the controller */ | 175 | /* calculate the timing information for the controller */ |
175 | 176 | ||
177 | clkrate /= 1000; /* turn clock into kHz for ease of use */ | ||
178 | |||
176 | if (plat != NULL) { | 179 | if (plat != NULL) { |
177 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); | 180 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); |
178 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); | 181 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); |
@@ -183,16 +186,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
183 | twrph0 = 8; | 186 | twrph0 = 8; |
184 | twrph1 = 8; | 187 | twrph1 = 8; |
185 | } | 188 | } |
186 | 189 | ||
187 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { | 190 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { |
188 | printk(KERN_ERR PFX "cannot get timings suitable for board\n"); | 191 | printk(KERN_ERR PFX "cannot get timings suitable for board\n"); |
189 | return -EINVAL; | 192 | return -EINVAL; |
190 | } | 193 | } |
191 | 194 | ||
192 | printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n", | 195 | printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", |
193 | to_ns(tacls, clkrate), | 196 | tacls, to_ns(tacls, clkrate), |
194 | to_ns(twrph0, clkrate), | 197 | twrph0, to_ns(twrph0, clkrate), |
195 | to_ns(twrph1, clkrate)); | 198 | twrph1, to_ns(twrph1, clkrate)); |
196 | 199 | ||
197 | if (!info->is_s3c2440) { | 200 | if (!info->is_s3c2440) { |
198 | cfg = S3C2410_NFCONF_EN; | 201 | cfg = S3C2410_NFCONF_EN; |
@@ -216,7 +219,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
216 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | 219 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) |
217 | { | 220 | { |
218 | struct s3c2410_nand_info *info; | 221 | struct s3c2410_nand_info *info; |
219 | struct s3c2410_nand_mtd *nmtd; | 222 | struct s3c2410_nand_mtd *nmtd; |
220 | struct nand_chip *this = mtd->priv; | 223 | struct nand_chip *this = mtd->priv; |
221 | void __iomem *reg; | 224 | void __iomem *reg; |
222 | unsigned long cur; | 225 | unsigned long cur; |
@@ -249,7 +252,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
249 | writel(cur, reg); | 252 | writel(cur, reg); |
250 | } | 253 | } |
251 | 254 | ||
252 | /* command and control functions | 255 | /* command and control functions |
253 | * | 256 | * |
254 | * Note, these all use tglx's method of changing the IO_ADDR_W field | 257 | * Note, these all use tglx's method of changing the IO_ADDR_W field |
255 | * to make the code simpler, and use the nand layer's code to issue the | 258 | * to make the code simpler, and use the nand layer's code to issue the |
@@ -321,7 +324,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) | |||
321 | static int s3c2410_nand_devready(struct mtd_info *mtd) | 324 | static int s3c2410_nand_devready(struct mtd_info *mtd) |
322 | { | 325 | { |
323 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 326 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
324 | 327 | ||
325 | if (info->is_s3c2440) | 328 | if (info->is_s3c2440) |
326 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; | 329 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; |
327 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; | 330 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; |
@@ -342,7 +345,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
342 | 345 | ||
343 | if (read_ecc[0] == calc_ecc[0] && | 346 | if (read_ecc[0] == calc_ecc[0] && |
344 | read_ecc[1] == calc_ecc[1] && | 347 | read_ecc[1] == calc_ecc[1] && |
345 | read_ecc[2] == calc_ecc[2]) | 348 | read_ecc[2] == calc_ecc[2]) |
346 | return 0; | 349 | return 0; |
347 | 350 | ||
348 | /* we curently have no method for correcting the error */ | 351 | /* we curently have no method for correcting the error */ |
@@ -433,14 +436,14 @@ static int s3c2410_nand_remove(struct device *dev) | |||
433 | 436 | ||
434 | dev_set_drvdata(dev, NULL); | 437 | dev_set_drvdata(dev, NULL); |
435 | 438 | ||
436 | if (info == NULL) | 439 | if (info == NULL) |
437 | return 0; | 440 | return 0; |
438 | 441 | ||
439 | /* first thing we need to do is release all our mtds | 442 | /* first thing we need to do is release all our mtds |
440 | * and their partitions, then go through freeing the | 443 | * and their partitions, then go through freeing the |
441 | * resources used | 444 | * resources used |
442 | */ | 445 | */ |
443 | 446 | ||
444 | if (info->mtds != NULL) { | 447 | if (info->mtds != NULL) { |
445 | struct s3c2410_nand_mtd *ptr = info->mtds; | 448 | struct s3c2410_nand_mtd *ptr = info->mtds; |
446 | int mtdno; | 449 | int mtdno; |
@@ -504,7 +507,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
504 | 507 | ||
505 | /* s3c2410_nand_init_chip | 508 | /* s3c2410_nand_init_chip |
506 | * | 509 | * |
507 | * init a single instance of an chip | 510 | * init a single instance of an chip |
508 | */ | 511 | */ |
509 | 512 | ||
510 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | 513 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, |
@@ -576,7 +579,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
576 | 579 | ||
577 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 580 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
578 | if (info == NULL) { | 581 | if (info == NULL) { |
579 | printk(KERN_ERR PFX "no memory for flash info\n"); | 582 | dev_err(dev, "no memory for flash info\n"); |
580 | err = -ENOMEM; | 583 | err = -ENOMEM; |
581 | goto exit_error; | 584 | goto exit_error; |
582 | } | 585 | } |
@@ -591,7 +594,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
591 | 594 | ||
592 | info->clk = clk_get(dev, "nand"); | 595 | info->clk = clk_get(dev, "nand"); |
593 | if (IS_ERR(info->clk)) { | 596 | if (IS_ERR(info->clk)) { |
594 | printk(KERN_ERR PFX "failed to get clock"); | 597 | dev_err(dev, "failed to get clock"); |
595 | err = -ENOENT; | 598 | err = -ENOENT; |
596 | goto exit_error; | 599 | goto exit_error; |
597 | } | 600 | } |
@@ -608,7 +611,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
608 | info->area = request_mem_region(res->start, size, pdev->name); | 611 | info->area = request_mem_region(res->start, size, pdev->name); |
609 | 612 | ||
610 | if (info->area == NULL) { | 613 | if (info->area == NULL) { |
611 | printk(KERN_ERR PFX "cannot reserve register region\n"); | 614 | dev_err(dev, "cannot reserve register region\n"); |
612 | err = -ENOENT; | 615 | err = -ENOENT; |
613 | goto exit_error; | 616 | goto exit_error; |
614 | } | 617 | } |
@@ -619,12 +622,12 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
619 | info->is_s3c2440 = is_s3c2440; | 622 | info->is_s3c2440 = is_s3c2440; |
620 | 623 | ||
621 | if (info->regs == NULL) { | 624 | if (info->regs == NULL) { |
622 | printk(KERN_ERR PFX "cannot reserve register region\n"); | 625 | dev_err(dev, "cannot reserve register region\n"); |
623 | err = -EIO; | 626 | err = -EIO; |
624 | goto exit_error; | 627 | goto exit_error; |
625 | } | 628 | } |
626 | 629 | ||
627 | printk(KERN_INFO PFX "mapped registers at %p\n", info->regs); | 630 | dev_dbg(dev, "mapped registers at %p\n", info->regs); |
628 | 631 | ||
629 | /* initialise the hardware */ | 632 | /* initialise the hardware */ |
630 | 633 | ||
@@ -642,7 +645,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
642 | size = nr_sets * sizeof(*info->mtds); | 645 | size = nr_sets * sizeof(*info->mtds); |
643 | info->mtds = kmalloc(size, GFP_KERNEL); | 646 | info->mtds = kmalloc(size, GFP_KERNEL); |
644 | if (info->mtds == NULL) { | 647 | if (info->mtds == NULL) { |
645 | printk(KERN_ERR PFX "failed to allocate mtd storage\n"); | 648 | dev_err(dev, "failed to allocate mtd storage\n"); |
646 | err = -ENOMEM; | 649 | err = -ENOMEM; |
647 | goto exit_error; | 650 | goto exit_error; |
648 | } | 651 | } |
@@ -656,7 +659,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
656 | for (setno = 0; setno < nr_sets; setno++, nmtd++) { | 659 | for (setno = 0; setno < nr_sets; setno++, nmtd++) { |
657 | pr_debug("initialising set %d (%p, info %p)\n", | 660 | pr_debug("initialising set %d (%p, info %p)\n", |
658 | setno, nmtd, info); | 661 | setno, nmtd, info); |
659 | 662 | ||
660 | s3c2410_nand_init_chip(info, nmtd, sets); | 663 | s3c2410_nand_init_chip(info, nmtd, sets); |
661 | 664 | ||
662 | nmtd->scan_res = nand_scan(&nmtd->mtd, | 665 | nmtd->scan_res = nand_scan(&nmtd->mtd, |
@@ -669,7 +672,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
669 | if (sets != NULL) | 672 | if (sets != NULL) |
670 | sets++; | 673 | sets++; |
671 | } | 674 | } |
672 | 675 | ||
673 | pr_debug("initialised ok\n"); | 676 | pr_debug("initialised ok\n"); |
674 | return 0; | 677 | return 0; |
675 | 678 | ||
@@ -695,6 +698,7 @@ static int s3c2440_nand_probe(struct device *dev) | |||
695 | 698 | ||
696 | static struct device_driver s3c2410_nand_driver = { | 699 | static struct device_driver s3c2410_nand_driver = { |
697 | .name = "s3c2410-nand", | 700 | .name = "s3c2410-nand", |
701 | .owner = THIS_MODULE, | ||
698 | .bus = &platform_bus_type, | 702 | .bus = &platform_bus_type, |
699 | .probe = s3c2410_nand_probe, | 703 | .probe = s3c2410_nand_probe, |
700 | .remove = s3c2410_nand_remove, | 704 | .remove = s3c2410_nand_remove, |
@@ -702,6 +706,7 @@ static struct device_driver s3c2410_nand_driver = { | |||
702 | 706 | ||
703 | static struct device_driver s3c2440_nand_driver = { | 707 | static struct device_driver s3c2440_nand_driver = { |
704 | .name = "s3c2440-nand", | 708 | .name = "s3c2440-nand", |
709 | .owner = THIS_MODULE, | ||
705 | .bus = &platform_bus_type, | 710 | .bus = &platform_bus_type, |
706 | .probe = s3c2440_nand_probe, | 711 | .probe = s3c2440_nand_probe, |
707 | .remove = s3c2410_nand_remove, | 712 | .remove = s3c2410_nand_remove, |
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 88b5b5b40b43..1924a4f137c7 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
5 | * | 5 | * |
6 | * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ | 6 | * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ |
7 | * | 7 | * |
8 | * Based on Sharp's NAND driver sharp_sl.c | 8 | * Based on Sharp's NAND driver sharp_sl.c |
9 | * | 9 | * |
@@ -76,14 +76,14 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { | |||
76 | }, | 76 | }, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * hardware specific access to control-lines | 80 | * hardware specific access to control-lines |
81 | */ | 81 | */ |
82 | static void | 82 | static void |
83 | sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) | 83 | sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) |
84 | { | 84 | { |
85 | switch (cmd) { | 85 | switch (cmd) { |
86 | case NAND_CTL_SETCLE: | 86 | case NAND_CTL_SETCLE: |
87 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); | 87 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); |
88 | break; | 88 | break; |
89 | case NAND_CTL_CLRCLE: | 89 | case NAND_CTL_CLRCLE: |
@@ -97,10 +97,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) | |||
97 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); | 97 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); |
98 | break; | 98 | break; |
99 | 99 | ||
100 | case NAND_CTL_SETNCE: | 100 | case NAND_CTL_SETNCE: |
101 | writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); | 101 | writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); |
102 | break; | 102 | break; |
103 | case NAND_CTL_CLRNCE: | 103 | case NAND_CTL_CLRNCE: |
104 | writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); | 104 | writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); |
105 | break; | 105 | break; |
106 | } | 106 | } |
@@ -115,6 +115,23 @@ static struct nand_bbt_descr sharpsl_bbt = { | |||
115 | .pattern = scan_ff_pattern | 115 | .pattern = scan_ff_pattern |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static struct nand_bbt_descr sharpsl_akita_bbt = { | ||
119 | .options = 0, | ||
120 | .offs = 4, | ||
121 | .len = 1, | ||
122 | .pattern = scan_ff_pattern | ||
123 | }; | ||
124 | |||
125 | static struct nand_oobinfo akita_oobinfo = { | ||
126 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
127 | .eccbytes = 24, | ||
128 | .eccpos = { | ||
129 | 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, | ||
130 | 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, | ||
131 | 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, | ||
132 | .oobfree = { {0x08, 0x09} } | ||
133 | }; | ||
134 | |||
118 | static int | 135 | static int |
119 | sharpsl_nand_dev_ready(struct mtd_info* mtd) | 136 | sharpsl_nand_dev_ready(struct mtd_info* mtd) |
120 | { | 137 | { |
@@ -160,7 +177,7 @@ sharpsl_nand_init(void) | |||
160 | printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); | 177 | printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); |
161 | return -ENOMEM; | 178 | return -ENOMEM; |
162 | } | 179 | } |
163 | 180 | ||
164 | /* map physical adress */ | 181 | /* map physical adress */ |
165 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); | 182 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); |
166 | if(!sharpsl_io_base){ | 183 | if(!sharpsl_io_base){ |
@@ -168,7 +185,7 @@ sharpsl_nand_init(void) | |||
168 | kfree(sharpsl_mtd); | 185 | kfree(sharpsl_mtd); |
169 | return -EIO; | 186 | return -EIO; |
170 | } | 187 | } |
171 | 188 | ||
172 | /* Get pointer to private data */ | 189 | /* Get pointer to private data */ |
173 | this = (struct nand_chip *) (&sharpsl_mtd[1]); | 190 | this = (struct nand_chip *) (&sharpsl_mtd[1]); |
174 | 191 | ||
@@ -194,10 +211,14 @@ sharpsl_nand_init(void) | |||
194 | this->chip_delay = 15; | 211 | this->chip_delay = 15; |
195 | /* set eccmode using hardware ECC */ | 212 | /* set eccmode using hardware ECC */ |
196 | this->eccmode = NAND_ECC_HW3_256; | 213 | this->eccmode = NAND_ECC_HW3_256; |
214 | this->badblock_pattern = &sharpsl_bbt; | ||
215 | if (machine_is_akita() || machine_is_borzoi()) { | ||
216 | this->badblock_pattern = &sharpsl_akita_bbt; | ||
217 | this->autooob = &akita_oobinfo; | ||
218 | } | ||
197 | this->enable_hwecc = sharpsl_nand_enable_hwecc; | 219 | this->enable_hwecc = sharpsl_nand_enable_hwecc; |
198 | this->calculate_ecc = sharpsl_nand_calculate_ecc; | 220 | this->calculate_ecc = sharpsl_nand_calculate_ecc; |
199 | this->correct_data = nand_correct_data; | 221 | this->correct_data = nand_correct_data; |
200 | this->badblock_pattern = &sharpsl_bbt; | ||
201 | 222 | ||
202 | /* Scan to find existence of the device */ | 223 | /* Scan to find existence of the device */ |
203 | err=nand_scan(sharpsl_mtd,1); | 224 | err=nand_scan(sharpsl_mtd,1); |
@@ -211,7 +232,7 @@ sharpsl_nand_init(void) | |||
211 | sharpsl_mtd->name = "sharpsl-nand"; | 232 | sharpsl_mtd->name = "sharpsl-nand"; |
212 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, | 233 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, |
213 | &sharpsl_partition_info, 0); | 234 | &sharpsl_partition_info, 0); |
214 | 235 | ||
215 | if (nr_partitions <= 0) { | 236 | if (nr_partitions <= 0) { |
216 | nr_partitions = DEFAULT_NUM_PARTITIONS; | 237 | nr_partitions = DEFAULT_NUM_PARTITIONS; |
217 | sharpsl_partition_info = sharpsl_nand_default_partition_info; | 238 | sharpsl_partition_info = sharpsl_nand_default_partition_info; |
@@ -230,7 +251,7 @@ sharpsl_nand_init(void) | |||
230 | } | 251 | } |
231 | } | 252 | } |
232 | 253 | ||
233 | if (machine_is_husky() || machine_is_borzoi()) { | 254 | if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) { |
234 | /* Need to use small eraseblock size for backward compatibility */ | 255 | /* Need to use small eraseblock size for backward compatibility */ |
235 | sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; | 256 | sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; |
236 | } | 257 | } |
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index b777c412b758..32541cbb0103 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * to controllines (due to change in nand.c) | 8 | * to controllines (due to change in nand.c) |
9 | * page_cache added | 9 | * page_cache added |
10 | * | 10 | * |
11 | * $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner Exp $ | 11 | * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
@@ -82,7 +82,7 @@ const static struct mtd_partition partition_info[] = { | |||
82 | #define NUM_PARTITIONS 2 | 82 | #define NUM_PARTITIONS 2 |
83 | 83 | ||
84 | 84 | ||
85 | /* | 85 | /* |
86 | * hardware specific access to control-lines | 86 | * hardware specific access to control-lines |
87 | */ | 87 | */ |
88 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ | 88 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ |
@@ -137,7 +137,7 @@ int __init spia_init (void) | |||
137 | /* Set address of hardware control function */ | 137 | /* Set address of hardware control function */ |
138 | this->hwcontrol = spia_hwcontrol; | 138 | this->hwcontrol = spia_hwcontrol; |
139 | /* 15 us command delay time */ | 139 | /* 15 us command delay time */ |
140 | this->chip_delay = 15; | 140 | this->chip_delay = 15; |
141 | 141 | ||
142 | /* Scan to find existence of the device */ | 142 | /* Scan to find existence of the device */ |
143 | if (nand_scan (spia_mtd, 1)) { | 143 | if (nand_scan (spia_mtd, 1)) { |
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 52c808fb5fa9..7609c43cb3ec 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * This is a device driver for the NAND flash device found on the | 15 | * This is a device driver for the NAND flash device found on the |
16 | * TI fido board. It supports 32MiB and 64MiB cards | 16 | * TI fido board. It supports 32MiB and 64MiB cards |
17 | * | 17 | * |
18 | * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ | 18 | * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
@@ -57,7 +57,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE; | |||
57 | #endif | 57 | #endif |
58 | #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) | 58 | #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) |
59 | #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) | 59 | #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Define partitions for flash devices | 62 | * Define partitions for flash devices |
63 | */ | 63 | */ |
@@ -91,7 +91,7 @@ static struct mtd_partition partition_info32M[] = { | |||
91 | 91 | ||
92 | #define NUM_PARTITIONS32M 3 | 92 | #define NUM_PARTITIONS32M 3 |
93 | #define NUM_PARTITIONS64M 4 | 93 | #define NUM_PARTITIONS64M 4 |
94 | /* | 94 | /* |
95 | * hardware specific access to control-lines | 95 | * hardware specific access to control-lines |
96 | */ | 96 | */ |
97 | 97 | ||
@@ -146,7 +146,7 @@ int __init toto_init (void) | |||
146 | this->hwcontrol = toto_hwcontrol; | 146 | this->hwcontrol = toto_hwcontrol; |
147 | this->dev_ready = NULL; | 147 | this->dev_ready = NULL; |
148 | /* 25 us command delay time */ | 148 | /* 25 us command delay time */ |
149 | this->chip_delay = 30; | 149 | this->chip_delay = 30; |
150 | this->eccmode = NAND_ECC_SOFT; | 150 | this->eccmode = NAND_ECC_SOFT; |
151 | 151 | ||
152 | /* Scan to find existance of the device */ | 152 | /* Scan to find existance of the device */ |
@@ -157,10 +157,10 @@ int __init toto_init (void) | |||
157 | 157 | ||
158 | /* Register the partitions */ | 158 | /* Register the partitions */ |
159 | switch(toto_mtd->size){ | 159 | switch(toto_mtd->size){ |
160 | case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; | 160 | case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; |
161 | case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; | 161 | case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; |
162 | default: { | 162 | default: { |
163 | printk (KERN_WARNING "Unsupported Nand device\n"); | 163 | printk (KERN_WARNING "Unsupported Nand device\n"); |
164 | err = -ENXIO; | 164 | err = -ENXIO; |
165 | goto out_buf; | 165 | goto out_buf; |
166 | } | 166 | } |
@@ -170,9 +170,9 @@ int __init toto_init (void) | |||
170 | archflashwp(0,0); /* open up flash for writing */ | 170 | archflashwp(0,0); /* open up flash for writing */ |
171 | 171 | ||
172 | goto out; | 172 | goto out; |
173 | 173 | ||
174 | out_buf: | 174 | out_buf: |
175 | kfree (this->data_buf); | 175 | kfree (this->data_buf); |
176 | out_mtd: | 176 | out_mtd: |
177 | kfree (toto_mtd); | 177 | kfree (toto_mtd); |
178 | out: | 178 | out: |
@@ -194,7 +194,7 @@ static void __exit toto_cleanup (void) | |||
194 | 194 | ||
195 | /* stop flash writes */ | 195 | /* stop flash writes */ |
196 | archflashwp(0,1); | 196 | archflashwp(0,1); |
197 | 197 | ||
198 | /* release gpios to system */ | 198 | /* release gpios to system */ |
199 | gpiorelease(NAND_MASK); | 199 | gpiorelease(NAND_MASK); |
200 | } | 200 | } |
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 062ff3877536..d7cd5fa16ba4 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* Linux driver for NAND Flash Translation Layer */ | 1 | /* Linux driver for NAND Flash Translation Layer */ |
2 | /* (c) 1999 Machine Vision Holdings, Inc. */ | 2 | /* (c) 1999 Machine Vision Holdings, Inc. */ |
3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ | 3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ |
4 | /* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */ | 4 | /* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */ |
5 | 5 | ||
6 | /* | 6 | /* |
7 | The contents of this file are distributed under the GNU General | 7 | The contents of this file are distributed under the GNU General |
@@ -101,14 +101,14 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
101 | 101 | ||
102 | if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { | 102 | if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { |
103 | /* | 103 | /* |
104 | Oh no we don't have | 104 | Oh no we don't have |
105 | mbd.size == heads * cylinders * sectors | 105 | mbd.size == heads * cylinders * sectors |
106 | */ | 106 | */ |
107 | printk(KERN_WARNING "NFTL: cannot calculate a geometry to " | 107 | printk(KERN_WARNING "NFTL: cannot calculate a geometry to " |
108 | "match size of 0x%lx.\n", nftl->mbd.size); | 108 | "match size of 0x%lx.\n", nftl->mbd.size); |
109 | printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " | 109 | printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " |
110 | "(== 0x%lx sects)\n", | 110 | "(== 0x%lx sects)\n", |
111 | nftl->cylinders, nftl->heads , nftl->sectors, | 111 | nftl->cylinders, nftl->heads , nftl->sectors, |
112 | (long)nftl->cylinders * (long)nftl->heads * | 112 | (long)nftl->cylinders * (long)nftl->heads * |
113 | (long)nftl->sectors ); | 113 | (long)nftl->sectors ); |
114 | } | 114 | } |
@@ -174,7 +174,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) | |||
174 | 174 | ||
175 | if (!silly--) { | 175 | if (!silly--) { |
176 | printk("Argh! No free blocks found! LastFreeEUN = %d, " | 176 | printk("Argh! No free blocks found! LastFreeEUN = %d, " |
177 | "FirstEUN = %d\n", nftl->LastFreeEUN, | 177 | "FirstEUN = %d\n", nftl->LastFreeEUN, |
178 | le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); | 178 | le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); |
179 | return 0xffff; | 179 | return 0xffff; |
180 | } | 180 | } |
@@ -206,7 +206,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
206 | "Virtual Unit Chain %d!\n", thisVUC); | 206 | "Virtual Unit Chain %d!\n", thisVUC); |
207 | return BLOCK_NIL; | 207 | return BLOCK_NIL; |
208 | } | 208 | } |
209 | 209 | ||
210 | /* Scan to find the Erase Unit which holds the actual data for each | 210 | /* Scan to find the Erase Unit which holds the actual data for each |
211 | 512-byte block within the Chain. | 211 | 512-byte block within the Chain. |
212 | */ | 212 | */ |
@@ -223,7 +223,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
223 | if (block == 2) { | 223 | if (block == 2) { |
224 | foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; | 224 | foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; |
225 | if (foldmark == FOLD_MARK_IN_PROGRESS) { | 225 | if (foldmark == FOLD_MARK_IN_PROGRESS) { |
226 | DEBUG(MTD_DEBUG_LEVEL1, | 226 | DEBUG(MTD_DEBUG_LEVEL1, |
227 | "Write Inhibited on EUN %d\n", thisEUN); | 227 | "Write Inhibited on EUN %d\n", thisEUN); |
228 | inplace = 0; | 228 | inplace = 0; |
229 | } else { | 229 | } else { |
@@ -245,7 +245,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
245 | if (!BlockFreeFound[block]) | 245 | if (!BlockFreeFound[block]) |
246 | BlockMap[block] = thisEUN; | 246 | BlockMap[block] = thisEUN; |
247 | else | 247 | else |
248 | printk(KERN_WARNING | 248 | printk(KERN_WARNING |
249 | "SECTOR_USED found after SECTOR_FREE " | 249 | "SECTOR_USED found after SECTOR_FREE " |
250 | "in Virtual Unit Chain %d for block %d\n", | 250 | "in Virtual Unit Chain %d for block %d\n", |
251 | thisVUC, block); | 251 | thisVUC, block); |
@@ -254,7 +254,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
254 | if (!BlockFreeFound[block]) | 254 | if (!BlockFreeFound[block]) |
255 | BlockMap[block] = BLOCK_NIL; | 255 | BlockMap[block] = BLOCK_NIL; |
256 | else | 256 | else |
257 | printk(KERN_WARNING | 257 | printk(KERN_WARNING |
258 | "SECTOR_DELETED found after SECTOR_FREE " | 258 | "SECTOR_DELETED found after SECTOR_FREE " |
259 | "in Virtual Unit Chain %d for block %d\n", | 259 | "in Virtual Unit Chain %d for block %d\n", |
260 | thisVUC, block); | 260 | thisVUC, block); |
@@ -273,14 +273,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
273 | thisVUC); | 273 | thisVUC); |
274 | return BLOCK_NIL; | 274 | return BLOCK_NIL; |
275 | } | 275 | } |
276 | 276 | ||
277 | thisEUN = nftl->ReplUnitTable[thisEUN]; | 277 | thisEUN = nftl->ReplUnitTable[thisEUN]; |
278 | } | 278 | } |
279 | 279 | ||
280 | if (inplace) { | 280 | if (inplace) { |
281 | /* We're being asked to be a fold-in-place. Check | 281 | /* We're being asked to be a fold-in-place. Check |
282 | that all blocks which actually have data associated | 282 | that all blocks which actually have data associated |
283 | with them (i.e. BlockMap[block] != BLOCK_NIL) are | 283 | with them (i.e. BlockMap[block] != BLOCK_NIL) are |
284 | either already present or SECTOR_FREE in the target | 284 | either already present or SECTOR_FREE in the target |
285 | block. If not, we're going to have to fold out-of-place | 285 | block. If not, we're going to have to fold out-of-place |
286 | anyway. | 286 | anyway. |
@@ -293,7 +293,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
293 | "block %d was %x lastEUN, " | 293 | "block %d was %x lastEUN, " |
294 | "and is in EUN %d (%s) %d\n", | 294 | "and is in EUN %d (%s) %d\n", |
295 | thisVUC, block, BlockLastState[block], | 295 | thisVUC, block, BlockLastState[block], |
296 | BlockMap[block], | 296 | BlockMap[block], |
297 | BlockMap[block]== targetEUN ? "==" : "!=", | 297 | BlockMap[block]== targetEUN ? "==" : "!=", |
298 | targetEUN); | 298 | targetEUN); |
299 | inplace = 0; | 299 | inplace = 0; |
@@ -310,17 +310,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
310 | inplace = 0; | 310 | inplace = 0; |
311 | } | 311 | } |
312 | } | 312 | } |
313 | 313 | ||
314 | if (!inplace) { | 314 | if (!inplace) { |
315 | DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " | 315 | DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " |
316 | "Trying out-of-place\n", thisVUC); | 316 | "Trying out-of-place\n", thisVUC); |
317 | /* We need to find a targetEUN to fold into. */ | 317 | /* We need to find a targetEUN to fold into. */ |
318 | targetEUN = NFTL_findfreeblock(nftl, 1); | 318 | targetEUN = NFTL_findfreeblock(nftl, 1); |
319 | if (targetEUN == BLOCK_NIL) { | 319 | if (targetEUN == BLOCK_NIL) { |
320 | /* Ouch. Now we're screwed. We need to do a | 320 | /* Ouch. Now we're screwed. We need to do a |
321 | fold-in-place of another chain to make room | 321 | fold-in-place of another chain to make room |
322 | for this one. We need a better way of selecting | 322 | for this one. We need a better way of selecting |
323 | which chain to fold, because makefreeblock will | 323 | which chain to fold, because makefreeblock will |
324 | only ask us to fold the same one again. | 324 | only ask us to fold the same one again. |
325 | */ | 325 | */ |
326 | printk(KERN_WARNING | 326 | printk(KERN_WARNING |
@@ -334,7 +334,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
334 | chain by selecting the longer one */ | 334 | chain by selecting the longer one */ |
335 | oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); | 335 | oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); |
336 | oob.u.c.unused = 0xffffffff; | 336 | oob.u.c.unused = 0xffffffff; |
337 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, | 337 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, |
338 | 8, &retlen, (char *)&oob.u); | 338 | 8, &retlen, (char *)&oob.u); |
339 | } | 339 | } |
340 | 340 | ||
@@ -357,14 +357,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
357 | happen in case of media errors or deleted blocks) */ | 357 | happen in case of media errors or deleted blocks) */ |
358 | if (BlockMap[block] == BLOCK_NIL) | 358 | if (BlockMap[block] == BLOCK_NIL) |
359 | continue; | 359 | continue; |
360 | 360 | ||
361 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), | 361 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), |
362 | 512, &retlen, movebuf); | 362 | 512, &retlen, movebuf); |
363 | if (ret < 0) { | 363 | if (ret < 0) { |
364 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) | 364 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) |
365 | + (block * 512), 512, &retlen, | 365 | + (block * 512), 512, &retlen, |
366 | movebuf); | 366 | movebuf); |
367 | if (ret != -EIO) | 367 | if (ret != -EIO) |
368 | printk("Error went away on retry.\n"); | 368 | printk("Error went away on retry.\n"); |
369 | } | 369 | } |
370 | memset(&oob, 0xff, sizeof(struct nftl_oob)); | 370 | memset(&oob, 0xff, sizeof(struct nftl_oob)); |
@@ -372,18 +372,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
372 | MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), | 372 | MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), |
373 | 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); | 373 | 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); |
374 | } | 374 | } |
375 | 375 | ||
376 | /* add the header so that it is now a valid chain */ | 376 | /* add the header so that it is now a valid chain */ |
377 | oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum | 377 | oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum |
378 | = cpu_to_le16(thisVUC); | 378 | = cpu_to_le16(thisVUC); |
379 | oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; | 379 | oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; |
380 | 380 | ||
381 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, | 381 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, |
382 | 8, &retlen, (char *)&oob.u); | 382 | 8, &retlen, (char *)&oob.u); |
383 | 383 | ||
384 | /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ | 384 | /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ |
385 | 385 | ||
386 | /* At this point, we have two different chains for this Virtual Unit, and no way to tell | 386 | /* At this point, we have two different chains for this Virtual Unit, and no way to tell |
387 | them apart. If we crash now, we get confused. However, both contain the same data, so we | 387 | them apart. If we crash now, we get confused. However, both contain the same data, so we |
388 | shouldn't actually lose data in this case. It's just that when we load up on a medium which | 388 | shouldn't actually lose data in this case. It's just that when we load up on a medium which |
389 | has duplicate chains, we need to free one of the chains because it's not necessary any more. | 389 | has duplicate chains, we need to free one of the chains because it's not necessary any more. |
@@ -391,7 +391,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
391 | thisEUN = nftl->EUNtable[thisVUC]; | 391 | thisEUN = nftl->EUNtable[thisVUC]; |
392 | DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); | 392 | DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); |
393 | 393 | ||
394 | /* For each block in the old chain (except the targetEUN of course), | 394 | /* For each block in the old chain (except the targetEUN of course), |
395 | free it and make it available for future use */ | 395 | free it and make it available for future use */ |
396 | while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { | 396 | while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { |
397 | unsigned int EUNtmp; | 397 | unsigned int EUNtmp; |
@@ -409,7 +409,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
409 | } | 409 | } |
410 | thisEUN = EUNtmp; | 410 | thisEUN = EUNtmp; |
411 | } | 411 | } |
412 | 412 | ||
413 | /* Make this the new start of chain for thisVUC */ | 413 | /* Make this the new start of chain for thisVUC */ |
414 | nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; | 414 | nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; |
415 | nftl->EUNtable[thisVUC] = targetEUN; | 415 | nftl->EUNtable[thisVUC] = targetEUN; |
@@ -419,7 +419,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
419 | 419 | ||
420 | static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) | 420 | static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) |
421 | { | 421 | { |
422 | /* This is the part that needs some cleverness applied. | 422 | /* This is the part that needs some cleverness applied. |
423 | For now, I'm doing the minimum applicable to actually | 423 | For now, I'm doing the minimum applicable to actually |
424 | get the thing to work. | 424 | get the thing to work. |
425 | Wear-levelling and other clever stuff needs to be implemented | 425 | Wear-levelling and other clever stuff needs to be implemented |
@@ -466,7 +466,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) | |||
466 | return NFTL_foldchain (nftl, LongestChain, pendingblock); | 466 | return NFTL_foldchain (nftl, LongestChain, pendingblock); |
467 | } | 467 | } |
468 | 468 | ||
469 | /* NFTL_findwriteunit: Return the unit number into which we can write | 469 | /* NFTL_findwriteunit: Return the unit number into which we can write |
470 | for this block. Make it available if it isn't already | 470 | for this block. Make it available if it isn't already |
471 | */ | 471 | */ |
472 | static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | 472 | static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) |
@@ -484,7 +484,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
484 | a free space for the block in question. | 484 | a free space for the block in question. |
485 | */ | 485 | */ |
486 | 486 | ||
487 | /* This condition catches the 0x[7f]fff cases, as well as | 487 | /* This condition catches the 0x[7f]fff cases, as well as |
488 | being a sanity check for past-end-of-media access | 488 | being a sanity check for past-end-of-media access |
489 | */ | 489 | */ |
490 | lastEUN = BLOCK_NIL; | 490 | lastEUN = BLOCK_NIL; |
@@ -499,7 +499,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
499 | 499 | ||
500 | MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, | 500 | MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, |
501 | 8, &retlen, (char *)&bci); | 501 | 8, &retlen, (char *)&bci); |
502 | 502 | ||
503 | DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", | 503 | DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", |
504 | block , writeEUN, le16_to_cpu(bci.Status)); | 504 | block , writeEUN, le16_to_cpu(bci.Status)); |
505 | 505 | ||
@@ -514,10 +514,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
514 | break; | 514 | break; |
515 | default: | 515 | default: |
516 | // Invalid block. Don't use it any more. Must implement. | 516 | // Invalid block. Don't use it any more. Must implement. |
517 | break; | 517 | break; |
518 | } | 518 | } |
519 | 519 | ||
520 | if (!silly--) { | 520 | if (!silly--) { |
521 | printk(KERN_WARNING | 521 | printk(KERN_WARNING |
522 | "Infinite loop in Virtual Unit Chain 0x%x\n", | 522 | "Infinite loop in Virtual Unit Chain 0x%x\n", |
523 | thisVUC); | 523 | thisVUC); |
@@ -528,7 +528,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
528 | writeEUN = nftl->ReplUnitTable[writeEUN]; | 528 | writeEUN = nftl->ReplUnitTable[writeEUN]; |
529 | } | 529 | } |
530 | 530 | ||
531 | /* OK. We didn't find one in the existing chain, or there | 531 | /* OK. We didn't find one in the existing chain, or there |
532 | is no existing chain. */ | 532 | is no existing chain. */ |
533 | 533 | ||
534 | /* Try to find an already-free block */ | 534 | /* Try to find an already-free block */ |
@@ -542,12 +542,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
542 | 542 | ||
543 | /* First remember the start of this chain */ | 543 | /* First remember the start of this chain */ |
544 | //u16 startEUN = nftl->EUNtable[thisVUC]; | 544 | //u16 startEUN = nftl->EUNtable[thisVUC]; |
545 | 545 | ||
546 | //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); | 546 | //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); |
547 | writeEUN = NFTL_makefreeblock(nftl, 0xffff); | 547 | writeEUN = NFTL_makefreeblock(nftl, 0xffff); |
548 | 548 | ||
549 | if (writeEUN == BLOCK_NIL) { | 549 | if (writeEUN == BLOCK_NIL) { |
550 | /* OK, we accept that the above comment is | 550 | /* OK, we accept that the above comment is |
551 | lying - there may have been free blocks | 551 | lying - there may have been free blocks |
552 | last time we called NFTL_findfreeblock(), | 552 | last time we called NFTL_findfreeblock(), |
553 | but they are reserved for when we're | 553 | but they are reserved for when we're |
@@ -558,21 +558,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
558 | } | 558 | } |
559 | if (writeEUN == BLOCK_NIL) { | 559 | if (writeEUN == BLOCK_NIL) { |
560 | /* Ouch. This should never happen - we should | 560 | /* Ouch. This should never happen - we should |
561 | always be able to make some room somehow. | 561 | always be able to make some room somehow. |
562 | If we get here, we've allocated more storage | 562 | If we get here, we've allocated more storage |
563 | space than actual media, or our makefreeblock | 563 | space than actual media, or our makefreeblock |
564 | routine is missing something. | 564 | routine is missing something. |
565 | */ | 565 | */ |
566 | printk(KERN_WARNING "Cannot make free space.\n"); | 566 | printk(KERN_WARNING "Cannot make free space.\n"); |
567 | return BLOCK_NIL; | 567 | return BLOCK_NIL; |
568 | } | 568 | } |
569 | //printk("Restarting scan\n"); | 569 | //printk("Restarting scan\n"); |
570 | lastEUN = BLOCK_NIL; | 570 | lastEUN = BLOCK_NIL; |
571 | continue; | 571 | continue; |
572 | } | 572 | } |
573 | 573 | ||
574 | /* We've found a free block. Insert it into the chain. */ | 574 | /* We've found a free block. Insert it into the chain. */ |
575 | 575 | ||
576 | if (lastEUN != BLOCK_NIL) { | 576 | if (lastEUN != BLOCK_NIL) { |
577 | thisVUC |= 0x8000; /* It's a replacement block */ | 577 | thisVUC |= 0x8000; /* It's a replacement block */ |
578 | } else { | 578 | } else { |
@@ -745,7 +745,7 @@ extern char nftlmountrev[]; | |||
745 | 745 | ||
746 | static int __init init_nftl(void) | 746 | static int __init init_nftl(void) |
747 | { | 747 | { |
748 | printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev); | 748 | printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev); |
749 | 749 | ||
750 | return register_mtd_blktrans(&nftl_tr); | 750 | return register_mtd_blktrans(&nftl_tr); |
751 | } | 751 | } |
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 84afd9029f53..3b104ebb219a 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * NFTL mount code with extensive checks | 2 | * NFTL mount code with extensive checks |
3 | * | 3 | * |
4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
5 | * Copyright (C) 2000 Netgem S.A. | 5 | * Copyright (C) 2000 Netgem S.A. |
6 | * | 6 | * |
7 | * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $ | 7 | * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 gleixner Exp $ |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -31,7 +31,7 @@ | |||
31 | 31 | ||
32 | #define SECTORSIZE 512 | 32 | #define SECTORSIZE 512 |
33 | 33 | ||
34 | char nftlmountrev[]="$Revision: 1.40 $"; | 34 | char nftlmountrev[]="$Revision: 1.41 $"; |
35 | 35 | ||
36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the | 36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the |
37 | * various device information of the NFTL partition and Bad Unit Table. Update | 37 | * various device information of the NFTL partition and Bad Unit Table. Update |
@@ -47,7 +47,7 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
47 | struct NFTLMediaHeader *mh = &nftl->MediaHdr; | 47 | struct NFTLMediaHeader *mh = &nftl->MediaHdr; |
48 | unsigned int i; | 48 | unsigned int i; |
49 | 49 | ||
50 | /* Assume logical EraseSize == physical erasesize for starting the scan. | 50 | /* Assume logical EraseSize == physical erasesize for starting the scan. |
51 | We'll sort it out later if we find a MediaHeader which says otherwise */ | 51 | We'll sort it out later if we find a MediaHeader which says otherwise */ |
52 | /* Actually, we won't. The new DiskOnChip driver has already scanned | 52 | /* Actually, we won't. The new DiskOnChip driver has already scanned |
53 | the MediaHeader and adjusted the virtual erasesize it presents in | 53 | the MediaHeader and adjusted the virtual erasesize it presents in |
@@ -83,9 +83,9 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
83 | if (retlen < 6 || memcmp(buf, "ANAND", 6)) { | 83 | if (retlen < 6 || memcmp(buf, "ANAND", 6)) { |
84 | /* ANAND\0 not found. Continue */ | 84 | /* ANAND\0 not found. Continue */ |
85 | #if 0 | 85 | #if 0 |
86 | printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", | 86 | printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", |
87 | block * nftl->EraseSize, nftl->mbd.mtd->index); | 87 | block * nftl->EraseSize, nftl->mbd.mtd->index); |
88 | #endif | 88 | #endif |
89 | continue; | 89 | continue; |
90 | } | 90 | } |
91 | 91 | ||
@@ -103,7 +103,7 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
103 | */ | 103 | */ |
104 | if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { | 104 | if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { |
105 | printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", | 105 | printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", |
106 | block * nftl->EraseSize, nftl->mbd.mtd->index, | 106 | block * nftl->EraseSize, nftl->mbd.mtd->index, |
107 | le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); | 107 | le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); |
108 | continue; | 108 | continue; |
109 | } | 109 | } |
@@ -175,7 +175,7 @@ device is already correct. | |||
175 | nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); | 175 | nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); |
176 | if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { | 176 | if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { |
177 | printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); | 177 | printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); |
178 | printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", | 178 | printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", |
179 | nftl->nb_boot_blocks, nftl->nb_blocks); | 179 | nftl->nb_boot_blocks, nftl->nb_blocks); |
180 | return -1; | 180 | return -1; |
181 | } | 181 | } |
@@ -187,7 +187,7 @@ device is already correct. | |||
187 | nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); | 187 | nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); |
188 | return -1; | 188 | return -1; |
189 | } | 189 | } |
190 | 190 | ||
191 | nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); | 191 | nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); |
192 | 192 | ||
193 | /* If we're not using the last sectors in the device for some reason, | 193 | /* If we're not using the last sectors in the device for some reason, |
@@ -210,12 +210,12 @@ device is already correct. | |||
210 | printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); | 210 | printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); |
211 | return -ENOMEM; | 211 | return -ENOMEM; |
212 | } | 212 | } |
213 | 213 | ||
214 | /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ | 214 | /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ |
215 | for (i = 0; i < nftl->nb_boot_blocks; i++) | 215 | for (i = 0; i < nftl->nb_boot_blocks; i++) |
216 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; | 216 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; |
217 | /* mark all remaining blocks as potentially containing data */ | 217 | /* mark all remaining blocks as potentially containing data */ |
218 | for (; i < nftl->nb_blocks; i++) { | 218 | for (; i < nftl->nb_blocks; i++) { |
219 | nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; | 219 | nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; |
220 | } | 220 | } |
221 | 221 | ||
@@ -245,12 +245,12 @@ The new DiskOnChip driver already scanned the bad block table. Just query it. | |||
245 | if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize)) | 245 | if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize)) |
246 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; | 246 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; |
247 | } | 247 | } |
248 | 248 | ||
249 | nftl->MediaUnit = block; | 249 | nftl->MediaUnit = block; |
250 | boot_record_count++; | 250 | boot_record_count++; |
251 | 251 | ||
252 | } /* foreach (block) */ | 252 | } /* foreach (block) */ |
253 | 253 | ||
254 | return boot_record_count?0:-1; | 254 | return boot_record_count?0:-1; |
255 | } | 255 | } |
256 | 256 | ||
@@ -265,7 +265,7 @@ static int memcmpb(void *a, int c, int n) | |||
265 | } | 265 | } |
266 | 266 | ||
267 | /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */ | 267 | /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */ |
268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, | 268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, |
269 | int check_oob) | 269 | int check_oob) |
270 | { | 270 | { |
271 | int i; | 271 | int i; |
@@ -293,7 +293,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int | |||
293 | * | 293 | * |
294 | * Return: 0 when succeed, -1 on error. | 294 | * Return: 0 when succeed, -1 on error. |
295 | * | 295 | * |
296 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? | 296 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? |
297 | */ | 297 | */ |
298 | int NFTL_formatblock(struct NFTLrecord *nftl, int block) | 298 | int NFTL_formatblock(struct NFTLrecord *nftl, int block) |
299 | { | 299 | { |
@@ -385,7 +385,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b | |||
385 | /* verify that the sector is really free. If not, mark | 385 | /* verify that the sector is really free. If not, mark |
386 | as ignore */ | 386 | as ignore */ |
387 | if (memcmpb(&bci, 0xff, 8) != 0 || | 387 | if (memcmpb(&bci, 0xff, 8) != 0 || |
388 | check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, | 388 | check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, |
389 | SECTORSIZE, 0) != 0) { | 389 | SECTORSIZE, 0) != 0) { |
390 | printk("Incorrect free sector %d in block %d: " | 390 | printk("Incorrect free sector %d in block %d: " |
391 | "marking it as ignored\n", | 391 | "marking it as ignored\n", |
@@ -486,7 +486,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) | |||
486 | size_t retlen; | 486 | size_t retlen; |
487 | 487 | ||
488 | /* check erase mark. */ | 488 | /* check erase mark. */ |
489 | if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, | 489 | if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, |
490 | &retlen, (char *)&h1) < 0) | 490 | &retlen, (char *)&h1) < 0) |
491 | return -1; | 491 | return -1; |
492 | 492 | ||
@@ -501,7 +501,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) | |||
501 | h1.EraseMark = cpu_to_le16(ERASE_MARK); | 501 | h1.EraseMark = cpu_to_le16(ERASE_MARK); |
502 | h1.EraseMark1 = cpu_to_le16(ERASE_MARK); | 502 | h1.EraseMark1 = cpu_to_le16(ERASE_MARK); |
503 | h1.WearInfo = cpu_to_le32(0); | 503 | h1.WearInfo = cpu_to_le32(0); |
504 | if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, | 504 | if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, |
505 | &retlen, (char *)&h1) < 0) | 505 | &retlen, (char *)&h1) < 0) |
506 | return -1; | 506 | return -1; |
507 | } else { | 507 | } else { |
@@ -582,9 +582,9 @@ int NFTL_mount(struct NFTLrecord *s) | |||
582 | 582 | ||
583 | for (;;) { | 583 | for (;;) { |
584 | /* read the block header. If error, we format the chain */ | 584 | /* read the block header. If error, we format the chain */ |
585 | if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, | 585 | if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, |
586 | &retlen, (char *)&h0) < 0 || | 586 | &retlen, (char *)&h0) < 0 || |
587 | MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, | 587 | MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, |
588 | &retlen, (char *)&h1) < 0) { | 588 | &retlen, (char *)&h1) < 0) { |
589 | s->ReplUnitTable[block] = BLOCK_NIL; | 589 | s->ReplUnitTable[block] = BLOCK_NIL; |
590 | do_format_chain = 1; | 590 | do_format_chain = 1; |
@@ -639,7 +639,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
639 | first_logical_block = logical_block; | 639 | first_logical_block = logical_block; |
640 | } else { | 640 | } else { |
641 | if (logical_block != first_logical_block) { | 641 | if (logical_block != first_logical_block) { |
642 | printk("Block %d: incorrect logical block: %d expected: %d\n", | 642 | printk("Block %d: incorrect logical block: %d expected: %d\n", |
643 | block, logical_block, first_logical_block); | 643 | block, logical_block, first_logical_block); |
644 | /* the chain is incorrect : we must format it, | 644 | /* the chain is incorrect : we must format it, |
645 | but we need to read it completly */ | 645 | but we need to read it completly */ |
@@ -668,7 +668,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
668 | s->ReplUnitTable[block] = BLOCK_NIL; | 668 | s->ReplUnitTable[block] = BLOCK_NIL; |
669 | break; | 669 | break; |
670 | } else if (rep_block >= s->nb_blocks) { | 670 | } else if (rep_block >= s->nb_blocks) { |
671 | printk("Block %d: referencing invalid block %d\n", | 671 | printk("Block %d: referencing invalid block %d\n", |
672 | block, rep_block); | 672 | block, rep_block); |
673 | do_format_chain = 1; | 673 | do_format_chain = 1; |
674 | s->ReplUnitTable[block] = BLOCK_NIL; | 674 | s->ReplUnitTable[block] = BLOCK_NIL; |
@@ -688,7 +688,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
688 | s->ReplUnitTable[block] = rep_block; | 688 | s->ReplUnitTable[block] = rep_block; |
689 | s->EUNtable[first_logical_block] = BLOCK_NIL; | 689 | s->EUNtable[first_logical_block] = BLOCK_NIL; |
690 | } else { | 690 | } else { |
691 | printk("Block %d: referencing block %d already in another chain\n", | 691 | printk("Block %d: referencing block %d already in another chain\n", |
692 | block, rep_block); | 692 | block, rep_block); |
693 | /* XXX: should handle correctly fold in progress chains */ | 693 | /* XXX: should handle correctly fold in progress chains */ |
694 | do_format_chain = 1; | 694 | do_format_chain = 1; |
@@ -710,7 +710,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
710 | } else { | 710 | } else { |
711 | unsigned int first_block1, chain_to_format, chain_length1; | 711 | unsigned int first_block1, chain_to_format, chain_length1; |
712 | int fold_mark; | 712 | int fold_mark; |
713 | 713 | ||
714 | /* valid chain : get foldmark */ | 714 | /* valid chain : get foldmark */ |
715 | fold_mark = get_fold_mark(s, first_block); | 715 | fold_mark = get_fold_mark(s, first_block); |
716 | if (fold_mark == 0) { | 716 | if (fold_mark == 0) { |
@@ -729,9 +729,9 @@ int NFTL_mount(struct NFTLrecord *s) | |||
729 | if (first_block1 != BLOCK_NIL) { | 729 | if (first_block1 != BLOCK_NIL) { |
730 | /* XXX: what to do if same length ? */ | 730 | /* XXX: what to do if same length ? */ |
731 | chain_length1 = calc_chain_length(s, first_block1); | 731 | chain_length1 = calc_chain_length(s, first_block1); |
732 | printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", | 732 | printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", |
733 | first_block1, chain_length1, first_block, chain_length); | 733 | first_block1, chain_length1, first_block, chain_length); |
734 | 734 | ||
735 | if (chain_length >= chain_length1) { | 735 | if (chain_length >= chain_length1) { |
736 | chain_to_format = first_block1; | 736 | chain_to_format = first_block1; |
737 | s->EUNtable[first_logical_block] = first_block; | 737 | s->EUNtable[first_logical_block] = first_block; |
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig new file mode 100644 index 000000000000..126ff6bf63d5 --- /dev/null +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -0,0 +1,38 @@ | |||
1 | # | ||
2 | # linux/drivers/mtd/onenand/Kconfig | ||
3 | # | ||
4 | |||
5 | menu "OneNAND Flash Device Drivers" | ||
6 | depends on MTD != n | ||
7 | |||
8 | config MTD_ONENAND | ||
9 | tristate "OneNAND Device Support" | ||
10 | depends on MTD | ||
11 | help | ||
12 | This enables support for accessing all type of OneNAND flash | ||
13 | devices. For further information see | ||
14 | <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>. | ||
15 | |||
16 | config MTD_ONENAND_VERIFY_WRITE | ||
17 | bool "Verify OneNAND page writes" | ||
18 | depends on MTD_ONENAND | ||
19 | help | ||
20 | This adds an extra check when data is written to the flash. The | ||
21 | OneNAND flash device internally checks only bits transitioning | ||
22 | from 1 to 0. There is a rare possibility that even though the | ||
23 | device thinks the write was successful, a bit could have been | ||
24 | flipped accidentaly due to device wear or something else. | ||
25 | |||
26 | config MTD_ONENAND_GENERIC | ||
27 | tristate "OneNAND Flash device via platform device driver" | ||
28 | depends on MTD_ONENAND && ARM | ||
29 | help | ||
30 | Support for OneNAND flash via platform device driver. | ||
31 | |||
32 | config MTD_ONENAND_SYNC_READ | ||
33 | bool "OneNAND Sync. Burst Read Support" | ||
34 | depends on ARCH_OMAP | ||
35 | help | ||
36 | This enables support for Sync. Burst Read. | ||
37 | |||
38 | endmenu | ||
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile new file mode 100644 index 000000000000..269cfe467345 --- /dev/null +++ b/drivers/mtd/onenand/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the OneNAND MTD | ||
3 | # | ||
4 | |||
5 | # Core functionality. | ||
6 | obj-$(CONFIG_MTD_ONENAND) += onenand.o | ||
7 | |||
8 | # Board specific. | ||
9 | obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o | ||
10 | |||
11 | onenand-objs = onenand_base.o onenand_bbt.o | ||
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c new file mode 100644 index 000000000000..48cce431f89f --- /dev/null +++ b/drivers/mtd/onenand/generic.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/generic.c | ||
3 | * | ||
4 | * Copyright (c) 2005 Samsung Electronics | ||
5 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Overview: | ||
12 | * This is a device driver for the OneNAND flash for generic boards. | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/onenand.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/mach/flash.h> | ||
24 | |||
25 | #define DRIVER_NAME "onenand" | ||
26 | |||
27 | |||
28 | #ifdef CONFIG_MTD_PARTITIONS | ||
29 | static const char *part_probes[] = { "cmdlinepart", NULL, }; | ||
30 | #endif | ||
31 | |||
32 | struct onenand_info { | ||
33 | struct mtd_info mtd; | ||
34 | struct mtd_partition *parts; | ||
35 | struct onenand_chip onenand; | ||
36 | }; | ||
37 | |||
38 | static int __devinit generic_onenand_probe(struct device *dev) | ||
39 | { | ||
40 | struct onenand_info *info; | ||
41 | struct platform_device *pdev = to_platform_device(dev); | ||
42 | struct onenand_platform_data *pdata = pdev->dev.platform_data; | ||
43 | struct resource *res = pdev->resource; | ||
44 | unsigned long size = res->end - res->start + 1; | ||
45 | int err; | ||
46 | |||
47 | info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL); | ||
48 | if (!info) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | memset(info, 0, sizeof(struct onenand_info)); | ||
52 | |||
53 | if (!request_mem_region(res->start, size, dev->driver->name)) { | ||
54 | err = -EBUSY; | ||
55 | goto out_free_info; | ||
56 | } | ||
57 | |||
58 | info->onenand.base = ioremap(res->start, size); | ||
59 | if (!info->onenand.base) { | ||
60 | err = -ENOMEM; | ||
61 | goto out_release_mem_region; | ||
62 | } | ||
63 | |||
64 | info->onenand.mmcontrol = pdata->mmcontrol; | ||
65 | |||
66 | info->mtd.name = pdev->dev.bus_id; | ||
67 | info->mtd.priv = &info->onenand; | ||
68 | info->mtd.owner = THIS_MODULE; | ||
69 | |||
70 | if (onenand_scan(&info->mtd, 1)) { | ||
71 | err = -ENXIO; | ||
72 | goto out_iounmap; | ||
73 | } | ||
74 | |||
75 | #ifdef CONFIG_MTD_PARTITIONS | ||
76 | err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); | ||
77 | if (err > 0) | ||
78 | add_mtd_partitions(&info->mtd, info->parts, err); | ||
79 | else if (err < 0 && pdata->parts) | ||
80 | add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts); | ||
81 | else | ||
82 | #endif | ||
83 | err = add_mtd_device(&info->mtd); | ||
84 | |||
85 | dev_set_drvdata(&pdev->dev, info); | ||
86 | |||
87 | return 0; | ||
88 | |||
89 | out_iounmap: | ||
90 | iounmap(info->onenand.base); | ||
91 | out_release_mem_region: | ||
92 | release_mem_region(res->start, size); | ||
93 | out_free_info: | ||
94 | kfree(info); | ||
95 | |||
96 | return err; | ||
97 | } | ||
98 | |||
99 | static int __devexit generic_onenand_remove(struct device *dev) | ||
100 | { | ||
101 | struct platform_device *pdev = to_platform_device(dev); | ||
102 | struct onenand_info *info = dev_get_drvdata(&pdev->dev); | ||
103 | struct resource *res = pdev->resource; | ||
104 | unsigned long size = res->end - res->start + 1; | ||
105 | |||
106 | dev_set_drvdata(&pdev->dev, NULL); | ||
107 | |||
108 | if (info) { | ||
109 | if (info->parts) | ||
110 | del_mtd_partitions(&info->mtd); | ||
111 | else | ||
112 | del_mtd_device(&info->mtd); | ||
113 | |||
114 | onenand_release(&info->mtd); | ||
115 | release_mem_region(res->start, size); | ||
116 | iounmap(info->onenand.base); | ||
117 | kfree(info); | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static struct device_driver generic_onenand_driver = { | ||
124 | .name = DRIVER_NAME, | ||
125 | .bus = &platform_bus_type, | ||
126 | .probe = generic_onenand_probe, | ||
127 | .remove = __devexit_p(generic_onenand_remove), | ||
128 | }; | ||
129 | |||
130 | MODULE_ALIAS(DRIVER_NAME); | ||
131 | |||
132 | static int __init generic_onenand_init(void) | ||
133 | { | ||
134 | return driver_register(&generic_onenand_driver); | ||
135 | } | ||
136 | |||
137 | static void __exit generic_onenand_exit(void) | ||
138 | { | ||
139 | driver_unregister(&generic_onenand_driver); | ||
140 | } | ||
141 | |||
142 | module_init(generic_onenand_init); | ||
143 | module_exit(generic_onenand_exit); | ||
144 | |||
145 | MODULE_LICENSE("GPL"); | ||
146 | MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); | ||
147 | MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards"); | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c new file mode 100644 index 000000000000..cc38fa0d45c6 --- /dev/null +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -0,0 +1,1588 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/onenand_base.c | ||
3 | * | ||
4 | * Copyright (C) 2005 Samsung Electronics | ||
5 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/mtd/mtd.h> | ||
16 | #include <linux/mtd/onenand.h> | ||
17 | #include <linux/mtd/partitions.h> | ||
18 | |||
19 | #include <asm/io.h> | ||
20 | |||
21 | /** | ||
22 | * onenand_oob_64 - oob info for large (2KB) page | ||
23 | */ | ||
24 | static struct nand_oobinfo onenand_oob_64 = { | ||
25 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
26 | .eccbytes = 20, | ||
27 | .eccpos = { | ||
28 | 8, 9, 10, 11, 12, | ||
29 | 24, 25, 26, 27, 28, | ||
30 | 40, 41, 42, 43, 44, | ||
31 | 56, 57, 58, 59, 60, | ||
32 | }, | ||
33 | .oobfree = { | ||
34 | {2, 3}, {14, 2}, {18, 3}, {30, 2}, | ||
35 | {24, 3}, {46, 2}, {40, 3}, {62, 2} } | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * onenand_oob_32 - oob info for middle (1KB) page | ||
40 | */ | ||
41 | static struct nand_oobinfo onenand_oob_32 = { | ||
42 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
43 | .eccbytes = 10, | ||
44 | .eccpos = { | ||
45 | 8, 9, 10, 11, 12, | ||
46 | 24, 25, 26, 27, 28, | ||
47 | }, | ||
48 | .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} } | ||
49 | }; | ||
50 | |||
51 | static const unsigned char ffchars[] = { | ||
52 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
53 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ | ||
54 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
55 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */ | ||
56 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
57 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */ | ||
58 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
59 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */ | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * onenand_readw - [OneNAND Interface] Read OneNAND register | ||
64 | * @param addr address to read | ||
65 | * | ||
66 | * Read OneNAND register | ||
67 | */ | ||
68 | static unsigned short onenand_readw(void __iomem *addr) | ||
69 | { | ||
70 | return readw(addr); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * onenand_writew - [OneNAND Interface] Write OneNAND register with value | ||
75 | * @param value value to write | ||
76 | * @param addr address to write | ||
77 | * | ||
78 | * Write OneNAND register with value | ||
79 | */ | ||
80 | static void onenand_writew(unsigned short value, void __iomem *addr) | ||
81 | { | ||
82 | writew(value, addr); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * onenand_block_address - [DEFAULT] Get block address | ||
87 | * @param this onenand chip data structure | ||
88 | * @param block the block | ||
89 | * @return translated block address if DDP, otherwise same | ||
90 | * | ||
91 | * Setup Start Address 1 Register (F100h) | ||
92 | */ | ||
93 | static int onenand_block_address(struct onenand_chip *this, int block) | ||
94 | { | ||
95 | if (this->device_id & ONENAND_DEVICE_IS_DDP) { | ||
96 | /* Device Flash Core select, NAND Flash Block Address */ | ||
97 | int dfs = 0; | ||
98 | |||
99 | if (block & this->density_mask) | ||
100 | dfs = 1; | ||
101 | |||
102 | return (dfs << ONENAND_DDP_SHIFT) | | ||
103 | (block & (this->density_mask - 1)); | ||
104 | } | ||
105 | |||
106 | return block; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * onenand_bufferram_address - [DEFAULT] Get bufferram address | ||
111 | * @param this onenand chip data structure | ||
112 | * @param block the block | ||
113 | * @return set DBS value if DDP, otherwise 0 | ||
114 | * | ||
115 | * Setup Start Address 2 Register (F101h) for DDP | ||
116 | */ | ||
117 | static int onenand_bufferram_address(struct onenand_chip *this, int block) | ||
118 | { | ||
119 | if (this->device_id & ONENAND_DEVICE_IS_DDP) { | ||
120 | /* Device BufferRAM Select */ | ||
121 | int dbs = 0; | ||
122 | |||
123 | if (block & this->density_mask) | ||
124 | dbs = 1; | ||
125 | |||
126 | return (dbs << ONENAND_DDP_SHIFT); | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * onenand_page_address - [DEFAULT] Get page address | ||
134 | * @param page the page address | ||
135 | * @param sector the sector address | ||
136 | * @return combined page and sector address | ||
137 | * | ||
138 | * Setup Start Address 8 Register (F107h) | ||
139 | */ | ||
140 | static int onenand_page_address(int page, int sector) | ||
141 | { | ||
142 | /* Flash Page Address, Flash Sector Address */ | ||
143 | int fpa, fsa; | ||
144 | |||
145 | fpa = page & ONENAND_FPA_MASK; | ||
146 | fsa = sector & ONENAND_FSA_MASK; | ||
147 | |||
148 | return ((fpa << ONENAND_FPA_SHIFT) | fsa); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * onenand_buffer_address - [DEFAULT] Get buffer address | ||
153 | * @param dataram1 DataRAM index | ||
154 | * @param sectors the sector address | ||
155 | * @param count the number of sectors | ||
156 | * @return the start buffer value | ||
157 | * | ||
158 | * Setup Start Buffer Register (F200h) | ||
159 | */ | ||
160 | static int onenand_buffer_address(int dataram1, int sectors, int count) | ||
161 | { | ||
162 | int bsa, bsc; | ||
163 | |||
164 | /* BufferRAM Sector Address */ | ||
165 | bsa = sectors & ONENAND_BSA_MASK; | ||
166 | |||
167 | if (dataram1) | ||
168 | bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */ | ||
169 | else | ||
170 | bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */ | ||
171 | |||
172 | /* BufferRAM Sector Count */ | ||
173 | bsc = count & ONENAND_BSC_MASK; | ||
174 | |||
175 | return ((bsa << ONENAND_BSA_SHIFT) | bsc); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * onenand_command - [DEFAULT] Send command to OneNAND device | ||
180 | * @param mtd MTD device structure | ||
181 | * @param cmd the command to be sent | ||
182 | * @param addr offset to read from or write to | ||
183 | * @param len number of bytes to read or write | ||
184 | * | ||
185 | * Send command to OneNAND device. This function is used for middle/large page | ||
186 | * devices (1KB/2KB Bytes per page) | ||
187 | */ | ||
188 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | ||
189 | { | ||
190 | struct onenand_chip *this = mtd->priv; | ||
191 | int value, readcmd = 0; | ||
192 | int block, page; | ||
193 | /* Now we use page size operation */ | ||
194 | int sectors = 4, count = 4; | ||
195 | |||
196 | /* Address translation */ | ||
197 | switch (cmd) { | ||
198 | case ONENAND_CMD_UNLOCK: | ||
199 | case ONENAND_CMD_LOCK: | ||
200 | case ONENAND_CMD_LOCK_TIGHT: | ||
201 | block = -1; | ||
202 | page = -1; | ||
203 | break; | ||
204 | |||
205 | case ONENAND_CMD_ERASE: | ||
206 | case ONENAND_CMD_BUFFERRAM: | ||
207 | block = (int) (addr >> this->erase_shift); | ||
208 | page = -1; | ||
209 | break; | ||
210 | |||
211 | default: | ||
212 | block = (int) (addr >> this->erase_shift); | ||
213 | page = (int) (addr >> this->page_shift); | ||
214 | page &= this->page_mask; | ||
215 | break; | ||
216 | } | ||
217 | |||
218 | /* NOTE: The setting order of the registers is very important! */ | ||
219 | if (cmd == ONENAND_CMD_BUFFERRAM) { | ||
220 | /* Select DataRAM for DDP */ | ||
221 | value = onenand_bufferram_address(this, block); | ||
222 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
223 | |||
224 | /* Switch to the next data buffer */ | ||
225 | ONENAND_SET_NEXT_BUFFERRAM(this); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | if (block != -1) { | ||
231 | /* Write 'DFS, FBA' of Flash */ | ||
232 | value = onenand_block_address(this, block); | ||
233 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | ||
234 | } | ||
235 | |||
236 | if (page != -1) { | ||
237 | int dataram; | ||
238 | |||
239 | switch (cmd) { | ||
240 | case ONENAND_CMD_READ: | ||
241 | case ONENAND_CMD_READOOB: | ||
242 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); | ||
243 | readcmd = 1; | ||
244 | break; | ||
245 | |||
246 | default: | ||
247 | dataram = ONENAND_CURRENT_BUFFERRAM(this); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | /* Write 'FPA, FSA' of Flash */ | ||
252 | value = onenand_page_address(page, sectors); | ||
253 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8); | ||
254 | |||
255 | /* Write 'BSA, BSC' of DataRAM */ | ||
256 | value = onenand_buffer_address(dataram, sectors, count); | ||
257 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); | ||
258 | |||
259 | if (readcmd) { | ||
260 | /* Select DataRAM for DDP */ | ||
261 | value = onenand_bufferram_address(this, block); | ||
262 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Interrupt clear */ | ||
267 | this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT); | ||
268 | |||
269 | /* Write command */ | ||
270 | this->write_word(cmd, this->base + ONENAND_REG_COMMAND); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * onenand_wait - [DEFAULT] wait until the command is done | ||
277 | * @param mtd MTD device structure | ||
278 | * @param state state to select the max. timeout value | ||
279 | * | ||
280 | * Wait for command done. This applies to all OneNAND command | ||
281 | * Read can take up to 30us, erase up to 2ms and program up to 350us | ||
282 | * according to general OneNAND specs | ||
283 | */ | ||
284 | static int onenand_wait(struct mtd_info *mtd, int state) | ||
285 | { | ||
286 | struct onenand_chip * this = mtd->priv; | ||
287 | unsigned long timeout; | ||
288 | unsigned int flags = ONENAND_INT_MASTER; | ||
289 | unsigned int interrupt = 0; | ||
290 | unsigned int ctrl, ecc; | ||
291 | |||
292 | /* The 20 msec is enough */ | ||
293 | timeout = jiffies + msecs_to_jiffies(20); | ||
294 | while (time_before(jiffies, timeout)) { | ||
295 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
296 | |||
297 | if (interrupt & flags) | ||
298 | break; | ||
299 | |||
300 | if (state != FL_READING) | ||
301 | cond_resched(); | ||
302 | } | ||
303 | /* To get correct interrupt status in timeout case */ | ||
304 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
305 | |||
306 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | ||
307 | |||
308 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
309 | /* It maybe occur at initial bad block */ | ||
310 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); | ||
311 | /* Clear other interrupt bits for preventing ECC error */ | ||
312 | interrupt &= ONENAND_INT_MASTER; | ||
313 | } | ||
314 | |||
315 | if (ctrl & ONENAND_CTRL_LOCK) { | ||
316 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl); | ||
317 | return -EACCES; | ||
318 | } | ||
319 | |||
320 | if (interrupt & ONENAND_INT_READ) { | ||
321 | ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | ||
322 | if (ecc & ONENAND_ECC_2BIT_ALL) { | ||
323 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); | ||
324 | return -EBADMSG; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * onenand_bufferram_offset - [DEFAULT] BufferRAM offset | ||
333 | * @param mtd MTD data structure | ||
334 | * @param area BufferRAM area | ||
335 | * @return offset given area | ||
336 | * | ||
337 | * Return BufferRAM offset given area | ||
338 | */ | ||
339 | static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) | ||
340 | { | ||
341 | struct onenand_chip *this = mtd->priv; | ||
342 | |||
343 | if (ONENAND_CURRENT_BUFFERRAM(this)) { | ||
344 | if (area == ONENAND_DATARAM) | ||
345 | return mtd->oobblock; | ||
346 | if (area == ONENAND_SPARERAM) | ||
347 | return mtd->oobsize; | ||
348 | } | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area | ||
355 | * @param mtd MTD data structure | ||
356 | * @param area BufferRAM area | ||
357 | * @param buffer the databuffer to put/get data | ||
358 | * @param offset offset to read from or write to | ||
359 | * @param count number of bytes to read/write | ||
360 | * | ||
361 | * Read the BufferRAM area | ||
362 | */ | ||
363 | static int onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
364 | unsigned char *buffer, int offset, size_t count) | ||
365 | { | ||
366 | struct onenand_chip *this = mtd->priv; | ||
367 | void __iomem *bufferram; | ||
368 | |||
369 | bufferram = this->base + area; | ||
370 | |||
371 | bufferram += onenand_bufferram_offset(mtd, area); | ||
372 | |||
373 | memcpy(buffer, bufferram + offset, count); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode | ||
380 | * @param mtd MTD data structure | ||
381 | * @param area BufferRAM area | ||
382 | * @param buffer the databuffer to put/get data | ||
383 | * @param offset offset to read from or write to | ||
384 | * @param count number of bytes to read/write | ||
385 | * | ||
386 | * Read the BufferRAM area with Sync. Burst Mode | ||
387 | */ | ||
388 | static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, | ||
389 | unsigned char *buffer, int offset, size_t count) | ||
390 | { | ||
391 | struct onenand_chip *this = mtd->priv; | ||
392 | void __iomem *bufferram; | ||
393 | |||
394 | bufferram = this->base + area; | ||
395 | |||
396 | bufferram += onenand_bufferram_offset(mtd, area); | ||
397 | |||
398 | this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); | ||
399 | |||
400 | memcpy(buffer, bufferram + offset, count); | ||
401 | |||
402 | this->mmcontrol(mtd, 0); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area | ||
409 | * @param mtd MTD data structure | ||
410 | * @param area BufferRAM area | ||
411 | * @param buffer the databuffer to put/get data | ||
412 | * @param offset offset to read from or write to | ||
413 | * @param count number of bytes to read/write | ||
414 | * | ||
415 | * Write the BufferRAM area | ||
416 | */ | ||
417 | static int onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
418 | const unsigned char *buffer, int offset, size_t count) | ||
419 | { | ||
420 | struct onenand_chip *this = mtd->priv; | ||
421 | void __iomem *bufferram; | ||
422 | |||
423 | bufferram = this->base + area; | ||
424 | |||
425 | bufferram += onenand_bufferram_offset(mtd, area); | ||
426 | |||
427 | memcpy(bufferram + offset, buffer, count); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * onenand_check_bufferram - [GENERIC] Check BufferRAM information | ||
434 | * @param mtd MTD data structure | ||
435 | * @param addr address to check | ||
436 | * @return 1 if there are valid data, otherwise 0 | ||
437 | * | ||
438 | * Check bufferram if there is data we required | ||
439 | */ | ||
440 | static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) | ||
441 | { | ||
442 | struct onenand_chip *this = mtd->priv; | ||
443 | int block, page; | ||
444 | int i; | ||
445 | |||
446 | block = (int) (addr >> this->erase_shift); | ||
447 | page = (int) (addr >> this->page_shift); | ||
448 | page &= this->page_mask; | ||
449 | |||
450 | i = ONENAND_CURRENT_BUFFERRAM(this); | ||
451 | |||
452 | /* Is there valid data? */ | ||
453 | if (this->bufferram[i].block == block && | ||
454 | this->bufferram[i].page == page && | ||
455 | this->bufferram[i].valid) | ||
456 | return 1; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /** | ||
462 | * onenand_update_bufferram - [GENERIC] Update BufferRAM information | ||
463 | * @param mtd MTD data structure | ||
464 | * @param addr address to update | ||
465 | * @param valid valid flag | ||
466 | * | ||
467 | * Update BufferRAM information | ||
468 | */ | ||
469 | static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, | ||
470 | int valid) | ||
471 | { | ||
472 | struct onenand_chip *this = mtd->priv; | ||
473 | int block, page; | ||
474 | int i; | ||
475 | |||
476 | block = (int) (addr >> this->erase_shift); | ||
477 | page = (int) (addr >> this->page_shift); | ||
478 | page &= this->page_mask; | ||
479 | |||
480 | /* Invalidate BufferRAM */ | ||
481 | for (i = 0; i < MAX_BUFFERRAM; i++) { | ||
482 | if (this->bufferram[i].block == block && | ||
483 | this->bufferram[i].page == page) | ||
484 | this->bufferram[i].valid = 0; | ||
485 | } | ||
486 | |||
487 | /* Update BufferRAM */ | ||
488 | i = ONENAND_CURRENT_BUFFERRAM(this); | ||
489 | this->bufferram[i].block = block; | ||
490 | this->bufferram[i].page = page; | ||
491 | this->bufferram[i].valid = valid; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * onenand_get_device - [GENERIC] Get chip for selected access | ||
498 | * @param mtd MTD device structure | ||
499 | * @param new_state the state which is requested | ||
500 | * | ||
501 | * Get the device and lock it for exclusive access | ||
502 | */ | ||
503 | static int onenand_get_device(struct mtd_info *mtd, int new_state) | ||
504 | { | ||
505 | struct onenand_chip *this = mtd->priv; | ||
506 | DECLARE_WAITQUEUE(wait, current); | ||
507 | |||
508 | /* | ||
509 | * Grab the lock and see if the device is available | ||
510 | */ | ||
511 | while (1) { | ||
512 | spin_lock(&this->chip_lock); | ||
513 | if (this->state == FL_READY) { | ||
514 | this->state = new_state; | ||
515 | spin_unlock(&this->chip_lock); | ||
516 | break; | ||
517 | } | ||
518 | if (new_state == FL_PM_SUSPENDED) { | ||
519 | spin_unlock(&this->chip_lock); | ||
520 | return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; | ||
521 | } | ||
522 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
523 | add_wait_queue(&this->wq, &wait); | ||
524 | spin_unlock(&this->chip_lock); | ||
525 | schedule(); | ||
526 | remove_wait_queue(&this->wq, &wait); | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * onenand_release_device - [GENERIC] release chip | ||
534 | * @param mtd MTD device structure | ||
535 | * | ||
536 | * Deselect, release chip lock and wake up anyone waiting on the device | ||
537 | */ | ||
538 | static void onenand_release_device(struct mtd_info *mtd) | ||
539 | { | ||
540 | struct onenand_chip *this = mtd->priv; | ||
541 | |||
542 | /* Release the chip */ | ||
543 | spin_lock(&this->chip_lock); | ||
544 | this->state = FL_READY; | ||
545 | wake_up(&this->wq); | ||
546 | spin_unlock(&this->chip_lock); | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * onenand_read_ecc - [MTD Interface] Read data with ECC | ||
551 | * @param mtd MTD device structure | ||
552 | * @param from offset to read from | ||
553 | * @param len number of bytes to read | ||
554 | * @param retlen pointer to variable to store the number of read bytes | ||
555 | * @param buf the databuffer to put data | ||
556 | * @param oob_buf filesystem supplied oob data buffer | ||
557 | * @param oobsel oob selection structure | ||
558 | * | ||
559 | * OneNAND read with ECC | ||
560 | */ | ||
561 | static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
562 | size_t *retlen, u_char *buf, | ||
563 | u_char *oob_buf, struct nand_oobinfo *oobsel) | ||
564 | { | ||
565 | struct onenand_chip *this = mtd->priv; | ||
566 | int read = 0, column; | ||
567 | int thislen; | ||
568 | int ret = 0; | ||
569 | |||
570 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | ||
571 | |||
572 | /* Do not allow reads past end of device */ | ||
573 | if ((from + len) > mtd->size) { | ||
574 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); | ||
575 | *retlen = 0; | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | /* Grab the lock and see if the device is available */ | ||
580 | onenand_get_device(mtd, FL_READING); | ||
581 | |||
582 | /* TODO handling oob */ | ||
583 | |||
584 | while (read < len) { | ||
585 | thislen = min_t(int, mtd->oobblock, len - read); | ||
586 | |||
587 | column = from & (mtd->oobblock - 1); | ||
588 | if (column + thislen > mtd->oobblock) | ||
589 | thislen = mtd->oobblock - column; | ||
590 | |||
591 | if (!onenand_check_bufferram(mtd, from)) { | ||
592 | this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); | ||
593 | |||
594 | ret = this->wait(mtd, FL_READING); | ||
595 | /* First copy data and check return value for ECC handling */ | ||
596 | onenand_update_bufferram(mtd, from, 1); | ||
597 | } | ||
598 | |||
599 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
600 | |||
601 | read += thislen; | ||
602 | |||
603 | if (read == len) | ||
604 | break; | ||
605 | |||
606 | if (ret) { | ||
607 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); | ||
608 | goto out; | ||
609 | } | ||
610 | |||
611 | from += thislen; | ||
612 | buf += thislen; | ||
613 | } | ||
614 | |||
615 | out: | ||
616 | /* Deselect and wake up anyone waiting on the device */ | ||
617 | onenand_release_device(mtd); | ||
618 | |||
619 | /* | ||
620 | * Return success, if no ECC failures, else -EBADMSG | ||
621 | * fs driver will take care of that, because | ||
622 | * retlen == desired len and result == -EBADMSG | ||
623 | */ | ||
624 | *retlen = read; | ||
625 | return ret; | ||
626 | } | ||
627 | |||
628 | /** | ||
629 | * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc | ||
630 | * @param mtd MTD device structure | ||
631 | * @param from offset to read from | ||
632 | * @param len number of bytes to read | ||
633 | * @param retlen pointer to variable to store the number of read bytes | ||
634 | * @param buf the databuffer to put data | ||
635 | * | ||
636 | * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL | ||
637 | */ | ||
638 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
639 | size_t *retlen, u_char *buf) | ||
640 | { | ||
641 | return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
642 | } | ||
643 | |||
644 | /** | ||
645 | * onenand_read_oob - [MTD Interface] OneNAND read out-of-band | ||
646 | * @param mtd MTD device structure | ||
647 | * @param from offset to read from | ||
648 | * @param len number of bytes to read | ||
649 | * @param retlen pointer to variable to store the number of read bytes | ||
650 | * @param buf the databuffer to put data | ||
651 | * | ||
652 | * OneNAND read out-of-band data from the spare area | ||
653 | */ | ||
654 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | ||
655 | size_t *retlen, u_char *buf) | ||
656 | { | ||
657 | struct onenand_chip *this = mtd->priv; | ||
658 | int read = 0, thislen, column; | ||
659 | int ret = 0; | ||
660 | |||
661 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | ||
662 | |||
663 | /* Initialize return length value */ | ||
664 | *retlen = 0; | ||
665 | |||
666 | /* Do not allow reads past end of device */ | ||
667 | if (unlikely((from + len) > mtd->size)) { | ||
668 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | /* Grab the lock and see if the device is available */ | ||
673 | onenand_get_device(mtd, FL_READING); | ||
674 | |||
675 | column = from & (mtd->oobsize - 1); | ||
676 | |||
677 | while (read < len) { | ||
678 | thislen = mtd->oobsize - column; | ||
679 | thislen = min_t(int, thislen, len); | ||
680 | |||
681 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); | ||
682 | |||
683 | onenand_update_bufferram(mtd, from, 0); | ||
684 | |||
685 | ret = this->wait(mtd, FL_READING); | ||
686 | /* First copy data and check return value for ECC handling */ | ||
687 | |||
688 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | ||
689 | |||
690 | read += thislen; | ||
691 | |||
692 | if (read == len) | ||
693 | break; | ||
694 | |||
695 | if (ret) { | ||
696 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); | ||
697 | goto out; | ||
698 | } | ||
699 | |||
700 | buf += thislen; | ||
701 | |||
702 | /* Read more? */ | ||
703 | if (read < len) { | ||
704 | /* Page size */ | ||
705 | from += mtd->oobblock; | ||
706 | column = 0; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | out: | ||
711 | /* Deselect and wake up anyone waiting on the device */ | ||
712 | onenand_release_device(mtd); | ||
713 | |||
714 | *retlen = read; | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE | ||
719 | /** | ||
720 | * onenand_verify_page - [GENERIC] verify the chip contents after a write | ||
721 | * @param mtd MTD device structure | ||
722 | * @param buf the databuffer to verify | ||
723 | * | ||
724 | * Check DataRAM area directly | ||
725 | */ | ||
726 | static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | ||
727 | { | ||
728 | struct onenand_chip *this = mtd->priv; | ||
729 | void __iomem *dataram0, *dataram1; | ||
730 | int ret = 0; | ||
731 | |||
732 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); | ||
733 | |||
734 | ret = this->wait(mtd, FL_READING); | ||
735 | if (ret) | ||
736 | return ret; | ||
737 | |||
738 | onenand_update_bufferram(mtd, addr, 1); | ||
739 | |||
740 | /* Check, if the two dataram areas are same */ | ||
741 | dataram0 = this->base + ONENAND_DATARAM; | ||
742 | dataram1 = dataram0 + mtd->oobblock; | ||
743 | |||
744 | if (memcmp(dataram0, dataram1, mtd->oobblock)) | ||
745 | return -EBADMSG; | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | #else | ||
750 | #define onenand_verify_page(...) (0) | ||
751 | #endif | ||
752 | |||
753 | #define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) | ||
754 | |||
755 | /** | ||
756 | * onenand_write_ecc - [MTD Interface] OneNAND write with ECC | ||
757 | * @param mtd MTD device structure | ||
758 | * @param to offset to write to | ||
759 | * @param len number of bytes to write | ||
760 | * @param retlen pointer to variable to store the number of written bytes | ||
761 | * @param buf the data to write | ||
762 | * @param eccbuf filesystem supplied oob data buffer | ||
763 | * @param oobsel oob selection structure | ||
764 | * | ||
765 | * OneNAND write with ECC | ||
766 | */ | ||
767 | static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
768 | size_t *retlen, const u_char *buf, | ||
769 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
770 | { | ||
771 | struct onenand_chip *this = mtd->priv; | ||
772 | int written = 0; | ||
773 | int ret = 0; | ||
774 | |||
775 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | ||
776 | |||
777 | /* Initialize retlen, in case of early exit */ | ||
778 | *retlen = 0; | ||
779 | |||
780 | /* Do not allow writes past end of device */ | ||
781 | if (unlikely((to + len) > mtd->size)) { | ||
782 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | /* Reject writes, which are not page aligned */ | ||
787 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | ||
788 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | /* Grab the lock and see if the device is available */ | ||
793 | onenand_get_device(mtd, FL_WRITING); | ||
794 | |||
795 | /* Loop until all data write */ | ||
796 | while (written < len) { | ||
797 | int thislen = min_t(int, mtd->oobblock, len - written); | ||
798 | |||
799 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | ||
800 | |||
801 | this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); | ||
802 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
803 | |||
804 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | ||
805 | |||
806 | onenand_update_bufferram(mtd, to, 1); | ||
807 | |||
808 | ret = this->wait(mtd, FL_WRITING); | ||
809 | if (ret) { | ||
810 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); | ||
811 | goto out; | ||
812 | } | ||
813 | |||
814 | written += thislen; | ||
815 | |||
816 | /* Only check verify write turn on */ | ||
817 | ret = onenand_verify_page(mtd, (u_char *) buf, to); | ||
818 | if (ret) { | ||
819 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); | ||
820 | goto out; | ||
821 | } | ||
822 | |||
823 | if (written == len) | ||
824 | break; | ||
825 | |||
826 | to += thislen; | ||
827 | buf += thislen; | ||
828 | } | ||
829 | |||
830 | out: | ||
831 | /* Deselect and wake up anyone waiting on the device */ | ||
832 | onenand_release_device(mtd); | ||
833 | |||
834 | *retlen = written; | ||
835 | |||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | /** | ||
840 | * onenand_write - [MTD Interface] compability function for onenand_write_ecc | ||
841 | * @param mtd MTD device structure | ||
842 | * @param to offset to write to | ||
843 | * @param len number of bytes to write | ||
844 | * @param retlen pointer to variable to store the number of written bytes | ||
845 | * @param buf the data to write | ||
846 | * | ||
847 | * This function simply calls onenand_write_ecc | ||
848 | * with oob buffer and oobsel = NULL | ||
849 | */ | ||
850 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
851 | size_t *retlen, const u_char *buf) | ||
852 | { | ||
853 | return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * onenand_write_oob - [MTD Interface] OneNAND write out-of-band | ||
858 | * @param mtd MTD device structure | ||
859 | * @param to offset to write to | ||
860 | * @param len number of bytes to write | ||
861 | * @param retlen pointer to variable to store the number of written bytes | ||
862 | * @param buf the data to write | ||
863 | * | ||
864 | * OneNAND write out-of-band | ||
865 | */ | ||
866 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | ||
867 | size_t *retlen, const u_char *buf) | ||
868 | { | ||
869 | struct onenand_chip *this = mtd->priv; | ||
870 | int column, status; | ||
871 | int written = 0; | ||
872 | |||
873 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | ||
874 | |||
875 | /* Initialize retlen, in case of early exit */ | ||
876 | *retlen = 0; | ||
877 | |||
878 | /* Do not allow writes past end of device */ | ||
879 | if (unlikely((to + len) > mtd->size)) { | ||
880 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); | ||
881 | return -EINVAL; | ||
882 | } | ||
883 | |||
884 | /* Grab the lock and see if the device is available */ | ||
885 | onenand_get_device(mtd, FL_WRITING); | ||
886 | |||
887 | /* Loop until all data write */ | ||
888 | while (written < len) { | ||
889 | int thislen = min_t(int, mtd->oobsize, len - written); | ||
890 | |||
891 | column = to & (mtd->oobsize - 1); | ||
892 | |||
893 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); | ||
894 | |||
895 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
896 | this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | ||
897 | |||
898 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); | ||
899 | |||
900 | onenand_update_bufferram(mtd, to, 0); | ||
901 | |||
902 | status = this->wait(mtd, FL_WRITING); | ||
903 | if (status) | ||
904 | goto out; | ||
905 | |||
906 | written += thislen; | ||
907 | |||
908 | if (written == len) | ||
909 | break; | ||
910 | |||
911 | to += thislen; | ||
912 | buf += thislen; | ||
913 | } | ||
914 | |||
915 | out: | ||
916 | /* Deselect and wake up anyone waiting on the device */ | ||
917 | onenand_release_device(mtd); | ||
918 | |||
919 | *retlen = written; | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | /** | ||
925 | * onenand_writev_ecc - [MTD Interface] write with iovec with ecc | ||
926 | * @param mtd MTD device structure | ||
927 | * @param vecs the iovectors to write | ||
928 | * @param count number of vectors | ||
929 | * @param to offset to write to | ||
930 | * @param retlen pointer to variable to store the number of written bytes | ||
931 | * @param eccbuf filesystem supplied oob data buffer | ||
932 | * @param oobsel oob selection structure | ||
933 | * | ||
934 | * OneNAND write with iovec with ecc | ||
935 | */ | ||
936 | static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
937 | unsigned long count, loff_t to, size_t *retlen, | ||
938 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
939 | { | ||
940 | struct onenand_chip *this = mtd->priv; | ||
941 | unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf; | ||
942 | size_t total_len, len; | ||
943 | int i, written = 0; | ||
944 | int ret = 0; | ||
945 | |||
946 | /* Preset written len for early exit */ | ||
947 | *retlen = 0; | ||
948 | |||
949 | /* Calculate total length of data */ | ||
950 | total_len = 0; | ||
951 | for (i = 0; i < count; i++) | ||
952 | total_len += vecs[i].iov_len; | ||
953 | |||
954 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); | ||
955 | |||
956 | /* Do not allow write past end of the device */ | ||
957 | if (unlikely((to + total_len) > mtd->size)) { | ||
958 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | |||
962 | /* Reject writes, which are not page aligned */ | ||
963 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { | ||
964 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); | ||
965 | return -EINVAL; | ||
966 | } | ||
967 | |||
968 | /* Grab the lock and see if the device is available */ | ||
969 | onenand_get_device(mtd, FL_WRITING); | ||
970 | |||
971 | /* TODO handling oob */ | ||
972 | |||
973 | /* Loop until all keve's data has been written */ | ||
974 | len = 0; | ||
975 | while (count) { | ||
976 | pbuf = buffer; | ||
977 | /* | ||
978 | * If the given tuple is >= pagesize then | ||
979 | * write it out from the iov | ||
980 | */ | ||
981 | if ((vecs->iov_len - len) >= mtd->oobblock) { | ||
982 | pbuf = vecs->iov_base + len; | ||
983 | |||
984 | len += mtd->oobblock; | ||
985 | |||
986 | /* Check, if we have to switch to the next tuple */ | ||
987 | if (len >= (int) vecs->iov_len) { | ||
988 | vecs++; | ||
989 | len = 0; | ||
990 | count--; | ||
991 | } | ||
992 | } else { | ||
993 | int cnt = 0, thislen; | ||
994 | while (cnt < mtd->oobblock) { | ||
995 | thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len); | ||
996 | memcpy(buffer + cnt, vecs->iov_base + len, thislen); | ||
997 | cnt += thislen; | ||
998 | len += thislen; | ||
999 | |||
1000 | /* Check, if we have to switch to the next tuple */ | ||
1001 | if (len >= (int) vecs->iov_len) { | ||
1002 | vecs++; | ||
1003 | len = 0; | ||
1004 | count--; | ||
1005 | } | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | ||
1010 | |||
1011 | this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock); | ||
1012 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
1013 | |||
1014 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | ||
1015 | |||
1016 | onenand_update_bufferram(mtd, to, 1); | ||
1017 | |||
1018 | ret = this->wait(mtd, FL_WRITING); | ||
1019 | if (ret) { | ||
1020 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | /* Only check verify write turn on */ | ||
1026 | ret = onenand_verify_page(mtd, (u_char *) pbuf, to); | ||
1027 | if (ret) { | ||
1028 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); | ||
1029 | goto out; | ||
1030 | } | ||
1031 | |||
1032 | written += mtd->oobblock; | ||
1033 | |||
1034 | to += mtd->oobblock; | ||
1035 | } | ||
1036 | |||
1037 | out: | ||
1038 | /* Deselect and wakt up anyone waiting on the device */ | ||
1039 | onenand_release_device(mtd); | ||
1040 | |||
1041 | *retlen = written; | ||
1042 | |||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | /** | ||
1047 | * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc | ||
1048 | * @param mtd MTD device structure | ||
1049 | * @param vecs the iovectors to write | ||
1050 | * @param count number of vectors | ||
1051 | * @param to offset to write to | ||
1052 | * @param retlen pointer to variable to store the number of written bytes | ||
1053 | * | ||
1054 | * OneNAND write with kvec. This just calls the ecc function | ||
1055 | */ | ||
1056 | static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
1057 | unsigned long count, loff_t to, size_t *retlen) | ||
1058 | { | ||
1059 | return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * onenand_block_checkbad - [GENERIC] Check if a block is marked bad | ||
1064 | * @param mtd MTD device structure | ||
1065 | * @param ofs offset from device start | ||
1066 | * @param getchip 0, if the chip is already selected | ||
1067 | * @param allowbbt 1, if its allowed to access the bbt area | ||
1068 | * | ||
1069 | * Check, if the block is bad. Either by reading the bad block table or | ||
1070 | * calling of the scan function. | ||
1071 | */ | ||
1072 | static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) | ||
1073 | { | ||
1074 | struct onenand_chip *this = mtd->priv; | ||
1075 | struct bbm_info *bbm = this->bbm; | ||
1076 | |||
1077 | /* Return info from the table */ | ||
1078 | return bbm->isbad_bbt(mtd, ofs, allowbbt); | ||
1079 | } | ||
1080 | |||
1081 | /** | ||
1082 | * onenand_erase - [MTD Interface] erase block(s) | ||
1083 | * @param mtd MTD device structure | ||
1084 | * @param instr erase instruction | ||
1085 | * | ||
1086 | * Erase one ore more blocks | ||
1087 | */ | ||
1088 | static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
1089 | { | ||
1090 | struct onenand_chip *this = mtd->priv; | ||
1091 | unsigned int block_size; | ||
1092 | loff_t addr; | ||
1093 | int len; | ||
1094 | int ret = 0; | ||
1095 | |||
1096 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); | ||
1097 | |||
1098 | block_size = (1 << this->erase_shift); | ||
1099 | |||
1100 | /* Start address must align on block boundary */ | ||
1101 | if (unlikely(instr->addr & (block_size - 1))) { | ||
1102 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); | ||
1103 | return -EINVAL; | ||
1104 | } | ||
1105 | |||
1106 | /* Length must align on block boundary */ | ||
1107 | if (unlikely(instr->len & (block_size - 1))) { | ||
1108 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n"); | ||
1109 | return -EINVAL; | ||
1110 | } | ||
1111 | |||
1112 | /* Do not allow erase past end of device */ | ||
1113 | if (unlikely((instr->len + instr->addr) > mtd->size)) { | ||
1114 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | instr->fail_addr = 0xffffffff; | ||
1119 | |||
1120 | /* Grab the lock and see if the device is available */ | ||
1121 | onenand_get_device(mtd, FL_ERASING); | ||
1122 | |||
1123 | /* Loop throught the pages */ | ||
1124 | len = instr->len; | ||
1125 | addr = instr->addr; | ||
1126 | |||
1127 | instr->state = MTD_ERASING; | ||
1128 | |||
1129 | while (len) { | ||
1130 | |||
1131 | /* Check if we have a bad block, we do not erase bad blocks */ | ||
1132 | if (onenand_block_checkbad(mtd, addr, 0, 0)) { | ||
1133 | printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); | ||
1134 | instr->state = MTD_ERASE_FAILED; | ||
1135 | goto erase_exit; | ||
1136 | } | ||
1137 | |||
1138 | this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); | ||
1139 | |||
1140 | ret = this->wait(mtd, FL_ERASING); | ||
1141 | /* Check, if it is write protected */ | ||
1142 | if (ret) { | ||
1143 | if (ret == -EPERM) | ||
1144 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n"); | ||
1145 | else | ||
1146 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); | ||
1147 | instr->state = MTD_ERASE_FAILED; | ||
1148 | instr->fail_addr = addr; | ||
1149 | goto erase_exit; | ||
1150 | } | ||
1151 | |||
1152 | len -= block_size; | ||
1153 | addr += block_size; | ||
1154 | } | ||
1155 | |||
1156 | instr->state = MTD_ERASE_DONE; | ||
1157 | |||
1158 | erase_exit: | ||
1159 | |||
1160 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; | ||
1161 | /* Do call back function */ | ||
1162 | if (!ret) | ||
1163 | mtd_erase_callback(instr); | ||
1164 | |||
1165 | /* Deselect and wake up anyone waiting on the device */ | ||
1166 | onenand_release_device(mtd); | ||
1167 | |||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | /** | ||
1172 | * onenand_sync - [MTD Interface] sync | ||
1173 | * @param mtd MTD device structure | ||
1174 | * | ||
1175 | * Sync is actually a wait for chip ready function | ||
1176 | */ | ||
1177 | static void onenand_sync(struct mtd_info *mtd) | ||
1178 | { | ||
1179 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n"); | ||
1180 | |||
1181 | /* Grab the lock and see if the device is available */ | ||
1182 | onenand_get_device(mtd, FL_SYNCING); | ||
1183 | |||
1184 | /* Release it and go back */ | ||
1185 | onenand_release_device(mtd); | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | /** | ||
1190 | * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad | ||
1191 | * @param mtd MTD device structure | ||
1192 | * @param ofs offset relative to mtd start | ||
1193 | * | ||
1194 | * Check whether the block is bad | ||
1195 | */ | ||
1196 | static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) | ||
1197 | { | ||
1198 | /* Check for invalid offset */ | ||
1199 | if (ofs > mtd->size) | ||
1200 | return -EINVAL; | ||
1201 | |||
1202 | return onenand_block_checkbad(mtd, ofs, 1, 0); | ||
1203 | } | ||
1204 | |||
1205 | /** | ||
1206 | * onenand_default_block_markbad - [DEFAULT] mark a block bad | ||
1207 | * @param mtd MTD device structure | ||
1208 | * @param ofs offset from device start | ||
1209 | * | ||
1210 | * This is the default implementation, which can be overridden by | ||
1211 | * a hardware specific driver. | ||
1212 | */ | ||
1213 | static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
1214 | { | ||
1215 | struct onenand_chip *this = mtd->priv; | ||
1216 | struct bbm_info *bbm = this->bbm; | ||
1217 | u_char buf[2] = {0, 0}; | ||
1218 | size_t retlen; | ||
1219 | int block; | ||
1220 | |||
1221 | /* Get block number */ | ||
1222 | block = ((int) ofs) >> bbm->bbt_erase_shift; | ||
1223 | if (bbm->bbt) | ||
1224 | bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | ||
1225 | |||
1226 | /* We write two bytes, so we dont have to mess with 16 bit access */ | ||
1227 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); | ||
1228 | return mtd->write_oob(mtd, ofs , 2, &retlen, buf); | ||
1229 | } | ||
1230 | |||
1231 | /** | ||
1232 | * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad | ||
1233 | * @param mtd MTD device structure | ||
1234 | * @param ofs offset relative to mtd start | ||
1235 | * | ||
1236 | * Mark the block as bad | ||
1237 | */ | ||
1238 | static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
1239 | { | ||
1240 | struct onenand_chip *this = mtd->priv; | ||
1241 | int ret; | ||
1242 | |||
1243 | ret = onenand_block_isbad(mtd, ofs); | ||
1244 | if (ret) { | ||
1245 | /* If it was bad already, return success and do nothing */ | ||
1246 | if (ret > 0) | ||
1247 | return 0; | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | return this->block_markbad(mtd, ofs); | ||
1252 | } | ||
1253 | |||
1254 | /** | ||
1255 | * onenand_unlock - [MTD Interface] Unlock block(s) | ||
1256 | * @param mtd MTD device structure | ||
1257 | * @param ofs offset relative to mtd start | ||
1258 | * @param len number of bytes to unlock | ||
1259 | * | ||
1260 | * Unlock one or more blocks | ||
1261 | */ | ||
1262 | static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | ||
1263 | { | ||
1264 | struct onenand_chip *this = mtd->priv; | ||
1265 | int start, end, block, value, status; | ||
1266 | |||
1267 | start = ofs >> this->erase_shift; | ||
1268 | end = len >> this->erase_shift; | ||
1269 | |||
1270 | /* Continuous lock scheme */ | ||
1271 | if (this->options & ONENAND_CONT_LOCK) { | ||
1272 | /* Set start block address */ | ||
1273 | this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | ||
1274 | /* Set end block address */ | ||
1275 | this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); | ||
1276 | /* Write unlock command */ | ||
1277 | this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); | ||
1278 | |||
1279 | /* There's no return value */ | ||
1280 | this->wait(mtd, FL_UNLOCKING); | ||
1281 | |||
1282 | /* Sanity check */ | ||
1283 | while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) | ||
1284 | & ONENAND_CTRL_ONGO) | ||
1285 | continue; | ||
1286 | |||
1287 | /* Check lock status */ | ||
1288 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | ||
1289 | if (!(status & ONENAND_WP_US)) | ||
1290 | printk(KERN_ERR "wp status = 0x%x\n", status); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | /* Block lock scheme */ | ||
1296 | for (block = start; block < end; block++) { | ||
1297 | /* Set start block address */ | ||
1298 | this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | ||
1299 | /* Write unlock command */ | ||
1300 | this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); | ||
1301 | |||
1302 | /* There's no return value */ | ||
1303 | this->wait(mtd, FL_UNLOCKING); | ||
1304 | |||
1305 | /* Sanity check */ | ||
1306 | while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) | ||
1307 | & ONENAND_CTRL_ONGO) | ||
1308 | continue; | ||
1309 | |||
1310 | /* Set block address for read block status */ | ||
1311 | value = onenand_block_address(this, block); | ||
1312 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | ||
1313 | |||
1314 | /* Check lock status */ | ||
1315 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | ||
1316 | if (!(status & ONENAND_WP_US)) | ||
1317 | printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); | ||
1318 | } | ||
1319 | |||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /** | ||
1324 | * onenand_print_device_info - Print device ID | ||
1325 | * @param device device ID | ||
1326 | * | ||
1327 | * Print device ID | ||
1328 | */ | ||
1329 | static void onenand_print_device_info(int device) | ||
1330 | { | ||
1331 | int vcc, demuxed, ddp, density; | ||
1332 | |||
1333 | vcc = device & ONENAND_DEVICE_VCC_MASK; | ||
1334 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; | ||
1335 | ddp = device & ONENAND_DEVICE_IS_DDP; | ||
1336 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
1337 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", | ||
1338 | demuxed ? "" : "Muxed ", | ||
1339 | ddp ? "(DDP)" : "", | ||
1340 | (16 << density), | ||
1341 | vcc ? "2.65/3.3" : "1.8", | ||
1342 | device); | ||
1343 | } | ||
1344 | |||
1345 | static const struct onenand_manufacturers onenand_manuf_ids[] = { | ||
1346 | {ONENAND_MFR_SAMSUNG, "Samsung"}, | ||
1347 | {ONENAND_MFR_UNKNOWN, "Unknown"} | ||
1348 | }; | ||
1349 | |||
1350 | /** | ||
1351 | * onenand_check_maf - Check manufacturer ID | ||
1352 | * @param manuf manufacturer ID | ||
1353 | * | ||
1354 | * Check manufacturer ID | ||
1355 | */ | ||
1356 | static int onenand_check_maf(int manuf) | ||
1357 | { | ||
1358 | int i; | ||
1359 | |||
1360 | for (i = 0; onenand_manuf_ids[i].id; i++) { | ||
1361 | if (manuf == onenand_manuf_ids[i].id) | ||
1362 | break; | ||
1363 | } | ||
1364 | |||
1365 | printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", | ||
1366 | onenand_manuf_ids[i].name, manuf); | ||
1367 | |||
1368 | return (i != ONENAND_MFR_UNKNOWN); | ||
1369 | } | ||
1370 | |||
1371 | /** | ||
1372 | * onenand_probe - [OneNAND Interface] Probe the OneNAND device | ||
1373 | * @param mtd MTD device structure | ||
1374 | * | ||
1375 | * OneNAND detection method: | ||
1376 | * Compare the the values from command with ones from register | ||
1377 | */ | ||
1378 | static int onenand_probe(struct mtd_info *mtd) | ||
1379 | { | ||
1380 | struct onenand_chip *this = mtd->priv; | ||
1381 | int bram_maf_id, bram_dev_id, maf_id, dev_id; | ||
1382 | int version_id; | ||
1383 | int density; | ||
1384 | |||
1385 | /* Send the command for reading device ID from BootRAM */ | ||
1386 | this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); | ||
1387 | |||
1388 | /* Read manufacturer and device IDs from BootRAM */ | ||
1389 | bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0); | ||
1390 | bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2); | ||
1391 | |||
1392 | /* Check manufacturer ID */ | ||
1393 | if (onenand_check_maf(bram_maf_id)) | ||
1394 | return -ENXIO; | ||
1395 | |||
1396 | /* Reset OneNAND to read default register values */ | ||
1397 | this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); | ||
1398 | |||
1399 | /* Read manufacturer and device IDs from Register */ | ||
1400 | maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); | ||
1401 | dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); | ||
1402 | |||
1403 | /* Check OneNAND device */ | ||
1404 | if (maf_id != bram_maf_id || dev_id != bram_dev_id) | ||
1405 | return -ENXIO; | ||
1406 | |||
1407 | /* Flash device information */ | ||
1408 | onenand_print_device_info(dev_id); | ||
1409 | this->device_id = dev_id; | ||
1410 | |||
1411 | density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
1412 | this->chipsize = (16 << density) << 20; | ||
1413 | /* Set density mask. it is used for DDP */ | ||
1414 | this->density_mask = (1 << (density + 6)); | ||
1415 | |||
1416 | /* OneNAND page size & block size */ | ||
1417 | /* The data buffer size is equal to page size */ | ||
1418 | mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); | ||
1419 | mtd->oobsize = mtd->oobblock >> 5; | ||
1420 | /* Pagers per block is always 64 in OneNAND */ | ||
1421 | mtd->erasesize = mtd->oobblock << 6; | ||
1422 | |||
1423 | this->erase_shift = ffs(mtd->erasesize) - 1; | ||
1424 | this->page_shift = ffs(mtd->oobblock) - 1; | ||
1425 | this->ppb_shift = (this->erase_shift - this->page_shift); | ||
1426 | this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; | ||
1427 | |||
1428 | /* REVIST: Multichip handling */ | ||
1429 | |||
1430 | mtd->size = this->chipsize; | ||
1431 | |||
1432 | /* Version ID */ | ||
1433 | version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); | ||
1434 | printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); | ||
1435 | |||
1436 | /* Lock scheme */ | ||
1437 | if (density <= ONENAND_DEVICE_DENSITY_512Mb && | ||
1438 | !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { | ||
1439 | printk(KERN_INFO "Lock scheme is Continues Lock\n"); | ||
1440 | this->options |= ONENAND_CONT_LOCK; | ||
1441 | } | ||
1442 | |||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | /** | ||
1447 | * onenand_suspend - [MTD Interface] Suspend the OneNAND flash | ||
1448 | * @param mtd MTD device structure | ||
1449 | */ | ||
1450 | static int onenand_suspend(struct mtd_info *mtd) | ||
1451 | { | ||
1452 | return onenand_get_device(mtd, FL_PM_SUSPENDED); | ||
1453 | } | ||
1454 | |||
1455 | /** | ||
1456 | * onenand_resume - [MTD Interface] Resume the OneNAND flash | ||
1457 | * @param mtd MTD device structure | ||
1458 | */ | ||
1459 | static void onenand_resume(struct mtd_info *mtd) | ||
1460 | { | ||
1461 | struct onenand_chip *this = mtd->priv; | ||
1462 | |||
1463 | if (this->state == FL_PM_SUSPENDED) | ||
1464 | onenand_release_device(mtd); | ||
1465 | else | ||
1466 | printk(KERN_ERR "resume() called for the chip which is not" | ||
1467 | "in suspended state\n"); | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | /** | ||
1472 | * onenand_scan - [OneNAND Interface] Scan for the OneNAND device | ||
1473 | * @param mtd MTD device structure | ||
1474 | * @param maxchips Number of chips to scan for | ||
1475 | * | ||
1476 | * This fills out all the not initialized function pointers | ||
1477 | * with the defaults. | ||
1478 | * The flash ID is read and the mtd/chip structures are | ||
1479 | * filled with the appropriate values. | ||
1480 | */ | ||
1481 | int onenand_scan(struct mtd_info *mtd, int maxchips) | ||
1482 | { | ||
1483 | struct onenand_chip *this = mtd->priv; | ||
1484 | |||
1485 | if (!this->read_word) | ||
1486 | this->read_word = onenand_readw; | ||
1487 | if (!this->write_word) | ||
1488 | this->write_word = onenand_writew; | ||
1489 | |||
1490 | if (!this->command) | ||
1491 | this->command = onenand_command; | ||
1492 | if (!this->wait) | ||
1493 | this->wait = onenand_wait; | ||
1494 | |||
1495 | if (!this->read_bufferram) | ||
1496 | this->read_bufferram = onenand_read_bufferram; | ||
1497 | if (!this->write_bufferram) | ||
1498 | this->write_bufferram = onenand_write_bufferram; | ||
1499 | |||
1500 | if (!this->block_markbad) | ||
1501 | this->block_markbad = onenand_default_block_markbad; | ||
1502 | if (!this->scan_bbt) | ||
1503 | this->scan_bbt = onenand_default_bbt; | ||
1504 | |||
1505 | if (onenand_probe(mtd)) | ||
1506 | return -ENXIO; | ||
1507 | |||
1508 | /* Set Sync. Burst Read after probing */ | ||
1509 | if (this->mmcontrol) { | ||
1510 | printk(KERN_INFO "OneNAND Sync. Burst Read support\n"); | ||
1511 | this->read_bufferram = onenand_sync_read_bufferram; | ||
1512 | } | ||
1513 | |||
1514 | this->state = FL_READY; | ||
1515 | init_waitqueue_head(&this->wq); | ||
1516 | spin_lock_init(&this->chip_lock); | ||
1517 | |||
1518 | switch (mtd->oobsize) { | ||
1519 | case 64: | ||
1520 | this->autooob = &onenand_oob_64; | ||
1521 | break; | ||
1522 | |||
1523 | case 32: | ||
1524 | this->autooob = &onenand_oob_32; | ||
1525 | break; | ||
1526 | |||
1527 | default: | ||
1528 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", | ||
1529 | mtd->oobsize); | ||
1530 | /* To prevent kernel oops */ | ||
1531 | this->autooob = &onenand_oob_32; | ||
1532 | break; | ||
1533 | } | ||
1534 | |||
1535 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | ||
1536 | |||
1537 | /* Fill in remaining MTD driver data */ | ||
1538 | mtd->type = MTD_NANDFLASH; | ||
1539 | mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; | ||
1540 | mtd->ecctype = MTD_ECC_SW; | ||
1541 | mtd->erase = onenand_erase; | ||
1542 | mtd->point = NULL; | ||
1543 | mtd->unpoint = NULL; | ||
1544 | mtd->read = onenand_read; | ||
1545 | mtd->write = onenand_write; | ||
1546 | mtd->read_ecc = onenand_read_ecc; | ||
1547 | mtd->write_ecc = onenand_write_ecc; | ||
1548 | mtd->read_oob = onenand_read_oob; | ||
1549 | mtd->write_oob = onenand_write_oob; | ||
1550 | mtd->readv = NULL; | ||
1551 | mtd->readv_ecc = NULL; | ||
1552 | mtd->writev = onenand_writev; | ||
1553 | mtd->writev_ecc = onenand_writev_ecc; | ||
1554 | mtd->sync = onenand_sync; | ||
1555 | mtd->lock = NULL; | ||
1556 | mtd->unlock = onenand_unlock; | ||
1557 | mtd->suspend = onenand_suspend; | ||
1558 | mtd->resume = onenand_resume; | ||
1559 | mtd->block_isbad = onenand_block_isbad; | ||
1560 | mtd->block_markbad = onenand_block_markbad; | ||
1561 | mtd->owner = THIS_MODULE; | ||
1562 | |||
1563 | /* Unlock whole block */ | ||
1564 | mtd->unlock(mtd, 0x0, this->chipsize); | ||
1565 | |||
1566 | return this->scan_bbt(mtd); | ||
1567 | } | ||
1568 | |||
1569 | /** | ||
1570 | * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device | ||
1571 | * @param mtd MTD device structure | ||
1572 | */ | ||
1573 | void onenand_release(struct mtd_info *mtd) | ||
1574 | { | ||
1575 | #ifdef CONFIG_MTD_PARTITIONS | ||
1576 | /* Deregister partitions */ | ||
1577 | del_mtd_partitions (mtd); | ||
1578 | #endif | ||
1579 | /* Deregister the device */ | ||
1580 | del_mtd_device (mtd); | ||
1581 | } | ||
1582 | |||
1583 | EXPORT_SYMBOL_GPL(onenand_scan); | ||
1584 | EXPORT_SYMBOL_GPL(onenand_release); | ||
1585 | |||
1586 | MODULE_LICENSE("GPL"); | ||
1587 | MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); | ||
1588 | MODULE_DESCRIPTION("Generic OneNAND flash driver code"); | ||
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c new file mode 100644 index 000000000000..f40190f499e1 --- /dev/null +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/onenand_bbt.c | ||
3 | * | ||
4 | * Bad Block Table support for the OneNAND driver | ||
5 | * | ||
6 | * Copyright(c) 2005 Samsung Electronics | ||
7 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
8 | * | ||
9 | * Derived from nand_bbt.c | ||
10 | * | ||
11 | * TODO: | ||
12 | * Split BBT core and chip specific BBT. | ||
13 | */ | ||
14 | |||
15 | #include <linux/slab.h> | ||
16 | #include <linux/mtd/mtd.h> | ||
17 | #include <linux/mtd/onenand.h> | ||
18 | #include <linux/mtd/compatmac.h> | ||
19 | |||
20 | /** | ||
21 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | ||
22 | * @param buf the buffer to search | ||
23 | * @param len the length of buffer to search | ||
24 | * @param paglen the pagelength | ||
25 | * @param td search pattern descriptor | ||
26 | * | ||
27 | * Check for a pattern at the given place. Used to search bad block | ||
28 | * tables and good / bad block identifiers. Same as check_pattern, but | ||
29 | * no optional empty check and the pattern is expected to start | ||
30 | * at offset 0. | ||
31 | * | ||
32 | */ | ||
33 | static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) | ||
34 | { | ||
35 | int i; | ||
36 | uint8_t *p = buf; | ||
37 | |||
38 | /* Compare the pattern */ | ||
39 | for (i = 0; i < td->len; i++) { | ||
40 | if (p[i] != td->pattern[i]) | ||
41 | return -1; | ||
42 | } | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * create_bbt - [GENERIC] Create a bad block table by scanning the device | ||
48 | * @param mtd MTD device structure | ||
49 | * @param buf temporary buffer | ||
50 | * @param bd descriptor for the good/bad block search pattern | ||
51 | * @param chip create the table for a specific chip, -1 read all chips. | ||
52 | * Applies only if NAND_BBT_PERCHIP option is set | ||
53 | * | ||
54 | * Create a bad block table by scanning the device | ||
55 | * for the given good/bad block identify pattern | ||
56 | */ | ||
57 | static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | ||
58 | { | ||
59 | struct onenand_chip *this = mtd->priv; | ||
60 | struct bbm_info *bbm = this->bbm; | ||
61 | int i, j, numblocks, len, scanlen; | ||
62 | int startblock; | ||
63 | loff_t from; | ||
64 | size_t readlen, ooblen; | ||
65 | |||
66 | printk(KERN_INFO "Scanning device for bad blocks\n"); | ||
67 | |||
68 | len = 1; | ||
69 | |||
70 | /* We need only read few bytes from the OOB area */ | ||
71 | scanlen = ooblen = 0; | ||
72 | readlen = bd->len; | ||
73 | |||
74 | /* chip == -1 case only */ | ||
75 | /* Note that numblocks is 2 * (real numblocks) here; | ||
76 | * see i += 2 below as it makses shifting and masking less painful | ||
77 | */ | ||
78 | numblocks = mtd->size >> (bbm->bbt_erase_shift - 1); | ||
79 | startblock = 0; | ||
80 | from = 0; | ||
81 | |||
82 | for (i = startblock; i < numblocks; ) { | ||
83 | int ret; | ||
84 | |||
85 | for (j = 0; j < len; j++) { | ||
86 | size_t retlen; | ||
87 | |||
88 | /* No need to read pages fully, | ||
89 | * just read required OOB bytes */ | ||
90 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, | ||
91 | readlen, &retlen, &buf[0]); | ||
92 | |||
93 | if (ret) | ||
94 | return ret; | ||
95 | |||
96 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | ||
97 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
98 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
99 | i >> 1, (unsigned int) from); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | i += 2; | ||
104 | from += (1 << bbm->bbt_erase_shift); | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | |||
111 | /** | ||
112 | * onenand_memory_bbt - [GENERIC] create a memory based bad block table | ||
113 | * @param mtd MTD device structure | ||
114 | * @param bd descriptor for the good/bad block search pattern | ||
115 | * | ||
116 | * The function creates a memory based bbt by scanning the device | ||
117 | * for manufacturer / software marked good / bad blocks | ||
118 | */ | ||
119 | static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | ||
120 | { | ||
121 | unsigned char data_buf[MAX_ONENAND_PAGESIZE]; | ||
122 | |||
123 | bd->options &= ~NAND_BBT_SCANEMPTY; | ||
124 | return create_bbt(mtd, data_buf, bd, -1); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad | ||
129 | * @param mtd MTD device structure | ||
130 | * @param offs offset in the device | ||
131 | * @param allowbbt allow access to bad block table region | ||
132 | */ | ||
133 | static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) | ||
134 | { | ||
135 | struct onenand_chip *this = mtd->priv; | ||
136 | struct bbm_info *bbm = this->bbm; | ||
137 | int block; | ||
138 | uint8_t res; | ||
139 | |||
140 | /* Get block number * 2 */ | ||
141 | block = (int) (offs >> (bbm->bbt_erase_shift - 1)); | ||
142 | res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; | ||
143 | |||
144 | DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", | ||
145 | (unsigned int) offs, block >> 1, res); | ||
146 | |||
147 | switch ((int) res) { | ||
148 | case 0x00: return 0; | ||
149 | case 0x01: return 1; | ||
150 | case 0x02: return allowbbt ? 0 : 1; | ||
151 | } | ||
152 | |||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s) | ||
158 | * @param mtd MTD device structure | ||
159 | * @param bd descriptor for the good/bad block search pattern | ||
160 | * | ||
161 | * The function checks, if a bad block table(s) is/are already | ||
162 | * available. If not it scans the device for manufacturer | ||
163 | * marked good / bad blocks and writes the bad block table(s) to | ||
164 | * the selected place. | ||
165 | * | ||
166 | * The bad block table memory is allocated here. It must be freed | ||
167 | * by calling the onenand_free_bbt function. | ||
168 | * | ||
169 | */ | ||
170 | int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) | ||
171 | { | ||
172 | struct onenand_chip *this = mtd->priv; | ||
173 | struct bbm_info *bbm = this->bbm; | ||
174 | int len, ret = 0; | ||
175 | |||
176 | len = mtd->size >> (this->erase_shift + 2); | ||
177 | /* Allocate memory (2bit per block) */ | ||
178 | bbm->bbt = kmalloc(len, GFP_KERNEL); | ||
179 | if (!bbm->bbt) { | ||
180 | printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); | ||
181 | return -ENOMEM; | ||
182 | } | ||
183 | /* Clear the memory bad block table */ | ||
184 | memset(bbm->bbt, 0x00, len); | ||
185 | |||
186 | /* Set the bad block position */ | ||
187 | bbm->badblockpos = ONENAND_BADBLOCK_POS; | ||
188 | |||
189 | /* Set erase shift */ | ||
190 | bbm->bbt_erase_shift = this->erase_shift; | ||
191 | |||
192 | if (!bbm->isbad_bbt) | ||
193 | bbm->isbad_bbt = onenand_isbad_bbt; | ||
194 | |||
195 | /* Scan the device to build a memory based bad block table */ | ||
196 | if ((ret = onenand_memory_bbt(mtd, bd))) { | ||
197 | printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n"); | ||
198 | kfree(bbm->bbt); | ||
199 | bbm->bbt = NULL; | ||
200 | } | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Define some generic bad / good block scan pattern which are used | ||
207 | * while scanning a device for factory marked good / bad blocks. | ||
208 | */ | ||
209 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
210 | |||
211 | static struct nand_bbt_descr largepage_memorybased = { | ||
212 | .options = 0, | ||
213 | .offs = 0, | ||
214 | .len = 2, | ||
215 | .pattern = scan_ff_pattern, | ||
216 | }; | ||
217 | |||
218 | /** | ||
219 | * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device | ||
220 | * @param mtd MTD device structure | ||
221 | * | ||
222 | * This function selects the default bad block table | ||
223 | * support for the device and calls the onenand_scan_bbt function | ||
224 | */ | ||
225 | int onenand_default_bbt(struct mtd_info *mtd) | ||
226 | { | ||
227 | struct onenand_chip *this = mtd->priv; | ||
228 | struct bbm_info *bbm; | ||
229 | |||
230 | this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL); | ||
231 | if (!this->bbm) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | bbm = this->bbm; | ||
235 | |||
236 | memset(bbm, 0, sizeof(struct bbm_info)); | ||
237 | |||
238 | /* 1KB page has same configuration as 2KB page */ | ||
239 | if (!bbm->badblock_pattern) | ||
240 | bbm->badblock_pattern = &largepage_memorybased; | ||
241 | |||
242 | return onenand_scan_bbt(mtd, bbm->badblock_pattern); | ||
243 | } | ||
244 | |||
245 | EXPORT_SYMBOL(onenand_scan_bbt); | ||
246 | EXPORT_SYMBOL(onenand_default_bbt); | ||
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 13f9e992bef8..7b7ca5ab5ae4 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $ | 2 | * $Id: redboot.c,v 1.18 2005/11/07 11:14:21 gleixner Exp $ |
3 | * | 3 | * |
4 | * Parse RedBoot-style Flash Image System (FIS) tables and | 4 | * Parse RedBoot-style Flash Image System (FIS) tables and |
5 | * produce a Linux partition array to match. | 5 | * produce a Linux partition array to match. |
@@ -39,7 +39,7 @@ static inline int redboot_checksum(struct fis_image_desc *img) | |||
39 | return 1; | 39 | return 1; |
40 | } | 40 | } |
41 | 41 | ||
42 | static int parse_redboot_partitions(struct mtd_info *master, | 42 | static int parse_redboot_partitions(struct mtd_info *master, |
43 | struct mtd_partition **pparts, | 43 | struct mtd_partition **pparts, |
44 | unsigned long fis_origin) | 44 | unsigned long fis_origin) |
45 | { | 45 | { |
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c new file mode 100644 index 000000000000..041ee59ea77d --- /dev/null +++ b/drivers/mtd/rfd_ftl.c | |||
@@ -0,0 +1,855 @@ | |||
1 | /* | ||
2 | * rfd_ftl.c -- resident flash disk (flash translation layer) | ||
3 | * | ||
4 | * Copyright (C) 2005 Sean Young <sean@mess.org> | ||
5 | * | ||
6 | * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $ | ||
7 | * | ||
8 | * This type of flash translation layer (FTL) is used by the Embedded BIOS | ||
9 | * by General Software. It is known as the Resident Flash Disk (RFD), see: | ||
10 | * | ||
11 | * http://www.gensw.com/pages/prod/bios/rfd.htm | ||
12 | * | ||
13 | * based on ftl.c | ||
14 | */ | ||
15 | |||
16 | #include <linux/hdreg.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/blktrans.h> | ||
19 | #include <linux/mtd/mtd.h> | ||
20 | #include <linux/vmalloc.h> | ||
21 | |||
22 | #include <asm/types.h> | ||
23 | |||
24 | #define const_cpu_to_le16 __constant_cpu_to_le16 | ||
25 | |||
26 | static int block_size = 0; | ||
27 | module_param(block_size, int, 0); | ||
28 | MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); | ||
29 | |||
30 | #define PREFIX "rfd_ftl: " | ||
31 | |||
32 | /* Major device # for FTL device */ | ||
33 | |||
34 | /* A request for this major has been sent to device@lanana.org */ | ||
35 | #ifndef RFD_FTL_MAJOR | ||
36 | #define RFD_FTL_MAJOR 95 | ||
37 | #endif | ||
38 | |||
39 | /* Maximum number of partitions in an FTL region */ | ||
40 | #define PART_BITS 4 | ||
41 | |||
42 | /* An erase unit should start with this value */ | ||
43 | #define RFD_MAGIC 0x9193 | ||
44 | |||
45 | /* the second value is 0xffff or 0xffc8; function unknown */ | ||
46 | |||
47 | /* the third value is always 0xffff, ignored */ | ||
48 | |||
49 | /* next is an array of mapping for each corresponding sector */ | ||
50 | #define HEADER_MAP_OFFSET 3 | ||
51 | #define SECTOR_DELETED 0x0000 | ||
52 | #define SECTOR_ZERO 0xfffe | ||
53 | #define SECTOR_FREE 0xffff | ||
54 | |||
55 | #define SECTOR_SIZE 512 | ||
56 | |||
57 | #define SECTORS_PER_TRACK 63 | ||
58 | |||
59 | struct block { | ||
60 | enum { | ||
61 | BLOCK_OK, | ||
62 | BLOCK_ERASING, | ||
63 | BLOCK_ERASED, | ||
64 | BLOCK_FAILED | ||
65 | } state; | ||
66 | int free_sectors; | ||
67 | int used_sectors; | ||
68 | int erases; | ||
69 | u_long offset; | ||
70 | }; | ||
71 | |||
72 | struct partition { | ||
73 | struct mtd_blktrans_dev mbd; | ||
74 | |||
75 | u_int block_size; /* size of erase unit */ | ||
76 | u_int total_blocks; /* number of erase units */ | ||
77 | u_int header_sectors_per_block; /* header sectors in erase unit */ | ||
78 | u_int data_sectors_per_block; /* data sectors in erase unit */ | ||
79 | u_int sector_count; /* sectors in translated disk */ | ||
80 | u_int header_size; /* bytes in header sector */ | ||
81 | int reserved_block; /* block next up for reclaim */ | ||
82 | int current_block; /* block to write to */ | ||
83 | u16 *header_cache; /* cached header */ | ||
84 | |||
85 | int is_reclaiming; | ||
86 | int cylinders; | ||
87 | int errors; | ||
88 | u_long *sector_map; | ||
89 | struct block *blocks; | ||
90 | }; | ||
91 | |||
92 | static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf); | ||
93 | |||
94 | static int build_block_map(struct partition *part, int block_no) | ||
95 | { | ||
96 | struct block *block = &part->blocks[block_no]; | ||
97 | int i; | ||
98 | |||
99 | block->offset = part->block_size * block_no; | ||
100 | |||
101 | if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) { | ||
102 | block->state = BLOCK_ERASED; /* assumption */ | ||
103 | block->free_sectors = part->data_sectors_per_block; | ||
104 | part->reserved_block = block_no; | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | block->state = BLOCK_OK; | ||
109 | |||
110 | for (i=0; i<part->data_sectors_per_block; i++) { | ||
111 | u16 entry; | ||
112 | |||
113 | entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]); | ||
114 | |||
115 | if (entry == SECTOR_DELETED) | ||
116 | continue; | ||
117 | |||
118 | if (entry == SECTOR_FREE) { | ||
119 | block->free_sectors++; | ||
120 | continue; | ||
121 | } | ||
122 | |||
123 | if (entry == SECTOR_ZERO) | ||
124 | entry = 0; | ||
125 | |||
126 | if (entry >= part->sector_count) { | ||
127 | printk(KERN_NOTICE PREFIX | ||
128 | "'%s': unit #%d: entry %d corrupt, " | ||
129 | "sector %d out of range\n", | ||
130 | part->mbd.mtd->name, block_no, i, entry); | ||
131 | continue; | ||
132 | } | ||
133 | |||
134 | if (part->sector_map[entry] != -1) { | ||
135 | printk(KERN_NOTICE PREFIX | ||
136 | "'%s': more than one entry for sector %d\n", | ||
137 | part->mbd.mtd->name, entry); | ||
138 | part->errors = 1; | ||
139 | continue; | ||
140 | } | ||
141 | |||
142 | part->sector_map[entry] = block->offset + | ||
143 | (i + part->header_sectors_per_block) * SECTOR_SIZE; | ||
144 | |||
145 | block->used_sectors++; | ||
146 | } | ||
147 | |||
148 | if (block->free_sectors == part->data_sectors_per_block) | ||
149 | part->reserved_block = block_no; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int scan_header(struct partition *part) | ||
155 | { | ||
156 | int sectors_per_block; | ||
157 | int i, rc = -ENOMEM; | ||
158 | int blocks_found; | ||
159 | size_t retlen; | ||
160 | |||
161 | sectors_per_block = part->block_size / SECTOR_SIZE; | ||
162 | part->total_blocks = part->mbd.mtd->size / part->block_size; | ||
163 | |||
164 | if (part->total_blocks < 2) | ||
165 | return -ENOENT; | ||
166 | |||
167 | /* each erase block has three bytes header, followed by the map */ | ||
168 | part->header_sectors_per_block = | ||
169 | ((HEADER_MAP_OFFSET + sectors_per_block) * | ||
170 | sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; | ||
171 | |||
172 | part->data_sectors_per_block = sectors_per_block - | ||
173 | part->header_sectors_per_block; | ||
174 | |||
175 | part->header_size = (HEADER_MAP_OFFSET + | ||
176 | part->data_sectors_per_block) * sizeof(u16); | ||
177 | |||
178 | part->cylinders = (part->data_sectors_per_block * | ||
179 | (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK; | ||
180 | |||
181 | part->sector_count = part->cylinders * SECTORS_PER_TRACK; | ||
182 | |||
183 | part->current_block = -1; | ||
184 | part->reserved_block = -1; | ||
185 | part->is_reclaiming = 0; | ||
186 | |||
187 | part->header_cache = kmalloc(part->header_size, GFP_KERNEL); | ||
188 | if (!part->header_cache) | ||
189 | goto err; | ||
190 | |||
191 | part->blocks = kcalloc(part->total_blocks, sizeof(struct block), | ||
192 | GFP_KERNEL); | ||
193 | if (!part->blocks) | ||
194 | goto err; | ||
195 | |||
196 | part->sector_map = vmalloc(part->sector_count * sizeof(u_long)); | ||
197 | if (!part->sector_map) { | ||
198 | printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " | ||
199 | "sector map", part->mbd.mtd->name); | ||
200 | goto err; | ||
201 | } | ||
202 | |||
203 | for (i=0; i<part->sector_count; i++) | ||
204 | part->sector_map[i] = -1; | ||
205 | |||
206 | for (i=0, blocks_found=0; i<part->total_blocks; i++) { | ||
207 | rc = part->mbd.mtd->read(part->mbd.mtd, | ||
208 | i * part->block_size, part->header_size, | ||
209 | &retlen, (u_char*)part->header_cache); | ||
210 | |||
211 | if (!rc && retlen != part->header_size) | ||
212 | rc = -EIO; | ||
213 | |||
214 | if (rc) | ||
215 | goto err; | ||
216 | |||
217 | if (!build_block_map(part, i)) | ||
218 | blocks_found++; | ||
219 | } | ||
220 | |||
221 | if (blocks_found == 0) { | ||
222 | printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n", | ||
223 | part->mbd.mtd->name); | ||
224 | rc = -ENOENT; | ||
225 | goto err; | ||
226 | } | ||
227 | |||
228 | if (part->reserved_block == -1) { | ||
229 | printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n", | ||
230 | part->mbd.mtd->name); | ||
231 | |||
232 | part->errors = 1; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | |||
237 | err: | ||
238 | vfree(part->sector_map); | ||
239 | kfree(part->header_cache); | ||
240 | kfree(part->blocks); | ||
241 | |||
242 | return rc; | ||
243 | } | ||
244 | |||
245 | static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) | ||
246 | { | ||
247 | struct partition *part = (struct partition*)dev; | ||
248 | u_long addr; | ||
249 | size_t retlen; | ||
250 | int rc; | ||
251 | |||
252 | if (sector >= part->sector_count) | ||
253 | return -EIO; | ||
254 | |||
255 | addr = part->sector_map[sector]; | ||
256 | if (addr != -1) { | ||
257 | rc = part->mbd.mtd->read(part->mbd.mtd, addr, SECTOR_SIZE, | ||
258 | &retlen, (u_char*)buf); | ||
259 | if (!rc && retlen != SECTOR_SIZE) | ||
260 | rc = -EIO; | ||
261 | |||
262 | if (rc) { | ||
263 | printk(KERN_WARNING PREFIX "error reading '%s' at " | ||
264 | "0x%lx\n", part->mbd.mtd->name, addr); | ||
265 | return rc; | ||
266 | } | ||
267 | } else | ||
268 | memset(buf, 0, SECTOR_SIZE); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static void erase_callback(struct erase_info *erase) | ||
274 | { | ||
275 | struct partition *part; | ||
276 | u16 magic; | ||
277 | int i, rc; | ||
278 | size_t retlen; | ||
279 | |||
280 | part = (struct partition*)erase->priv; | ||
281 | |||
282 | i = erase->addr / part->block_size; | ||
283 | if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { | ||
284 | printk(KERN_ERR PREFIX "erase callback for unknown offset %x " | ||
285 | "on '%s'\n", erase->addr, part->mbd.mtd->name); | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | if (erase->state != MTD_ERASE_DONE) { | ||
290 | printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " | ||
291 | "state %d\n", erase->addr, | ||
292 | part->mbd.mtd->name, erase->state); | ||
293 | |||
294 | part->blocks[i].state = BLOCK_FAILED; | ||
295 | part->blocks[i].free_sectors = 0; | ||
296 | part->blocks[i].used_sectors = 0; | ||
297 | |||
298 | kfree(erase); | ||
299 | |||
300 | return; | ||
301 | } | ||
302 | |||
303 | magic = const_cpu_to_le16(RFD_MAGIC); | ||
304 | |||
305 | part->blocks[i].state = BLOCK_ERASED; | ||
306 | part->blocks[i].free_sectors = part->data_sectors_per_block; | ||
307 | part->blocks[i].used_sectors = 0; | ||
308 | part->blocks[i].erases++; | ||
309 | |||
310 | rc = part->mbd.mtd->write(part->mbd.mtd, | ||
311 | part->blocks[i].offset, sizeof(magic), &retlen, | ||
312 | (u_char*)&magic); | ||
313 | |||
314 | if (!rc && retlen != sizeof(magic)) | ||
315 | rc = -EIO; | ||
316 | |||
317 | if (rc) { | ||
318 | printk(KERN_NOTICE PREFIX "'%s': unable to write RFD " | ||
319 | "header at 0x%lx\n", | ||
320 | part->mbd.mtd->name, | ||
321 | part->blocks[i].offset); | ||
322 | part->blocks[i].state = BLOCK_FAILED; | ||
323 | } | ||
324 | else | ||
325 | part->blocks[i].state = BLOCK_OK; | ||
326 | |||
327 | kfree(erase); | ||
328 | } | ||
329 | |||
330 | static int erase_block(struct partition *part, int block) | ||
331 | { | ||
332 | struct erase_info *erase; | ||
333 | int rc = -ENOMEM; | ||
334 | |||
335 | erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); | ||
336 | if (!erase) | ||
337 | goto err; | ||
338 | |||
339 | erase->mtd = part->mbd.mtd; | ||
340 | erase->callback = erase_callback; | ||
341 | erase->addr = part->blocks[block].offset; | ||
342 | erase->len = part->block_size; | ||
343 | erase->priv = (u_long)part; | ||
344 | |||
345 | part->blocks[block].state = BLOCK_ERASING; | ||
346 | part->blocks[block].free_sectors = 0; | ||
347 | |||
348 | rc = part->mbd.mtd->erase(part->mbd.mtd, erase); | ||
349 | |||
350 | if (rc) { | ||
351 | printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' " | ||
352 | "failed\n", erase->addr, erase->len, | ||
353 | part->mbd.mtd->name); | ||
354 | kfree(erase); | ||
355 | } | ||
356 | |||
357 | err: | ||
358 | return rc; | ||
359 | } | ||
360 | |||
361 | static int move_block_contents(struct partition *part, int block_no, u_long *old_sector) | ||
362 | { | ||
363 | void *sector_data; | ||
364 | u16 *map; | ||
365 | size_t retlen; | ||
366 | int i, rc = -ENOMEM; | ||
367 | |||
368 | part->is_reclaiming = 1; | ||
369 | |||
370 | sector_data = kmalloc(SECTOR_SIZE, GFP_KERNEL); | ||
371 | if (!sector_data) | ||
372 | goto err3; | ||
373 | |||
374 | map = kmalloc(part->header_size, GFP_KERNEL); | ||
375 | if (!map) | ||
376 | goto err2; | ||
377 | |||
378 | rc = part->mbd.mtd->read(part->mbd.mtd, | ||
379 | part->blocks[block_no].offset, part->header_size, | ||
380 | &retlen, (u_char*)map); | ||
381 | |||
382 | if (!rc && retlen != part->header_size) | ||
383 | rc = -EIO; | ||
384 | |||
385 | if (rc) { | ||
386 | printk(KERN_NOTICE PREFIX "error reading '%s' at " | ||
387 | "0x%lx\n", part->mbd.mtd->name, | ||
388 | part->blocks[block_no].offset); | ||
389 | |||
390 | goto err; | ||
391 | } | ||
392 | |||
393 | for (i=0; i<part->data_sectors_per_block; i++) { | ||
394 | u16 entry = le16_to_cpu(map[HEADER_MAP_OFFSET + i]); | ||
395 | u_long addr; | ||
396 | |||
397 | |||
398 | if (entry == SECTOR_FREE || entry == SECTOR_DELETED) | ||
399 | continue; | ||
400 | |||
401 | if (entry == SECTOR_ZERO) | ||
402 | entry = 0; | ||
403 | |||
404 | /* already warned about and ignored in build_block_map() */ | ||
405 | if (entry >= part->sector_count) | ||
406 | continue; | ||
407 | |||
408 | addr = part->blocks[block_no].offset + | ||
409 | (i + part->header_sectors_per_block) * SECTOR_SIZE; | ||
410 | |||
411 | if (*old_sector == addr) { | ||
412 | *old_sector = -1; | ||
413 | if (!part->blocks[block_no].used_sectors--) { | ||
414 | rc = erase_block(part, block_no); | ||
415 | break; | ||
416 | } | ||
417 | continue; | ||
418 | } | ||
419 | rc = part->mbd.mtd->read(part->mbd.mtd, addr, | ||
420 | SECTOR_SIZE, &retlen, sector_data); | ||
421 | |||
422 | if (!rc && retlen != SECTOR_SIZE) | ||
423 | rc = -EIO; | ||
424 | |||
425 | if (rc) { | ||
426 | printk(KERN_NOTICE PREFIX "'%s': Unable to " | ||
427 | "read sector for relocation\n", | ||
428 | part->mbd.mtd->name); | ||
429 | |||
430 | goto err; | ||
431 | } | ||
432 | |||
433 | rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part, | ||
434 | entry, sector_data); | ||
435 | |||
436 | if (rc) | ||
437 | goto err; | ||
438 | } | ||
439 | |||
440 | err: | ||
441 | kfree(map); | ||
442 | err2: | ||
443 | kfree(sector_data); | ||
444 | err3: | ||
445 | part->is_reclaiming = 0; | ||
446 | |||
447 | return rc; | ||
448 | } | ||
449 | |||
450 | static int reclaim_block(struct partition *part, u_long *old_sector) | ||
451 | { | ||
452 | int block, best_block, score, old_sector_block; | ||
453 | int rc; | ||
454 | |||
455 | /* we have a race if sync doesn't exist */ | ||
456 | if (part->mbd.mtd->sync) | ||
457 | part->mbd.mtd->sync(part->mbd.mtd); | ||
458 | |||
459 | score = 0x7fffffff; /* MAX_INT */ | ||
460 | best_block = -1; | ||
461 | if (*old_sector != -1) | ||
462 | old_sector_block = *old_sector / part->block_size; | ||
463 | else | ||
464 | old_sector_block = -1; | ||
465 | |||
466 | for (block=0; block<part->total_blocks; block++) { | ||
467 | int this_score; | ||
468 | |||
469 | if (block == part->reserved_block) | ||
470 | continue; | ||
471 | |||
472 | /* | ||
473 | * Postpone reclaiming if there is a free sector as | ||
474 | * more removed sectors is more efficient (have to move | ||
475 | * less). | ||
476 | */ | ||
477 | if (part->blocks[block].free_sectors) | ||
478 | return 0; | ||
479 | |||
480 | this_score = part->blocks[block].used_sectors; | ||
481 | |||
482 | if (block == old_sector_block) | ||
483 | this_score--; | ||
484 | else { | ||
485 | /* no point in moving a full block */ | ||
486 | if (part->blocks[block].used_sectors == | ||
487 | part->data_sectors_per_block) | ||
488 | continue; | ||
489 | } | ||
490 | |||
491 | this_score += part->blocks[block].erases; | ||
492 | |||
493 | if (this_score < score) { | ||
494 | best_block = block; | ||
495 | score = this_score; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | if (best_block == -1) | ||
500 | return -ENOSPC; | ||
501 | |||
502 | part->current_block = -1; | ||
503 | part->reserved_block = best_block; | ||
504 | |||
505 | pr_debug("reclaim_block: reclaiming block #%d with %d used " | ||
506 | "%d free sectors\n", best_block, | ||
507 | part->blocks[best_block].used_sectors, | ||
508 | part->blocks[best_block].free_sectors); | ||
509 | |||
510 | if (part->blocks[best_block].used_sectors) | ||
511 | rc = move_block_contents(part, best_block, old_sector); | ||
512 | else | ||
513 | rc = erase_block(part, best_block); | ||
514 | |||
515 | return rc; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * IMPROVE: It would be best to choose the block with the most deleted sectors, | ||
520 | * because if we fill that one up first it'll have the most chance of having | ||
521 | * the least live sectors at reclaim. | ||
522 | */ | ||
523 | static int find_free_block(const struct partition *part) | ||
524 | { | ||
525 | int block, stop; | ||
526 | |||
527 | block = part->current_block == -1 ? | ||
528 | jiffies % part->total_blocks : part->current_block; | ||
529 | stop = block; | ||
530 | |||
531 | do { | ||
532 | if (part->blocks[block].free_sectors && | ||
533 | block != part->reserved_block) | ||
534 | return block; | ||
535 | |||
536 | if (++block >= part->total_blocks) | ||
537 | block = 0; | ||
538 | |||
539 | } while (block != stop); | ||
540 | |||
541 | return -1; | ||
542 | } | ||
543 | |||
544 | static int find_writeable_block(struct partition *part, u_long *old_sector) | ||
545 | { | ||
546 | int rc, block; | ||
547 | size_t retlen; | ||
548 | |||
549 | block = find_free_block(part); | ||
550 | |||
551 | if (block == -1) { | ||
552 | if (!part->is_reclaiming) { | ||
553 | rc = reclaim_block(part, old_sector); | ||
554 | if (rc) | ||
555 | goto err; | ||
556 | |||
557 | block = find_free_block(part); | ||
558 | } | ||
559 | |||
560 | if (block == -1) { | ||
561 | rc = -ENOSPC; | ||
562 | goto err; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset, | ||
567 | part->header_size, &retlen, (u_char*)part->header_cache); | ||
568 | |||
569 | if (!rc && retlen != part->header_size) | ||
570 | rc = -EIO; | ||
571 | |||
572 | if (rc) { | ||
573 | printk(KERN_NOTICE PREFIX "'%s': unable to read header at " | ||
574 | "0x%lx\n", part->mbd.mtd->name, | ||
575 | part->blocks[block].offset); | ||
576 | goto err; | ||
577 | } | ||
578 | |||
579 | part->current_block = block; | ||
580 | |||
581 | err: | ||
582 | return rc; | ||
583 | } | ||
584 | |||
585 | static int mark_sector_deleted(struct partition *part, u_long old_addr) | ||
586 | { | ||
587 | int block, offset, rc; | ||
588 | u_long addr; | ||
589 | size_t retlen; | ||
590 | u16 del = const_cpu_to_le16(SECTOR_DELETED); | ||
591 | |||
592 | block = old_addr / part->block_size; | ||
593 | offset = (old_addr % part->block_size) / SECTOR_SIZE - | ||
594 | part->header_sectors_per_block; | ||
595 | |||
596 | addr = part->blocks[block].offset + | ||
597 | (HEADER_MAP_OFFSET + offset) * sizeof(u16); | ||
598 | rc = part->mbd.mtd->write(part->mbd.mtd, addr, | ||
599 | sizeof(del), &retlen, (u_char*)&del); | ||
600 | |||
601 | if (!rc && retlen != sizeof(del)) | ||
602 | rc = -EIO; | ||
603 | |||
604 | if (rc) { | ||
605 | printk(KERN_WARNING PREFIX "error writing '%s' at " | ||
606 | "0x%lx\n", part->mbd.mtd->name, addr); | ||
607 | if (rc) | ||
608 | goto err; | ||
609 | } | ||
610 | if (block == part->current_block) | ||
611 | part->header_cache[offset + HEADER_MAP_OFFSET] = del; | ||
612 | |||
613 | part->blocks[block].used_sectors--; | ||
614 | |||
615 | if (!part->blocks[block].used_sectors && | ||
616 | !part->blocks[block].free_sectors) | ||
617 | rc = erase_block(part, block); | ||
618 | |||
619 | err: | ||
620 | return rc; | ||
621 | } | ||
622 | |||
623 | static int find_free_sector(const struct partition *part, const struct block *block) | ||
624 | { | ||
625 | int i, stop; | ||
626 | |||
627 | i = stop = part->data_sectors_per_block - block->free_sectors; | ||
628 | |||
629 | do { | ||
630 | if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]) | ||
631 | == SECTOR_FREE) | ||
632 | return i; | ||
633 | |||
634 | if (++i == part->data_sectors_per_block) | ||
635 | i = 0; | ||
636 | } | ||
637 | while(i != stop); | ||
638 | |||
639 | return -1; | ||
640 | } | ||
641 | |||
642 | static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr) | ||
643 | { | ||
644 | struct partition *part = (struct partition*)dev; | ||
645 | struct block *block; | ||
646 | u_long addr; | ||
647 | int i; | ||
648 | int rc; | ||
649 | size_t retlen; | ||
650 | u16 entry; | ||
651 | |||
652 | if (part->current_block == -1 || | ||
653 | !part->blocks[part->current_block].free_sectors) { | ||
654 | |||
655 | rc = find_writeable_block(part, old_addr); | ||
656 | if (rc) | ||
657 | goto err; | ||
658 | } | ||
659 | |||
660 | block = &part->blocks[part->current_block]; | ||
661 | |||
662 | i = find_free_sector(part, block); | ||
663 | |||
664 | if (i < 0) { | ||
665 | rc = -ENOSPC; | ||
666 | goto err; | ||
667 | } | ||
668 | |||
669 | addr = (i + part->header_sectors_per_block) * SECTOR_SIZE + | ||
670 | block->offset; | ||
671 | rc = part->mbd.mtd->write(part->mbd.mtd, | ||
672 | addr, SECTOR_SIZE, &retlen, (u_char*)buf); | ||
673 | |||
674 | if (!rc && retlen != SECTOR_SIZE) | ||
675 | rc = -EIO; | ||
676 | |||
677 | if (rc) { | ||
678 | printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", | ||
679 | part->mbd.mtd->name, addr); | ||
680 | if (rc) | ||
681 | goto err; | ||
682 | } | ||
683 | |||
684 | part->sector_map[sector] = addr; | ||
685 | |||
686 | entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector); | ||
687 | |||
688 | part->header_cache[i + HEADER_MAP_OFFSET] = entry; | ||
689 | |||
690 | addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16); | ||
691 | rc = part->mbd.mtd->write(part->mbd.mtd, addr, | ||
692 | sizeof(entry), &retlen, (u_char*)&entry); | ||
693 | |||
694 | if (!rc && retlen != sizeof(entry)) | ||
695 | rc = -EIO; | ||
696 | |||
697 | if (rc) { | ||
698 | printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", | ||
699 | part->mbd.mtd->name, addr); | ||
700 | if (rc) | ||
701 | goto err; | ||
702 | } | ||
703 | block->used_sectors++; | ||
704 | block->free_sectors--; | ||
705 | |||
706 | err: | ||
707 | return rc; | ||
708 | } | ||
709 | |||
710 | static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) | ||
711 | { | ||
712 | struct partition *part = (struct partition*)dev; | ||
713 | u_long old_addr; | ||
714 | int i; | ||
715 | int rc = 0; | ||
716 | |||
717 | pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector); | ||
718 | |||
719 | if (part->reserved_block == -1) { | ||
720 | rc = -EACCES; | ||
721 | goto err; | ||
722 | } | ||
723 | |||
724 | if (sector >= part->sector_count) { | ||
725 | rc = -EIO; | ||
726 | goto err; | ||
727 | } | ||
728 | |||
729 | old_addr = part->sector_map[sector]; | ||
730 | |||
731 | for (i=0; i<SECTOR_SIZE; i++) { | ||
732 | if (!buf[i]) | ||
733 | continue; | ||
734 | |||
735 | rc = do_writesect(dev, sector, buf, &old_addr); | ||
736 | if (rc) | ||
737 | goto err; | ||
738 | break; | ||
739 | } | ||
740 | |||
741 | if (i == SECTOR_SIZE) | ||
742 | part->sector_map[sector] = -1; | ||
743 | |||
744 | if (old_addr != -1) | ||
745 | rc = mark_sector_deleted(part, old_addr); | ||
746 | |||
747 | err: | ||
748 | return rc; | ||
749 | } | ||
750 | |||
751 | static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) | ||
752 | { | ||
753 | struct partition *part = (struct partition*)dev; | ||
754 | |||
755 | geo->heads = 1; | ||
756 | geo->sectors = SECTORS_PER_TRACK; | ||
757 | geo->cylinders = part->cylinders; | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | ||
763 | { | ||
764 | struct partition *part; | ||
765 | |||
766 | if (mtd->type != MTD_NORFLASH) | ||
767 | return; | ||
768 | |||
769 | part = kcalloc(1, sizeof(struct partition), GFP_KERNEL); | ||
770 | if (!part) | ||
771 | return; | ||
772 | |||
773 | part->mbd.mtd = mtd; | ||
774 | |||
775 | if (block_size) | ||
776 | part->block_size = block_size; | ||
777 | else { | ||
778 | if (!mtd->erasesize) { | ||
779 | printk(KERN_NOTICE PREFIX "please provide block_size"); | ||
780 | return; | ||
781 | } | ||
782 | else | ||
783 | part->block_size = mtd->erasesize; | ||
784 | } | ||
785 | |||
786 | if (scan_header(part) == 0) { | ||
787 | part->mbd.size = part->sector_count; | ||
788 | part->mbd.blksize = SECTOR_SIZE; | ||
789 | part->mbd.tr = tr; | ||
790 | part->mbd.devnum = -1; | ||
791 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
792 | part->mbd.readonly = 1; | ||
793 | else if (part->errors) { | ||
794 | printk(KERN_NOTICE PREFIX "'%s': errors found, " | ||
795 | "setting read-only", mtd->name); | ||
796 | part->mbd.readonly = 1; | ||
797 | } | ||
798 | |||
799 | printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n", | ||
800 | mtd->name, mtd->type, mtd->flags); | ||
801 | |||
802 | if (!add_mtd_blktrans_dev((void*)part)) | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | kfree(part); | ||
807 | } | ||
808 | |||
809 | static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) | ||
810 | { | ||
811 | struct partition *part = (struct partition*)dev; | ||
812 | int i; | ||
813 | |||
814 | for (i=0; i<part->total_blocks; i++) { | ||
815 | pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n", | ||
816 | part->mbd.mtd->name, i, part->blocks[i].erases); | ||
817 | } | ||
818 | |||
819 | del_mtd_blktrans_dev(dev); | ||
820 | vfree(part->sector_map); | ||
821 | kfree(part->header_cache); | ||
822 | kfree(part->blocks); | ||
823 | kfree(part); | ||
824 | } | ||
825 | |||
826 | struct mtd_blktrans_ops rfd_ftl_tr = { | ||
827 | .name = "rfd", | ||
828 | .major = RFD_FTL_MAJOR, | ||
829 | .part_bits = PART_BITS, | ||
830 | .readsect = rfd_ftl_readsect, | ||
831 | .writesect = rfd_ftl_writesect, | ||
832 | .getgeo = rfd_ftl_getgeo, | ||
833 | .add_mtd = rfd_ftl_add_mtd, | ||
834 | .remove_dev = rfd_ftl_remove_dev, | ||
835 | .owner = THIS_MODULE, | ||
836 | }; | ||
837 | |||
838 | static int __init init_rfd_ftl(void) | ||
839 | { | ||
840 | return register_mtd_blktrans(&rfd_ftl_tr); | ||
841 | } | ||
842 | |||
843 | static void __exit cleanup_rfd_ftl(void) | ||
844 | { | ||
845 | deregister_mtd_blktrans(&rfd_ftl_tr); | ||
846 | } | ||
847 | |||
848 | module_init(init_rfd_ftl); | ||
849 | module_exit(cleanup_rfd_ftl); | ||
850 | |||
851 | MODULE_LICENSE("GPL"); | ||
852 | MODULE_AUTHOR("Sean Young <sean@mess.org>"); | ||
853 | MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, " | ||
854 | "used by General Software's Embedded BIOS"); | ||
855 | |||