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.
This commit is contained in:
commit
ab2020f2f1
|
@ -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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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 @@
|
||||||
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)
|
||||||
#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)
|
||||||
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)
|
||||||
|
|
||||||
#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)
|
||||||
#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)
|
||||||
}
|
}
|
||||||
#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)
|
||||||
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)
|
||||||
(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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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[] = {
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
#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)
|
||||||
}
|
}
|
||||||
#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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
/* 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[] = {
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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,
|
||||||
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 {
|
||||||
.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[] = {
|
||||||
{ "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[] = {
|
||||||
{ "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)
|
||||||
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)
|
||||||
|
|
||||||
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 @@ out:
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
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
|
||||||
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 @@
|
||||||
* 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[] = {
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
module_exit(ams_delta_cleanup);
|
|
||||||
|
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_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,
|
||||||
"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 @@
|
||||||
#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 = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
/*
|
/*
|
||||||
* Default partition tables to be used if the partition information not
|
* Default partition tables to be used if the partition information not
|
||||||
* provided through platform data
|
* provided through platform data.
|
||||||
*/
|
*
|
||||||
#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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[] = {
|
||||||
* 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 };
|
||||||
* @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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
* 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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
/* 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,
|
||||||
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 @@ ident_done:
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
#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
|
||||||
#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
|
||||||
|
|
||||||
/* 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
|
||||||
#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 {
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
* 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)
|
||||||
* 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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
/* 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)
|
||||||
|
|
||||||
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)
|
||||||
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 @@
|
||||||
#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 {
|
||||||
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,
|
||||||
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 @@ retry:
|
||||||
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 @@ retry:
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
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 @@ err_release_mem_region:
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
/* 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,
|
||||||
|
|
||||||
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
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
/* 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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
/* 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,
|
||||||
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)
|
||||||
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 {
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 {
|
||||||
|
|
||||||
/* 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 {
|
||||||
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 {
|
||||||
#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(®s->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 {
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
* 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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
#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 {
|
||||||
#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; }
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue