Commit ab2020f2 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6: (59 commits)
  mtd: mtdpart: disallow reading OOB past the end of the partition
  mtd: pxa3xx_nand: NULL dereference in pxa3xx_nand_probe
  UBI: use mtd->writebufsize to set minimal I/O unit size
  mtd: initialize writebufsize in the MTD object of a partition
  mtd: onenand: add mtd->writebufsize initialization
  mtd: nand: add mtd->writebufsize initialization
  mtd: cfi: add writebufsize initialization
  mtd: add writebufsize field to mtd_info struct
  mtd: OneNAND: OMAP2/3: prevent regulator sleeping while OneNAND is in use
  mtd: OneNAND: add enable / disable methods to onenand_chip
  mtd: m25p80: Fix JEDEC ID for AT26DF321
  mtd: txx9ndfmc: limit transfer bytes to 512 (ECC provides 6 bytes max)
  mtd: cfi_cmdset_0002: add support for Samsung K8D3x16UxC NOR chips
  mtd: cfi_cmdset_0002: add support for Samsung K8D6x16UxM NOR chips
  mtd: nand: ams-delta: drop omap_read/write, use ioremap
  mtd: m25p80: add debugging trace in sst_write
  mtd: nand: ams-delta: select for built-in by default
  mtd: OneNAND: lighten scary initial bad block messages
  mtd: OneNAND: OMAP2/3: add support for command line partitioning
  mtd: nand: rearrange ONFI revision checking, add ONFI 2.3
  ...

