diff options
Diffstat (limited to 'drivers')
39 files changed, 535 insertions, 316 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index b1f768917395..77414702cb00 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -53,9 +53,10 @@ config MTD_PARTITIONS | |||
53 | devices. Partitioning on NFTL 'devices' is a different - that's the | 53 | devices. Partitioning on NFTL 'devices' is a different - that's the |
54 | 'normal' form of partitioning used on a block device. | 54 | 'normal' form of partitioning used on a block device. |
55 | 55 | ||
56 | if MTD_PARTITIONS | ||
57 | |||
56 | config MTD_REDBOOT_PARTS | 58 | config MTD_REDBOOT_PARTS |
57 | tristate "RedBoot partition table parsing" | 59 | tristate "RedBoot partition table parsing" |
58 | depends on MTD_PARTITIONS | ||
59 | ---help--- | 60 | ---help--- |
60 | RedBoot is a ROM monitor and bootloader which deals with multiple | 61 | RedBoot is a ROM monitor and bootloader which deals with multiple |
61 | 'images' in flash devices by putting a table one of the erase | 62 | 'images' in flash devices by putting a table one of the erase |
@@ -72,9 +73,10 @@ config MTD_REDBOOT_PARTS | |||
72 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for | 73 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for |
73 | example. | 74 | example. |
74 | 75 | ||
76 | if MTD_REDBOOT_PARTS | ||
77 | |||
75 | config MTD_REDBOOT_DIRECTORY_BLOCK | 78 | config MTD_REDBOOT_DIRECTORY_BLOCK |
76 | int "Location of RedBoot partition table" | 79 | int "Location of RedBoot partition table" |
77 | depends on MTD_REDBOOT_PARTS | ||
78 | default "-1" | 80 | default "-1" |
79 | ---help--- | 81 | ---help--- |
80 | This option is the Linux counterpart to the | 82 | This option is the Linux counterpart to the |
@@ -91,18 +93,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK | |||
91 | 93 | ||
92 | config MTD_REDBOOT_PARTS_UNALLOCATED | 94 | config MTD_REDBOOT_PARTS_UNALLOCATED |
93 | bool "Include unallocated flash regions" | 95 | bool "Include unallocated flash regions" |
94 | depends on MTD_REDBOOT_PARTS | ||
95 | help | 96 | help |
96 | If you need to register each unallocated flash region as a MTD | 97 | If you need to register each unallocated flash region as a MTD |
97 | 'partition', enable this option. | 98 | 'partition', enable this option. |
98 | 99 | ||
99 | config MTD_REDBOOT_PARTS_READONLY | 100 | config MTD_REDBOOT_PARTS_READONLY |
100 | bool "Force read-only for RedBoot system images" | 101 | bool "Force read-only for RedBoot system images" |
101 | depends on MTD_REDBOOT_PARTS | ||
102 | help | 102 | help |
103 | If you need to force read-only for 'RedBoot', 'RedBoot Config' and | 103 | If you need to force read-only for 'RedBoot', 'RedBoot Config' and |
104 | 'FIS directory' images, enable this option. | 104 | 'FIS directory' images, enable this option. |
105 | 105 | ||
106 | endif # MTD_REDBOOT_PARTS | ||
107 | |||
106 | config MTD_CMDLINE_PARTS | 108 | config MTD_CMDLINE_PARTS |
107 | bool "Command line partition table parsing" | 109 | bool "Command line partition table parsing" |
108 | depends on MTD_PARTITIONS = "y" && MTD = "y" | 110 | depends on MTD_PARTITIONS = "y" && MTD = "y" |
@@ -142,7 +144,7 @@ config MTD_CMDLINE_PARTS | |||
142 | 144 | ||
143 | config MTD_AFS_PARTS | 145 | config MTD_AFS_PARTS |
144 | tristate "ARM Firmware Suite partition parsing" | 146 | tristate "ARM Firmware Suite partition parsing" |
145 | depends on ARM && MTD_PARTITIONS | 147 | depends on ARM |
146 | ---help--- | 148 | ---help--- |
147 | The ARM Firmware Suite allows the user to divide flash devices into | 149 | The ARM Firmware Suite allows the user to divide flash devices into |
148 | multiple 'images'. Each such image has a header containing its name | 150 | multiple 'images'. Each such image has a header containing its name |
@@ -158,8 +160,8 @@ config MTD_AFS_PARTS | |||
158 | example. | 160 | example. |
159 | 161 | ||
160 | config MTD_OF_PARTS | 162 | config MTD_OF_PARTS |
161 | tristate "Flash partition map based on OF description" | 163 | def_bool y |
162 | depends on OF && MTD_PARTITIONS | 164 | depends on OF |
163 | help | 165 | help |
164 | This provides a partition parsing function which derives | 166 | This provides a partition parsing function which derives |
165 | the partition map from the children of the flash node, | 167 | the partition map from the children of the flash node, |
@@ -167,10 +169,11 @@ config MTD_OF_PARTS | |||
167 | 169 | ||
168 | config MTD_AR7_PARTS | 170 | config MTD_AR7_PARTS |
169 | tristate "TI AR7 partitioning support" | 171 | tristate "TI AR7 partitioning support" |
170 | depends on MTD_PARTITIONS | ||
171 | ---help--- | 172 | ---help--- |
172 | TI AR7 partitioning support | 173 | TI AR7 partitioning support |
173 | 174 | ||
175 | endif # MTD_PARTITIONS | ||
176 | |||
174 | comment "User Modules And Translation Layers" | 177 | comment "User Modules And Translation Layers" |
175 | 178 | ||
176 | config MTD_CHAR | 179 | config MTD_CHAR |
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 760abc533395..d4e7f25b1ebb 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
@@ -6,13 +6,13 @@ | |||
6 | obj-$(CONFIG_MTD) += mtd.o | 6 | obj-$(CONFIG_MTD) += mtd.o |
7 | mtd-y := mtdcore.o mtdsuper.o | 7 | mtd-y := mtdcore.o mtdsuper.o |
8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o | 8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o |
9 | mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o | ||
9 | 10 | ||
10 | obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o | 11 | obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o |
11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o | 12 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o |
12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o | 13 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o |
13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o | 14 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o |
14 | obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o | 15 | obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o |
15 | obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o | ||
16 | 16 | ||
17 | # 'Users' - code which presents functionality to userspace. | 17 | # 'Users' - code which presents functionality to userspace. |
18 | obj-$(CONFIG_MTD_CHAR) += mtdchar.o | 18 | obj-$(CONFIG_MTD_CHAR) += mtdchar.o |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index ad9268b44416..a8c3e1c9b02a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
162 | #endif | 162 | #endif |
163 | 163 | ||
164 | /* Atmel chips don't use the same PRI format as Intel chips */ | 164 | /* Atmel chips don't use the same PRI format as Intel chips */ |
165 | static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | 165 | static void fixup_convert_atmel_pri(struct mtd_info *mtd) |
166 | { | 166 | { |
167 | struct map_info *map = mtd->priv; | 167 | struct map_info *map = mtd->priv; |
168 | struct cfi_private *cfi = map->fldrv_priv; | 168 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | |||
202 | cfi->cfiq->BufWriteTimeoutMax = 0; | 202 | cfi->cfiq->BufWriteTimeoutMax = 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) | 205 | static void fixup_at49bv640dx_lock(struct mtd_info *mtd) |
206 | { | 206 | { |
207 | struct map_info *map = mtd->priv; | 207 | struct map_info *map = mtd->priv; |
208 | struct cfi_private *cfi = map->fldrv_priv; | 208 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) | |||
214 | 214 | ||
215 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 215 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
216 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ | 216 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ |
217 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | 217 | static void fixup_intel_strataflash(struct mtd_info *mtd) |
218 | { | 218 | { |
219 | struct map_info *map = mtd->priv; | 219 | struct map_info *map = mtd->priv; |
220 | struct cfi_private *cfi = map->fldrv_priv; | 220 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | |||
227 | #endif | 227 | #endif |
228 | 228 | ||
229 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND | 229 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND |
230 | static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) | 230 | static void fixup_no_write_suspend(struct mtd_info *mtd) |
231 | { | 231 | { |
232 | struct map_info *map = mtd->priv; | 232 | struct map_info *map = mtd->priv; |
233 | struct cfi_private *cfi = map->fldrv_priv; | 233 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) | |||
240 | } | 240 | } |
241 | #endif | 241 | #endif |
242 | 242 | ||
243 | static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) | 243 | static void fixup_st_m28w320ct(struct mtd_info *mtd) |
244 | { | 244 | { |
245 | struct map_info *map = mtd->priv; | 245 | struct map_info *map = mtd->priv; |
246 | struct cfi_private *cfi = map->fldrv_priv; | 246 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) | |||
249 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ | 249 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ |
250 | } | 250 | } |
251 | 251 | ||
252 | static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) | 252 | static void fixup_st_m28w320cb(struct mtd_info *mtd) |
253 | { | 253 | { |
254 | struct map_info *map = mtd->priv; | 254 | struct map_info *map = mtd->priv; |
255 | struct cfi_private *cfi = map->fldrv_priv; | 255 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) | |||
259 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; | 259 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; |
260 | }; | 260 | }; |
261 | 261 | ||
262 | static void fixup_use_point(struct mtd_info *mtd, void *param) | 262 | static void fixup_use_point(struct mtd_info *mtd) |
263 | { | 263 | { |
264 | struct map_info *map = mtd->priv; | 264 | struct map_info *map = mtd->priv; |
265 | if (!mtd->point && map_is_linear(map)) { | 265 | if (!mtd->point && map_is_linear(map)) { |
@@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd, void *param) | |||
268 | } | 268 | } |
269 | } | 269 | } |
270 | 270 | ||
271 | static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | 271 | static void fixup_use_write_buffers(struct mtd_info *mtd) |
272 | { | 272 | { |
273 | struct map_info *map = mtd->priv; | 273 | struct map_info *map = mtd->priv; |
274 | struct cfi_private *cfi = map->fldrv_priv; | 274 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
282 | /* | 282 | /* |
283 | * Some chips power-up with all sectors locked by default. | 283 | * Some chips power-up with all sectors locked by default. |
284 | */ | 284 | */ |
285 | static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) | 285 | static void fixup_unlock_powerup_lock(struct mtd_info *mtd) |
286 | { | 286 | { |
287 | struct map_info *map = mtd->priv; | 287 | struct map_info *map = mtd->priv; |
288 | struct cfi_private *cfi = map->fldrv_priv; | 288 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) | |||
295 | } | 295 | } |
296 | 296 | ||
297 | static struct cfi_fixup cfi_fixup_table[] = { | 297 | static struct cfi_fixup cfi_fixup_table[] = { |
298 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | 298 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, |
299 | { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL }, | 299 | { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock }, |
300 | { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL }, | 300 | { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock }, |
301 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 301 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
302 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, | 302 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash }, |
303 | #endif | 303 | #endif |
304 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND | 304 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND |
305 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, | 305 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend }, |
306 | #endif | 306 | #endif |
307 | #if !FORCE_WORD_WRITE | 307 | #if !FORCE_WORD_WRITE |
308 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, | 308 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, |
309 | #endif | 309 | #endif |
310 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, | 310 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct }, |
311 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, | 311 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb }, |
312 | { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, | 312 | { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock }, |
313 | { 0, 0, NULL, NULL } | 313 | { 0, 0, NULL } |
314 | }; | 314 | }; |
315 | 315 | ||
316 | static struct cfi_fixup jedec_fixup_table[] = { | 316 | static struct cfi_fixup jedec_fixup_table[] = { |
317 | { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, | 317 | { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock }, |
318 | { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, | 318 | { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock }, |
319 | { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, | 319 | { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock }, |
320 | { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, | 320 | { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock }, |
321 | { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, | 321 | { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock }, |
322 | { 0, 0, NULL, NULL } | 322 | { 0, 0, NULL } |
323 | }; | 323 | }; |
324 | static struct cfi_fixup fixup_table[] = { | 324 | static struct cfi_fixup fixup_table[] = { |
325 | /* The CFI vendor ids and the JEDEC vendor IDs appear | 325 | /* The CFI vendor ids and the JEDEC vendor IDs appear |
@@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = { | |||
327 | * well. This table is to pick all cases where | 327 | * well. This table is to pick all cases where |
328 | * we know that is the case. | 328 | * we know that is the case. |
329 | */ | 329 | */ |
330 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, | 330 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point }, |
331 | { 0, 0, NULL, NULL } | 331 | { 0, 0, NULL } |
332 | }; | 332 | }; |
333 | 333 | ||
334 | static void cfi_fixup_major_minor(struct cfi_private *cfi, | 334 | static void cfi_fixup_major_minor(struct cfi_private *cfi, |
@@ -455,6 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
455 | mtd->flags = MTD_CAP_NORFLASH; | 455 | mtd->flags = MTD_CAP_NORFLASH; |
456 | mtd->name = map->name; | 456 | mtd->name = map->name; |
457 | mtd->writesize = 1; | 457 | mtd->writesize = 1; |
458 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | ||
458 | 459 | ||
459 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | 460 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; |
460 | 461 | ||
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 3b8e32d87977..f072fcfde04e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) | |||
134 | 134 | ||
135 | #ifdef AMD_BOOTLOC_BUG | 135 | #ifdef AMD_BOOTLOC_BUG |
136 | /* Wheee. Bring me the head of someone at AMD. */ | 136 | /* Wheee. Bring me the head of someone at AMD. */ |
137 | static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) | 137 | static void fixup_amd_bootblock(struct mtd_info *mtd) |
138 | { | 138 | { |
139 | struct map_info *map = mtd->priv; | 139 | struct map_info *map = mtd->priv; |
140 | struct cfi_private *cfi = map->fldrv_priv; | 140 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) | |||
186 | } | 186 | } |
187 | #endif | 187 | #endif |
188 | 188 | ||
189 | static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | 189 | static void fixup_use_write_buffers(struct mtd_info *mtd) |
190 | { | 190 | { |
191 | struct map_info *map = mtd->priv; | 191 | struct map_info *map = mtd->priv; |
192 | struct cfi_private *cfi = map->fldrv_priv; | 192 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
197 | } | 197 | } |
198 | 198 | ||
199 | /* Atmel chips don't use the same PRI format as AMD chips */ | 199 | /* Atmel chips don't use the same PRI format as AMD chips */ |
200 | static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | 200 | static void fixup_convert_atmel_pri(struct mtd_info *mtd) |
201 | { | 201 | { |
202 | struct map_info *map = mtd->priv; | 202 | struct map_info *map = mtd->priv; |
203 | struct cfi_private *cfi = map->fldrv_priv; | 203 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | |||
228 | cfi->cfiq->BufWriteTimeoutMax = 0; | 228 | cfi->cfiq->BufWriteTimeoutMax = 0; |
229 | } | 229 | } |
230 | 230 | ||
231 | static void fixup_use_secsi(struct mtd_info *mtd, void *param) | 231 | static void fixup_use_secsi(struct mtd_info *mtd) |
232 | { | 232 | { |
233 | /* Setup for chips with a secsi area */ | 233 | /* Setup for chips with a secsi area */ |
234 | mtd->read_user_prot_reg = cfi_amdstd_secsi_read; | 234 | mtd->read_user_prot_reg = cfi_amdstd_secsi_read; |
235 | mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; | 235 | mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; |
236 | } | 236 | } |
237 | 237 | ||
238 | static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) | 238 | static void fixup_use_erase_chip(struct mtd_info *mtd) |
239 | { | 239 | { |
240 | struct map_info *map = mtd->priv; | 240 | struct map_info *map = mtd->priv; |
241 | struct cfi_private *cfi = map->fldrv_priv; | 241 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) | |||
250 | * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors | 250 | * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors |
251 | * locked by default. | 251 | * locked by default. |
252 | */ | 252 | */ |
253 | static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) | 253 | static void fixup_use_atmel_lock(struct mtd_info *mtd) |
254 | { | 254 | { |
255 | mtd->lock = cfi_atmel_lock; | 255 | mtd->lock = cfi_atmel_lock; |
256 | mtd->unlock = cfi_atmel_unlock; | 256 | mtd->unlock = cfi_atmel_unlock; |
@@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd) | |||
271 | cfi->cfiq->NumEraseRegions = 1; | 271 | cfi->cfiq->NumEraseRegions = 1; |
272 | } | 272 | } |
273 | 273 | ||
274 | static void fixup_sst39vf(struct mtd_info *mtd, void *param) | 274 | static void fixup_sst39vf(struct mtd_info *mtd) |
275 | { | 275 | { |
276 | struct map_info *map = mtd->priv; | 276 | struct map_info *map = mtd->priv; |
277 | struct cfi_private *cfi = map->fldrv_priv; | 277 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param) | |||
282 | cfi->addr_unlock2 = 0x2AAA; | 282 | cfi->addr_unlock2 = 0x2AAA; |
283 | } | 283 | } |
284 | 284 | ||
285 | static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) | 285 | static void fixup_sst39vf_rev_b(struct mtd_info *mtd) |
286 | { | 286 | { |
287 | struct map_info *map = mtd->priv; | 287 | struct map_info *map = mtd->priv; |
288 | struct cfi_private *cfi = map->fldrv_priv; | 288 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) | |||
295 | cfi->sector_erase_cmd = CMD(0x50); | 295 | cfi->sector_erase_cmd = CMD(0x50); |
296 | } | 296 | } |
297 | 297 | ||
298 | static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) | 298 | static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd) |
299 | { | 299 | { |
300 | struct map_info *map = mtd->priv; | 300 | struct map_info *map = mtd->priv; |
301 | struct cfi_private *cfi = map->fldrv_priv; | 301 | struct cfi_private *cfi = map->fldrv_priv; |
302 | 302 | ||
303 | fixup_sst39vf_rev_b(mtd, param); | 303 | fixup_sst39vf_rev_b(mtd); |
304 | 304 | ||
305 | /* | 305 | /* |
306 | * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where | 306 | * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where |
@@ -310,7 +310,7 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) | |||
310 | pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); | 310 | pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); |
311 | } | 311 | } |
312 | 312 | ||
313 | static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) | 313 | static void fixup_s29gl064n_sectors(struct mtd_info *mtd) |
314 | { | 314 | { |
315 | struct map_info *map = mtd->priv; | 315 | struct map_info *map = mtd->priv; |
316 | struct cfi_private *cfi = map->fldrv_priv; | 316 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) | |||
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) | 324 | static void fixup_s29gl032n_sectors(struct mtd_info *mtd) |
325 | { | 325 | { |
326 | struct map_info *map = mtd->priv; | 326 | struct map_info *map = mtd->priv; |
327 | struct cfi_private *cfi = map->fldrv_priv; | 327 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) | |||
334 | 334 | ||
335 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ | 335 | /* Used to fix CFI-Tables of chips without Extended Query Tables */ |
336 | static struct cfi_fixup cfi_nopri_fixup_table[] = { | 336 | static struct cfi_fixup cfi_nopri_fixup_table[] = { |
337 | { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ | 337 | { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ |
338 | { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ | 338 | { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */ |
339 | { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ | 339 | { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */ |
340 | { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ | 340 | { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */ |
341 | { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ | 341 | { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */ |
342 | { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ | 342 | { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */ |
343 | { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ | 343 | { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */ |
344 | { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ | 344 | { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */ |
345 | { 0, 0, NULL, NULL } | 345 | { 0, 0, NULL } |
346 | }; | 346 | }; |
347 | 347 | ||
348 | static struct cfi_fixup cfi_fixup_table[] = { | 348 | static struct cfi_fixup cfi_fixup_table[] = { |
349 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | 349 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, |
350 | #ifdef AMD_BOOTLOC_BUG | 350 | #ifdef AMD_BOOTLOC_BUG |
351 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, | 351 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, |
352 | { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL }, | 352 | { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, |
353 | #endif | 353 | #endif |
354 | { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, | 354 | { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, |
355 | { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, | 355 | { CFI_MFR_AMD, 0x0053, fixup_use_secsi }, |
356 | { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, | 356 | { CFI_MFR_AMD, 0x0055, fixup_use_secsi }, |
357 | { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, | 357 | { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, |
358 | { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, | 358 | { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, |
359 | { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, | 359 | { CFI_MFR_AMD, 0x005F, fixup_use_secsi }, |
360 | { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, | 360 | { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, |
361 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, | 361 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, |
362 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, | 362 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, |
363 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, | 363 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, |
364 | { CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ | 364 | { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ |
365 | { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ | 365 | { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ |
366 | { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ | 366 | { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ |
367 | { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ | 367 | { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */ |
368 | #if !FORCE_WORD_WRITE | 368 | #if !FORCE_WORD_WRITE |
369 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, | 369 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, |
370 | #endif | 370 | #endif |
371 | { 0, 0, NULL, NULL } | 371 | { 0, 0, NULL } |
372 | }; | 372 | }; |
373 | static struct cfi_fixup jedec_fixup_table[] = { | 373 | static struct cfi_fixup jedec_fixup_table[] = { |
374 | { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, | 374 | { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock }, |
375 | { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, | 375 | { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock }, |
376 | { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, | 376 | { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock }, |
377 | { 0, 0, NULL, NULL } | 377 | { 0, 0, NULL } |
378 | }; | 378 | }; |
379 | 379 | ||
380 | static struct cfi_fixup fixup_table[] = { | 380 | static struct cfi_fixup fixup_table[] = { |
@@ -383,18 +383,30 @@ static struct cfi_fixup fixup_table[] = { | |||
383 | * well. This table is to pick all cases where | 383 | * well. This table is to pick all cases where |
384 | * we know that is the case. | 384 | * we know that is the case. |
385 | */ | 385 | */ |
386 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, | 386 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip }, |
387 | { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, | 387 | { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock }, |
388 | { 0, 0, NULL, NULL } | 388 | { 0, 0, NULL } |
389 | }; | 389 | }; |
390 | 390 | ||
391 | 391 | ||
392 | static void cfi_fixup_major_minor(struct cfi_private *cfi, | 392 | static void cfi_fixup_major_minor(struct cfi_private *cfi, |
393 | struct cfi_pri_amdstd *extp) | 393 | struct cfi_pri_amdstd *extp) |
394 | { | 394 | { |
395 | if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && | 395 | if (cfi->mfr == CFI_MFR_SAMSUNG) { |
396 | extp->MajorVersion == '0') | 396 | if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') || |
397 | extp->MajorVersion = '1'; | 397 | (extp->MajorVersion == '3' && extp->MinorVersion == '3')) { |
398 | /* | ||
399 | * Samsung K8P2815UQB and K8D6x16UxM chips | ||
400 | * report major=0 / minor=0. | ||
401 | * K8D3x16UxC chips report major=3 / minor=3. | ||
402 | */ | ||
403 | printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu" | ||
404 | " Extended Query version to 1.%c\n", | ||
405 | extp->MinorVersion); | ||
406 | extp->MajorVersion = '1'; | ||
407 | } | ||
408 | } | ||
409 | |||
398 | /* | 410 | /* |
399 | * SST 38VF640x chips report major=0xFF / minor=0xFF. | 411 | * SST 38VF640x chips report major=0xFF / minor=0xFF. |
400 | */ | 412 | */ |
@@ -428,6 +440,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
428 | mtd->flags = MTD_CAP_NORFLASH; | 440 | mtd->flags = MTD_CAP_NORFLASH; |
429 | mtd->name = map->name; | 441 | mtd->name = map->name; |
430 | mtd->writesize = 1; | 442 | mtd->writesize = 1; |
443 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | ||
444 | |||
445 | DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", | ||
446 | __func__, mtd->writebufsize); | ||
431 | 447 | ||
432 | mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; | 448 | mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; |
433 | 449 | ||
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 314af1f5a370..c04b7658abe9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -238,6 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
238 | mtd->resume = cfi_staa_resume; | 238 | mtd->resume = cfi_staa_resume; |
239 | mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; | 239 | mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; |
240 | mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ | 240 | mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ |
241 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | ||
241 | map->fldrv = &cfi_staa_chipdrv; | 242 | map->fldrv = &cfi_staa_chipdrv; |
242 | __module_get(THIS_MODULE); | 243 | __module_get(THIS_MODULE); |
243 | mtd->name = map->name; | 244 | mtd->name = map->name; |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 360525c637d2..6ae3d111e1e7 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) | |||
156 | for (f=fixups; f->fixup; f++) { | 156 | for (f=fixups; f->fixup; f++) { |
157 | if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && | 157 | if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && |
158 | ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { | 158 | ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { |
159 | f->fixup(mtd, f->param); | 159 | f->fixup(mtd); |
160 | } | 160 | } |
161 | } | 161 | } |
162 | } | 162 | } |
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index d18064977192..5e3cc80128aa 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h | |||
@@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
98 | return ret; | 98 | return ret; |
99 | } | 99 | } |
100 | 100 | ||
101 | static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) | 101 | static void fixup_use_fwh_lock(struct mtd_info *mtd) |
102 | { | 102 | { |
103 | printk(KERN_NOTICE "using fwh lock/unlock method\n"); | 103 | printk(KERN_NOTICE "using fwh lock/unlock method\n"); |
104 | /* Setup for the chips with the fwh lock method */ | 104 | /* Setup for the chips with the fwh lock method */ |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index bf5a002209bd..e4eba6cc1b2e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -51,6 +51,10 @@ | |||
51 | #define OPCODE_WRDI 0x04 /* Write disable */ | 51 | #define OPCODE_WRDI 0x04 /* Write disable */ |
52 | #define OPCODE_AAI_WP 0xad /* Auto address increment word program */ | 52 | #define OPCODE_AAI_WP 0xad /* Auto address increment word program */ |
53 | 53 | ||
54 | /* Used for Macronix flashes only. */ | ||
55 | #define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ | ||
56 | #define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ | ||
57 | |||
54 | /* Status Register bits. */ | 58 | /* Status Register bits. */ |
55 | #define SR_WIP 1 /* Write in progress */ | 59 | #define SR_WIP 1 /* Write in progress */ |
56 | #define SR_WEL 2 /* Write enable latch */ | 60 | #define SR_WEL 2 /* Write enable latch */ |
@@ -62,7 +66,7 @@ | |||
62 | 66 | ||
63 | /* Define max times to check status register before we give up. */ | 67 | /* Define max times to check status register before we give up. */ |
64 | #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ | 68 | #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ |
65 | #define MAX_CMD_SIZE 4 | 69 | #define MAX_CMD_SIZE 5 |
66 | 70 | ||
67 | #ifdef CONFIG_M25PXX_USE_FAST_READ | 71 | #ifdef CONFIG_M25PXX_USE_FAST_READ |
68 | #define OPCODE_READ OPCODE_FAST_READ | 72 | #define OPCODE_READ OPCODE_FAST_READ |
@@ -152,6 +156,16 @@ static inline int write_disable(struct m25p *flash) | |||
152 | } | 156 | } |
153 | 157 | ||
154 | /* | 158 | /* |
159 | * Enable/disable 4-byte addressing mode. | ||
160 | */ | ||
161 | static inline int set_4byte(struct m25p *flash, int enable) | ||
162 | { | ||
163 | u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B; | ||
164 | |||
165 | return spi_write_then_read(flash->spi, &code, 1, NULL, 0); | ||
166 | } | ||
167 | |||
168 | /* | ||
155 | * Service routine to read status register until ready, or timeout occurs. | 169 | * Service routine to read status register until ready, or timeout occurs. |
156 | * Returns non-zero if error. | 170 | * Returns non-zero if error. |
157 | */ | 171 | */ |
@@ -207,6 +221,7 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) | |||
207 | cmd[1] = addr >> (flash->addr_width * 8 - 8); | 221 | cmd[1] = addr >> (flash->addr_width * 8 - 8); |
208 | cmd[2] = addr >> (flash->addr_width * 8 - 16); | 222 | cmd[2] = addr >> (flash->addr_width * 8 - 16); |
209 | cmd[3] = addr >> (flash->addr_width * 8 - 24); | 223 | cmd[3] = addr >> (flash->addr_width * 8 - 24); |
224 | cmd[4] = addr >> (flash->addr_width * 8 - 32); | ||
210 | } | 225 | } |
211 | 226 | ||
212 | static int m25p_cmdsz(struct m25p *flash) | 227 | static int m25p_cmdsz(struct m25p *flash) |
@@ -482,6 +497,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
482 | size_t actual; | 497 | size_t actual; |
483 | int cmd_sz, ret; | 498 | int cmd_sz, ret; |
484 | 499 | ||
500 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", | ||
501 | dev_name(&flash->spi->dev), __func__, "to", | ||
502 | (u32)to, len); | ||
503 | |||
485 | *retlen = 0; | 504 | *retlen = 0; |
486 | 505 | ||
487 | /* sanity checks */ | 506 | /* sanity checks */ |
@@ -607,7 +626,6 @@ struct flash_info { | |||
607 | .sector_size = (_sector_size), \ | 626 | .sector_size = (_sector_size), \ |
608 | .n_sectors = (_n_sectors), \ | 627 | .n_sectors = (_n_sectors), \ |
609 | .page_size = 256, \ | 628 | .page_size = 256, \ |
610 | .addr_width = 3, \ | ||
611 | .flags = (_flags), \ | 629 | .flags = (_flags), \ |
612 | }) | 630 | }) |
613 | 631 | ||
@@ -635,7 +653,7 @@ static const struct spi_device_id m25p_ids[] = { | |||
635 | { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, | 653 | { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, |
636 | { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, | 654 | { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, |
637 | { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, | 655 | { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, |
638 | { "at26df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, | 656 | { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, |
639 | 657 | ||
640 | /* EON -- en25pxx */ | 658 | /* EON -- en25pxx */ |
641 | { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, | 659 | { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, |
@@ -653,6 +671,8 @@ static const struct spi_device_id m25p_ids[] = { | |||
653 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, | 671 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, |
654 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, | 672 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, |
655 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, | 673 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, |
674 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, | ||
675 | { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, | ||
656 | 676 | ||
657 | /* Spansion -- single (large) sector size only, at least | 677 | /* Spansion -- single (large) sector size only, at least |
658 | * for the chips listed here (without boot sectors). | 678 | * for the chips listed here (without boot sectors). |
@@ -764,6 +784,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) | |||
764 | return &m25p_ids[tmp]; | 784 | return &m25p_ids[tmp]; |
765 | } | 785 | } |
766 | } | 786 | } |
787 | dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); | ||
767 | return ERR_PTR(-ENODEV); | 788 | return ERR_PTR(-ENODEV); |
768 | } | 789 | } |
769 | 790 | ||
@@ -883,7 +904,17 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
883 | 904 | ||
884 | flash->mtd.dev.parent = &spi->dev; | 905 | flash->mtd.dev.parent = &spi->dev; |
885 | flash->page_size = info->page_size; | 906 | flash->page_size = info->page_size; |
886 | flash->addr_width = info->addr_width; | 907 | |
908 | if (info->addr_width) | ||
909 | flash->addr_width = info->addr_width; | ||
910 | else { | ||
911 | /* enable 4-byte addressing if the device exceeds 16MiB */ | ||
912 | if (flash->mtd.size > 0x1000000) { | ||
913 | flash->addr_width = 4; | ||
914 | set_4byte(flash, 1); | ||
915 | } else | ||
916 | flash->addr_width = 3; | ||
917 | } | ||
887 | 918 | ||
888 | dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, | 919 | dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, |
889 | (long long)flash->mtd.size >> 10); | 920 | (long long)flash->mtd.size >> 10); |
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 684247a8a5ed..c163e619abc9 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c | |||
@@ -335,7 +335,7 @@ out: | |||
335 | return ret; | 335 | return ret; |
336 | } | 336 | } |
337 | 337 | ||
338 | static struct flash_info *__init sst25l_match_device(struct spi_device *spi) | 338 | static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) |
339 | { | 339 | { |
340 | struct flash_info *flash_info = NULL; | 340 | struct flash_info *flash_info = NULL; |
341 | struct spi_message m; | 341 | struct spi_message m; |
@@ -375,7 +375,7 @@ static struct flash_info *__init sst25l_match_device(struct spi_device *spi) | |||
375 | return flash_info; | 375 | return flash_info; |
376 | } | 376 | } |
377 | 377 | ||
378 | static int __init sst25l_probe(struct spi_device *spi) | 378 | static int __devinit sst25l_probe(struct spi_device *spi) |
379 | { | 379 | { |
380 | struct flash_info *flash_info; | 380 | struct flash_info *flash_info; |
381 | struct sst25l_flash *flash; | 381 | struct sst25l_flash *flash; |
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 19fe92db0c46..77d64ce19e9f 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c | |||
@@ -149,11 +149,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
149 | if (request_resource(&iomem_resource, &window->rsrc)) { | 149 | if (request_resource(&iomem_resource, &window->rsrc)) { |
150 | window->rsrc.parent = NULL; | 150 | window->rsrc.parent = NULL; |
151 | printk(KERN_ERR MOD_NAME | 151 | printk(KERN_ERR MOD_NAME |
152 | " %s(): Unable to register resource" | 152 | " %s(): Unable to register resource %pR - kernel bug?\n", |
153 | " 0x%.16llx-0x%.16llx - kernel bug?\n", | 153 | __func__, &window->rsrc); |
154 | __func__, | ||
155 | (unsigned long long)window->rsrc.start, | ||
156 | (unsigned long long)window->rsrc.end); | ||
157 | } | 154 | } |
158 | 155 | ||
159 | 156 | ||
diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c index d175c120ee84..1f3049590d9e 100644 --- a/drivers/mtd/maps/bcm963xx-flash.c +++ b/drivers/mtd/maps/bcm963xx-flash.c | |||
@@ -196,10 +196,15 @@ static int bcm963xx_probe(struct platform_device *pdev) | |||
196 | bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); | 196 | bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); |
197 | if (!bcm963xx_mtd_info) { | 197 | if (!bcm963xx_mtd_info) { |
198 | dev_err(&pdev->dev, "failed to probe using CFI\n"); | 198 | dev_err(&pdev->dev, "failed to probe using CFI\n"); |
199 | bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map); | ||
200 | if (bcm963xx_mtd_info) | ||
201 | goto probe_ok; | ||
202 | dev_err(&pdev->dev, "failed to probe using JEDEC\n"); | ||
199 | err = -EIO; | 203 | err = -EIO; |
200 | goto err_probe; | 204 | goto err_probe; |
201 | } | 205 | } |
202 | 206 | ||
207 | probe_ok: | ||
203 | bcm963xx_mtd_info->owner = THIS_MODULE; | 208 | bcm963xx_mtd_info->owner = THIS_MODULE; |
204 | 209 | ||
205 | /* This is mutually exclusive */ | 210 | /* This is mutually exclusive */ |
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index ddb462bea9b5..5fdb7b26cea3 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c | |||
@@ -178,11 +178,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, | |||
178 | if (request_resource(&iomem_resource, &window->rsrc)) { | 178 | if (request_resource(&iomem_resource, &window->rsrc)) { |
179 | window->rsrc.parent = NULL; | 179 | window->rsrc.parent = NULL; |
180 | printk(KERN_ERR MOD_NAME | 180 | printk(KERN_ERR MOD_NAME |
181 | " %s(): Unable to register resource" | 181 | " %s(): Unable to register resource %pR - kernel bug?\n", |
182 | " 0x%.016llx-0x%.016llx - kernel bug?\n", | 182 | __func__, &window->rsrc); |
183 | __func__, | ||
184 | (unsigned long long)window->rsrc.start, | ||
185 | (unsigned long long)window->rsrc.end); | ||
186 | } | 183 | } |
187 | 184 | ||
188 | 185 | ||
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index d12c93dc1aad..4feb7507ab7c 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c | |||
@@ -242,12 +242,9 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, | |||
242 | window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 242 | window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
243 | if (request_resource(&iomem_resource, &window->rsrc)) { | 243 | if (request_resource(&iomem_resource, &window->rsrc)) { |
244 | window->rsrc.parent = NULL; | 244 | window->rsrc.parent = NULL; |
245 | printk(KERN_DEBUG MOD_NAME | 245 | printk(KERN_DEBUG MOD_NAME ": " |
246 | ": %s(): Unable to register resource" | 246 | "%s(): Unable to register resource %pR - kernel bug?\n", |
247 | " 0x%.08llx-0x%.08llx - kernel bug?\n", | 247 | __func__, &window->rsrc); |
248 | __func__, | ||
249 | (unsigned long long)window->rsrc.start, | ||
250 | (unsigned long long)window->rsrc.end); | ||
251 | } | 248 | } |
252 | 249 | ||
253 | /* Map the firmware hub into my address space. */ | 250 | /* Map the firmware hub into my address space. */ |
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index f102bf243a74..1337a4191a0c 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c | |||
@@ -175,12 +175,9 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
175 | window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 175 | window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
176 | if (request_resource(&iomem_resource, &window->rsrc)) { | 176 | if (request_resource(&iomem_resource, &window->rsrc)) { |
177 | window->rsrc.parent = NULL; | 177 | window->rsrc.parent = NULL; |
178 | printk(KERN_DEBUG MOD_NAME | 178 | printk(KERN_DEBUG MOD_NAME ": " |
179 | ": %s(): Unable to register resource" | 179 | "%s(): Unable to register resource %pR - kernel bug?\n", |
180 | " 0x%.16llx-0x%.16llx - kernel bug?\n", | 180 | __func__, &window->rsrc); |
181 | __func__, | ||
182 | (unsigned long long)window->rsrc.start, | ||
183 | (unsigned long long)window->rsrc.end); | ||
184 | } | 181 | } |
185 | 182 | ||
186 | /* Map the firmware hub into my address space. */ | 183 | /* Map the firmware hub into my address space. */ |
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 9861814aa027..8506578e6a35 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
@@ -274,9 +274,7 @@ static int __devinit of_flash_probe(struct platform_device *dev, | |||
274 | continue; | 274 | continue; |
275 | } | 275 | } |
276 | 276 | ||
277 | dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", | 277 | dev_dbg(&dev->dev, "of_flash device: %pR\n", &res); |
278 | (unsigned long long)res.start, | ||
279 | (unsigned long long)res.end); | ||
280 | 278 | ||
281 | err = -EBUSY; | 279 | err = -EBUSY; |
282 | res_size = resource_size(&res); | 280 | res_size = resource_size(&res); |
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index b5391ebb736e..027e628a4f1d 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c | |||
@@ -166,9 +166,8 @@ static int __init init_scx200_docflash(void) | |||
166 | outl(pmr, scx200_cb_base + SCx200_PMR); | 166 | outl(pmr, scx200_cb_base + SCx200_PMR); |
167 | } | 167 | } |
168 | 168 | ||
169 | printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n", | 169 | printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n", |
170 | (unsigned long long)docmem.start, | 170 | &docmem, width); |
171 | (unsigned long long)docmem.end, width); | ||
172 | 171 | ||
173 | scx200_docflash_map.size = size; | 172 | scx200_docflash_map.size = size; |
174 | if (width == 8) | 173 | if (width == 8) |
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 60146984f4be..c08e140d40ed 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c | |||
@@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void) | |||
139 | goto error_mem; | 139 | goto error_mem; |
140 | } | 140 | } |
141 | 141 | ||
142 | map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); | 142 | map_banks[idx]->name = kmalloc(16, GFP_KERNEL); |
143 | 143 | ||
144 | if (!map_banks[idx]->name) { | 144 | if (!map_banks[idx]->name) { |
145 | ret = -ENOMEM; | 145 | ret = -ENOMEM; |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 98240575a18d..145b3d0dc0db 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -522,10 +522,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, | |||
522 | if (!capable(CAP_SYS_ADMIN)) | 522 | if (!capable(CAP_SYS_ADMIN)) |
523 | return -EPERM; | 523 | return -EPERM; |
524 | 524 | ||
525 | /* Only master mtd device must be used to control partitions */ | ||
526 | if (!mtd_is_master(mtd)) | ||
527 | return -EINVAL; | ||
528 | |||
529 | if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) | 525 | if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) |
530 | return -EFAULT; | 526 | return -EFAULT; |
531 | 527 | ||
@@ -535,6 +531,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, | |||
535 | switch (a.op) { | 531 | switch (a.op) { |
536 | case BLKPG_ADD_PARTITION: | 532 | case BLKPG_ADD_PARTITION: |
537 | 533 | ||
534 | /* Only master mtd device must be used to add partitions */ | ||
535 | if (mtd_is_partition(mtd)) | ||
536 | return -EINVAL; | ||
537 | |||
538 | return mtd_add_partition(mtd, p.devname, p.start, p.length); | 538 | return mtd_add_partition(mtd, p.devname, p.start, p.length); |
539 | 539 | ||
540 | case BLKPG_DEL_PARTITION: | 540 | case BLKPG_DEL_PARTITION: |
@@ -601,6 +601,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
601 | } | 601 | } |
602 | 602 | ||
603 | case MEMGETINFO: | 603 | case MEMGETINFO: |
604 | memset(&info, 0, sizeof(info)); | ||
604 | info.type = mtd->type; | 605 | info.type = mtd->type; |
605 | info.flags = mtd->flags; | 606 | info.flags = mtd->flags; |
606 | info.size = mtd->size; | 607 | info.size = mtd->size; |
@@ -609,7 +610,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
609 | info.oobsize = mtd->oobsize; | 610 | info.oobsize = mtd->oobsize; |
610 | /* The below fields are obsolete */ | 611 | /* The below fields are obsolete */ |
611 | info.ecctype = -1; | 612 | info.ecctype = -1; |
612 | info.eccsize = 0; | ||
613 | if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) | 613 | if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) |
614 | return -EFAULT; | 614 | return -EFAULT; |
615 | break; | 615 | break; |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index bf8de0943103..5f5777bd3f75 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -776,6 +776,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
776 | concat->mtd.size = subdev[0]->size; | 776 | concat->mtd.size = subdev[0]->size; |
777 | concat->mtd.erasesize = subdev[0]->erasesize; | 777 | concat->mtd.erasesize = subdev[0]->erasesize; |
778 | concat->mtd.writesize = subdev[0]->writesize; | 778 | concat->mtd.writesize = subdev[0]->writesize; |
779 | concat->mtd.writebufsize = subdev[0]->writebufsize; | ||
779 | concat->mtd.subpage_sft = subdev[0]->subpage_sft; | 780 | concat->mtd.subpage_sft = subdev[0]->subpage_sft; |
780 | concat->mtd.oobsize = subdev[0]->oobsize; | 781 | concat->mtd.oobsize = subdev[0]->oobsize; |
781 | concat->mtd.oobavail = subdev[0]->oobavail; | 782 | concat->mtd.oobavail = subdev[0]->oobavail; |
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index c948150079be..e3e40f440323 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c | |||
@@ -401,7 +401,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) | |||
401 | printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); | 401 | printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); |
402 | 402 | ||
403 | cxt->mtd = NULL; | 403 | cxt->mtd = NULL; |
404 | flush_scheduled_work(); | 404 | flush_work_sync(&cxt->work_erase); |
405 | flush_work_sync(&cxt->work_write); | ||
405 | } | 406 | } |
406 | 407 | ||
407 | 408 | ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 79e3689f1e16..0a4760174782 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -120,8 +120,25 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, | |||
120 | return -EINVAL; | 120 | return -EINVAL; |
121 | if (ops->datbuf && from + ops->len > mtd->size) | 121 | if (ops->datbuf && from + ops->len > mtd->size) |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | res = part->master->read_oob(part->master, from + part->offset, ops); | ||
124 | 123 | ||
124 | /* | ||
125 | * If OOB is also requested, make sure that we do not read past the end | ||
126 | * of this partition. | ||
127 | */ | ||
128 | if (ops->oobbuf) { | ||
129 | size_t len, pages; | ||
130 | |||
131 | if (ops->mode == MTD_OOB_AUTO) | ||
132 | len = mtd->oobavail; | ||
133 | else | ||
134 | len = mtd->oobsize; | ||
135 | pages = mtd_div_by_ws(mtd->size, mtd); | ||
136 | pages -= mtd_div_by_ws(from, mtd); | ||
137 | if (ops->ooboffs + ops->ooblen > pages * len) | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | res = part->master->read_oob(part->master, from + part->offset, ops); | ||
125 | if (unlikely(res)) { | 142 | if (unlikely(res)) { |
126 | if (res == -EUCLEAN) | 143 | if (res == -EUCLEAN) |
127 | mtd->ecc_stats.corrected++; | 144 | mtd->ecc_stats.corrected++; |
@@ -384,6 +401,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, | |||
384 | slave->mtd.flags = master->flags & ~part->mask_flags; | 401 | slave->mtd.flags = master->flags & ~part->mask_flags; |
385 | slave->mtd.size = part->size; | 402 | slave->mtd.size = part->size; |
386 | slave->mtd.writesize = master->writesize; | 403 | slave->mtd.writesize = master->writesize; |
404 | slave->mtd.writebufsize = master->writebufsize; | ||
387 | slave->mtd.oobsize = master->oobsize; | 405 | slave->mtd.oobsize = master->oobsize; |
388 | slave->mtd.oobavail = master->oobavail; | 406 | slave->mtd.oobavail = master->oobavail; |
389 | slave->mtd.subpage_sft = master->subpage_sft; | 407 | slave->mtd.subpage_sft = master->subpage_sft; |
@@ -720,19 +738,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
720 | } | 738 | } |
721 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); | 739 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); |
722 | 740 | ||
723 | int mtd_is_master(struct mtd_info *mtd) | 741 | int mtd_is_partition(struct mtd_info *mtd) |
724 | { | 742 | { |
725 | struct mtd_part *part; | 743 | struct mtd_part *part; |
726 | int nopart = 0; | 744 | int ispart = 0; |
727 | 745 | ||
728 | mutex_lock(&mtd_partitions_mutex); | 746 | mutex_lock(&mtd_partitions_mutex); |
729 | list_for_each_entry(part, &mtd_partitions, list) | 747 | list_for_each_entry(part, &mtd_partitions, list) |
730 | if (&part->mtd == mtd) { | 748 | if (&part->mtd == mtd) { |
731 | nopart = 1; | 749 | ispart = 1; |
732 | break; | 750 | break; |
733 | } | 751 | } |
734 | mutex_unlock(&mtd_partitions_mutex); | 752 | mutex_unlock(&mtd_partitions_mutex); |
735 | 753 | ||
736 | return nopart; | 754 | return ispart; |
737 | } | 755 | } |
738 | EXPORT_SYMBOL_GPL(mtd_is_master); | 756 | EXPORT_SYMBOL_GPL(mtd_is_partition); |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8229802b4346..c89592239bc7 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -96,6 +96,7 @@ config MTD_NAND_SPIA | |||
96 | config MTD_NAND_AMS_DELTA | 96 | config MTD_NAND_AMS_DELTA |
97 | tristate "NAND Flash device on Amstrad E3" | 97 | tristate "NAND Flash device on Amstrad E3" |
98 | depends on MACH_AMS_DELTA | 98 | depends on MACH_AMS_DELTA |
99 | default y | ||
99 | help | 100 | help |
100 | Support for NAND flash on Amstrad E3 (Delta). | 101 | Support for NAND flash on Amstrad E3 (Delta). |
101 | 102 | ||
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 2548e1065bf8..a067d090cb31 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> | 4 | * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> |
5 | * | 5 | * |
6 | * Derived from drivers/mtd/toto.c | 6 | * Derived from drivers/mtd/toto.c |
7 | * Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> | ||
8 | * Partially stolen from drivers/mtd/nand/plat_nand.c | ||
7 | * | 9 | * |
8 | * 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 |
9 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
@@ -62,9 +64,10 @@ static struct mtd_partition partition_info[] = { | |||
62 | static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) | 64 | static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) |
63 | { | 65 | { |
64 | struct nand_chip *this = mtd->priv; | 66 | struct nand_chip *this = mtd->priv; |
67 | void __iomem *io_base = this->priv; | ||
65 | 68 | ||
66 | omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); | 69 | writew(0, io_base + OMAP_MPUIO_IO_CNTL); |
67 | omap_writew(byte, this->IO_ADDR_W); | 70 | writew(byte, this->IO_ADDR_W); |
68 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); | 71 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); |
69 | ndelay(40); | 72 | ndelay(40); |
70 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, | 73 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, |
@@ -75,11 +78,12 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd) | |||
75 | { | 78 | { |
76 | u_char res; | 79 | u_char res; |
77 | struct nand_chip *this = mtd->priv; | 80 | struct nand_chip *this = mtd->priv; |
81 | void __iomem *io_base = this->priv; | ||
78 | 82 | ||
79 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); | 83 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); |
80 | ndelay(40); | 84 | ndelay(40); |
81 | omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); | 85 | writew(~0, io_base + OMAP_MPUIO_IO_CNTL); |
82 | res = omap_readw(this->IO_ADDR_R); | 86 | res = readw(this->IO_ADDR_R); |
83 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, | 87 | ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, |
84 | AMS_DELTA_LATCH2_NAND_NRE); | 88 | AMS_DELTA_LATCH2_NAND_NRE); |
85 | 89 | ||
@@ -151,11 +155,16 @@ static int ams_delta_nand_ready(struct mtd_info *mtd) | |||
151 | /* | 155 | /* |
152 | * Main initialization routine | 156 | * Main initialization routine |
153 | */ | 157 | */ |
154 | static int __init ams_delta_init(void) | 158 | static int __devinit ams_delta_init(struct platform_device *pdev) |
155 | { | 159 | { |
156 | struct nand_chip *this; | 160 | struct nand_chip *this; |
161 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
162 | void __iomem *io_base; | ||
157 | int err = 0; | 163 | int err = 0; |
158 | 164 | ||
165 | if (!res) | ||
166 | return -ENXIO; | ||
167 | |||
159 | /* Allocate memory for MTD device structure and private data */ | 168 | /* Allocate memory for MTD device structure and private data */ |
160 | ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + | 169 | ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + |
161 | sizeof(struct nand_chip), GFP_KERNEL); | 170 | sizeof(struct nand_chip), GFP_KERNEL); |
@@ -177,9 +186,25 @@ static int __init ams_delta_init(void) | |||
177 | /* Link the private data with the MTD structure */ | 186 | /* Link the private data with the MTD structure */ |
178 | ams_delta_mtd->priv = this; | 187 | ams_delta_mtd->priv = this; |
179 | 188 | ||
189 | if (!request_mem_region(res->start, resource_size(res), | ||
190 | dev_name(&pdev->dev))) { | ||
191 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
192 | err = -EBUSY; | ||
193 | goto out_free; | ||
194 | } | ||
195 | |||
196 | io_base = ioremap(res->start, resource_size(res)); | ||
197 | if (io_base == NULL) { | ||
198 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
199 | err = -EIO; | ||
200 | goto out_release_io; | ||
201 | } | ||
202 | |||
203 | this->priv = io_base; | ||
204 | |||
180 | /* Set address of NAND IO lines */ | 205 | /* Set address of NAND IO lines */ |
181 | this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); | 206 | this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; |
182 | this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT); | 207 | this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; |
183 | this->read_byte = ams_delta_read_byte; | 208 | this->read_byte = ams_delta_read_byte; |
184 | this->write_buf = ams_delta_write_buf; | 209 | this->write_buf = ams_delta_write_buf; |
185 | this->read_buf = ams_delta_read_buf; | 210 | this->read_buf = ams_delta_read_buf; |
@@ -195,6 +220,8 @@ static int __init ams_delta_init(void) | |||
195 | this->chip_delay = 30; | 220 | this->chip_delay = 30; |
196 | this->ecc.mode = NAND_ECC_SOFT; | 221 | this->ecc.mode = NAND_ECC_SOFT; |
197 | 222 | ||
223 | platform_set_drvdata(pdev, io_base); | ||
224 | |||
198 | /* Set chip enabled, but */ | 225 | /* Set chip enabled, but */ |
199 | ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | | 226 | ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | |
200 | AMS_DELTA_LATCH2_NAND_NWE | | 227 | AMS_DELTA_LATCH2_NAND_NWE | |
@@ -214,25 +241,56 @@ static int __init ams_delta_init(void) | |||
214 | goto out; | 241 | goto out; |
215 | 242 | ||
216 | out_mtd: | 243 | out_mtd: |
244 | platform_set_drvdata(pdev, NULL); | ||
245 | iounmap(io_base); | ||
246 | out_release_io: | ||
247 | release_mem_region(res->start, resource_size(res)); | ||
248 | out_free: | ||
217 | kfree(ams_delta_mtd); | 249 | kfree(ams_delta_mtd); |
218 | out: | 250 | out: |
219 | return err; | 251 | return err; |
220 | } | 252 | } |
221 | 253 | ||
222 | module_init(ams_delta_init); | ||
223 | |||
224 | /* | 254 | /* |
225 | * Clean up routine | 255 | * Clean up routine |
226 | */ | 256 | */ |
227 | static void __exit ams_delta_cleanup(void) | 257 | static int __devexit ams_delta_cleanup(struct platform_device *pdev) |
228 | { | 258 | { |
259 | void __iomem *io_base = platform_get_drvdata(pdev); | ||
260 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
261 | |||
229 | /* Release resources, unregister device */ | 262 | /* Release resources, unregister device */ |
230 | nand_release(ams_delta_mtd); | 263 | nand_release(ams_delta_mtd); |
231 | 264 | ||
265 | iounmap(io_base); | ||
266 | release_mem_region(res->start, resource_size(res)); | ||
267 | |||
232 | /* Free the MTD device structure */ | 268 | /* Free the MTD device structure */ |
233 | kfree(ams_delta_mtd); | 269 | kfree(ams_delta_mtd); |
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static struct platform_driver ams_delta_nand_driver = { | ||
275 | .probe = ams_delta_init, | ||
276 | .remove = __devexit_p(ams_delta_cleanup), | ||
277 | .driver = { | ||
278 | .name = "ams-delta-nand", | ||
279 | .owner = THIS_MODULE, | ||
280 | }, | ||
281 | }; | ||
282 | |||
283 | static int __init ams_delta_nand_init(void) | ||
284 | { | ||
285 | return platform_driver_register(&ams_delta_nand_driver); | ||
286 | } | ||
287 | module_init(ams_delta_nand_init); | ||
288 | |||
289 | static void __exit ams_delta_nand_exit(void) | ||
290 | { | ||
291 | platform_driver_unregister(&ams_delta_nand_driver); | ||
234 | } | 292 | } |
235 | module_exit(ams_delta_cleanup); | 293 | module_exit(ams_delta_nand_exit); |
236 | 294 | ||
237 | MODULE_LICENSE("GPL"); | 295 | MODULE_LICENSE("GPL"); |
238 | MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); | 296 | MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index c141b07b25d1..7a13d42cbabd 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -388,6 +388,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
388 | "page_addr: 0x%x, column: 0x%x.\n", | 388 | "page_addr: 0x%x, column: 0x%x.\n", |
389 | page_addr, column); | 389 | page_addr, column); |
390 | 390 | ||
391 | elbc_fcm_ctrl->column = column; | ||
392 | elbc_fcm_ctrl->oob = 0; | ||
391 | elbc_fcm_ctrl->use_mdr = 1; | 393 | elbc_fcm_ctrl->use_mdr = 1; |
392 | 394 | ||
393 | fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | | 395 | fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 02edfba25b0c..205b10b9f9b9 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/mtd/fsmc.h> | 33 | #include <linux/mtd/fsmc.h> |
34 | #include <linux/amba/bus.h> | ||
34 | #include <mtd/mtd-abi.h> | 35 | #include <mtd/mtd-abi.h> |
35 | 36 | ||
36 | static struct nand_ecclayout fsmc_ecc1_layout = { | 37 | static struct nand_ecclayout fsmc_ecc1_layout = { |
@@ -119,21 +120,36 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { | |||
119 | } | 120 | } |
120 | }; | 121 | }; |
121 | 122 | ||
122 | /* | ||
123 | * Default partition tables to be used if the partition information not | ||
124 | * provided through platform data | ||
125 | */ | ||
126 | #define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} | ||
127 | 123 | ||
124 | #ifdef CONFIG_MTD_PARTITIONS | ||
128 | /* | 125 | /* |
126 | * Default partition tables to be used if the partition information not | ||
127 | * provided through platform data. | ||
128 | * | ||
129 | * Default partition layout for small page(= 512 bytes) devices | 129 | * Default partition layout for small page(= 512 bytes) devices |
130 | * Size for "Root file system" is updated in driver based on actual device size | 130 | * Size for "Root file system" is updated in driver based on actual device size |
131 | */ | 131 | */ |
132 | static struct mtd_partition partition_info_16KB_blk[] = { | 132 | static struct mtd_partition partition_info_16KB_blk[] = { |
133 | PARTITION("X-loader", 0, 4 * 0x4000), | 133 | { |
134 | PARTITION("U-Boot", 0x10000, 20 * 0x4000), | 134 | .name = "X-loader", |
135 | PARTITION("Kernel", 0x60000, 256 * 0x4000), | 135 | .offset = 0, |
136 | PARTITION("Root File System", 0x460000, 0), | 136 | .size = 4*0x4000, |
137 | }, | ||
138 | { | ||
139 | .name = "U-Boot", | ||
140 | .offset = 0x10000, | ||
141 | .size = 20*0x4000, | ||
142 | }, | ||
143 | { | ||
144 | .name = "Kernel", | ||
145 | .offset = 0x60000, | ||
146 | .size = 256*0x4000, | ||
147 | }, | ||
148 | { | ||
149 | .name = "Root File System", | ||
150 | .offset = 0x460000, | ||
151 | .size = 0, | ||
152 | }, | ||
137 | }; | 153 | }; |
138 | 154 | ||
139 | /* | 155 | /* |
@@ -141,19 +157,37 @@ static struct mtd_partition partition_info_16KB_blk[] = { | |||
141 | * Size for "Root file system" is updated in driver based on actual device size | 157 | * Size for "Root file system" is updated in driver based on actual device size |
142 | */ | 158 | */ |
143 | static struct mtd_partition partition_info_128KB_blk[] = { | 159 | static struct mtd_partition partition_info_128KB_blk[] = { |
144 | PARTITION("X-loader", 0, 4 * 0x20000), | 160 | { |
145 | PARTITION("U-Boot", 0x80000, 12 * 0x20000), | 161 | .name = "X-loader", |
146 | PARTITION("Kernel", 0x200000, 48 * 0x20000), | 162 | .offset = 0, |
147 | PARTITION("Root File System", 0x800000, 0), | 163 | .size = 4*0x20000, |
164 | }, | ||
165 | { | ||
166 | .name = "U-Boot", | ||
167 | .offset = 0x80000, | ||
168 | .size = 12*0x20000, | ||
169 | }, | ||
170 | { | ||
171 | .name = "Kernel", | ||
172 | .offset = 0x200000, | ||
173 | .size = 48*0x20000, | ||
174 | }, | ||
175 | { | ||
176 | .name = "Root File System", | ||
177 | .offset = 0x800000, | ||
178 | .size = 0, | ||
179 | }, | ||
148 | }; | 180 | }; |
149 | 181 | ||
150 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 182 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
151 | const char *part_probes[] = { "cmdlinepart", NULL }; | 183 | const char *part_probes[] = { "cmdlinepart", NULL }; |
152 | #endif | 184 | #endif |
185 | #endif | ||
153 | 186 | ||
154 | /** | 187 | /** |
155 | * struct fsmc_nand_data - atructure for FSMC NAND device state | 188 | * struct fsmc_nand_data - structure for FSMC NAND device state |
156 | * | 189 | * |
190 | * @pid: Part ID on the AMBA PrimeCell format | ||
157 | * @mtd: MTD info for a NAND flash. | 191 | * @mtd: MTD info for a NAND flash. |
158 | * @nand: Chip related info for a NAND flash. | 192 | * @nand: Chip related info for a NAND flash. |
159 | * @partitions: Partition info for a NAND Flash. | 193 | * @partitions: Partition info for a NAND Flash. |
@@ -169,6 +203,7 @@ const char *part_probes[] = { "cmdlinepart", NULL }; | |||
169 | * @regs_va: FSMC regs base address. | 203 | * @regs_va: FSMC regs base address. |
170 | */ | 204 | */ |
171 | struct fsmc_nand_data { | 205 | struct fsmc_nand_data { |
206 | u32 pid; | ||
172 | struct mtd_info mtd; | 207 | struct mtd_info mtd; |
173 | struct nand_chip nand; | 208 | struct nand_chip nand; |
174 | struct mtd_partition *partitions; | 209 | struct mtd_partition *partitions; |
@@ -508,7 +543,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
508 | struct nand_chip *nand; | 543 | struct nand_chip *nand; |
509 | struct fsmc_regs *regs; | 544 | struct fsmc_regs *regs; |
510 | struct resource *res; | 545 | struct resource *res; |
511 | int nr_parts, ret = 0; | 546 | int ret = 0; |
547 | u32 pid; | ||
548 | int i; | ||
512 | 549 | ||
513 | if (!pdata) { | 550 | if (!pdata) { |
514 | dev_err(&pdev->dev, "platform data is NULL\n"); | 551 | dev_err(&pdev->dev, "platform data is NULL\n"); |
@@ -598,6 +635,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
598 | if (ret) | 635 | if (ret) |
599 | goto err_probe1; | 636 | goto err_probe1; |
600 | 637 | ||
638 | /* | ||
639 | * This device ID is actually a common AMBA ID as used on the | ||
640 | * AMBA PrimeCell bus. However it is not a PrimeCell. | ||
641 | */ | ||
642 | for (pid = 0, i = 0; i < 4; i++) | ||
643 | pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); | ||
644 | host->pid = pid; | ||
645 | dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, " | ||
646 | "revision %02x, config %02x\n", | ||
647 | AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid), | ||
648 | AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); | ||
649 | |||
601 | host->bank = pdata->bank; | 650 | host->bank = pdata->bank; |
602 | host->select_chip = pdata->select_bank; | 651 | host->select_chip = pdata->select_bank; |
603 | regs = host->regs_va; | 652 | regs = host->regs_va; |
@@ -625,7 +674,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
625 | 674 | ||
626 | fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); | 675 | fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); |
627 | 676 | ||
628 | if (get_fsmc_version(host->regs_va) == FSMC_VER8) { | 677 | if (AMBA_REV_BITS(host->pid) >= 8) { |
629 | nand->ecc.read_page = fsmc_read_page_hwecc; | 678 | nand->ecc.read_page = fsmc_read_page_hwecc; |
630 | nand->ecc.calculate = fsmc_read_hwecc_ecc4; | 679 | nand->ecc.calculate = fsmc_read_hwecc_ecc4; |
631 | nand->ecc.correct = fsmc_correct_data; | 680 | nand->ecc.correct = fsmc_correct_data; |
@@ -645,7 +694,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
645 | goto err_probe; | 694 | goto err_probe; |
646 | } | 695 | } |
647 | 696 | ||
648 | if (get_fsmc_version(host->regs_va) == FSMC_VER8) { | 697 | if (AMBA_REV_BITS(host->pid) >= 8) { |
649 | if (host->mtd.writesize == 512) { | 698 | if (host->mtd.writesize == 512) { |
650 | nand->ecc.layout = &fsmc_ecc4_sp_layout; | 699 | nand->ecc.layout = &fsmc_ecc4_sp_layout; |
651 | host->ecc_place = &fsmc_ecc4_sp_place; | 700 | host->ecc_place = &fsmc_ecc4_sp_place; |
@@ -676,11 +725,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) | |||
676 | * Check if partition info passed via command line | 725 | * Check if partition info passed via command line |
677 | */ | 726 | */ |
678 | host->mtd.name = "nand"; | 727 | host->mtd.name = "nand"; |
679 | nr_parts = parse_mtd_partitions(&host->mtd, part_probes, | 728 | host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, |
680 | &host->partitions, 0); | 729 | &host->partitions, 0); |
681 | if (nr_parts > 0) { | 730 | if (host->nr_partitions <= 0) { |
682 | host->nr_partitions = nr_parts; | ||
683 | } else { | ||
684 | #endif | 731 | #endif |
685 | /* | 732 | /* |
686 | * Check if partition info passed via command line | 733 | * Check if partition info passed via command line |
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 67343fc31bd5..cea38a5d4ac5 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c | |||
@@ -251,58 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, | |||
251 | return 0; | 251 | return 0; |
252 | } | 252 | } |
253 | 253 | ||
254 | |||
255 | /* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos | ||
256 | * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit | ||
257 | * into the eccpos array. */ | ||
258 | static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | ||
259 | struct nand_chip *chip, uint8_t *buf, int page) | ||
260 | { | ||
261 | int i, eccsize = chip->ecc.size; | ||
262 | int eccbytes = chip->ecc.bytes; | ||
263 | int eccsteps = chip->ecc.steps; | ||
264 | uint8_t *p = buf; | ||
265 | unsigned int ecc_offset = chip->page_shift; | ||
266 | |||
267 | /* Read the OOB area first */ | ||
268 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
269 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
270 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | ||
271 | |||
272 | for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | ||
273 | int stat; | ||
274 | |||
275 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | ||
276 | chip->read_buf(mtd, p, eccsize); | ||
277 | |||
278 | stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL); | ||
279 | if (stat < 0) | ||
280 | mtd->ecc_stats.failed++; | ||
281 | else | ||
282 | mtd->ecc_stats.corrected += stat; | ||
283 | } | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */ | ||
288 | static void jz_nand_write_page_hwecc(struct mtd_info *mtd, | ||
289 | struct nand_chip *chip, const uint8_t *buf) | ||
290 | { | ||
291 | int i, eccsize = chip->ecc.size; | ||
292 | int eccbytes = chip->ecc.bytes; | ||
293 | int eccsteps = chip->ecc.steps; | ||
294 | const uint8_t *p = buf; | ||
295 | unsigned int ecc_offset = chip->page_shift; | ||
296 | |||
297 | for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | ||
298 | chip->ecc.hwctl(mtd, NAND_ECC_WRITE); | ||
299 | chip->write_buf(mtd, p, eccsize); | ||
300 | chip->ecc.calculate(mtd, p, &chip->oob_poi[i]); | ||
301 | } | ||
302 | |||
303 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
304 | } | ||
305 | |||
306 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 254 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
307 | static const char *part_probes[] = {"cmdline", NULL}; | 255 | static const char *part_probes[] = {"cmdline", NULL}; |
308 | #endif | 256 | #endif |
@@ -393,9 +341,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) | |||
393 | chip->ecc.size = 512; | 341 | chip->ecc.size = 512; |
394 | chip->ecc.bytes = 9; | 342 | chip->ecc.bytes = 9; |
395 | 343 | ||
396 | chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first; | ||
397 | chip->ecc.write_page = jz_nand_write_page_hwecc; | ||
398 | |||
399 | if (pdata) | 344 | if (pdata) |
400 | chip->ecc.layout = pdata->ecc_layout; | 345 | chip->ecc.layout = pdata->ecc_layout; |
401 | 346 | ||
@@ -489,7 +434,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) | |||
489 | return 0; | 434 | return 0; |
490 | } | 435 | } |
491 | 436 | ||
492 | struct platform_driver jz_nand_driver = { | 437 | static struct platform_driver jz_nand_driver = { |
493 | .probe = jz_nand_probe, | 438 | .probe = jz_nand_probe, |
494 | .remove = __devexit_p(jz_nand_remove), | 439 | .remove = __devexit_p(jz_nand_remove), |
495 | .driver = { | 440 | .driver = { |
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 214b03afdd48..ef932ba55a0b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1009 | struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; | 1009 | struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; |
1010 | struct mxc_nand_host *host; | 1010 | struct mxc_nand_host *host; |
1011 | struct resource *res; | 1011 | struct resource *res; |
1012 | int err = 0, nr_parts = 0; | 1012 | int err = 0, __maybe_unused nr_parts = 0; |
1013 | struct nand_ecclayout *oob_smallpage, *oob_largepage; | 1013 | struct nand_ecclayout *oob_smallpage, *oob_largepage; |
1014 | 1014 | ||
1015 | /* Allocate memory for MTD device structure and private data */ | 1015 | /* Allocate memory for MTD device structure and private data */ |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 31bf376b82a0..a9c6ce745767 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2865,20 +2865,24 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
2865 | 2865 | ||
2866 | /* check version */ | 2866 | /* check version */ |
2867 | val = le16_to_cpu(p->revision); | 2867 | val = le16_to_cpu(p->revision); |
2868 | if (val == 1 || val > (1 << 4)) { | 2868 | if (val & (1 << 5)) |
2869 | printk(KERN_INFO "%s: unsupported ONFI version: %d\n", | 2869 | chip->onfi_version = 23; |
2870 | __func__, val); | 2870 | else if (val & (1 << 4)) |
2871 | return 0; | ||
2872 | } | ||
2873 | |||
2874 | if (val & (1 << 4)) | ||
2875 | chip->onfi_version = 22; | 2871 | chip->onfi_version = 22; |
2876 | else if (val & (1 << 3)) | 2872 | else if (val & (1 << 3)) |
2877 | chip->onfi_version = 21; | 2873 | chip->onfi_version = 21; |
2878 | else if (val & (1 << 2)) | 2874 | else if (val & (1 << 2)) |
2879 | chip->onfi_version = 20; | 2875 | chip->onfi_version = 20; |
2880 | else | 2876 | else if (val & (1 << 1)) |
2881 | chip->onfi_version = 10; | 2877 | chip->onfi_version = 10; |
2878 | else | ||
2879 | chip->onfi_version = 0; | ||
2880 | |||
2881 | if (!chip->onfi_version) { | ||
2882 | printk(KERN_INFO "%s: unsupported ONFI version: %d\n", | ||
2883 | __func__, val); | ||
2884 | return 0; | ||
2885 | } | ||
2882 | 2886 | ||
2883 | sanitize_string(p->manufacturer, sizeof(p->manufacturer)); | 2887 | sanitize_string(p->manufacturer, sizeof(p->manufacturer)); |
2884 | sanitize_string(p->model, sizeof(p->model)); | 2888 | sanitize_string(p->model, sizeof(p->model)); |
@@ -2887,7 +2891,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | |||
2887 | mtd->writesize = le32_to_cpu(p->byte_per_page); | 2891 | mtd->writesize = le32_to_cpu(p->byte_per_page); |
2888 | mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; | 2892 | mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; |
2889 | mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); | 2893 | mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); |
2890 | chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; | 2894 | chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; |
2891 | busw = 0; | 2895 | busw = 0; |
2892 | if (le16_to_cpu(p->features) & 1) | 2896 | if (le16_to_cpu(p->features) & 1) |
2893 | busw = NAND_BUSWIDTH_16; | 2897 | busw = NAND_BUSWIDTH_16; |
@@ -3157,7 +3161,7 @@ ident_done: | |||
3157 | printk(KERN_INFO "NAND device: Manufacturer ID:" | 3161 | printk(KERN_INFO "NAND device: Manufacturer ID:" |
3158 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, | 3162 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, |
3159 | nand_manuf_ids[maf_idx].name, | 3163 | nand_manuf_ids[maf_idx].name, |
3160 | chip->onfi_version ? type->name : chip->onfi_params.model); | 3164 | chip->onfi_version ? chip->onfi_params.model : type->name); |
3161 | 3165 | ||
3162 | return type; | 3166 | return type; |
3163 | } | 3167 | } |
@@ -3435,6 +3439,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
3435 | mtd->resume = nand_resume; | 3439 | mtd->resume = nand_resume; |
3436 | mtd->block_isbad = nand_block_isbad; | 3440 | mtd->block_isbad = nand_block_isbad; |
3437 | mtd->block_markbad = nand_block_markbad; | 3441 | mtd->block_markbad = nand_block_markbad; |
3442 | mtd->writebufsize = mtd->writesize; | ||
3438 | 3443 | ||
3439 | /* propagate ecc.layout to mtd_info */ | 3444 | /* propagate ecc.layout to mtd_info */ |
3440 | mtd->ecclayout = chip->ecc.layout; | 3445 | mtd->ecclayout = chip->ecc.layout; |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 586b981f0e61..6ebd869993aa 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -1092,7 +1092,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
1092 | 1092 | ||
1093 | /** | 1093 | /** |
1094 | * verify_bbt_descr - verify the bad block description | 1094 | * verify_bbt_descr - verify the bad block description |
1095 | * @bd: the table to verify | 1095 | * @mtd: MTD device structure |
1096 | * @bd: the table to verify | ||
1096 | * | 1097 | * |
1097 | * This functions performs a few sanity checks on the bad block description | 1098 | * This functions performs a few sanity checks on the bad block description |
1098 | * table. | 1099 | * table. |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a6a73aab1253..a5aa99f014ba 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d | |||
210 | #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ | 210 | #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ |
211 | #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ | 211 | #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ |
212 | #define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ | 212 | #define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ |
213 | #define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ | 213 | #define STATE_CMD_PAGEPROG 0x00000004 /* start page program */ |
214 | #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ | 214 | #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ |
215 | #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ | 215 | #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ |
216 | #define STATE_CMD_STATUS 0x00000007 /* read status */ | 216 | #define STATE_CMD_STATUS 0x00000007 /* read status */ |
217 | #define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ | 217 | #define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ |
218 | #define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */ | 218 | #define STATE_CMD_SEQIN 0x00000009 /* sequential data input */ |
219 | #define STATE_CMD_READID 0x0000000A /* read ID */ | 219 | #define STATE_CMD_READID 0x0000000A /* read ID */ |
220 | #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ | 220 | #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ |
221 | #define STATE_CMD_RESET 0x0000000C /* reset */ | 221 | #define STATE_CMD_RESET 0x0000000C /* reset */ |
@@ -230,7 +230,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d | |||
230 | #define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ | 230 | #define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ |
231 | #define STATE_ADDR_MASK 0x00000070 /* address states mask */ | 231 | #define STATE_ADDR_MASK 0x00000070 /* address states mask */ |
232 | 232 | ||
233 | /* Durind data input/output the simulator is in these states */ | 233 | /* During data input/output the simulator is in these states */ |
234 | #define STATE_DATAIN 0x00000100 /* waiting for data input */ | 234 | #define STATE_DATAIN 0x00000100 /* waiting for data input */ |
235 | #define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ | 235 | #define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ |
236 | 236 | ||
@@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d | |||
248 | 248 | ||
249 | /* Simulator's actions bit masks */ | 249 | /* Simulator's actions bit masks */ |
250 | #define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ | 250 | #define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ |
251 | #define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */ | 251 | #define ACTION_PRGPAGE 0x00200000 /* program the internal buffer to flash */ |
252 | #define ACTION_SECERASE 0x00300000 /* erase sector */ | 252 | #define ACTION_SECERASE 0x00300000 /* erase sector */ |
253 | #define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ | 253 | #define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ |
254 | #define ACTION_HALFOFF 0x00500000 /* add to address half of page */ | 254 | #define ACTION_HALFOFF 0x00500000 /* add to address half of page */ |
@@ -263,18 +263,18 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d | |||
263 | #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ | 263 | #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ |
264 | #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ | 264 | #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ |
265 | #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ | 265 | #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ |
266 | #define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */ | 266 | #define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */ |
267 | #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ | 267 | #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ |
268 | #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ | 268 | #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ |
269 | #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ | 269 | #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ |
270 | #define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ | 270 | #define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ |
271 | 271 | ||
272 | /* Remove action bits ftom state */ | 272 | /* Remove action bits from state */ |
273 | #define NS_STATE(x) ((x) & ~ACTION_MASK) | 273 | #define NS_STATE(x) ((x) & ~ACTION_MASK) |
274 | 274 | ||
275 | /* | 275 | /* |
276 | * Maximum previous states which need to be saved. Currently saving is | 276 | * Maximum previous states which need to be saved. Currently saving is |
277 | * only needed for page programm operation with preceeded read command | 277 | * only needed for page program operation with preceded read command |
278 | * (which is only valid for 512-byte pages). | 278 | * (which is only valid for 512-byte pages). |
279 | */ | 279 | */ |
280 | #define NS_MAX_PREVSTATES 1 | 280 | #define NS_MAX_PREVSTATES 1 |
@@ -380,16 +380,16 @@ static struct nandsim_operations { | |||
380 | /* Read OOB */ | 380 | /* Read OOB */ |
381 | {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, | 381 | {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, |
382 | STATE_DATAOUT, STATE_READY}}, | 382 | STATE_DATAOUT, STATE_READY}}, |
383 | /* Programm page starting from the beginning */ | 383 | /* Program page starting from the beginning */ |
384 | {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, | 384 | {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, |
385 | STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, | 385 | STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, |
386 | /* Programm page starting from the beginning */ | 386 | /* Program page starting from the beginning */ |
387 | {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, | 387 | {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, |
388 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, | 388 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, |
389 | /* Programm page starting from the second half */ | 389 | /* Program page starting from the second half */ |
390 | {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, | 390 | {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, |
391 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, | 391 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, |
392 | /* Programm OOB */ | 392 | /* Program OOB */ |
393 | {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, | 393 | {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, |
394 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, | 394 | STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, |
395 | /* Erase sector */ | 395 | /* Erase sector */ |
@@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns) | |||
470 | err = -EINVAL; | 470 | err = -EINVAL; |
471 | goto err_close; | 471 | goto err_close; |
472 | } | 472 | } |
473 | ns->pages_written = vmalloc(ns->geom.pgnum); | 473 | ns->pages_written = vzalloc(ns->geom.pgnum); |
474 | if (!ns->pages_written) { | 474 | if (!ns->pages_written) { |
475 | NS_ERR("alloc_device: unable to allocate pages written array\n"); | 475 | NS_ERR("alloc_device: unable to allocate pages written array\n"); |
476 | err = -ENOMEM; | 476 | err = -ENOMEM; |
@@ -483,7 +483,6 @@ static int alloc_device(struct nandsim *ns) | |||
483 | goto err_free; | 483 | goto err_free; |
484 | } | 484 | } |
485 | ns->cfile = cfile; | 485 | ns->cfile = cfile; |
486 | memset(ns->pages_written, 0, ns->geom.pgnum); | ||
487 | return 0; | 486 | return 0; |
488 | } | 487 | } |
489 | 488 | ||
@@ -1171,9 +1170,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) | |||
1171 | * of supported operations. | 1170 | * of supported operations. |
1172 | * | 1171 | * |
1173 | * Operation can be unknown because of the following. | 1172 | * Operation can be unknown because of the following. |
1174 | * 1. New command was accepted and this is the firs call to find the | 1173 | * 1. New command was accepted and this is the first call to find the |
1175 | * correspondent states chain. In this case ns->npstates = 0; | 1174 | * correspondent states chain. In this case ns->npstates = 0; |
1176 | * 2. There is several operations which begin with the same command(s) | 1175 | * 2. There are several operations which begin with the same command(s) |
1177 | * (for example program from the second half and read from the | 1176 | * (for example program from the second half and read from the |
1178 | * second half operations both begin with the READ1 command). In this | 1177 | * second half operations both begin with the READ1 command). In this |
1179 | * case the ns->pstates[] array contains previous states. | 1178 | * case the ns->pstates[] array contains previous states. |
@@ -1186,7 +1185,7 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) | |||
1186 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is | 1185 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is |
1187 | * zeroed). | 1186 | * zeroed). |
1188 | * | 1187 | * |
1189 | * If there are several maches, the current state is pushed to the | 1188 | * If there are several matches, the current state is pushed to the |
1190 | * ns->pstates. | 1189 | * ns->pstates. |
1191 | * | 1190 | * |
1192 | * The operation can be unknown only while commands are input to the chip. | 1191 | * The operation can be unknown only while commands are input to the chip. |
@@ -1195,10 +1194,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) | |||
1195 | * operation is searched using the following pattern: | 1194 | * operation is searched using the following pattern: |
1196 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> | 1195 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> |
1197 | * | 1196 | * |
1198 | * It is supposed that this pattern must either match one operation on | 1197 | * It is supposed that this pattern must either match one operation or |
1199 | * none. There can't be ambiguity in that case. | 1198 | * none. There can't be ambiguity in that case. |
1200 | * | 1199 | * |
1201 | * If no matches found, the functions does the following: | 1200 | * If no matches found, the function does the following: |
1202 | * 1. if there are saved states present, try to ignore them and search | 1201 | * 1. if there are saved states present, try to ignore them and search |
1203 | * again only using the last command. If nothing was found, switch | 1202 | * again only using the last command. If nothing was found, switch |
1204 | * to the STATE_READY state. | 1203 | * to the STATE_READY state. |
@@ -1668,7 +1667,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
1668 | 1667 | ||
1669 | case ACTION_PRGPAGE: | 1668 | case ACTION_PRGPAGE: |
1670 | /* | 1669 | /* |
1671 | * Programm page - move internal buffer data to the page. | 1670 | * Program page - move internal buffer data to the page. |
1672 | */ | 1671 | */ |
1673 | 1672 | ||
1674 | if (ns->lines.wp) { | 1673 | if (ns->lines.wp) { |
@@ -1933,7 +1932,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) | |||
1933 | NS_DBG("read_byte: all bytes were read\n"); | 1932 | NS_DBG("read_byte: all bytes were read\n"); |
1934 | 1933 | ||
1935 | /* | 1934 | /* |
1936 | * The OPT_AUTOINCR allows to read next conseqitive pages without | 1935 | * The OPT_AUTOINCR allows to read next consecutive pages without |
1937 | * new read operation cycle. | 1936 | * new read operation cycle. |
1938 | */ | 1937 | */ |
1939 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { | 1938 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { |
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 6ddb2461d740..bb277a54986f 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c | |||
@@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev, | |||
107 | if (pasemi_nand_mtd) | 107 | if (pasemi_nand_mtd) |
108 | return -ENODEV; | 108 | return -ENODEV; |
109 | 109 | ||
110 | pr_debug("pasemi_nand at %llx-%llx\n", res.start, res.end); | 110 | pr_debug("pasemi_nand at %pR\n", &res); |
111 | 111 | ||
112 | /* Allocate memory for MTD device structure and private data */ | 112 | /* Allocate memory for MTD device structure and private data */ |
113 | pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + | 113 | pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 17f8518cc5eb..ea2c288df3f6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -885,6 +885,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | |||
885 | /* set info fields needed to __readid */ | 885 | /* set info fields needed to __readid */ |
886 | info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; | 886 | info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; |
887 | info->reg_ndcr = ndcr; | 887 | info->reg_ndcr = ndcr; |
888 | info->cmdset = &default_cmdset; | ||
888 | 889 | ||
889 | if (__readid(info, &id)) | 890 | if (__readid(info, &id)) |
890 | return -ENODEV; | 891 | return -ENODEV; |
@@ -915,7 +916,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | |||
915 | 916 | ||
916 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); | 917 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); |
917 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); | 918 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); |
918 | info->cmdset = &default_cmdset; | ||
919 | 919 | ||
920 | return 0; | 920 | return 0; |
921 | } | 921 | } |
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 054a41c0ef4a..ca270a4881a4 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c | |||
@@ -277,8 +277,9 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) | |||
277 | ret = nand_scan_ident(mtd, 1, NULL); | 277 | ret = nand_scan_ident(mtd, 1, NULL); |
278 | if (!ret) { | 278 | if (!ret) { |
279 | if (mtd->writesize >= 512) { | 279 | if (mtd->writesize >= 512) { |
280 | chip->ecc.size = mtd->writesize; | 280 | /* Hardware ECC 6 byte ECC per 512 Byte data */ |
281 | chip->ecc.bytes = 3 * (mtd->writesize / 256); | 281 | chip->ecc.size = 512; |
282 | chip->ecc.bytes = 6; | ||
282 | } | 283 | } |
283 | ret = nand_scan_tail(mtd); | 284 | ret = nand_scan_tail(mtd); |
284 | } | 285 | } |
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index d0894ca7798b..ac31f461cc1c 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | #include <linux/io.h> | 36 | #include <linux/io.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/regulator/consumer.h> | ||
38 | 39 | ||
39 | #include <asm/mach/flash.h> | 40 | #include <asm/mach/flash.h> |
40 | #include <plat/gpmc.h> | 41 | #include <plat/gpmc.h> |
@@ -63,8 +64,13 @@ struct omap2_onenand { | |||
63 | int dma_channel; | 64 | int dma_channel; |
64 | int freq; | 65 | int freq; |
65 | int (*setup)(void __iomem *base, int freq); | 66 | int (*setup)(void __iomem *base, int freq); |
67 | struct regulator *regulator; | ||
66 | }; | 68 | }; |
67 | 69 | ||
70 | #ifdef CONFIG_MTD_PARTITIONS | ||
71 | static const char *part_probes[] = { "cmdlinepart", NULL, }; | ||
72 | #endif | ||
73 | |||
68 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) | 74 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) |
69 | { | 75 | { |
70 | struct omap2_onenand *c = data; | 76 | struct omap2_onenand *c = data; |
@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, | |||
108 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) | 114 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) |
109 | { | 115 | { |
110 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | 116 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); |
117 | struct onenand_chip *this = mtd->priv; | ||
111 | unsigned int intr = 0; | 118 | unsigned int intr = 0; |
112 | unsigned int ctrl; | 119 | unsigned int ctrl, ctrl_mask; |
113 | unsigned long timeout; | 120 | unsigned long timeout; |
114 | u32 syscfg; | 121 | u32 syscfg; |
115 | 122 | ||
@@ -180,7 +187,8 @@ retry: | |||
180 | if (result == 0) { | 187 | if (result == 0) { |
181 | /* Timeout after 20ms */ | 188 | /* Timeout after 20ms */ |
182 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | 189 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); |
183 | if (ctrl & ONENAND_CTRL_ONGO) { | 190 | if (ctrl & ONENAND_CTRL_ONGO && |
191 | !this->ongoing) { | ||
184 | /* | 192 | /* |
185 | * The operation seems to be still going | 193 | * The operation seems to be still going |
186 | * so give it some more time. | 194 | * so give it some more time. |
@@ -269,7 +277,11 @@ retry: | |||
269 | return -EIO; | 277 | return -EIO; |
270 | } | 278 | } |
271 | 279 | ||
272 | if (ctrl & 0xFE9F) | 280 | ctrl_mask = 0xFE9F; |
281 | if (this->ongoing) | ||
282 | ctrl_mask &= ~0x8000; | ||
283 | |||
284 | if (ctrl & ctrl_mask) | ||
273 | wait_warn("unexpected controller status", state, ctrl, intr); | 285 | wait_warn("unexpected controller status", state, ctrl, intr); |
274 | 286 | ||
275 | return 0; | 287 | return 0; |
@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) | |||
591 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); | 603 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); |
592 | } | 604 | } |
593 | 605 | ||
606 | static int omap2_onenand_enable(struct mtd_info *mtd) | ||
607 | { | ||
608 | int ret; | ||
609 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
610 | |||
611 | ret = regulator_enable(c->regulator); | ||
612 | if (ret != 0) | ||
613 | dev_err(&c->pdev->dev, "cant enable regulator\n"); | ||
614 | |||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static int omap2_onenand_disable(struct mtd_info *mtd) | ||
619 | { | ||
620 | int ret; | ||
621 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
622 | |||
623 | ret = regulator_disable(c->regulator); | ||
624 | if (ret != 0) | ||
625 | dev_err(&c->pdev->dev, "cant disable regulator\n"); | ||
626 | |||
627 | return ret; | ||
628 | } | ||
629 | |||
594 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) | 630 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) |
595 | { | 631 | { |
596 | struct omap_onenand_platform_data *pdata; | 632 | struct omap_onenand_platform_data *pdata; |
@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
705 | } | 741 | } |
706 | } | 742 | } |
707 | 743 | ||
744 | if (pdata->regulator_can_sleep) { | ||
745 | c->regulator = regulator_get(&pdev->dev, "vonenand"); | ||
746 | if (IS_ERR(c->regulator)) { | ||
747 | dev_err(&pdev->dev, "Failed to get regulator\n"); | ||
748 | goto err_release_dma; | ||
749 | } | ||
750 | c->onenand.enable = omap2_onenand_enable; | ||
751 | c->onenand.disable = omap2_onenand_disable; | ||
752 | } | ||
753 | |||
708 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | 754 | if ((r = onenand_scan(&c->mtd, 1)) < 0) |
709 | goto err_release_dma; | 755 | goto err_release_regulator; |
710 | 756 | ||
711 | switch ((c->onenand.version_id >> 4) & 0xf) { | 757 | switch ((c->onenand.version_id >> 4) & 0xf) { |
712 | case 0: | 758 | case 0: |
@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
727 | } | 773 | } |
728 | 774 | ||
729 | #ifdef CONFIG_MTD_PARTITIONS | 775 | #ifdef CONFIG_MTD_PARTITIONS |
730 | if (pdata->parts != NULL) | 776 | r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); |
731 | r = add_mtd_partitions(&c->mtd, pdata->parts, | 777 | if (r > 0) |
732 | pdata->nr_parts); | 778 | r = add_mtd_partitions(&c->mtd, c->parts, r); |
779 | else if (pdata->parts != NULL) | ||
780 | r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); | ||
733 | else | 781 | else |
734 | #endif | 782 | #endif |
735 | r = add_mtd_device(&c->mtd); | 783 | r = add_mtd_device(&c->mtd); |
736 | if (r < 0) | 784 | if (r) |
737 | goto err_release_onenand; | 785 | goto err_release_onenand; |
738 | 786 | ||
739 | platform_set_drvdata(pdev, c); | 787 | platform_set_drvdata(pdev, c); |
@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
742 | 790 | ||
743 | err_release_onenand: | 791 | err_release_onenand: |
744 | onenand_release(&c->mtd); | 792 | onenand_release(&c->mtd); |
793 | err_release_regulator: | ||
794 | regulator_put(c->regulator); | ||
745 | err_release_dma: | 795 | err_release_dma: |
746 | if (c->dma_channel != -1) | 796 | if (c->dma_channel != -1) |
747 | omap_free_dma(c->dma_channel); | 797 | omap_free_dma(c->dma_channel); |
@@ -757,6 +807,7 @@ err_release_mem_region: | |||
757 | err_free_cs: | 807 | err_free_cs: |
758 | gpmc_cs_free(c->gpmc_cs); | 808 | gpmc_cs_free(c->gpmc_cs); |
759 | err_kfree: | 809 | err_kfree: |
810 | kfree(c->parts); | ||
760 | kfree(c); | 811 | kfree(c); |
761 | 812 | ||
762 | return r; | 813 | return r; |
@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
766 | { | 817 | { |
767 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); | 818 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); |
768 | 819 | ||
769 | BUG_ON(c == NULL); | ||
770 | |||
771 | #ifdef CONFIG_MTD_PARTITIONS | ||
772 | if (c->parts) | ||
773 | del_mtd_partitions(&c->mtd); | ||
774 | else | ||
775 | del_mtd_device(&c->mtd); | ||
776 | #else | ||
777 | del_mtd_device(&c->mtd); | ||
778 | #endif | ||
779 | |||
780 | onenand_release(&c->mtd); | 820 | onenand_release(&c->mtd); |
821 | regulator_put(c->regulator); | ||
781 | if (c->dma_channel != -1) | 822 | if (c->dma_channel != -1) |
782 | omap_free_dma(c->dma_channel); | 823 | omap_free_dma(c->dma_channel); |
783 | omap2_onenand_shutdown(pdev); | 824 | omap2_onenand_shutdown(pdev); |
@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
789 | iounmap(c->onenand.base); | 830 | iounmap(c->onenand.base); |
790 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); | 831 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); |
791 | gpmc_cs_free(c->gpmc_cs); | 832 | gpmc_cs_free(c->gpmc_cs); |
833 | kfree(c->parts); | ||
792 | kfree(c); | 834 | kfree(c); |
793 | 835 | ||
794 | return 0; | 836 | return 0; |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6b3a875647c9..bac41caa8df7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
400 | value = onenand_bufferram_address(this, block); | 400 | value = onenand_bufferram_address(this, block); |
401 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | 401 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); |
402 | 402 | ||
403 | if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || | 403 | if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) |
404 | ONENAND_IS_4KB_PAGE(this)) | ||
405 | /* It is always BufferRAM0 */ | 404 | /* It is always BufferRAM0 */ |
406 | ONENAND_SET_BUFFERRAM0(this); | 405 | ONENAND_SET_BUFFERRAM0(this); |
407 | else | 406 | else |
@@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
430 | case FLEXONENAND_CMD_RECOVER_LSB: | 429 | case FLEXONENAND_CMD_RECOVER_LSB: |
431 | case ONENAND_CMD_READ: | 430 | case ONENAND_CMD_READ: |
432 | case ONENAND_CMD_READOOB: | 431 | case ONENAND_CMD_READOOB: |
433 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 432 | if (ONENAND_IS_4KB_PAGE(this)) |
434 | /* It is always BufferRAM0 */ | 433 | /* It is always BufferRAM0 */ |
435 | dataram = ONENAND_SET_BUFFERRAM0(this); | 434 | dataram = ONENAND_SET_BUFFERRAM0(this); |
436 | else | 435 | else |
@@ -949,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state) | |||
949 | if (this->state == FL_READY) { | 948 | if (this->state == FL_READY) { |
950 | this->state = new_state; | 949 | this->state = new_state; |
951 | spin_unlock(&this->chip_lock); | 950 | spin_unlock(&this->chip_lock); |
951 | if (new_state != FL_PM_SUSPENDED && this->enable) | ||
952 | this->enable(mtd); | ||
952 | break; | 953 | break; |
953 | } | 954 | } |
954 | if (new_state == FL_PM_SUSPENDED) { | 955 | if (new_state == FL_PM_SUSPENDED) { |
@@ -975,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd) | |||
975 | { | 976 | { |
976 | struct onenand_chip *this = mtd->priv; | 977 | struct onenand_chip *this = mtd->priv; |
977 | 978 | ||
979 | if (this->state != FL_PM_SUSPENDED && this->disable) | ||
980 | this->disable(mtd); | ||
978 | /* Release the chip */ | 981 | /* Release the chip */ |
979 | spin_lock(&this->chip_lock); | 982 | spin_lock(&this->chip_lock); |
980 | this->state = FL_READY; | 983 | this->state = FL_READY; |
@@ -1353,7 +1356,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
1353 | 1356 | ||
1354 | stats = mtd->ecc_stats; | 1357 | stats = mtd->ecc_stats; |
1355 | 1358 | ||
1356 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1359 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1357 | 1360 | ||
1358 | while (read < len) { | 1361 | while (read < len) { |
1359 | cond_resched(); | 1362 | cond_resched(); |
@@ -1429,7 +1432,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1429 | int ret; | 1432 | int ret; |
1430 | 1433 | ||
1431 | onenand_get_device(mtd, FL_READING); | 1434 | onenand_get_device(mtd, FL_READING); |
1432 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 1435 | ret = ONENAND_IS_4KB_PAGE(this) ? |
1433 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : | 1436 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : |
1434 | onenand_read_ops_nolock(mtd, from, &ops); | 1437 | onenand_read_ops_nolock(mtd, from, &ops); |
1435 | onenand_release_device(mtd); | 1438 | onenand_release_device(mtd); |
@@ -1464,7 +1467,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1464 | 1467 | ||
1465 | onenand_get_device(mtd, FL_READING); | 1468 | onenand_get_device(mtd, FL_READING); |
1466 | if (ops->datbuf) | 1469 | if (ops->datbuf) |
1467 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 1470 | ret = ONENAND_IS_4KB_PAGE(this) ? |
1468 | onenand_mlc_read_ops_nolock(mtd, from, ops) : | 1471 | onenand_mlc_read_ops_nolock(mtd, from, ops) : |
1469 | onenand_read_ops_nolock(mtd, from, ops); | 1472 | onenand_read_ops_nolock(mtd, from, ops); |
1470 | else | 1473 | else |
@@ -1485,8 +1488,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1485 | { | 1488 | { |
1486 | struct onenand_chip *this = mtd->priv; | 1489 | struct onenand_chip *this = mtd->priv; |
1487 | unsigned long timeout; | 1490 | unsigned long timeout; |
1488 | unsigned int interrupt; | 1491 | unsigned int interrupt, ctrl, ecc, addr1, addr8; |
1489 | unsigned int ctrl; | ||
1490 | 1492 | ||
1491 | /* The 20 msec is enough */ | 1493 | /* The 20 msec is enough */ |
1492 | timeout = jiffies + msecs_to_jiffies(20); | 1494 | timeout = jiffies + msecs_to_jiffies(20); |
@@ -1498,25 +1500,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1498 | /* To get correct interrupt status in timeout case */ | 1500 | /* To get correct interrupt status in timeout case */ |
1499 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1501 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
1500 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1502 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
1503 | addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1); | ||
1504 | addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8); | ||
1501 | 1505 | ||
1502 | if (interrupt & ONENAND_INT_READ) { | 1506 | if (interrupt & ONENAND_INT_READ) { |
1503 | int ecc = onenand_read_ecc(this); | 1507 | ecc = onenand_read_ecc(this); |
1504 | if (ecc & ONENAND_ECC_2BIT_ALL) { | 1508 | if (ecc & ONENAND_ECC_2BIT_ALL) { |
1505 | printk(KERN_WARNING "%s: ecc error = 0x%04x, " | 1509 | printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x " |
1506 | "controller error 0x%04x\n", | 1510 | "intr 0x%04x addr1 %#x addr8 %#x\n", |
1507 | __func__, ecc, ctrl); | 1511 | __func__, ecc, ctrl, interrupt, addr1, addr8); |
1508 | return ONENAND_BBT_READ_ECC_ERROR; | 1512 | return ONENAND_BBT_READ_ECC_ERROR; |
1509 | } | 1513 | } |
1510 | } else { | 1514 | } else { |
1511 | printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", | 1515 | printk(KERN_ERR "%s: read timeout! ctrl 0x%04x " |
1512 | __func__, ctrl, interrupt); | 1516 | "intr 0x%04x addr1 %#x addr8 %#x\n", |
1517 | __func__, ctrl, interrupt, addr1, addr8); | ||
1513 | return ONENAND_BBT_READ_FATAL_ERROR; | 1518 | return ONENAND_BBT_READ_FATAL_ERROR; |
1514 | } | 1519 | } |
1515 | 1520 | ||
1516 | /* Initial bad block case: 0x2400 or 0x0400 */ | 1521 | /* Initial bad block case: 0x2400 or 0x0400 */ |
1517 | if (ctrl & ONENAND_CTRL_ERROR) { | 1522 | if (ctrl & ONENAND_CTRL_ERROR) { |
1518 | printk(KERN_DEBUG "%s: controller error = 0x%04x\n", | 1523 | printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x " |
1519 | __func__, ctrl); | 1524 | "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8); |
1520 | return ONENAND_BBT_READ_ERROR; | 1525 | return ONENAND_BBT_READ_ERROR; |
1521 | } | 1526 | } |
1522 | 1527 | ||
@@ -1558,7 +1563,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1558 | 1563 | ||
1559 | column = from & (mtd->oobsize - 1); | 1564 | column = from & (mtd->oobsize - 1); |
1560 | 1565 | ||
1561 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1566 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1562 | 1567 | ||
1563 | while (read < len) { | 1568 | while (read < len) { |
1564 | cond_resched(); | 1569 | cond_resched(); |
@@ -1612,7 +1617,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1612 | u_char *oob_buf = this->oob_buf; | 1617 | u_char *oob_buf = this->oob_buf; |
1613 | int status, i, readcmd; | 1618 | int status, i, readcmd; |
1614 | 1619 | ||
1615 | readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; | 1620 | readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; |
1616 | 1621 | ||
1617 | this->command(mtd, readcmd, to, mtd->oobsize); | 1622 | this->command(mtd, readcmd, to, mtd->oobsize); |
1618 | onenand_update_bufferram(mtd, to, 0); | 1623 | onenand_update_bufferram(mtd, to, 0); |
@@ -1845,7 +1850,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1845 | const u_char *buf = ops->datbuf; | 1850 | const u_char *buf = ops->datbuf; |
1846 | const u_char *oob = ops->oobbuf; | 1851 | const u_char *oob = ops->oobbuf; |
1847 | u_char *oobbuf; | 1852 | u_char *oobbuf; |
1848 | int ret = 0; | 1853 | int ret = 0, cmd; |
1849 | 1854 | ||
1850 | DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", | 1855 | DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", |
1851 | __func__, (unsigned int) to, (int) len); | 1856 | __func__, (unsigned int) to, (int) len); |
@@ -1954,7 +1959,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1954 | ONENAND_SET_NEXT_BUFFERRAM(this); | 1959 | ONENAND_SET_NEXT_BUFFERRAM(this); |
1955 | } | 1960 | } |
1956 | 1961 | ||
1957 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | 1962 | this->ongoing = 0; |
1963 | cmd = ONENAND_CMD_PROG; | ||
1964 | |||
1965 | /* Exclude 1st OTP and OTP blocks for cache program feature */ | ||
1966 | if (ONENAND_IS_CACHE_PROGRAM(this) && | ||
1967 | likely(onenand_block(this, to) != 0) && | ||
1968 | ONENAND_IS_4KB_PAGE(this) && | ||
1969 | ((written + thislen) < len)) { | ||
1970 | cmd = ONENAND_CMD_2X_CACHE_PROG; | ||
1971 | this->ongoing = 1; | ||
1972 | } | ||
1973 | |||
1974 | this->command(mtd, cmd, to, mtd->writesize); | ||
1958 | 1975 | ||
1959 | /* | 1976 | /* |
1960 | * 2 PLANE, MLC, and Flex-OneNAND wait here | 1977 | * 2 PLANE, MLC, and Flex-OneNAND wait here |
@@ -2067,7 +2084,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, | |||
2067 | 2084 | ||
2068 | oobbuf = this->oob_buf; | 2085 | oobbuf = this->oob_buf; |
2069 | 2086 | ||
2070 | oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; | 2087 | oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; |
2071 | 2088 | ||
2072 | /* Loop until all data write */ | 2089 | /* Loop until all data write */ |
2073 | while (written < len) { | 2090 | while (written < len) { |
@@ -2086,7 +2103,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, | |||
2086 | memcpy(oobbuf + column, buf, thislen); | 2103 | memcpy(oobbuf + column, buf, thislen); |
2087 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | 2104 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); |
2088 | 2105 | ||
2089 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { | 2106 | if (ONENAND_IS_4KB_PAGE(this)) { |
2090 | /* Set main area of DataRAM to 0xff*/ | 2107 | /* Set main area of DataRAM to 0xff*/ |
2091 | memset(this->page_buf, 0xff, mtd->writesize); | 2108 | memset(this->page_buf, 0xff, mtd->writesize); |
2092 | this->write_bufferram(mtd, ONENAND_DATARAM, | 2109 | this->write_bufferram(mtd, ONENAND_DATARAM, |
@@ -2481,7 +2498,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2481 | /* Grab the lock and see if the device is available */ | 2498 | /* Grab the lock and see if the device is available */ |
2482 | onenand_get_device(mtd, FL_ERASING); | 2499 | onenand_get_device(mtd, FL_ERASING); |
2483 | 2500 | ||
2484 | if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { | 2501 | if (ONENAND_IS_4KB_PAGE(this) || region || |
2502 | instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { | ||
2485 | /* region is set for Flex-OneNAND (no mb erase) */ | 2503 | /* region is set for Flex-OneNAND (no mb erase) */ |
2486 | ret = onenand_block_by_block_erase(mtd, instr, | 2504 | ret = onenand_block_by_block_erase(mtd, instr, |
2487 | region, block_size); | 2505 | region, block_size); |
@@ -3029,7 +3047,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
3029 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 3047 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
3030 | this->wait(mtd, FL_OTPING); | 3048 | this->wait(mtd, FL_OTPING); |
3031 | 3049 | ||
3032 | ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? | 3050 | ret = ONENAND_IS_4KB_PAGE(this) ? |
3033 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : | 3051 | onenand_mlc_read_ops_nolock(mtd, from, &ops) : |
3034 | onenand_read_ops_nolock(mtd, from, &ops); | 3052 | onenand_read_ops_nolock(mtd, from, &ops); |
3035 | 3053 | ||
@@ -3377,8 +3395,10 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3377 | case ONENAND_DEVICE_DENSITY_4Gb: | 3395 | case ONENAND_DEVICE_DENSITY_4Gb: |
3378 | if (ONENAND_IS_DDP(this)) | 3396 | if (ONENAND_IS_DDP(this)) |
3379 | this->options |= ONENAND_HAS_2PLANE; | 3397 | this->options |= ONENAND_HAS_2PLANE; |
3380 | else if (numbufs == 1) | 3398 | else if (numbufs == 1) { |
3381 | this->options |= ONENAND_HAS_4KB_PAGE; | 3399 | this->options |= ONENAND_HAS_4KB_PAGE; |
3400 | this->options |= ONENAND_HAS_CACHE_PROGRAM; | ||
3401 | } | ||
3382 | 3402 | ||
3383 | case ONENAND_DEVICE_DENSITY_2Gb: | 3403 | case ONENAND_DEVICE_DENSITY_2Gb: |
3384 | /* 2Gb DDP does not have 2 plane */ | 3404 | /* 2Gb DDP does not have 2 plane */ |
@@ -3399,7 +3419,11 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3399 | break; | 3419 | break; |
3400 | } | 3420 | } |
3401 | 3421 | ||
3402 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 3422 | /* The MLC has 4KiB pagesize. */ |
3423 | if (ONENAND_IS_MLC(this)) | ||
3424 | this->options |= ONENAND_HAS_4KB_PAGE; | ||
3425 | |||
3426 | if (ONENAND_IS_4KB_PAGE(this)) | ||
3403 | this->options &= ~ONENAND_HAS_2PLANE; | 3427 | this->options &= ~ONENAND_HAS_2PLANE; |
3404 | 3428 | ||
3405 | if (FLEXONENAND(this)) { | 3429 | if (FLEXONENAND(this)) { |
@@ -3415,6 +3439,8 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
3415 | printk(KERN_DEBUG "Chip has 2 plane\n"); | 3439 | printk(KERN_DEBUG "Chip has 2 plane\n"); |
3416 | if (this->options & ONENAND_HAS_4KB_PAGE) | 3440 | if (this->options & ONENAND_HAS_4KB_PAGE) |
3417 | printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); | 3441 | printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); |
3442 | if (this->options & ONENAND_HAS_CACHE_PROGRAM) | ||
3443 | printk(KERN_DEBUG "Chip has cache program feature\n"); | ||
3418 | } | 3444 | } |
3419 | 3445 | ||
3420 | /** | 3446 | /** |
@@ -3831,7 +3857,7 @@ static int onenand_probe(struct mtd_info *mtd) | |||
3831 | /* The data buffer size is equal to page size */ | 3857 | /* The data buffer size is equal to page size */ |
3832 | mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); | 3858 | mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); |
3833 | /* We use the full BufferRAM */ | 3859 | /* We use the full BufferRAM */ |
3834 | if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) | 3860 | if (ONENAND_IS_4KB_PAGE(this)) |
3835 | mtd->writesize <<= 1; | 3861 | mtd->writesize <<= 1; |
3836 | 3862 | ||
3837 | mtd->oobsize = mtd->writesize >> 5; | 3863 | mtd->oobsize = mtd->writesize >> 5; |
@@ -4054,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
4054 | mtd->block_isbad = onenand_block_isbad; | 4080 | mtd->block_isbad = onenand_block_isbad; |
4055 | mtd->block_markbad = onenand_block_markbad; | 4081 | mtd->block_markbad = onenand_block_markbad; |
4056 | mtd->owner = THIS_MODULE; | 4082 | mtd->owner = THIS_MODULE; |
4083 | mtd->writebufsize = mtd->writesize; | ||
4057 | 4084 | ||
4058 | /* Unlock whole block */ | 4085 | /* Unlock whole block */ |
4059 | this->unlock_all(mtd); | 4086 | this->unlock_all(mtd); |
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 01ab5b3c453b..fc2c16a0fd1c 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -91,16 +91,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
91 | for (j = 0; j < len; j++) { | 91 | for (j = 0; j < len; j++) { |
92 | /* No need to read pages fully, | 92 | /* No need to read pages fully, |
93 | * just read required OOB bytes */ | 93 | * just read required OOB bytes */ |
94 | ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); | 94 | ret = onenand_bbt_read_oob(mtd, |
95 | from + j * this->writesize + bd->offs, &ops); | ||
95 | 96 | ||
96 | /* If it is a initial bad block, just ignore it */ | 97 | /* If it is a initial bad block, just ignore it */ |
97 | if (ret == ONENAND_BBT_READ_FATAL_ERROR) | 98 | if (ret == ONENAND_BBT_READ_FATAL_ERROR) |
98 | return -EIO; | 99 | return -EIO; |
99 | 100 | ||
100 | if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { | 101 | if (ret || check_short_pattern(&buf[j * scanlen], |
102 | scanlen, this->writesize, bd)) { | ||
101 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); | 103 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); |
102 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 104 | printk(KERN_INFO "OneNAND eraseblock %d is an " |
103 | i >> 1, (unsigned int) from); | 105 | "initial bad block\n", i >> 1); |
104 | mtd->ecc_stats.badblocks++; | 106 | mtd->ecc_stats.badblocks++; |
105 | break; | 107 | break; |
106 | } | 108 | } |
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 0de7a05e6de0..a4c74a9ba430 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c | |||
@@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
651 | void __iomem *p; | 651 | void __iomem *p; |
652 | void *buf = (void *) buffer; | 652 | void *buf = (void *) buffer; |
653 | dma_addr_t dma_src, dma_dst; | 653 | dma_addr_t dma_src, dma_dst; |
654 | int err, page_dma = 0; | 654 | int err, ofs, page_dma = 0; |
655 | struct device *dev = &onenand->pdev->dev; | 655 | struct device *dev = &onenand->pdev->dev; |
656 | 656 | ||
657 | p = this->base + area; | 657 | p = this->base + area; |
@@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, | |||
677 | if (!page) | 677 | if (!page) |
678 | goto normal; | 678 | goto normal; |
679 | 679 | ||
680 | /* Page offset */ | ||
681 | ofs = ((size_t) buf & ~PAGE_MASK); | ||
680 | page_dma = 1; | 682 | page_dma = 1; |
683 | |||
681 | /* DMA routine */ | 684 | /* DMA routine */ |
682 | dma_src = onenand->phys_base + (p - this->base); | 685 | dma_src = onenand->phys_base + (p - this->base); |
683 | dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); | 686 | dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE); |
684 | } else { | 687 | } else { |
685 | /* DMA routine */ | 688 | /* DMA routine */ |
686 | dma_src = onenand->phys_base + (p - this->base); | 689 | dma_src = onenand->phys_base + (p - this->base); |
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5ebe280225d6..f49e49dc5928 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -672,7 +672,33 @@ static int io_init(struct ubi_device *ubi) | |||
672 | ubi->nor_flash = 1; | 672 | ubi->nor_flash = 1; |
673 | } | 673 | } |
674 | 674 | ||
675 | ubi->min_io_size = ubi->mtd->writesize; | 675 | /* |
676 | * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize | ||
677 | * for these purposes, not @mtd->writesize. At the moment this does not | ||
678 | * matter for NAND, because currently @mtd->writebufsize is equivalent to | ||
679 | * @mtd->writesize for all NANDs. However, some CFI NOR flashes may | ||
680 | * have @mtd->writebufsize which is multiple of @mtd->writesize. | ||
681 | * | ||
682 | * The reason we use @mtd->writebufsize for @ubi->min_io_size is that | ||
683 | * UBI and UBIFS recovery algorithms rely on the fact that if there was | ||
684 | * an unclean power cut, then we can find offset of the last corrupted | ||
685 | * node, align the offset to @ubi->min_io_size, read the rest of the | ||
686 | * eraseblock starting from this offset, and check whether there are | ||
687 | * only 0xFF bytes. If yes, then we are probably dealing with a | ||
688 | * corruption caused by a power cut, if not, then this is probably some | ||
689 | * severe corruption. | ||
690 | * | ||
691 | * Thus, we have to use the maximum write unit size of the flash, which | ||
692 | * is @mtd->writebufsize, because @mtd->writesize is the minimum write | ||
693 | * size, not the maximum. | ||
694 | */ | ||
695 | if (ubi->mtd->type == MTD_NANDFLASH) | ||
696 | ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize); | ||
697 | else if (ubi->mtd->type == MTD_NORFLASH) | ||
698 | ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0); | ||
699 | |||
700 | ubi->min_io_size = ubi->mtd->writebufsize; | ||
701 | |||
676 | ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; | 702 | ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; |
677 | 703 | ||
678 | /* | 704 | /* |
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index fcdb7f65fe0b..0b8141fc5c26 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
@@ -425,12 +425,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, | |||
425 | 425 | ||
426 | /* Read both LEB 0 and LEB 1 into memory */ | 426 | /* Read both LEB 0 and LEB 1 into memory */ |
427 | ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { | 427 | ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { |
428 | leb[seb->lnum] = vmalloc(ubi->vtbl_size); | 428 | leb[seb->lnum] = vzalloc(ubi->vtbl_size); |
429 | if (!leb[seb->lnum]) { | 429 | if (!leb[seb->lnum]) { |
430 | err = -ENOMEM; | 430 | err = -ENOMEM; |
431 | goto out_free; | 431 | goto out_free; |
432 | } | 432 | } |
433 | memset(leb[seb->lnum], 0, ubi->vtbl_size); | ||
434 | 433 | ||
435 | err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, | 434 | err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, |
436 | ubi->vtbl_size); | 435 | ubi->vtbl_size); |
@@ -516,10 +515,9 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, | |||
516 | int i; | 515 | int i; |
517 | struct ubi_vtbl_record *vtbl; | 516 | struct ubi_vtbl_record *vtbl; |
518 | 517 | ||
519 | vtbl = vmalloc(ubi->vtbl_size); | 518 | vtbl = vzalloc(ubi->vtbl_size); |
520 | if (!vtbl) | 519 | if (!vtbl) |
521 | return ERR_PTR(-ENOMEM); | 520 | return ERR_PTR(-ENOMEM); |
522 | memset(vtbl, 0, ubi->vtbl_size); | ||
523 | 521 | ||
524 | for (i = 0; i < ubi->vtbl_slots; i++) | 522 | for (i = 0; i < ubi->vtbl_slots; i++) |
525 | memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); | 523 | memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); |