Fix up trivial conflict in drivers/mtd/Kconfig as per DavidW.
parents 235646a4 154bf89f
...@@ -179,6 +179,22 @@ static struct omap_board_config_kernel ams_delta_config[] = { ...@@ -179,6 +179,22 @@ static struct omap_board_config_kernel ams_delta_config[] = {
{ OMAP_TAG_LCD, &ams_delta_lcd_config }, { OMAP_TAG_LCD, &ams_delta_lcd_config },
}; };
static struct resource ams_delta_nand_resources[] = {
[0] = {
.start = OMAP1_MPUIO_BASE,
.end = OMAP1_MPUIO_BASE +
OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device ams_delta_nand_device = {
.name = "ams-delta-nand",
.id = -1,
.num_resources = ARRAY_SIZE(ams_delta_nand_resources),
.resource = ams_delta_nand_resources,
};
static struct resource ams_delta_kp_resources[] = { static struct resource ams_delta_kp_resources[] = {
[0] = { [0] = {
.start = INT_KEYBOARD, .start = INT_KEYBOARD,
...@@ -265,6 +281,7 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = { ...@@ -265,6 +281,7 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
}; };
static struct platform_device *ams_delta_devices[] __initdata = { static struct platform_device *ams_delta_devices[] __initdata = {
&ams_delta_nand_device,
&ams_delta_kp_device, &ams_delta_kp_device,
&ams_delta_lcd_device, &ams_delta_lcd_device,
&ams_delta_led_device, &ams_delta_led_device,
......
...@@ -23,6 +23,7 @@ struct omap_onenand_platform_data { ...@@ -23,6 +23,7 @@ struct omap_onenand_platform_data {
int (*onenand_setup)(void __iomem *, int freq); int (*onenand_setup)(void __iomem *, int freq);
int dma_channel; int dma_channel;
u8 flags; u8 flags;
u8 regulator_can_sleep;
}; };
#define ONENAND_MAX_PARTITIONS 8 #define ONENAND_MAX_PARTITIONS 8
......
...@@ -53,9 +53,10 @@ config MTD_PARTITIONS ...@@ -53,9 +53,10 @@ config MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device. 'normal' form of partitioning used on a block device.
if MTD_PARTITIONS
config MTD_REDBOOT_PARTS config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing" tristate "RedBoot partition table parsing"
depends on MTD_PARTITIONS
---help--- ---help---
RedBoot is a ROM monitor and bootloader which deals with multiple RedBoot is a ROM monitor and bootloader which deals with multiple
'images' in flash devices by putting a table one of the erase 'images' in flash devices by putting a table one of the erase
...@@ -72,9 +73,10 @@ config MTD_REDBOOT_PARTS ...@@ -72,9 +73,10 @@ config MTD_REDBOOT_PARTS
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example. example.
if MTD_REDBOOT_PARTS
config MTD_REDBOOT_DIRECTORY_BLOCK config MTD_REDBOOT_DIRECTORY_BLOCK
int "Location of RedBoot partition table" int "Location of RedBoot partition table"
depends on MTD_REDBOOT_PARTS
default "-1" default "-1"
---help--- ---help---
This option is the Linux counterpart to the This option is the Linux counterpart to the
...@@ -91,18 +93,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK ...@@ -91,18 +93,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
config MTD_REDBOOT_PARTS_UNALLOCATED config MTD_REDBOOT_PARTS_UNALLOCATED
bool "Include unallocated flash regions" bool "Include unallocated flash regions"
depends on MTD_REDBOOT_PARTS
help help
If you need to register each unallocated flash region as a MTD If you need to register each unallocated flash region as a MTD
'partition', enable this option. 'partition', enable this option.
config MTD_REDBOOT_PARTS_READONLY config MTD_REDBOOT_PARTS_READONLY
bool "Force read-only for RedBoot system images" bool "Force read-only for RedBoot system images"
depends on MTD_REDBOOT_PARTS
help help
If you need to force read-only for 'RedBoot', 'RedBoot Config' and If you need to force read-only for 'RedBoot', 'RedBoot Config' and
'FIS directory' images, enable this option. 'FIS directory' images, enable this option.
endif # MTD_REDBOOT_PARTS
config MTD_CMDLINE_PARTS config MTD_CMDLINE_PARTS
bool "Command line partition table parsing" bool "Command line partition table parsing"
depends on MTD_PARTITIONS = "y" && MTD = "y" depends on MTD_PARTITIONS = "y" && MTD = "y"
...@@ -142,7 +144,7 @@ config MTD_CMDLINE_PARTS ...@@ -142,7 +144,7 @@ config MTD_CMDLINE_PARTS
config MTD_AFS_PARTS config MTD_AFS_PARTS
tristate "ARM Firmware Suite partition parsing" tristate "ARM Firmware Suite partition parsing"
depends on ARM && MTD_PARTITIONS depends on ARM
---help--- ---help---
The ARM Firmware Suite allows the user to divide flash devices into The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name multiple 'images'. Each such image has a header containing its name
...@@ -158,8 +160,8 @@ config MTD_AFS_PARTS ...@@ -158,8 +160,8 @@ config MTD_AFS_PARTS
example. example.
config MTD_OF_PARTS config MTD_OF_PARTS
tristate "Flash partition map based on OF description" def_bool y
depends on OF && MTD_PARTITIONS depends on OF
help help
This provides a partition parsing function which derives This provides a partition parsing function which derives
the partition map from the children of the flash node, the partition map from the children of the flash node,
...@@ -167,10 +169,11 @@ config MTD_OF_PARTS ...@@ -167,10 +169,11 @@ config MTD_OF_PARTS
config MTD_AR7_PARTS config MTD_AR7_PARTS
tristate "TI AR7 partitioning support" tristate "TI AR7 partitioning support"
depends on MTD_PARTITIONS
---help--- ---help---
TI AR7 partitioning support TI AR7 partitioning support
endif # MTD_PARTITIONS
comment "User Modules And Translation Layers" comment "User Modules And Translation Layers"
config MTD_CHAR config MTD_CHAR
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
obj-$(CONFIG_MTD) += mtd.o obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o mtd-y := mtdcore.o mtdsuper.o
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
# 'Users' - code which presents functionality to userspace. # 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o obj-$(CONFIG_MTD_CHAR) += mtdchar.o
......
...@@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) ...@@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
#endif #endif
/* Atmel chips don't use the same PRI format as Intel chips */ /* Atmel chips don't use the same PRI format as Intel chips */
static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) static void fixup_convert_atmel_pri(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) ...@@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
cfi->cfiq->BufWriteTimeoutMax = 0; cfi->cfiq->BufWriteTimeoutMax = 0;
} }
static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) static void fixup_at49bv640dx_lock(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) ...@@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param)
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) static void fixup_intel_strataflash(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) ...@@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
#endif #endif
#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) static void fixup_no_write_suspend(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) ...@@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
} }
#endif #endif
static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) static void fixup_st_m28w320ct(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) ...@@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
} }
static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) static void fixup_st_m28w320cb(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) ...@@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
(cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
}; };
static void fixup_use_point(struct mtd_info *mtd, void *param) static void fixup_use_point(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
if (!mtd->point && map_is_linear(map)) { if (!mtd->point && map_is_linear(map)) {
...@@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd, void *param) ...@@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd, void *param)
} }
} }
static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) static void fixup_use_write_buffers(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) ...@@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
/* /*
* Some chips power-up with all sectors locked by default. * Some chips power-up with all sectors locked by default.
*/ */
static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) static void fixup_unlock_powerup_lock(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) ...@@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
} }
static struct cfi_fixup cfi_fixup_table[] = { static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
{ CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL }, { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock },
{ CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL }, { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock },
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash },
#endif #endif
#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend },
#endif #endif
#if !FORCE_WORD_WRITE #if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
#endif #endif
{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct },
{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb },
{ CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock },
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static struct cfi_fixup jedec_fixup_table[] = { static struct cfi_fixup jedec_fixup_table[] = {
{ CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock },
{ CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock },
{ CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock },
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static struct cfi_fixup fixup_table[] = { static struct cfi_fixup fixup_table[] = {
/* The CFI vendor ids and the JEDEC vendor IDs appear /* The CFI vendor ids and the JEDEC vendor IDs appear
...@@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = { ...@@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = {
* well. This table is to pick all cases where * well. This table is to pick all cases where
* we know that is the case. * we know that is the case.
*/ */
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point },
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static void cfi_fixup_major_minor(struct cfi_private *cfi, 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,6 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH; mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name; mtd->name = map->name;
mtd->writesize = 1; mtd->writesize = 1;
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
......
...@@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) ...@@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp)
#ifdef AMD_BOOTLOC_BUG #ifdef AMD_BOOTLOC_BUG
/* Wheee. Bring me the head of someone at AMD. */ /* Wheee. Bring me the head of someone at AMD. */
static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) static void fixup_amd_bootblock(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) ...@@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)
} }
#endif #endif
static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) static void fixup_use_write_buffers(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) ...@@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
} }
/* Atmel chips don't use the same PRI format as AMD chips */ /* Atmel chips don't use the same PRI format as AMD chips */
static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) static void fixup_convert_atmel_pri(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) ...@@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
cfi->cfiq->BufWriteTimeoutMax = 0; cfi->cfiq->BufWriteTimeoutMax = 0;
} }
static void fixup_use_secsi(struct mtd_info *mtd, void *param) static void fixup_use_secsi(struct mtd_info *mtd)
{ {
/* Setup for chips with a secsi area */ /* Setup for chips with a secsi area */
mtd->read_user_prot_reg = cfi_amdstd_secsi_read; mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
} }
static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) static void fixup_use_erase_chip(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) ...@@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
* Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors
* locked by default. * locked by default.
*/ */
static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) static void fixup_use_atmel_lock(struct mtd_info *mtd)
{ {
mtd->lock = cfi_atmel_lock; mtd->lock = cfi_atmel_lock;
mtd->unlock = cfi_atmel_unlock; mtd->unlock = cfi_atmel_unlock;
...@@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd) ...@@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd)
cfi->cfiq->NumEraseRegions = 1; cfi->cfiq->NumEraseRegions = 1;
} }
static void fixup_sst39vf(struct mtd_info *mtd, void *param) static void fixup_sst39vf(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param) ...@@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param)
cfi->addr_unlock2 = 0x2AAA; cfi->addr_unlock2 = 0x2AAA;
} }
static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) static void fixup_sst39vf_rev_b(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) ...@@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)
cfi->sector_erase_cmd = CMD(0x50); cfi->sector_erase_cmd = CMD(0x50);
} }
static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
fixup_sst39vf_rev_b(mtd, param); fixup_sst39vf_rev_b(mtd);
/* /*
* CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where * 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,7 +310,7 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param)
pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);
} }
static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) ...@@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param)
} }
} }
static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) ...@@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
/* Used to fix CFI-Tables of chips without Extended Query Tables */ /* Used to fix CFI-Tables of chips without Extended Query Tables */
static struct cfi_fixup cfi_nopri_fixup_table[] = { static struct cfi_fixup cfi_nopri_fixup_table[] = {
{ CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
{ CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */
{ CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */
{ CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */
{ CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */
{ CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */
{ CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */
{ CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static struct cfi_fixup cfi_fixup_table[] = { static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
#ifdef AMD_BOOTLOC_BUG #ifdef AMD_BOOTLOC_BUG
{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock },
{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL }, { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },
#endif #endif
{ CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x0050, fixup_use_secsi },
{ CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x0053, fixup_use_secsi },
{ CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x0055, fixup_use_secsi },
{ CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x0056, fixup_use_secsi },
{ CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x005C, fixup_use_secsi },
{ CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, { CFI_MFR_AMD, 0x005F, fixup_use_secsi },
{ CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
{ CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
{ CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
{ CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
{ CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */
#if !FORCE_WORD_WRITE #if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
#endif #endif
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static struct cfi_fixup jedec_fixup_table[] = { static struct cfi_fixup jedec_fixup_table[] = {
{ CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock },
{ CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock },
{ CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock },
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static struct cfi_fixup fixup_table[] = { static struct cfi_fixup fixup_table[] = {
...@@ -383,18 +383,30 @@ static struct cfi_fixup fixup_table[] = { ...@@ -383,18 +383,30 @@ static struct cfi_fixup fixup_table[] = {
* well. This table is to pick all cases where * well. This table is to pick all cases where
* we know that is the case. * we know that is the case.
*/ */
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip },
{ CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock },
{ 0, 0, NULL, NULL } { 0, 0, NULL }
}; };
static void cfi_fixup_major_minor(struct cfi_private *cfi, static void cfi_fixup_major_minor(struct cfi_private *cfi,
struct cfi_pri_amdstd *extp) struct cfi_pri_amdstd *extp)
{ {
if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && if (cfi->mfr == CFI_MFR_SAMSUNG) {
extp->MajorVersion == '0') if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') ||
extp->MajorVersion = '1'; (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
/*
* Samsung K8P2815UQB and K8D6x16UxM chips
* report major=0 / minor=0.
* K8D3x16UxC chips report major=3 / minor=3.
*/
printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu"
" Extended Query version to 1.%c\n",
extp->MinorVersion);
extp->MajorVersion = '1';
}
}
/* /*
* SST 38VF640x chips report major=0xFF / minor=0xFF. * SST 38VF640x chips report major=0xFF / minor=0xFF.
*/ */
...@@ -428,6 +440,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) ...@@ -428,6 +440,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH; mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name; mtd->name = map->name;
mtd->writesize = 1; mtd->writesize = 1;
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n",
__func__, mtd->writebufsize);
mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
......
...@@ -238,6 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) ...@@ -238,6 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->resume = cfi_staa_resume; mtd->resume = cfi_staa_resume;
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
map->fldrv = &cfi_staa_chipdrv; map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
mtd->name = map->name; mtd->name = map->name;
......
...@@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) ...@@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
for (f=fixups; f->fixup; f++) { for (f=fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
f->fixup(mtd, f->param); f->fixup(mtd);
} }
} }
} }
......
...@@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
return ret; return ret;
} }
static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) static void fixup_use_fwh_lock(struct mtd_info *mtd)
{ {
printk(KERN_NOTICE "using fwh lock/unlock method\n"); printk(KERN_NOTICE "using fwh lock/unlock method\n");
/* Setup for the chips with the fwh lock method */ /* Setup for the chips with the fwh lock method */
......
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
#define OPCODE_WRDI 0x04 /* Write disable */ #define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ #define OPCODE_AAI_WP 0xad /* Auto address increment word program */
/* Used for Macronix flashes only. */
#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
/* Status Register bits. */ /* Status Register bits. */
#define SR_WIP 1 /* Write in progress */ #define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */ #define SR_WEL 2 /* Write enable latch */
...@@ -62,7 +66,7 @@ ...@@ -62,7 +66,7 @@
/* Define max times to check status register before we give up. */ /* Define max times to check status register before we give up. */
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
#define MAX_CMD_SIZE 4 #define MAX_CMD_SIZE 5
#ifdef CONFIG_M25PXX_USE_FAST_READ #ifdef CONFIG_M25PXX_USE_FAST_READ
#define OPCODE_READ OPCODE_FAST_READ #define OPCODE_READ OPCODE_FAST_READ
...@@ -151,6 +155,16 @@ static inline int write_disable(struct m25p *flash) ...@@ -151,6 +155,16 @@ static inline int write_disable(struct m25p *flash)
return spi_write_then_read(flash->spi, &code, 1, NULL, 0); return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
} }
/*
* Enable/disable 4-byte addressing mode.
*/
static inline int set_4byte(struct m25p *flash, int enable)
{
u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B;
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}
/* /*
* Service routine to read status register until ready, or timeout occurs. * Service routine to read status register until ready, or timeout occurs.
* Returns non-zero if error. * Returns non-zero if error.
...@@ -207,6 +221,7 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) ...@@ -207,6 +221,7 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd)
cmd[1] = addr >> (flash->addr_width * 8 - 8); cmd[1] = addr >> (flash->addr_width * 8 - 8);
cmd[2] = addr >> (flash->addr_width * 8 - 16); cmd[2] = addr >> (flash->addr_width * 8 - 16);
cmd[3] = addr >> (flash->addr_width * 8 - 24); cmd[3] = addr >> (flash->addr_width * 8 - 24);
cmd[4] = addr >> (flash->addr_width * 8 - 32);
} }
static int m25p_cmdsz(struct m25p *flash) 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,6 +497,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t actual; size_t actual;
int cmd_sz, ret; int cmd_sz, ret;
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
dev_name(&flash->spi->dev), __func__, "to",
(u32)to, len);
*retlen = 0; *retlen = 0;
/* sanity checks */ /* sanity checks */
...@@ -607,7 +626,6 @@ struct flash_info { ...@@ -607,7 +626,6 @@ struct flash_info {
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = 256, \ .page_size = 256, \
.addr_width = 3, \
.flags = (_flags), \ .flags = (_flags), \
}) })
...@@ -635,7 +653,7 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -635,7 +653,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
{ "at26df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
/* EON -- en25pxx */ /* EON -- en25pxx */
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
...@@ -653,6 +671,8 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -653,6 +671,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
/* Spansion -- single (large) sector size only, at least /* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors). * 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,6 +784,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
return &m25p_ids[tmp]; return &m25p_ids[tmp];
} }
} }
dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
...@@ -883,7 +904,17 @@ static int __devinit m25p_probe(struct spi_device *spi) ...@@ -883,7 +904,17 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.dev.parent = &spi->dev; flash->mtd.dev.parent = &spi->dev;
flash->page_size = info->page_size; flash->page_size = info->page_size;
flash->addr_width = info->addr_width;
if (info->addr_width)
flash->addr_width = info->addr_width;
else {
/* enable 4-byte addressing if the device exceeds 16MiB */
if (flash->mtd.size > 0x1000000) {
flash->addr_width = 4;
set_4byte(flash, 1);
} else
flash->addr_width = 3;
}
dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
(long long)flash->mtd.size >> 10); (long long)flash->mtd.size >> 10);
......
...@@ -335,7 +335,7 @@ static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -335,7 +335,7 @@ static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len,
return ret; return ret;
} }
static struct flash_info *__init sst25l_match_device(struct spi_device *spi) static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
{ {
struct flash_info *flash_info = NULL; struct flash_info *flash_info = NULL;
struct spi_message m; struct spi_message m;
...@@ -375,7 +375,7 @@ static struct flash_info *__init sst25l_match_device(struct spi_device *spi) ...@@ -375,7 +375,7 @@ static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
return flash_info; return flash_info;
} }
static int __init sst25l_probe(struct spi_device *spi) static int __devinit sst25l_probe(struct spi_device *spi)
{ {
struct flash_info *flash_info; struct flash_info *flash_info;
struct sst25l_flash *flash; struct sst25l_flash *flash;
......
...@@ -149,11 +149,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, ...@@ -149,11 +149,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
if (request_resource(&iomem_resource, &window->rsrc)) { if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL; window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME printk(KERN_ERR MOD_NAME
" %s(): Unable to register resource" " %s(): Unable to register resource %pR - kernel bug?\n",
" 0x%.16llx-0x%.16llx - kernel bug?\n", __func__, &window->rsrc);
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
} }
......
...@@ -196,10 +196,15 @@ static int bcm963xx_probe(struct platform_device *pdev) ...@@ -196,10 +196,15 @@ static int bcm963xx_probe(struct platform_device *pdev)
bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map);
if (!bcm963xx_mtd_info) { if (!bcm963xx_mtd_info) {
dev_err(&pdev->dev, "failed to probe using CFI\n"); dev_err(&pdev->dev, "failed to probe using CFI\n");
bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map);
if (bcm963xx_mtd_info)
goto probe_ok;
dev_err(&pdev->dev, "failed to probe using JEDEC\n");
err = -EIO; err = -EIO;
goto err_probe; goto err_probe;
} }
probe_ok:
bcm963xx_mtd_info->owner = THIS_MODULE; bcm963xx_mtd_info->owner = THIS_MODULE;
/* This is mutually exclusive */ /* This is mutually exclusive */
......
...@@ -178,11 +178,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, ...@@ -178,11 +178,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
if (request_resource(&iomem_resource, &window->rsrc)) { if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL; window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME printk(KERN_ERR MOD_NAME
" %s(): Unable to register resource" " %s(): Unable to register resource %pR - kernel bug?\n",
" 0x%.016llx-0x%.016llx - kernel bug?\n", __func__, &window->rsrc);
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
} }
......
...@@ -242,12 +242,9 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, ...@@ -242,12 +242,9 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) { if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL; window->rsrc.parent = NULL;
printk(KERN_DEBUG MOD_NAME printk(KERN_DEBUG MOD_NAME ": "
": %s(): Unable to register resource" "%s(): Unable to register resource %pR - kernel bug?\n",
" 0x%.08llx-0x%.08llx - kernel bug?\n", __func__, &window->rsrc);
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
} }
/* Map the firmware hub into my address space. */ /* Map the firmware hub into my address space. */
......
...@@ -175,12 +175,9 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, ...@@ -175,12 +175,9 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) { if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL; window->rsrc.parent = NULL;
printk(KERN_DEBUG MOD_NAME printk(KERN_DEBUG MOD_NAME ": "
": %s(): Unable to register resource" "%s(): Unable to register resource %pR - kernel bug?\n",
" 0x%.16llx-0x%.16llx - kernel bug?\n", __func__, &window->rsrc);
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
} }
/* Map the firmware hub into my address space. */ /* Map the firmware hub into my address space. */
......
...@@ -274,9 +274,7 @@ static int __devinit of_flash_probe(struct platform_device *dev, ...@@ -274,9 +274,7 @@ static int __devinit of_flash_probe(struct platform_device *dev,
continue; continue;
} }
dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
(unsigned long long)res.start,
(unsigned long long)res.end);
err = -EBUSY; err = -EBUSY;
res_size = resource_size(&res); res_size = resource_size(&res);
......
...@@ -166,9 +166,8 @@ static int __init init_scx200_docflash(void) ...@@ -166,9 +166,8 @@ static int __init init_scx200_docflash(void)
outl(pmr, scx200_cb_base + SCx200_PMR); outl(pmr, scx200_cb_base + SCx200_PMR);
} }
printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n", printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n",
(unsigned long long)docmem.start, &docmem, width);
(unsigned long long)docmem.end, width);
scx200_docflash_map.size = size; scx200_docflash_map.size = size;
if (width == 8) if (width == 8)
......
...@@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void) ...@@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void)
goto error_mem; goto error_mem;
} }
map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); map_banks[idx]->name = kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) { if (!map_banks[idx]->name) {
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -522,10 +522,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, ...@@ -522,10 +522,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
/* Only master mtd device must be used to control partitions */
if (!mtd_is_master(mtd))
return -EINVAL;
if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
return -EFAULT; return -EFAULT;
...@@ -535,6 +531,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, ...@@ -535,6 +531,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
switch (a.op) { switch (a.op) {
case BLKPG_ADD_PARTITION: case BLKPG_ADD_PARTITION:
/* Only master mtd device must be used to add partitions */
if (mtd_is_partition(mtd))
return -EINVAL;
return mtd_add_partition(mtd, p.devname, p.start, p.length); return mtd_add_partition(mtd, p.devname, p.start, p.length);
case BLKPG_DEL_PARTITION: case BLKPG_DEL_PARTITION:
...@@ -601,6 +601,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -601,6 +601,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
} }
case MEMGETINFO: case MEMGETINFO:
memset(&info, 0, sizeof(info));
info.type = mtd->type; info.type = mtd->type;
info.flags = mtd->flags; info.flags = mtd->flags;
info.size = mtd->size; info.size = mtd->size;
...@@ -609,7 +610,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -609,7 +610,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
info.oobsize = mtd->oobsize; info.oobsize = mtd->oobsize;
/* The below fields are obsolete */ /* The below fields are obsolete */
info.ecctype = -1; info.ecctype = -1;
info.eccsize = 0;
if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
return -EFAULT; return -EFAULT;
break; break;
......
...@@ -776,6 +776,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -776,6 +776,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.size = subdev[0]->size; concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize; concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.writebufsize = subdev[0]->writebufsize;
concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail; concat->mtd.oobavail = subdev[0]->oobavail;
......
...@@ -401,7 +401,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) ...@@ -401,7 +401,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n");
cxt->mtd = NULL; cxt->mtd = NULL;
flush_scheduled_work(); flush_work_sync(&cxt->work_erase);
flush_work_sync(&cxt->work_write);
} }
......
...@@ -120,8 +120,25 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -120,8 +120,25 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL; return -EINVAL;
if (ops->datbuf && from + ops->len > mtd->size) if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL; return -EINVAL;
res = part->master->read_oob(part->master, from + part->offset, ops);
/*
* If OOB is also requested, make sure that we do not read past the end
* of this partition.
*/
if (ops->oobbuf) {
size_t len, pages;
if (ops->mode == MTD_OOB_AUTO)
len = mtd->oobavail;
else
len = mtd->oobsize;
pages = mtd_div_by_ws(mtd->size, mtd);
pages -= mtd_div_by_ws(from, mtd);
if (ops->ooboffs + ops->ooblen > pages * len)
return -EINVAL;
}
res = part->master->read_oob(part->master, from + part->offset, ops);
if (unlikely(res)) { if (unlikely(res)) {
if (res == -EUCLEAN) if (res == -EUCLEAN)
mtd->ecc_stats.corrected++; mtd->ecc_stats.corrected++;
...@@ -384,6 +401,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -384,6 +401,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.flags = master->flags & ~part->mask_flags; slave->mtd.flags = master->flags & ~part->mask_flags;
slave->mtd.size = part->size; slave->mtd.size = part->size;
slave->mtd.writesize = master->writesize; slave->mtd.writesize = master->writesize;
slave->mtd.writebufsize = master->writebufsize;
slave->mtd.oobsize = master->oobsize; slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail; slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft; slave->mtd.subpage_sft = master->subpage_sft;
...@@ -720,19 +738,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, ...@@ -720,19 +738,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
} }
EXPORT_SYMBOL_GPL(parse_mtd_partitions); EXPORT_SYMBOL_GPL(parse_mtd_partitions);
int mtd_is_master(struct mtd_info *mtd) int mtd_is_partition(struct mtd_info *mtd)
{ {
struct mtd_part *part; struct mtd_part *part;
int nopart = 0; int ispart = 0;
mutex_lock(&mtd_partitions_mutex); mutex_lock(&mtd_partitions_mutex);
list_for_each_entry(part, &mtd_partitions, list) list_for_each_entry(part, &mtd_partitions, list)
if (&part->mtd == mtd) { if (&part->mtd == mtd) {
nopart = 1; ispart = 1;
break; break;
} }
mutex_unlock(&mtd_partitions_mutex); mutex_unlock(&mtd_partitions_mutex);
return nopart; return ispart;
} }
EXPORT_SYMBOL_GPL(mtd_is_master); EXPORT_SYMBOL_GPL(mtd_is_partition);
...@@ -96,6 +96,7 @@ config MTD_NAND_SPIA ...@@ -96,6 +96,7 @@ config MTD_NAND_SPIA
config MTD_NAND_AMS_DELTA config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3" tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA depends on MACH_AMS_DELTA
default y
help help
Support for NAND flash on Amstrad E3 (Delta). Support for NAND flash on Amstrad E3 (Delta).
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
* *
* Derived from drivers/mtd/toto.c * Derived from drivers/mtd/toto.c
* Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
* Partially stolen from drivers/mtd/nand/plat_nand.c
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -62,9 +64,10 @@ static struct mtd_partition partition_info[] = { ...@@ -62,9 +64,10 @@ static struct mtd_partition partition_info[] = {
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
void __iomem *io_base = this->priv;
omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); writew(0, io_base + OMAP_MPUIO_IO_CNTL);
omap_writew(byte, this->IO_ADDR_W); writew(byte, this->IO_ADDR_W);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
ndelay(40); ndelay(40);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 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,11 +78,12 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd)
{ {
u_char res; u_char res;
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
void __iomem *io_base = this->priv;
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
ndelay(40); ndelay(40);
omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
res = omap_readw(this->IO_ADDR_R); res = readw(this->IO_ADDR_R);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
AMS_DELTA_LATCH2_NAND_NRE); AMS_DELTA_LATCH2_NAND_NRE);
...@@ -151,11 +155,16 @@ static int ams_delta_nand_ready(struct mtd_info *mtd) ...@@ -151,11 +155,16 @@ static int ams_delta_nand_ready(struct mtd_info *mtd)
/* /*
* Main initialization routine * Main initialization routine
*/ */
static int __init ams_delta_init(void) static int __devinit ams_delta_init(struct platform_device *pdev)
{ {
struct nand_chip *this; struct nand_chip *this;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *io_base;
int err = 0; int err = 0;
if (!res)
return -ENXIO;
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
sizeof(struct nand_chip), GFP_KERNEL); sizeof(struct nand_chip), GFP_KERNEL);
...@@ -177,9 +186,25 @@ static int __init ams_delta_init(void) ...@@ -177,9 +186,25 @@ static int __init ams_delta_init(void)
/* Link the private data with the MTD structure */ /* Link the private data with the MTD structure */
ams_delta_mtd->priv = this; ams_delta_mtd->priv = this;
if (!request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev))) {
dev_err(&pdev->dev, "request_mem_region failed\n");
err = -EBUSY;
goto out_free;
}
io_base = ioremap(res->start, resource_size(res));
if (io_base == NULL) {
dev_err(&pdev->dev, "ioremap failed\n");
err = -EIO;
goto out_release_io;
}
this->priv = io_base;
/* Set address of NAND IO lines */ /* Set address of NAND IO lines */
this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT); this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
this->read_byte = ams_delta_read_byte; this->read_byte = ams_delta_read_byte;
this->write_buf = ams_delta_write_buf; this->write_buf = ams_delta_write_buf;
this->read_buf = ams_delta_read_buf; this->read_buf = ams_delta_read_buf;
...@@ -195,6 +220,8 @@ static int __init ams_delta_init(void) ...@@ -195,6 +220,8 @@ static int __init ams_delta_init(void)
this->chip_delay = 30; this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT; this->ecc.mode = NAND_ECC_SOFT;
platform_set_drvdata(pdev, io_base);
/* Set chip enabled, but */ /* Set chip enabled, but */
ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_NWE |
...@@ -214,25 +241,56 @@ static int __init ams_delta_init(void) ...@@ -214,25 +241,56 @@ static int __init ams_delta_init(void)
goto out; goto out;
out_mtd: out_mtd:
platform_set_drvdata(pdev, NULL);
iounmap(io_base);
out_release_io:
release_mem_region(res->start, resource_size(res));
out_free:
kfree(ams_delta_mtd); kfree(ams_delta_mtd);
out: out:
return err; return err;
} }
module_init(ams_delta_init);
/* /*
* Clean up routine * Clean up routine
*/ */
static void __exit ams_delta_cleanup(void) static int __devexit ams_delta_cleanup(struct platform_device *pdev)
{ {
void __iomem *io_base = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* Release resources, unregister device */ /* Release resources, unregister device */
nand_release(ams_delta_mtd); nand_release(ams_delta_mtd);
iounmap(io_base);
release_mem_region(res->start, resource_size(res));
/* Free the MTD device structure */ /* Free the MTD device structure */
kfree(ams_delta_mtd); kfree(ams_delta_mtd);
return 0;
}
static struct platform_driver ams_delta_nand_driver = {
.probe = ams_delta_init,
.remove = __devexit_p(ams_delta_cleanup),
.driver = {
.name = "ams-delta-nand",
.owner = THIS_MODULE,
},
};
static int __init ams_delta_nand_init(void)
{
return platform_driver_register(&ams_delta_nand_driver);
}
module_init(ams_delta_nand_init);
static void __exit ams_delta_nand_exit(void)
{
platform_driver_unregister(&ams_delta_nand_driver);
} }
module_exit(ams_delta_cleanup); module_exit(ams_delta_nand_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
......
...@@ -388,6 +388,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, ...@@ -388,6 +388,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
"page_addr: 0x%x, column: 0x%x.\n", "page_addr: 0x%x, column: 0x%x.\n",
page_addr, column); page_addr, column);
elbc_fcm_ctrl->column = column;
elbc_fcm_ctrl->oob = 0;
elbc_fcm_ctrl->use_mdr = 1; elbc_fcm_ctrl->use_mdr = 1;
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mtd/fsmc.h> #include <linux/mtd/fsmc.h>
#include <linux/amba/bus.h>
#include <mtd/mtd-abi.h> #include <mtd/mtd-abi.h>
static struct nand_ecclayout fsmc_ecc1_layout = { static struct nand_ecclayout fsmc_ecc1_layout = {
...@@ -119,21 +120,36 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { ...@@ -119,21 +120,36 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
} }
}; };
/*
* Default partition tables to be used if the partition information not
* provided through platform data
*/
#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz}
#ifdef CONFIG_MTD_PARTITIONS
/* /*
* Default partition tables to be used if the partition information not
* provided through platform data.
*
* Default partition layout for small page(= 512 bytes) devices * Default partition layout for small page(= 512 bytes) devices
* Size for "Root file system" is updated in driver based on actual device size * Size for "Root file system" is updated in driver based on actual device size
*/ */
static struct mtd_partition partition_info_16KB_blk[] = { static struct mtd_partition partition_info_16KB_blk[] = {
PARTITION("X-loader", 0, 4 * 0x4000), {
PARTITION("U-Boot", 0x10000, 20 * 0x4000), .name = "X-loader",
PARTITION("Kernel", 0x60000, 256 * 0x4000), .offset = 0,
PARTITION("Root File System", 0x460000, 0), .size = 4*0x4000,
},
{
.name = "U-Boot",
.offset = 0x10000,
.size = 20*0x4000,
},
{
.name = "Kernel",
.offset = 0x60000,
.size = 256*0x4000,
},
{
.name = "Root File System",
.offset = 0x460000,
.size = 0,
},
}; };
/* /*
...@@ -141,19 +157,37 @@ static struct mtd_partition partition_info_16KB_blk[] = { ...@@ -141,19 +157,37 @@ static struct mtd_partition partition_info_16KB_blk[] = {
* Size for "Root file system" is updated in driver based on actual device size * Size for "Root file system" is updated in driver based on actual device size
*/ */
static struct mtd_partition partition_info_128KB_blk[] = { static struct mtd_partition partition_info_128KB_blk[] = {
PARTITION("X-loader", 0, 4 * 0x20000), {
PARTITION("U-Boot", 0x80000, 12 * 0x20000), .name = "X-loader",
PARTITION("Kernel", 0x200000, 48 * 0x20000), .offset = 0,
PARTITION("Root File System", 0x800000, 0), .size = 4*0x20000,
},
{
.name = "U-Boot",
.offset = 0x80000,
.size = 12*0x20000,
},
{
.name = "Kernel",
.offset = 0x200000,
.size = 48*0x20000,
},
{
.name = "Root File System",
.offset = 0x800000,
.size = 0,
},
}; };
#ifdef CONFIG_MTD_CMDLINE_PARTS #ifdef CONFIG_MTD_CMDLINE_PARTS
const char *part_probes[] = { "cmdlinepart", NULL }; const char *part_probes[] = { "cmdlinepart", NULL };
#endif #endif
#endif
/** /**
* struct fsmc_nand_data - atructure for FSMC NAND device state * struct fsmc_nand_data - structure for FSMC NAND device state
* *
* @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash. * @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash. * @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash. * @partitions: Partition info for a NAND Flash.
...@@ -169,6 +203,7 @@ const char *part_probes[] = { "cmdlinepart", NULL }; ...@@ -169,6 +203,7 @@ const char *part_probes[] = { "cmdlinepart", NULL };
* @regs_va: FSMC regs base address. * @regs_va: FSMC regs base address.
*/ */
struct fsmc_nand_data { struct fsmc_nand_data {
u32 pid;
struct mtd_info mtd; struct mtd_info mtd;
struct nand_chip nand; struct nand_chip nand;
struct mtd_partition *partitions; struct mtd_partition *partitions;
...@@ -508,7 +543,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -508,7 +543,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
struct nand_chip *nand; struct nand_chip *nand;
struct fsmc_regs *regs; struct fsmc_regs *regs;
struct resource *res; struct resource *res;
int nr_parts, ret = 0; int ret = 0;
u32 pid;
int i;
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "platform data is NULL\n"); dev_err(&pdev->dev, "platform data is NULL\n");
...@@ -598,6 +635,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -598,6 +635,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_probe1; goto err_probe1;
/*
* This device ID is actually a common AMBA ID as used on the
* AMBA PrimeCell bus. However it is not a PrimeCell.
*/
for (pid = 0, i = 0; i < 4; i++)
pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
host->pid = pid;
dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
"revision %02x, config %02x\n",
AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
host->bank = pdata->bank; host->bank = pdata->bank;
host->select_chip = pdata->select_bank; host->select_chip = pdata->select_bank;
regs = host->regs_va; regs = host->regs_va;
...@@ -625,7 +674,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -625,7 +674,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16);
if (get_fsmc_version(host->regs_va) == FSMC_VER8) { if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc; nand->ecc.read_page = fsmc_read_page_hwecc;
nand->ecc.calculate = fsmc_read_hwecc_ecc4; nand->ecc.calculate = fsmc_read_hwecc_ecc4;
nand->ecc.correct = fsmc_correct_data; nand->ecc.correct = fsmc_correct_data;
...@@ -645,7 +694,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -645,7 +694,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
goto err_probe; goto err_probe;
} }
if (get_fsmc_version(host->regs_va) == FSMC_VER8) { if (AMBA_REV_BITS(host->pid) >= 8) {
if (host->mtd.writesize == 512) { if (host->mtd.writesize == 512) {
nand->ecc.layout = &fsmc_ecc4_sp_layout; nand->ecc.layout = &fsmc_ecc4_sp_layout;
host->ecc_place = &fsmc_ecc4_sp_place; host->ecc_place = &fsmc_ecc4_sp_place;
...@@ -676,11 +725,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -676,11 +725,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* Check if partition info passed via command line * Check if partition info passed via command line
*/ */
host->mtd.name = "nand"; host->mtd.name = "nand";
nr_parts = parse_mtd_partitions(&host->mtd, part_probes, host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes,
&host->partitions, 0); &host->partitions, 0);
if (nr_parts > 0) { if (host->nr_partitions <= 0) {
host->nr_partitions = nr_parts;
} else {
#endif #endif
/* /*
* Check if partition info passed via command line * Check if partition info passed via command line
......
...@@ -251,58 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, ...@@ -251,58 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
return 0; return 0;
} }
/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos
* handling. The ecc area is for 4k chips 72 bytes long and thus does not fit
* into the eccpos array. */
static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
unsigned int ecc_offset = chip->page_shift;
/* Read the OOB area first */
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL);
if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
}
return 0;
}
/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */
static void jz_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
const uint8_t *p = buf;
unsigned int ecc_offset = chip->page_shift;
for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
chip->write_buf(mtd, p, eccsize);
chip->ecc.calculate(mtd, p, &chip->oob_poi[i]);
}
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
}
#ifdef CONFIG_MTD_CMDLINE_PARTS #ifdef CONFIG_MTD_CMDLINE_PARTS
static const char *part_probes[] = {"cmdline", NULL}; static const char *part_probes[] = {"cmdline", NULL};
#endif #endif
...@@ -393,9 +341,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) ...@@ -393,9 +341,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
chip->ecc.size = 512; chip->ecc.size = 512;
chip->ecc.bytes = 9; chip->ecc.bytes = 9;
chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first;
chip->ecc.write_page = jz_nand_write_page_hwecc;
if (pdata) if (pdata)
chip->ecc.layout = pdata->ecc_layout; chip->ecc.layout = pdata->ecc_layout;
...@@ -489,7 +434,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) ...@@ -489,7 +434,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
struct platform_driver jz_nand_driver = { static struct platform_driver jz_nand_driver = {
.probe = jz_nand_probe, .probe = jz_nand_probe,
.remove = __devexit_p(jz_nand_remove), .remove = __devexit_p(jz_nand_remove),
.driver = { .driver = {
......
...@@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) ...@@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
struct mxc_nand_host *host; struct mxc_nand_host *host;
struct resource *res; struct resource *res;
int err = 0, nr_parts = 0; int err = 0, __maybe_unused nr_parts = 0;
struct nand_ecclayout *oob_smallpage, *oob_largepage; struct nand_ecclayout *oob_smallpage, *oob_largepage;
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
......
...@@ -2865,20 +2865,24 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2865,20 +2865,24 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
/* check version */ /* check version */
val = le16_to_cpu(p->revision); val = le16_to_cpu(p->revision);
if (val == 1 || val > (1 << 4)) { if (val & (1 << 5))
printk(KERN_INFO "%s: unsupported ONFI version: %d\n", chip->onfi_version = 23;
__func__, val); else if (val & (1 << 4))
return 0;
}
if (val & (1 << 4))
chip->onfi_version = 22; chip->onfi_version = 22;
else if (val & (1 << 3)) else if (val & (1 << 3))
chip->onfi_version = 21; chip->onfi_version = 21;
else if (val & (1 << 2)) else if (val & (1 << 2))
chip->onfi_version = 20; chip->onfi_version = 20;
else else if (val & (1 << 1))
chip->onfi_version = 10; chip->onfi_version = 10;
else
chip->onfi_version = 0;
if (!chip->onfi_version) {
printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
__func__, val);
return 0;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model)); 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,7 +2891,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
mtd->writesize = le32_to_cpu(p->byte_per_page); mtd->writesize = le32_to_cpu(p->byte_per_page);
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
busw = 0; busw = 0;
if (le16_to_cpu(p->features) & 1) if (le16_to_cpu(p->features) & 1)
busw = NAND_BUSWIDTH_16; busw = NAND_BUSWIDTH_16;
...@@ -3157,7 +3161,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ...@@ -3157,7 +3161,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
printk(KERN_INFO "NAND device: Manufacturer ID:" printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
nand_manuf_ids[maf_idx].name, nand_manuf_ids[maf_idx].name,
chip->onfi_version ? type->name : chip->onfi_params.model); chip->onfi_version ? chip->onfi_params.model : type->name);
return type; return type;
} }
...@@ -3435,6 +3439,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -3435,6 +3439,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->resume = nand_resume; mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad; mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad; mtd->block_markbad = nand_block_markbad;
mtd->writebufsize = mtd->writesize;
/* propagate ecc.layout to mtd_info */ /* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout; mtd->ecclayout = chip->ecc.layout;
......
...@@ -1092,7 +1092,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) ...@@ -1092,7 +1092,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
/** /**
* verify_bbt_descr - verify the bad block description * verify_bbt_descr - verify the bad block description
* @bd: the table to verify * @mtd: MTD device structure
* @bd: the table to verify
* *
* This functions performs a few sanity checks on the bad block description * This functions performs a few sanity checks on the bad block description
* table. * table.
......
...@@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d ...@@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */
#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */
#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ #define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ #define STATE_CMD_PAGEPROG 0x00000004 /* start page program */
#define STATE_CMD_READOOB 0x00000005 /* read OOB area */ #define STATE_CMD_READOOB 0x00000005 /* read OOB area */
#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
#define STATE_CMD_STATUS 0x00000007 /* read status */ #define STATE_CMD_STATUS 0x00000007 /* read status */
#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ #define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */
#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */ #define STATE_CMD_SEQIN 0x00000009 /* sequential data input */
#define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_READID 0x0000000A /* read ID */
#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */
#define STATE_CMD_RESET 0x0000000C /* reset */ #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,7 +230,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ #define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */
#define STATE_ADDR_MASK 0x00000070 /* address states mask */ #define STATE_ADDR_MASK 0x00000070 /* address states mask */
/* Durind data input/output the simulator is in these states */ /* During data input/output the simulator is in these states */
#define STATE_DATAIN 0x00000100 /* waiting for data input */ #define STATE_DATAIN 0x00000100 /* waiting for data input */
#define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ #define STATE_DATAIN_MASK 0x00000100 /* data input states mask */
...@@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d ...@@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
/* Simulator's actions bit masks */ /* Simulator's actions bit masks */
#define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ #define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */
#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */ #define ACTION_PRGPAGE 0x00200000 /* program the internal buffer to flash */
#define ACTION_SECERASE 0x00300000 /* erase sector */ #define ACTION_SECERASE 0x00300000 /* erase sector */
#define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ #define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */
#define ACTION_HALFOFF 0x00500000 /* add to address half of page */ #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,18 +263,18 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */ #define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ #define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */
/* Remove action bits ftom state */ /* Remove action bits from state */
#define NS_STATE(x) ((x) & ~ACTION_MASK) #define NS_STATE(x) ((x) & ~ACTION_MASK)
/* /*
* Maximum previous states which need to be saved. Currently saving is * Maximum previous states which need to be saved. Currently saving is
* only needed for page programm operation with preceeded read command * only needed for page program operation with preceded read command
* (which is only valid for 512-byte pages). * (which is only valid for 512-byte pages).
*/ */
#define NS_MAX_PREVSTATES 1 #define NS_MAX_PREVSTATES 1
...@@ -380,16 +380,16 @@ static struct nandsim_operations { ...@@ -380,16 +380,16 @@ static struct nandsim_operations {
/* Read OOB */ /* Read OOB */
{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
STATE_DATAOUT, STATE_READY}}, STATE_DATAOUT, STATE_READY}},
/* Programm page starting from the beginning */ /* Program page starting from the beginning */
{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
/* Programm page starting from the beginning */ /* Program page starting from the beginning */
{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
/* Programm page starting from the second half */ /* Program page starting from the second half */
{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
/* Programm OOB */ /* Program OOB */
{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
/* Erase sector */ /* Erase sector */
...@@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns) ...@@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns)
err = -EINVAL; err = -EINVAL;
goto err_close; goto err_close;
} }
ns->pages_written = vmalloc(ns->geom.pgnum); ns->pages_written = vzalloc(ns->geom.pgnum);
if (!ns->pages_written) { if (!ns->pages_written) {
NS_ERR("alloc_device: unable to allocate pages written array\n"); NS_ERR("alloc_device: unable to allocate pages written array\n");
err = -ENOMEM; err = -ENOMEM;
...@@ -483,7 +483,6 @@ static int alloc_device(struct nandsim *ns) ...@@ -483,7 +483,6 @@ static int alloc_device(struct nandsim *ns)
goto err_free; goto err_free;
} }
ns->cfile = cfile; ns->cfile = cfile;
memset(ns->pages_written, 0, ns->geom.pgnum);
return 0; return 0;
} }
...@@ -1171,9 +1170,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) ...@@ -1171,9 +1170,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* of supported operations. * of supported operations.
* *
* Operation can be unknown because of the following. * Operation can be unknown because of the following.
* 1. New command was accepted and this is the firs call to find the * 1. New command was accepted and this is the first call to find the
* correspondent states chain. In this case ns->npstates = 0; * correspondent states chain. In this case ns->npstates = 0;
* 2. There is several operations which begin with the same command(s) * 2. There are several operations which begin with the same command(s)
* (for example program from the second half and read from the * (for example program from the second half and read from the
* second half operations both begin with the READ1 command). In this * second half operations both begin with the READ1 command). In this
* case the ns->pstates[] array contains previous states. * 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,7 +1185,7 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
* zeroed). * zeroed).
* *
* If there are several maches, the current state is pushed to the * If there are several matches, the current state is pushed to the
* ns->pstates. * ns->pstates.
* *
* The operation can be unknown only while commands are input to the chip. * 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,10 +1194,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* operation is searched using the following pattern: * operation is searched using the following pattern:
* ns->pstates[0], ... ns->pstates[ns->npstates], <address input> * ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
* *
* It is supposed that this pattern must either match one operation on * It is supposed that this pattern must either match one operation or
* none. There can't be ambiguity in that case. * none. There can't be ambiguity in that case.
* *
* If no matches found, the functions does the following: * If no matches found, the function does the following:
* 1. if there are saved states present, try to ignore them and search * 1. if there are saved states present, try to ignore them and search
* again only using the last command. If nothing was found, switch * again only using the last command. If nothing was found, switch
* to the STATE_READY state. * to the STATE_READY state.
...@@ -1668,7 +1667,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) ...@@ -1668,7 +1667,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
case ACTION_PRGPAGE: case ACTION_PRGPAGE:
/* /*
* Programm page - move internal buffer data to the page. * Program page - move internal buffer data to the page.
*/ */
if (ns->lines.wp) { if (ns->lines.wp) {
...@@ -1933,7 +1932,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) ...@@ -1933,7 +1932,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
NS_DBG("read_byte: all bytes were read\n"); NS_DBG("read_byte: all bytes were read\n");
/* /*
* The OPT_AUTOINCR allows to read next conseqitive pages without * The OPT_AUTOINCR allows to read next consecutive pages without
* new read operation cycle. * new read operation cycle.
*/ */
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
......
...@@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev, ...@@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev,
if (pasemi_nand_mtd) if (pasemi_nand_mtd)
return -ENODEV; return -ENODEV;
pr_debug("pasemi_nand at %llx-%llx\n", res.start, res.end); pr_debug("pasemi_nand at %pR\n", &res);
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) +
......
...@@ -885,6 +885,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) ...@@ -885,6 +885,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
/* set info fields needed to __readid */ /* set info fields needed to __readid */
info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
info->reg_ndcr = ndcr; info->reg_ndcr = ndcr;
info->cmdset = &default_cmdset;
if (__readid(info, &id)) if (__readid(info, &id))
return -ENODEV; return -ENODEV;
...@@ -915,7 +916,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) ...@@ -915,7 +916,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
info->ndtr1cs0 = nand_readl(info, NDTR1CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
info->cmdset = &default_cmdset;
return 0; return 0;
} }
......
...@@ -277,8 +277,9 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) ...@@ -277,8 +277,9 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
ret = nand_scan_ident(mtd, 1, NULL); ret = nand_scan_ident(mtd, 1, NULL);
if (!ret) { if (!ret) {
if (mtd->writesize >= 512) { if (mtd->writesize >= 512) {
chip->ecc.size = mtd->writesize; /* Hardware ECC 6 byte ECC per 512 Byte data */
chip->ecc.bytes = 3 * (mtd->writesize / 256); chip->ecc.size = 512;
chip->ecc.bytes = 6;
} }
ret = nand_scan_tail(mtd); ret = nand_scan_tail(mtd);
} }
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <asm/mach/flash.h> #include <asm/mach/flash.h>
#include <plat/gpmc.h> #include <plat/gpmc.h>
...@@ -63,8 +64,13 @@ struct omap2_onenand { ...@@ -63,8 +64,13 @@ struct omap2_onenand {
int dma_channel; int dma_channel;
int freq; int freq;
int (*setup)(void __iomem *base, int freq); int (*setup)(void __iomem *base, int freq);
struct regulator *regulator;
}; };
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probes[] = { "cmdlinepart", NULL, };
#endif
static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
{ {
struct omap2_onenand *c = data; struct omap2_onenand *c = data;
...@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, ...@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl,
static int omap2_onenand_wait(struct mtd_info *mtd, int state) static int omap2_onenand_wait(struct mtd_info *mtd, int state)
{ {
struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
struct onenand_chip *this = mtd->priv;
unsigned int intr = 0; unsigned int intr = 0;
unsigned int ctrl; unsigned int ctrl, ctrl_mask;
unsigned long timeout; unsigned long timeout;
u32 syscfg; u32 syscfg;
...@@ -180,7 +187,8 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) ...@@ -180,7 +187,8 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
if (result == 0) { if (result == 0) {
/* Timeout after 20ms */ /* Timeout after 20ms */
ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
if (ctrl & ONENAND_CTRL_ONGO) { if (ctrl & ONENAND_CTRL_ONGO &&
!this->ongoing) {
/* /*
* The operation seems to be still going * The operation seems to be still going
* so give it some more time. * so give it some more time.
...@@ -269,7 +277,11 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) ...@@ -269,7 +277,11 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
return -EIO; return -EIO;
} }
if (ctrl & 0xFE9F) ctrl_mask = 0xFE9F;
if (this->ongoing)
ctrl_mask &= ~0x8000;
if (ctrl & ctrl_mask)
wait_warn("unexpected controller status", state, ctrl, intr); wait_warn("unexpected controller status", state, ctrl, intr);
return 0; return 0;
...@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) ...@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
} }
static int omap2_onenand_enable(struct mtd_info *mtd)
{
int ret;
struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
ret = regulator_enable(c->regulator);
if (ret != 0)
dev_err(&c->pdev->dev, "cant enable regulator\n");
return ret;
}
static int omap2_onenand_disable(struct mtd_info *mtd)
{
int ret;
struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
ret = regulator_disable(c->regulator);
if (ret != 0)
dev_err(&c->pdev->dev, "cant disable regulator\n");
return ret;
}
static int __devinit omap2_onenand_probe(struct platform_device *pdev) static int __devinit omap2_onenand_probe(struct platform_device *pdev)
{ {
struct omap_onenand_platform_data *pdata; struct omap_onenand_platform_data *pdata;
...@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) ...@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
} }
} }
if (pdata->regulator_can_sleep) {
c->regulator = regulator_get(&pdev->dev, "vonenand");
if (IS_ERR(c->regulator)) {
dev_err(&pdev->dev, "Failed to get regulator\n");
goto err_release_dma;
}
c->onenand.enable = omap2_onenand_enable;
c->onenand.disable = omap2_onenand_disable;
}
if ((r = onenand_scan(&c->mtd, 1)) < 0) if ((r = onenand_scan(&c->mtd, 1)) < 0)
goto err_release_dma; goto err_release_regulator;
switch ((c->onenand.version_id >> 4) & 0xf) { switch ((c->onenand.version_id >> 4) & 0xf) {
case 0: case 0:
...@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) ...@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
} }
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
if (pdata->parts != NULL) r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0);
r = add_mtd_partitions(&c->mtd, pdata->parts, if (r > 0)
pdata->nr_parts); r = add_mtd_partitions(&c->mtd, c->parts, r);
else if (pdata->parts != NULL)
r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts);
else else
#endif #endif
r = add_mtd_device(&c->mtd); r = add_mtd_device(&c->mtd);
if (r < 0) if (r)
goto err_release_onenand; goto err_release_onenand;
platform_set_drvdata(pdev, c); platform_set_drvdata(pdev, c);
...@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) ...@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
err_release_onenand: err_release_onenand:
onenand_release(&c->mtd); onenand_release(&c->mtd);
err_release_regulator:
regulator_put(c->regulator);
err_release_dma: err_release_dma:
if (c->dma_channel != -1) if (c->dma_channel != -1)
omap_free_dma(c->dma_channel); omap_free_dma(c->dma_channel);
...@@ -757,6 +807,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) ...@@ -757,6 +807,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
err_free_cs: err_free_cs:
gpmc_cs_free(c->gpmc_cs); gpmc_cs_free(c->gpmc_cs);
err_kfree: err_kfree:
kfree(c->parts);
kfree(c); kfree(c);
return r; return r;
...@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) ...@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
{ {
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
BUG_ON(c == NULL);
#ifdef CONFIG_MTD_PARTITIONS
if (c->parts)
del_mtd_partitions(&c->mtd);
else
del_mtd_device(&c->mtd);
#else
del_mtd_device(&c->mtd);
#endif
onenand_release(&c->mtd); onenand_release(&c->mtd);
regulator_put(c->regulator);
if (c->dma_channel != -1) if (c->dma_channel != -1)
omap_free_dma(c->dma_channel); omap_free_dma(c->dma_channel);
omap2_onenand_shutdown(pdev); omap2_onenand_shutdown(pdev);
...@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) ...@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
iounmap(c->onenand.base); iounmap(c->onenand.base);
release_mem_region(c->phys_base, ONENAND_IO_SIZE); release_mem_region(c->phys_base, ONENAND_IO_SIZE);
gpmc_cs_free(c->gpmc_cs); gpmc_cs_free(c->gpmc_cs);
kfree(c->parts);
kfree(c); kfree(c);
return 0; return 0;
......
...@@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le ...@@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
value = onenand_bufferram_address(this, block); value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this))
ONENAND_IS_4KB_PAGE(this))
/* It is always BufferRAM0 */ /* It is always BufferRAM0 */
ONENAND_SET_BUFFERRAM0(this); ONENAND_SET_BUFFERRAM0(this);
else else
...@@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le ...@@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case FLEXONENAND_CMD_RECOVER_LSB: case FLEXONENAND_CMD_RECOVER_LSB:
case ONENAND_CMD_READ: case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB: case ONENAND_CMD_READOOB:
if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) if (ONENAND_IS_4KB_PAGE(this))
/* It is always BufferRAM0 */ /* It is always BufferRAM0 */
dataram = ONENAND_SET_BUFFERRAM0(this); dataram = ONENAND_SET_BUFFERRAM0(this);
else else
...@@ -949,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state) ...@@ -949,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state)
if (this->state == FL_READY) { if (this->state == FL_READY) {
this->state = new_state; this->state = new_state;
spin_unlock(&this->chip_lock); spin_unlock(&this->chip_lock);
if (new_state != FL_PM_SUSPENDED && this->enable)
this->enable(mtd);
break; break;
} }
if (new_state == FL_PM_SUSPENDED) { if (new_state == FL_PM_SUSPENDED) {
...@@ -975,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd) ...@@ -975,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd)
{ {
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
if (this->state != FL_PM_SUSPENDED && this->disable)
this->disable(mtd);
/* Release the chip */ /* Release the chip */
spin_lock(&this->chip_lock); spin_lock(&this->chip_lock);
this->state = FL_READY; this->state = FL_READY;
...@@ -1353,7 +1356,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1353,7 +1356,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats; stats = mtd->ecc_stats;
readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
while (read < len) { while (read < len) {
cond_resched(); cond_resched();
...@@ -1429,7 +1432,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -1429,7 +1432,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
int ret; int ret;
onenand_get_device(mtd, FL_READING); onenand_get_device(mtd, FL_READING);
ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_mlc_read_ops_nolock(mtd, from, &ops) :
onenand_read_ops_nolock(mtd, from, &ops); onenand_read_ops_nolock(mtd, from, &ops);
onenand_release_device(mtd); onenand_release_device(mtd);
...@@ -1464,7 +1467,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -1464,7 +1467,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
onenand_get_device(mtd, FL_READING); onenand_get_device(mtd, FL_READING);
if (ops->datbuf) if (ops->datbuf)
ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, ops) : onenand_mlc_read_ops_nolock(mtd, from, ops) :
onenand_read_ops_nolock(mtd, from, ops); onenand_read_ops_nolock(mtd, from, ops);
else else
...@@ -1485,8 +1488,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) ...@@ -1485,8 +1488,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
{ {
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
unsigned long timeout; unsigned long timeout;
unsigned int interrupt; unsigned int interrupt, ctrl, ecc, addr1, addr8;
unsigned int ctrl;
/* The 20 msec is enough */ /* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(20); timeout = jiffies + msecs_to_jiffies(20);
...@@ -1498,25 +1500,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) ...@@ -1498,25 +1500,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
/* To get correct interrupt status in timeout case */ /* To get correct interrupt status in timeout case */
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
if (interrupt & ONENAND_INT_READ) { if (interrupt & ONENAND_INT_READ) {
int ecc = onenand_read_ecc(this); ecc = onenand_read_ecc(this);
if (ecc & ONENAND_ECC_2BIT_ALL) { if (ecc & ONENAND_ECC_2BIT_ALL) {
printk(KERN_WARNING "%s: ecc error = 0x%04x, " printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
"controller error 0x%04x\n", "intr 0x%04x addr1 %#x addr8 %#x\n",
__func__, ecc, ctrl); __func__, ecc, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_ECC_ERROR; return ONENAND_BBT_READ_ECC_ERROR;
} }
} else { } else {
printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
__func__, ctrl, interrupt); "intr 0x%04x addr1 %#x addr8 %#x\n",
__func__, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_FATAL_ERROR; return ONENAND_BBT_READ_FATAL_ERROR;
} }
/* Initial bad block case: 0x2400 or 0x0400 */ /* Initial bad block case: 0x2400 or 0x0400 */
if (ctrl & ONENAND_CTRL_ERROR) { if (ctrl & ONENAND_CTRL_ERROR) {
printk(KERN_DEBUG "%s: controller error = 0x%04x\n", printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
__func__, ctrl); "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_ERROR; return ONENAND_BBT_READ_ERROR;
} }
...@@ -1558,7 +1563,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -1558,7 +1563,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
column = from & (mtd->oobsize - 1); column = from & (mtd->oobsize - 1);
readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
while (read < len) { while (read < len) {
cond_resched(); cond_resched();
...@@ -1612,7 +1617,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to ...@@ -1612,7 +1617,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
u_char *oob_buf = this->oob_buf; u_char *oob_buf = this->oob_buf;
int status, i, readcmd; int status, i, readcmd;
readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
this->command(mtd, readcmd, to, mtd->oobsize); this->command(mtd, readcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0); onenand_update_bufferram(mtd, to, 0);
...@@ -1845,7 +1850,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ...@@ -1845,7 +1850,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
const u_char *buf = ops->datbuf; const u_char *buf = ops->datbuf;
const u_char *oob = ops->oobbuf; const u_char *oob = ops->oobbuf;
u_char *oobbuf; u_char *oobbuf;
int ret = 0; int ret = 0, cmd;
DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int) to, (int) len); __func__, (unsigned int) to, (int) len);
...@@ -1954,7 +1959,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ...@@ -1954,7 +1959,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
ONENAND_SET_NEXT_BUFFERRAM(this); ONENAND_SET_NEXT_BUFFERRAM(this);
} }
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); this->ongoing = 0;
cmd = ONENAND_CMD_PROG;
/* Exclude 1st OTP and OTP blocks for cache program feature */
if (ONENAND_IS_CACHE_PROGRAM(this) &&
likely(onenand_block(this, to) != 0) &&
ONENAND_IS_4KB_PAGE(this) &&
((written + thislen) < len)) {
cmd = ONENAND_CMD_2X_CACHE_PROG;
this->ongoing = 1;
}
this->command(mtd, cmd, to, mtd->writesize);
/* /*
* 2 PLANE, MLC, and Flex-OneNAND wait here * 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,7 +2084,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf; oobbuf = this->oob_buf;
oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
/* Loop until all data write */ /* Loop until all data write */
while (written < len) { while (written < len) {
...@@ -2086,7 +2103,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, ...@@ -2086,7 +2103,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
memcpy(oobbuf + column, buf, thislen); memcpy(oobbuf + column, buf, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { if (ONENAND_IS_4KB_PAGE(this)) {
/* Set main area of DataRAM to 0xff*/ /* Set main area of DataRAM to 0xff*/
memset(this->page_buf, 0xff, mtd->writesize); memset(this->page_buf, 0xff, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM, this->write_bufferram(mtd, ONENAND_DATARAM,
...@@ -2481,7 +2498,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -2481,7 +2498,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Grab the lock and see if the device is available */ /* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_ERASING); onenand_get_device(mtd, FL_ERASING);
if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { if (ONENAND_IS_4KB_PAGE(this) || region ||
instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
/* region is set for Flex-OneNAND (no mb erase) */ /* region is set for Flex-OneNAND (no mb erase) */
ret = onenand_block_by_block_erase(mtd, instr, ret = onenand_block_by_block_erase(mtd, instr,
region, block_size); region, block_size);
...@@ -3029,7 +3047,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -3029,7 +3047,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING); this->wait(mtd, FL_OTPING);
ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_mlc_read_ops_nolock(mtd, from, &ops) :
onenand_read_ops_nolock(mtd, from, &ops); onenand_read_ops_nolock(mtd, from, &ops);
...@@ -3377,8 +3395,10 @@ static void onenand_check_features(struct mtd_info *mtd) ...@@ -3377,8 +3395,10 @@ static void onenand_check_features(struct mtd_info *mtd)
case ONENAND_DEVICE_DENSITY_4Gb: case ONENAND_DEVICE_DENSITY_4Gb:
if (ONENAND_IS_DDP(this)) if (ONENAND_IS_DDP(this))
this->options |= ONENAND_HAS_2PLANE; this->options |= ONENAND_HAS_2PLANE;
else if (numbufs == 1) else if (numbufs == 1) {
this->options |= ONENAND_HAS_4KB_PAGE; this->options |= ONENAND_HAS_4KB_PAGE;
this->options |= ONENAND_HAS_CACHE_PROGRAM;
}
case ONENAND_DEVICE_DENSITY_2Gb: case ONENAND_DEVICE_DENSITY_2Gb:
/* 2Gb DDP does not have 2 plane */ /* 2Gb DDP does not have 2 plane */
...@@ -3399,7 +3419,11 @@ static void onenand_check_features(struct mtd_info *mtd) ...@@ -3399,7 +3419,11 @@ static void onenand_check_features(struct mtd_info *mtd)
break; break;
} }
if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) /* The MLC has 4KiB pagesize. */
if (ONENAND_IS_MLC(this))
this->options |= ONENAND_HAS_4KB_PAGE;
if (ONENAND_IS_4KB_PAGE(this))
this->options &= ~ONENAND_HAS_2PLANE; this->options &= ~ONENAND_HAS_2PLANE;
if (FLEXONENAND(this)) { if (FLEXONENAND(this)) {
...@@ -3415,6 +3439,8 @@ static void onenand_check_features(struct mtd_info *mtd) ...@@ -3415,6 +3439,8 @@ static void onenand_check_features(struct mtd_info *mtd)
printk(KERN_DEBUG "Chip has 2 plane\n"); printk(KERN_DEBUG "Chip has 2 plane\n");
if (this->options & ONENAND_HAS_4KB_PAGE) if (this->options & ONENAND_HAS_4KB_PAGE)
printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
if (this->options & ONENAND_HAS_CACHE_PROGRAM)
printk(KERN_DEBUG "Chip has cache program feature\n");
} }
/** /**
...@@ -3831,7 +3857,7 @@ static int onenand_probe(struct mtd_info *mtd) ...@@ -3831,7 +3857,7 @@ static int onenand_probe(struct mtd_info *mtd)
/* The data buffer size is equal to page size */ /* The data buffer size is equal to page size */
mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
/* We use the full BufferRAM */ /* We use the full BufferRAM */
if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) if (ONENAND_IS_4KB_PAGE(this))
mtd->writesize <<= 1; mtd->writesize <<= 1;
mtd->oobsize = mtd->writesize >> 5; mtd->oobsize = mtd->writesize >> 5;
...@@ -4054,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -4054,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->block_isbad = onenand_block_isbad; mtd->block_isbad = onenand_block_isbad;
mtd->block_markbad = onenand_block_markbad; mtd->block_markbad = onenand_block_markbad;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->writebufsize = mtd->writesize;
/* Unlock whole block */ /* Unlock whole block */
this->unlock_all(mtd); this->unlock_all(mtd);
......
...@@ -91,16 +91,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr ...@@ -91,16 +91,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
/* No need to read pages fully, /* No need to read pages fully,
* just read required OOB bytes */ * just read required OOB bytes */
ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); ret = onenand_bbt_read_oob(mtd,
from + j * this->writesize + bd->offs, &ops);
/* If it is a initial bad block, just ignore it */ /* If it is a initial bad block, just ignore it */
if (ret == ONENAND_BBT_READ_FATAL_ERROR) if (ret == ONENAND_BBT_READ_FATAL_ERROR)
return -EIO; return -EIO;
if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { if (ret || check_short_pattern(&buf[j * scanlen],
scanlen, this->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", printk(KERN_INFO "OneNAND eraseblock %d is an "
i >> 1, (unsigned int) from); "initial bad block\n", i >> 1);
mtd->ecc_stats.badblocks++; mtd->ecc_stats.badblocks++;
break; break;
} }
......
...@@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, ...@@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
void __iomem *p; void __iomem *p;
void *buf = (void *) buffer; void *buf = (void *) buffer;
dma_addr_t dma_src, dma_dst; dma_addr_t dma_src, dma_dst;
int err, page_dma = 0; int err, ofs, page_dma = 0;
struct device *dev = &onenand->pdev->dev; struct device *dev = &onenand->pdev->dev;
p = this->base + area; p = this->base + area;
...@@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, ...@@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
if (!page) if (!page)
goto normal; goto normal;
/* Page offset */
ofs = ((size_t) buf & ~PAGE_MASK);
page_dma = 1; page_dma = 1;
/* DMA routine */ /* DMA routine */
dma_src = onenand->phys_base + (p - this->base); dma_src = onenand->phys_base + (p - this->base);
dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE);
} else { } else {
/* DMA routine */ /* DMA routine */
dma_src = onenand->phys_base + (p - this->base); dma_src = onenand->phys_base + (p - this->base);
......
...@@ -672,7 +672,33 @@ static int io_init(struct ubi_device *ubi) ...@@ -672,7 +672,33 @@ static int io_init(struct ubi_device *ubi)
ubi->nor_flash = 1; ubi->nor_flash = 1;
} }
ubi->min_io_size = ubi->mtd->writesize; /*
* Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize
* for these purposes, not @mtd->writesize. At the moment this does not
* matter for NAND, because currently @mtd->writebufsize is equivalent to
* @mtd->writesize for all NANDs. However, some CFI NOR flashes may
* have @mtd->writebufsize which is multiple of @mtd->writesize.
*
* The reason we use @mtd->writebufsize for @ubi->min_io_size is that
* UBI and UBIFS recovery algorithms rely on the fact that if there was
* an unclean power cut, then we can find offset of the last corrupted
* node, align the offset to @ubi->min_io_size, read the rest of the
* eraseblock starting from this offset, and check whether there are
* only 0xFF bytes. If yes, then we are probably dealing with a
* corruption caused by a power cut, if not, then this is probably some
* severe corruption.
*
* Thus, we have to use the maximum write unit size of the flash, which
* is @mtd->writebufsize, because @mtd->writesize is the minimum write
* size, not the maximum.
*/
if (ubi->mtd->type == MTD_NANDFLASH)
ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize);
else if (ubi->mtd->type == MTD_NORFLASH)
ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0);
ubi->min_io_size = ubi->mtd->writebufsize;
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* /*
......
...@@ -425,12 +425,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, ...@@ -425,12 +425,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
/* Read both LEB 0 and LEB 1 into memory */ /* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
leb[seb->lnum] = vmalloc(ubi->vtbl_size); leb[seb->lnum] = vzalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) { if (!leb[seb->lnum]) {
err = -ENOMEM; err = -ENOMEM;
goto out_free; goto out_free;
} }
memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size); ubi->vtbl_size);
...@@ -516,10 +515,9 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, ...@@ -516,10 +515,9 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
int i; int i;
struct ubi_vtbl_record *vtbl; struct ubi_vtbl_record *vtbl;
vtbl = vmalloc(ubi->vtbl_size); vtbl = vzalloc(ubi->vtbl_size);
if (!vtbl) if (!vtbl)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
......
...@@ -336,14 +336,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) ...@@ -336,14 +336,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
#ifndef __ECOS #ifndef __ECOS
if (jffs2_blocks_use_vmalloc(c)) if (jffs2_blocks_use_vmalloc(c))
c->blocks = vmalloc(size); c->blocks = vzalloc(size);
else else
#endif #endif
c->blocks = kmalloc(size, GFP_KERNEL); c->blocks = kzalloc(size, GFP_KERNEL);
if (!c->blocks) if (!c->blocks)
return -ENOMEM; return -ENOMEM;
memset(c->blocks, 0, size);
for (i=0; i<c->nr_blocks; i++) { for (i=0; i<c->nr_blocks; i++) {
INIT_LIST_HEAD(&c->blocks[i].list); INIT_LIST_HEAD(&c->blocks[i].list);
c->blocks[i].offset = i * c->sector_size; c->blocks[i].offset = i * c->sector_size;
......
...@@ -144,4 +144,4 @@ struct jffs2_sb_info { ...@@ -144,4 +144,4 @@ struct jffs2_sb_info {
void *os_priv; void *os_priv;
}; };
#endif /* _JFFS2_FB_SB */ #endif /* _JFFS2_FS_SB */
...@@ -151,7 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat ...@@ -151,7 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rx.hdr_crc), crc); offset, je32_to_cpu(rx.hdr_crc), crc);
xd->flags |= JFFS2_XFLAGS_INVALID; xd->flags |= JFFS2_XFLAGS_INVALID;
return EIO; return -EIO;
} }
totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
...@@ -167,7 +167,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat ...@@ -167,7 +167,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
je32_to_cpu(rx.xid), xd->xid, je32_to_cpu(rx.xid), xd->xid,
je32_to_cpu(rx.version), xd->version); je32_to_cpu(rx.version), xd->version);
xd->flags |= JFFS2_XFLAGS_INVALID; xd->flags |= JFFS2_XFLAGS_INVALID;
return EIO; return -EIO;
} }
xd->xprefix = rx.xprefix; xd->xprefix = rx.xprefix;
xd->name_len = rx.name_len; xd->name_len = rx.name_len;
...@@ -230,7 +230,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum ...@@ -230,7 +230,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
ref_offset(xd->node), xd->data_crc, crc); ref_offset(xd->node), xd->data_crc, crc);
kfree(data); kfree(data);
xd->flags |= JFFS2_XFLAGS_INVALID; xd->flags |= JFFS2_XFLAGS_INVALID;
return EIO; return -EIO;
} }
xd->flags |= JFFS2_XFLAGS_HOT; xd->flags |= JFFS2_XFLAGS_HOT;
...@@ -268,7 +268,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x ...@@ -268,7 +268,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
if (xd->xname) if (xd->xname)
return 0; return 0;
if (xd->flags & JFFS2_XFLAGS_INVALID) if (xd->flags & JFFS2_XFLAGS_INVALID)
return EIO; return -EIO;
if (unlikely(is_xattr_datum_unchecked(c, xd))) if (unlikely(is_xattr_datum_unchecked(c, xd)))
rc = do_verify_xattr_datum(c, xd); rc = do_verify_xattr_datum(c, xd);
if (!rc) if (!rc)
...@@ -460,7 +460,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref ...@@ -460,7 +460,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
if (crc != je32_to_cpu(rr.node_crc)) { if (crc != je32_to_cpu(rr.node_crc)) {
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rr.node_crc), crc); offset, je32_to_cpu(rr.node_crc), crc);
return EIO; return -EIO;
} }
if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
|| je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
...@@ -470,7 +470,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref ...@@ -470,7 +470,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
je32_to_cpu(rr.totlen), PAD(sizeof(rr))); je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
return EIO; return -EIO;
} }
ref->ino = je32_to_cpu(rr.ino); ref->ino = je32_to_cpu(rr.ino);
ref->xid = je32_to_cpu(rr.xid); ref->xid = je32_to_cpu(rr.xid);
......
...@@ -527,8 +527,7 @@ struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t s ...@@ -527,8 +527,7 @@ struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t s
struct cfi_fixup { struct cfi_fixup {
uint16_t mfr; uint16_t mfr;
uint16_t id; uint16_t id;
void (*fixup)(struct mtd_info *mtd, void* param); void (*fixup)(struct mtd_info *mtd);
void* param;
}; };
#define CFI_MFR_ANY 0xFFFF #define CFI_MFR_ANY 0xFFFF
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#ifndef __MTD_FSMC_H #ifndef __MTD_FSMC_H
#define __MTD_FSMC_H #define __MTD_FSMC_H
#include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -27,7 +28,7 @@ ...@@ -27,7 +28,7 @@
/* /*
* The placement of the Command Latch Enable (CLE) and * The placement of the Command Latch Enable (CLE) and
* Address Latch Enable (ALE) is twised around in the * Address Latch Enable (ALE) is twisted around in the
* SPEAR310 implementation. * SPEAR310 implementation.
*/ */
#if defined(CONFIG_MACH_SPEAR310) #if defined(CONFIG_MACH_SPEAR310)
...@@ -62,7 +63,7 @@ struct fsmc_nor_bank_regs { ...@@ -62,7 +63,7 @@ struct fsmc_nor_bank_regs {
/* ctrl_tim register definitions */ /* ctrl_tim register definitions */
struct fsms_nand_bank_regs { struct fsmc_nand_bank_regs {
uint32_t pc; uint32_t pc;
uint32_t sts; uint32_t sts;
uint32_t comm; uint32_t comm;
...@@ -78,7 +79,7 @@ struct fsms_nand_bank_regs { ...@@ -78,7 +79,7 @@ struct fsms_nand_bank_regs {
struct fsmc_regs { struct fsmc_regs {
struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS]; struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS];
uint8_t reserved_1[0x40 - 0x20]; uint8_t reserved_1[0x40 - 0x20];
struct fsms_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS]; struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS];
uint8_t reserved_2[0xfe0 - 0xc0]; uint8_t reserved_2[0xfe0 - 0xc0];
uint32_t peripid0; /* 0xfe0 */ uint32_t peripid0; /* 0xfe0 */
uint32_t peripid1; /* 0xfe4 */ uint32_t peripid1; /* 0xfe4 */
...@@ -114,25 +115,6 @@ struct fsmc_regs { ...@@ -114,25 +115,6 @@ struct fsmc_regs {
#define FSMC_THOLD_4 (4 << 16) #define FSMC_THOLD_4 (4 << 16)
#define FSMC_THIZ_1 (1 << 24) #define FSMC_THIZ_1 (1 << 24)
/* peripid2 register definitions */
#define FSMC_REVISION_MSK (0xf)
#define FSMC_REVISION_SHFT (0x4)
#define FSMC_VER1 1
#define FSMC_VER2 2
#define FSMC_VER3 3
#define FSMC_VER4 4
#define FSMC_VER5 5
#define FSMC_VER6 6
#define FSMC_VER7 7
#define FSMC_VER8 8
static inline uint32_t get_fsmc_version(struct fsmc_regs *regs)
{
return (readl(&regs->peripid2) >> FSMC_REVISION_SHFT) &
FSMC_REVISION_MSK;
}
/* /*
* There are 13 bytes of ecc for every 512 byte block in FSMC version 8 * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
* and it has to be read consecutively and immediately after the 512 * and it has to be read consecutively and immediately after the 512
......
...@@ -144,6 +144,17 @@ struct mtd_info { ...@@ -144,6 +144,17 @@ struct mtd_info {
*/ */
uint32_t writesize; uint32_t writesize;
/*
* Size of the write buffer used by the MTD. MTD devices having a write
* buffer can write multiple writesize chunks at a time. E.g. while
* writing 4 * writesize bytes to a device with 2 * writesize bytes
* buffer the MTD driver can (but doesn't have to) do 2 writesize
* operations, but not 4. Currently, all NANDs have writebufsize
* equivalent to writesize (NAND page size). Some NOR flashes do have
* writebufsize greater than writesize.
*/
uint32_t writebufsize;
uint32_t oobsize; // Amount of OOB data per block (e.g. 16) uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
uint32_t oobavail; // Available OOB bytes per block uint32_t oobavail; // Available OOB bytes per block
......
...@@ -448,6 +448,8 @@ struct nand_buffers { ...@@ -448,6 +448,8 @@ struct nand_buffers {
* See the defines for further explanation. * See the defines for further explanation.
* @badblockpos: [INTERN] position of the bad block marker in the oob * @badblockpos: [INTERN] position of the bad block marker in the oob
* area. * area.
* @badblockbits: [INTERN] number of bits to left-shift the bad block
* number
* @cellinfo: [INTERN] MLC/multichip data from chip ident * @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips * @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays * @chipsize: [INTERN] the size of one chip for multichip arrays
......
...@@ -118,6 +118,8 @@ struct onenand_chip { ...@@ -118,6 +118,8 @@ struct onenand_chip {
int (*chip_probe)(struct mtd_info *mtd); int (*chip_probe)(struct mtd_info *mtd);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
int (*scan_bbt)(struct mtd_info *mtd); int (*scan_bbt)(struct mtd_info *mtd);
int (*enable)(struct mtd_info *mtd);
int (*disable)(struct mtd_info *mtd);
struct completion complete; struct completion complete;
int irq; int irq;
...@@ -137,6 +139,14 @@ struct onenand_chip { ...@@ -137,6 +139,14 @@ struct onenand_chip {
void *bbm; void *bbm;
void *priv; void *priv;
/*
* Shows that the current operation is composed
* of sequence of commands. For example, cache program.
* Such command status OnGo bit is checked at the end of
* sequence.
*/
unsigned int ongoing;
}; };
/* /*
...@@ -171,6 +181,9 @@ struct onenand_chip { ...@@ -171,6 +181,9 @@ struct onenand_chip {
#define ONENAND_IS_2PLANE(this) (0) #define ONENAND_IS_2PLANE(this) (0)
#endif #endif
#define ONENAND_IS_CACHE_PROGRAM(this) \
(this->options & ONENAND_HAS_CACHE_PROGRAM)
/* Check byte access in OneNAND */ /* Check byte access in OneNAND */
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) #define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
...@@ -181,6 +194,7 @@ struct onenand_chip { ...@@ -181,6 +194,7 @@ struct onenand_chip {
#define ONENAND_HAS_UNLOCK_ALL (0x0002) #define ONENAND_HAS_UNLOCK_ALL (0x0002)
#define ONENAND_HAS_2PLANE (0x0004) #define ONENAND_HAS_2PLANE (0x0004)
#define ONENAND_HAS_4KB_PAGE (0x0008) #define ONENAND_HAS_4KB_PAGE (0x0008)
#define ONENAND_HAS_CACHE_PROGRAM (0x0010)
#define ONENAND_SKIP_UNLOCK_CHECK (0x0100) #define ONENAND_SKIP_UNLOCK_CHECK (0x0100)
#define ONENAND_PAGEBUF_ALLOC (0x1000) #define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000) #define ONENAND_OOBBUF_ALLOC (0x2000)
......
...@@ -89,7 +89,7 @@ static inline int mtd_has_cmdlinepart(void) { return 1; } ...@@ -89,7 +89,7 @@ static inline int mtd_has_cmdlinepart(void) { return 1; }
static inline int mtd_has_cmdlinepart(void) { return 0; } static inline int mtd_has_cmdlinepart(void) { return 0; }
#endif #endif
int mtd_is_master(struct mtd_info *mtd); int mtd_is_partition(struct mtd_info *mtd);
int mtd_add_partition(struct mtd_info *master, char *name, int mtd_add_partition(struct mtd_info *master, char *name,
long long offset, long long length); long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno); int mtd_del_partition(struct mtd_info *master, int partno);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment