Commit be967b7e authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.infradead.org/mtd-2.6: (199 commits)
  [MTD] NAND: Fix breakage all over the place
  [PATCH] NAND: fix remaining OOB length calculation
  [MTD] NAND Fixup NDFC merge brokeness
  [MTD NAND] S3C2410 driver cleanup
  [MTD NAND] s3c24x0 board: Fix clock handling, ensure proper initialisation.
  [JFFS2] Check CRC32 on dirent and data nodes each time they're read
  [JFFS2] When retiring nextblock, allocate a node_ref for the wasted space
  [JFFS2] Mark XATTR support as experimental, for now
  [JFFS2] Don't trust node headers before the CRC is checked.
  [MTD] Restore MTD_ROM and MTD_RAM types
  [MTD] assume mtd->writesize is 1 for NOR flashes
  [MTD NAND] Fix s3c2410 NAND driver so it at least _looks_ like it compiles
  [MTD] Prepare physmap for 64-bit-resources
  [JFFS2] Fix more breakage caused by janitorial meddling.
  [JFFS2] Remove stray __exit from jffs2_compressors_exit()
  [MTD] Allow alternate JFFS2 mount variant for root filesystem.
  [MTD] Disconnect struct mtd_info from ABI
  [MTD] replace MTD_RAM with MTD_GENERIC_TYPE
  [MTD] replace MTD_ROM with MTD_GENERIC_TYPE
  [MTD] remove a forgotten MTD_XIP
  ...
parents eef11427 7bc3312b
......@@ -1843,12 +1843,12 @@ S: linux-scsi@vger.kernel.org
W: http://megaraid.lsilogic.com
S: Maintained
MEMORY TECHNOLOGY DEVICES
MEMORY TECHNOLOGY DEVICES (MTD)
P: David Woodhouse
M: dwmw2@infradead.org
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
T: git kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6.git
T: git git://git.infradead.org/mtd-2.6.git
S: Maintained
MICROTEK X6 SCANNER
......
......@@ -78,7 +78,7 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
option.
The option specifies which Flash sectors holds the RedBoot
partition table. A zero or positive value gives an absolete
partition table. A zero or positive value gives an absolute
erase block number. A negative value specifies a number of
sectors before the end of the device.
......@@ -103,7 +103,7 @@ config MTD_CMDLINE_PARTS
bool "Command line partition table parsing"
depends on MTD_PARTITIONS = "y"
---help---
Allow generic configuration of the MTD paritition tables via the kernel
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
different kinds of flash memory are available.
......
......@@ -30,7 +30,6 @@ config MTD_JEDECPROBE
config MTD_GEN_PROBE
tristate
select OBSOLETE_INTERMODULE
config MTD_CFI_ADV_OPTIONS
bool "Flash chip driver advanced configuration options"
......
......@@ -3,13 +3,6 @@
#
# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
# *** BIG UGLY NOTE ***
#
# The removal of get_module_symbol() and replacement with
# inter_module_register() et al has introduced a link order dependency
# here where previously there was none. We now have to ensure that
# the CFI command set drivers are linked before gen_probe.o
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
......
......@@ -97,7 +97,6 @@ struct amd_flash_private {
int interleave;
int numchips;
unsigned long chipshift;
// const char *im_name;
struct flchip chips[0];
};
......@@ -131,12 +130,6 @@ static struct mtd_chip_driver amd_flash_chipdrv = {
.module = THIS_MODULE
};
static const char im_name[] = "amd_flash";
static inline __u32 wide_read(struct map_info *map, __u32 addr)
{
if (map->buswidth == 1) {
......@@ -737,6 +730,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
offset += dev_size;
}
mtd->type = MTD_NORFLASH;
mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->erase = amd_flash_erase;
......
This diff is collapsed.
......@@ -236,6 +236,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->resume = cfi_amdstd_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;
if (cfi->cfi_mode==CFI_MODE_CFI){
unsigned char bootloc;
......@@ -326,7 +327,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
return cfi_amdstd_setup(mtd);
}
EXPORT_SYMBOL_GPL(cfi_cmdset_0002);
static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
{
......@@ -1758,25 +1759,6 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd)
kfree(mtd->eraseregions);
}
static char im_name[]="cfi_cmdset_0002";
static int __init cfi_amdstd_init(void)
{
inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
return 0;
}
static void __exit cfi_amdstd_exit(void)
{
inter_module_unregister(im_name);
}
module_init(cfi_amdstd_init);
module_exit(cfi_amdstd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
......@@ -162,6 +162,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
return cfi_staa_setup(map);
}
EXPORT_SYMBOL_GPL(cfi_cmdset_0020);
static struct mtd_info *cfi_staa_setup(struct map_info *map)
{
......@@ -237,9 +238,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->unlock = cfi_staa_unlock;
mtd->suspend = cfi_staa_suspend;
mtd->resume = cfi_staa_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE);
mtd->name = map->name;
......@@ -1410,20 +1410,4 @@ static void cfi_staa_destroy(struct mtd_info *mtd)
kfree(cfi);
}
static char im_name[]="cfi_cmdset_0020";
static int __init cfi_staa_init(void)
{
inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
return 0;
}
static void __exit cfi_staa_exit(void)
{
inter_module_unregister(im_name);
}
module_init(cfi_staa_init);
module_exit(cfi_staa_exit);
MODULE_LICENSE("GPL");
......@@ -349,12 +349,12 @@ static void print_cfi_ident(struct cfi_ident *cfip)
else
printk("No Vpp line\n");
printk("Typical byte/word write timeout: %d s\n", 1<<cfip->WordWriteTimeoutTyp);
printk("Maximum byte/word write timeout: %d s\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
printk("Typical full buffer write timeout: %d s\n", 1<<cfip->BufWriteTimeoutTyp);
printk("Maximum full buffer write timeout: %d s\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
}
else
printk("Full buffer write not supported\n");
......
......@@ -37,8 +37,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */
if (mtd)
if (mtd) {
if (mtd->size > map->size) {
printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
(unsigned long)mtd->size >> 10,
(unsigned long)map->size >> 10);
mtd->size = map->size;
}
return mtd;
}
printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
......@@ -100,7 +107,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
* Align bitmap storage size to full byte.
*/
max_chips = map->size >> cfi.chipshift;
mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
if (!max_chips) {
printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n");
max_chips = 1;
}
mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
chip_map = kmalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
......@@ -194,25 +206,28 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)
char probename[32];
#ifdef CONFIG_MODULES
char probename[16+sizeof(MODULE_SYMBOL_PREFIX)];
cfi_cmdset_fn_t *probe_function;
sprintf(probename, "cfi_cmdset_%4.4X", type);
sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type);
probe_function = inter_module_get_request(probename, probename);
probe_function = __symbol_get(probename);
if (!probe_function) {
request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1);
probe_function = __symbol_get(probename);
}
if (probe_function) {
struct mtd_info *mtd;
mtd = (*probe_function)(map, primary);
/* If it was happy, it'll have increased its own use count */
inter_module_put(probename);
symbol_put_addr(probe_function);
return mtd;
}
#endif
printk(KERN_NOTICE "Support for command set %04X not present\n",
type);
printk(KERN_NOTICE "Support for command set %04X not present\n", type);
return NULL;
}
......@@ -226,12 +241,8 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
return NULL;
switch(type){
/* Urgh. Ifdefs. The version with weak symbols was
* _much_ nicer. Shame it didn't seem to work on
* anything but x86, really.
* But we can't rely in inter_module_get() because
* that'd mean we depend on link order.
*/
/* We need these for the !CONFIG_MODULES case,
because symbol_get() doesn't work there */
#ifdef CONFIG_MTD_CFI_INTELEXT
case 0x0001:
case 0x0003:
......@@ -246,9 +257,9 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
case 0x0020:
return cfi_cmdset_0020(map, primary);
#endif
}
default:
return cfi_cmdset_unknown(map, primary);
}
}
MODULE_LICENSE("GPL");
......
......@@ -70,7 +70,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->read = mapram_read;
mtd->write = mapram_write;
mtd->sync = mapram_nop;
mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
mtd->flags = MTD_CAP_RAM;
mtd->erasesize = PAGE_SIZE;
while(mtd->size & (mtd->erasesize - 1))
......
......@@ -46,9 +46,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->write = maprom_write;
mtd->sync = maprom_nop;
mtd->flags = MTD_CAP_ROM;
mtd->erasesize = 131072;
while(mtd->size & (mtd->erasesize - 1))
mtd->erasesize >>= 1;
mtd->erasesize = map->size;
__module_get(THIS_MODULE);
return mtd;
......
......@@ -140,6 +140,7 @@ static struct mtd_info *sharp_probe(struct map_info *map)
mtd->suspend = sharp_suspend;
mtd->resume = sharp_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->writesize = 1;
mtd->name = map->name;
memset(sharp, 0, sizeof(*sharp));
......
......@@ -47,6 +47,11 @@ config MTD_MS02NV
accelerator. Say Y here if you have a DECstation 5000/2x0 or a
DECsystem 5900 equipped with such a module.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module will
be called ms02-nv.o.
config MTD_DATAFLASH
tristate "Support for AT45xxx DataFlash"
depends on MTD && SPI_MASTER && EXPERIMENTAL
......@@ -209,7 +214,6 @@ config MTD_DOC2001PLUS
config MTD_DOCPROBE
tristate
select MTD_DOCECC
select OBSOLETE_INTERMODULE
config MTD_DOCECC
tristate
......
......@@ -3,13 +3,6 @@
#
# $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $
# *** BIG UGLY NOTE ***
#
# The removal of get_module_symbol() and replacement with
# inter_module_register() et al has introduced a link order dependency
# here where previously there was none. We now have to ensure that
# doc200[01].o are linked before docprobe.o
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
......
......@@ -4,7 +4,7 @@
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
* Copyright (C) 2004,2005 Jrn Engel <joern@wh.fh-wedel.de>
* Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
*/
......@@ -331,7 +331,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
dev->mtd.writev = default_mtd_writev;
dev->mtd.sync = block2mtd_sync;
dev->mtd.read = block2mtd_read;
dev->mtd.readv = default_mtd_readv;
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
......@@ -351,6 +350,12 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
}
/* This function works similar to reguler strtoul. In addition, it
* allows some suffixes for a more human-readable number format:
* ki, Ki, kiB, KiB - multiply result with 1024
* Mi, MiB - multiply result with 1024^2
* Gi, GiB - multiply result with 1024^3
*/
static int ustrtoul(const char *cp, char **endp, unsigned int base)
{
unsigned long result = simple_strtoul(cp, endp, base);
......@@ -359,12 +364,17 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
result *= 1024;
case 'M':
result *= 1024;
case 'K':
case 'k':
result *= 1024;
/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
if ((*endp)[1] == 'i')
if ((*endp)[1] == 'i') {
if ((*endp)[2] == 'B')
(*endp) += 3;
else
(*endp) += 2;
}
}
return result;
}
......@@ -418,7 +428,8 @@ static inline void kill_final_newline(char *str)
static int block2mtd_setup(const char *val, struct kernel_param *kp)
{
char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
char buf[80+12]; /* 80 for device, 12 for erase size */
char *str = buf;
char *token[2];
char *name;
size_t erase_size = PAGE_SIZE;
......@@ -430,7 +441,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
strcpy(str, val);
kill_final_newline(str);
for (i=0; i<2; i++)
for (i = 0; i < 2; i++)
token[i] = strsep(&str, ",");
if (str)
......@@ -449,9 +460,11 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
if (token[1]) {
ret = parse_num(&erase_size, token[1]);
if (ret)
if (ret) {
kfree(name);
parse_err("illegal erase size");
}
}
add_device(name, erase_size);
......
......@@ -59,13 +59,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
......@@ -517,16 +514,9 @@ static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
static const char im_name[] = "DoC2k_init";
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
* inter_module_get which will bump the use count of this module. The
* addresses passed back in mtd are valid as long as the use count of
* this module is non-zero, i.e. between inter_module_get and
* inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
*/
static void DoC2k_init(struct mtd_info *mtd)
/* This routine is found from the docprobe code by symbol_get(),
* which will bump the use count of this module. */
void DoC2k_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
......@@ -586,7 +576,7 @@ static void DoC2k_init(struct mtd_info *mtd)
mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
mtd->oobblock = 512;
mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
......@@ -594,9 +584,6 @@ static void DoC2k_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->writev_ecc = doc_writev_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
......@@ -623,6 +610,7 @@ static void DoC2k_init(struct mtd_info *mtd)
return;
}
}
EXPORT_SYMBOL_GPL(DoC2k_init);
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
......@@ -971,72 +959,18 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return 0;
}
static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
static char static_buf[512];
static DEFINE_MUTEX(writev_buf_mutex);
size_t totretlen = 0;
size_t thisvecofs = 0;
int ret= 0;
mutex_lock(&writev_buf_mutex);
while(count) {
size_t thislen, thisretlen;
unsigned char *buf;
buf = vecs->iov_base + thisvecofs;
thislen = vecs->iov_len - thisvecofs;
if (thislen >= 512) {
thislen = thislen & ~(512-1);
thisvecofs += thislen;
} else {
/* Not enough to fill a page. Copy into buf */
memcpy(static_buf, buf, thislen);
buf = &static_buf[thislen];
while(count && thislen < 512) {
vecs++;
count--;
thisvecofs = min((512-thislen), vecs->iov_len);
memcpy(buf, vecs->iov_base, thisvecofs);
thislen += thisvecofs;
buf += thisvecofs;
}
buf = static_buf;
}
if (count && thisvecofs == vecs->iov_len) {
thisvecofs = 0;
vecs++;
count--;
}
ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
totretlen += thisretlen;
if (ret || thisretlen != thislen)
break;
to += thislen;
}
mutex_unlock(&writev_buf_mutex);
*retlen = totretlen;
return ret;
}
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, u_char * buf)
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
struct DiskOnChip *this = mtd->priv;
int len256 = 0, ret;
struct Nand *mychip;
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OOB_PLACE);
ofs += ops->ooboffs;
mutex_lock(&this->lock);
......@@ -1077,7 +1011,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
DoC_ReadBuf(this, &buf[len256], len - len256);
*retlen = len;
ops->retlen = len;
/* Reading the full OOB data drops us off of the end of the page,
* causing the flash device to go into busy mode, so we need
* to wait until ready 11.4.1 and Toshiba TC58256FT docs */
......@@ -1192,14 +1126,17 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
}
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, const u_char * buf)
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
struct DiskOnChip *this = mtd->priv;
int ret;
BUG_ON(ops->mode != MTD_OOB_PLACE);
mutex_lock(&this->lock);
ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf);
ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len,
&ops->retlen, ops->oobbuf);
mutex_unlock(&this->lock);
return ret;
......@@ -1277,12 +1214,6 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
static int __init init_doc2000(void)
{
inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
return 0;
}
static void __exit cleanup_doc2000(void)
{
struct mtd_info *mtd;
......@@ -1298,11 +1229,9 @@ static void __exit cleanup_doc2000(void)
kfree(this->chips);
kfree(mtd);
}
inter_module_unregister(im_name);
}
module_exit(cleanup_doc2000);
module_init(init_doc2000);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
......
......@@ -43,10 +43,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
static struct mtd_info *docmillist = NULL;
......@@ -324,16 +324,9 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
static const char im_name[] = "DoCMil_init";
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
* inter_module_get which will bump the use count of this module. The
* addresses passed back in mtd are valid as long as the use count of
* this module is non-zero, i.e. between inter_module_get and
* inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
*/
static void DoCMil_init(struct mtd_info *mtd)
/* This routine is found from the docprobe code by symbol_get(),
* which will bump the use count of this module. */
void DoCMil_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
......@@ -368,7 +361,7 @@ static void DoCMil_init(struct mtd_info *mtd)
/* FIXME: erase size is not always 8KiB */
mtd->erasesize = 0x2000;
mtd->oobblock = 512;
mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
......@@ -376,8 +369,6 @@ static void DoCMil_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
......@@ -401,6 +392,7 @@ static void DoCMil_init(struct mtd_info *mtd)
return;
}
}
EXPORT_SYMBOL_GPL(DoCMil_init);
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
......@@ -670,8 +662,8 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
return ret;
}
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf)
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
......@@ -680,6 +672,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OOB_PLACE);
ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
......@@ -716,13 +714,13 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
#endif
buf[len - 1] = ReadDOC(docptr, LastDataRead);
*retlen = len;
ops->retlen = len;
return 0;
}
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf)
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
#ifndef USE_MEMCPY
int i;
......@@ -732,6 +730,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OOB_PLACE);
ofs += ops->ooboffs;
/* Find the chip which is to be used and select it */
if (this->curfloor != mychip->floor) {
......@@ -783,12 +787,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
printk("Error programming oob data\n");
/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
*retlen = 0;
ops->retlen = 0;
ret = -EIO;
}
dummy = ReadDOC(docptr, LastDataRead);
*retlen = len;
ops->retlen = len;
return ret;
}
......@@ -856,12 +860,6 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
static int __init init_doc2001(void)
{
inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
return 0;
}
static void __exit cleanup_doc2001(void)
{
struct mtd_info *mtd;
......@@ -877,11 +875,9 @@ static void __exit cleanup_doc2001(void)
kfree(this->chips);
kfree(mtd);
}
inter_module_unregister(im_name);
}
module_exit(cleanup_doc2001);
module_init(init_doc2001);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
......
......@@ -47,10 +47,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf,
struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
static struct mtd_info *docmilpluslist = NULL;
......@@ -447,16 +447,9 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
static const char im_name[] = "DoCMilPlus_init";
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
* inter_module_get which will bump the use count of this module. The
* addresses passed back in mtd are valid as long as the use count of
* this module is non-zero, i.e. between inter_module_get and
* inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
*/
static void DoCMilPlus_init(struct mtd_info *mtd)
/* This routine is found from the docprobe code by symbol_get(),
* which will bump the use count of this module. */
void DoCMilPlus_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
......@@ -490,7 +483,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
mtd->size = 0;
mtd->erasesize = 0;
mtd->oobblock = 512;
mtd->writesize = 512;
mtd->oobsize = 16;
mtd->owner = THIS_MODULE;
mtd->erase = doc_erase;
......@@ -498,8 +491,6 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
mtd->unpoint = NULL;
mtd->read = doc_read;
mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
......@@ -524,6 +515,7 @@ static void DoCMilPlus_init(struct mtd_info *mtd)
return;
}
}
EXPORT_SYMBOL_GPL(DoCMilPlus_init);
#if 0
static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
......@@ -876,14 +868,20 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return ret;
}
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf)
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
loff_t fofs, base;
struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OOB_PLACE);
ofs += ops->ooboffs;
DoC_CheckASIC(docptr);
......@@ -949,12 +947,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
*retlen = len;
ops->retlen = len;
return 0;
}
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf)
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
{
volatile char dummy;
loff_t fofs, base;
......@@ -963,6 +961,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
int ret = 0;
uint8_t *buf = ops->oobbuf;
size_t len = ops->len;
BUG_ON(ops->mode != MTD_OOB_PLACE);
ofs += ops->ooboffs;
DoC_CheckASIC(docptr);
......@@ -1038,7 +1042,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
printk("MTD: Error 0x%x programming oob at 0x%x\n",
dummy, (int)ofs);
/* FIXME: implement Bad Block Replacement */
*retlen = 0;
ops->retlen = 0;
ret = -EIO;
}
dummy = ReadDOC(docptr, Mplus_LastDataRead);
......@@ -1051,7 +1055,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
*retlen = len;
ops->retlen = len;
return ret;
}
......@@ -1122,12 +1126,6 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
static int __init init_doc2001plus(void)
{
inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
return 0;
}
static void __exit cleanup_doc2001plus(void)
{
struct mtd_info *mtd;
......@@ -1143,11 +1141,9 @@ static void __exit cleanup_doc2001plus(void)
kfree(this->chips);
kfree(mtd);
}
inter_module_unregister(im_name);
}
module_exit(cleanup_doc2001plus);
module_init(init_doc2001plus);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
......
......@@ -231,6 +231,10 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
static int docfound;
extern void DoC2k_init(struct mtd_info *);
extern void DoCMil_init(struct mtd_info *);
extern void DoCMilPlus_init(struct mtd_info *);
static void __init DoC_Probe(unsigned long physadr)
{
void __iomem *docptr;
......@@ -239,8 +243,6 @@ static void __init DoC_Probe(unsigned long physadr)
int ChipID;
char namebuf[15];
char *name = namebuf;
char *im_funcname = NULL;
char *im_modname = NULL;
void (*initroutine)(struct mtd_info *) = NULL;
docptr = ioremap(physadr, DOC_IOREMAP_LEN);
......@@ -278,41 +280,33 @@ static void __init DoC_Probe(unsigned long physadr)
switch(ChipID) {
case DOC_ChipID_Doc2kTSOP:
name="2000 TSOP";
im_funcname = "DoC2k_init";
im_modname = "doc2000";
initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_Doc2k:
name="2000";
im_funcname = "DoC2k_init";
im_modname = "doc2000";
initroutine = symbol_request(DoC2k_init);
break;
case DOC_ChipID_DocMil:
name="Millennium";
#ifdef DOC_SINGLE_DRIVER
im_funcname = "DoC2k_init";
im_modname = "doc2000";
initroutine = symbol_request(DoC2k_init);
#else
im_funcname = "DoCMil_init";
im_modname = "doc2001";
initroutine = symbol_request(DoCMil_init);
#endif /* DOC_SINGLE_DRIVER */
break;
case DOC_ChipID_DocMilPlus16:
case DOC_ChipID_DocMilPlus32:
name="MillenniumPlus";
im_funcname = "DoCMilPlus_init";
im_modname = "doc2001plus";
initroutine = symbol_request(DoCMilPlus_init);
break;
}
if (im_funcname)
initroutine = inter_module_get_request(im_funcname, im_modname);
if (initroutine) {
(*initroutine)(mtd);
inter_module_put(im_funcname);
symbol_put_addr(initroutine);
return;
}
printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
......
......@@ -635,6 +635,7 @@ int __init lart_flash_init (void)
printk ("%s: This looks like a LART board to me.\n",module_name);
mtd.name = module_name;
mtd.type = MTD_NORFLASH;
mtd.writesize = 1;
mtd.flags = MTD_CAP_NORFLASH;
mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
......
......@@ -465,6 +465,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.name = spi->dev.bus_id;
flash->mtd.type = MTD_NORFLASH;
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
flash->mtd.erasesize = info->sector_size;
......
......@@ -219,7 +219,7 @@ static int __init ms02nv_init_one(ulong addr)
mp->uaddr = phys_to_virt(fixaddr);
mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM | MTD_XIP;
mtd->flags = MTD_CAP_RAM;
mtd->size = fixsize;
mtd->name = (char *)ms02nv_name;
mtd->owner = THIS_MODULE;
......
......@@ -106,6 +106,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM;
mtd->size = size;
mtd->writesize = 1;
mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address;
......
/**
* $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
*
* Copyright (c) ???? Jochen Schuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Jrn Engel <joern@wh.fh-wedel.de>
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
......@@ -142,7 +142,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
new->mtd.name = name;
new->mtd.size = len;
new->mtd.flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
new->mtd.flags = MTD_CAP_RAM;
new->mtd.erase = phram_erase;
new->mtd.point = phram_point;
new->mtd.unpoint = phram_unpoint;
......@@ -266,12 +266,16 @@ static int phram_setup(const char *val, struct kernel_param *kp)
return 0;
ret = parse_num32(&start, token[1]);
if (ret)
if (ret) {
kfree(name);
parse_err("illegal start address\n");
}
ret = parse_num32(&len, token[2]);
if (ret)
if (ret) {
kfree(name);
parse_err("illegal device length\n");
}
register_device(name, start, len);
......@@ -296,5 +300,5 @@ module_init(init_phram);
module_exit(cleanup_phram);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jrn Engel <joern@wh.fh-wedel.de>");
MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
MODULE_DESCRIPTION("MTD driver for physical RAM");
......@@ -200,8 +200,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->name = name;
(*curmtd)->mtdinfo->size = length;
(*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
(*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
(*curmtd)->mtdinfo->erase = slram_erase;
(*curmtd)->mtdinfo->point = slram_point;
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
......
......@@ -36,6 +36,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h>
#include <linux/mtd/inftl.h>
#include <linux/mtd/nand.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <asm/io.h>
......@@ -79,8 +80,6 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512;
inftl->mbd.tr = tr;
memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (INFTL_mount(inftl) < 0) {
printk(KERN_WARNING "INFTL: could not mount device\n");
......@@ -151,6 +150,69 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
* Actual INFTL access routines.
*/
/*
* Read oob data from flash
*/
int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
size_t *retlen, uint8_t *buf)
{
struct mtd_oob_ops ops;
int res;
ops.mode = MTD_OOB_PLACE;
ops.ooboffs = offs & (mtd->writesize - 1);
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
return res;
}
/*
* Write oob data to flash
*/
int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
size_t *retlen, uint8_t *buf)
{
struct mtd_oob_ops ops;
int res;
ops.mode = MTD_OOB_PLACE;
ops.ooboffs = offs & (mtd->writesize - 1);
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
return res;
}
/*
* Write data and oob to flash
*/
static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
size_t *retlen, uint8_t *buf, uint8_t *oob)
{
struct mtd_oob_ops ops;
int res;
ops.mode = MTD_OOB_PLACE;
ops.ooboffs = offs;
ops.ooblen = mtd->oobsize;
ops.oobbuf = oob;
ops.datbuf = buf;
ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
return res;
}
/*
* INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
* This function is used when the give Virtual Unit Chain.
......@@ -198,6 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
u16 BlockMap[MAX_SECTORS_PER_UNIT];
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
unsigned int thisEUN, prevEUN, status;
struct mtd_info *mtd = inftl->mbd.mtd;
int block, silly;
unsigned int targetEUN;
struct inftl_oob oob;
......@@ -227,8 +290,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
continue;
if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
+ (block * SECTORSIZE), 16 , &retlen,
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
+ (block * SECTORSIZE), 16, &retlen,
(char *)&oob) < 0)
status = SECTOR_IGNORE;
else
......@@ -289,22 +352,24 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
if (BlockMap[block] == BLOCK_NIL)
continue;
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
(block * SECTORSIZE), SECTORSIZE, &retlen,
movebuf);
if (ret < 0 && ret != -EUCLEAN) {
ret = mtd->read(mtd,
(inftl->EraseSize * BlockMap[block]) +
(block * SECTORSIZE), SECTORSIZE,
&retlen, movebuf);
if (ret < 0) {
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE),
SECTORSIZE, &retlen, movebuf);
if (ret != -EIO)
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
"away on retry?\n");
}
memset(&oob, 0xff, sizeof(struct inftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
(block * SECTORSIZE), SECTORSIZE, &retlen,
movebuf, (char *)&oob, &inftl->oobinfo);
movebuf, (char *)&oob);
}
/*
......@@ -415,6 +480,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
unsigned int thisEUN, writeEUN, prev_block, status;
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
struct mtd_info *mtd = inftl->mbd.mtd;
struct inftl_oob oob;
struct inftl_bci bci;
unsigned char anac, nacs, parity;
......@@ -434,7 +500,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
silly = MAX_LOOPS;
while (thisEUN <= inftl->lastEUN) {
MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
blockofs, 8, &retlen, (char *)&bci);
status = bci.Status | bci.Status1;
......@@ -522,7 +588,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
nacs = 0;
thisEUN = inftl->VUtable[thisVUC];
if (thisEUN != BLOCK_NIL) {
MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize
inftl_read_oob(mtd, thisEUN * inftl->EraseSize
+ 8, 8, &retlen, (char *)&oob.u);
anac = oob.u.a.ANAC + 1;
nacs = oob.u.a.NACs + 1;
......@@ -544,7 +610,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
oob.u.a.parityPerField = parity;
oob.u.a.discarded = 0xaa;
MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8,
inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,
&retlen, (char *)&oob.u);
/* Also back up header... */
......@@ -555,7 +621,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
oob.u.b.parityPerField = parity;
oob.u.b.discarded = 0xaa;
MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
inftl_write_oob(mtd, writeEUN * inftl->EraseSize +
SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
......@@ -576,6 +642,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
*/
static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
{
struct mtd_info *mtd = inftl->mbd.mtd;
unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
unsigned int thisEUN, status;
......@@ -606,7 +673,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
if (BlockUsed[block] || BlockDeleted[block])
continue;
if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
+ (block * SECTORSIZE), 8 , &retlen,
(char *)&bci) < 0)
status = SECTOR_IGNORE;
......@@ -697,6 +764,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
{
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
struct mtd_info *mtd = inftl->mbd.mtd;
unsigned int status;
int silly = MAX_LOOPS;
size_t retlen;
......@@ -706,7 +774,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
"block=%d)\n", inftl, block);
while (thisEUN < inftl->nb_blocks) {
if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
blockofs, 8, &retlen, (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
......@@ -741,10 +809,10 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
if (thisEUN != BLOCK_NIL) {
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
return -EIO;
bci.Status = bci.Status1 = SECTOR_DELETED;
if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
return -EIO;
INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
}
......@@ -784,9 +852,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
memset(&oob, 0xff, sizeof(struct inftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
blockofs, SECTORSIZE, &retlen, (char *)buffer,
(char *)&oob, &inftl->oobinfo);
(char *)&oob);
/*
* need to write SECTOR_USED flags since they are not written
* in mtd_writeecc
......@@ -804,6 +873,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
struct INFTLrecord *inftl = (void *)mbd;
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
struct mtd_info *mtd = inftl->mbd.mtd;
unsigned int status;
int silly = MAX_LOOPS;
struct inftl_bci bci;
......@@ -813,7 +883,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
"buffer=%p)\n", inftl, block, buffer);
while (thisEUN < inftl->nb_blocks) {
if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
blockofs, 8, &retlen, (char *)&bci) < 0)
status = SECTOR_IGNORE;
else
......@@ -852,8 +922,10 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
} else {
size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
buffer))
int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
/* Handle corrected bit flips gracefully */
if (ret < 0 && ret != -EUCLEAN)
return -EIO;
}
return 0;
......
......@@ -43,6 +43,11 @@
char inftlmountrev[]="$Revision: 1.18 $";
extern int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
size_t *retlen, uint8_t *buf);
extern int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
size_t *retlen, uint8_t *buf);
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
* contains the various device information of the INFTL partition and
......@@ -57,6 +62,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
unsigned int i, block;
u8 buf[SECTORSIZE];
struct INFTLMediaHeader *mh = &inftl->MediaHdr;
struct mtd_info *mtd = inftl->mbd.mtd;
struct INFTLPartition *ip;
size_t retlen;
......@@ -80,7 +86,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
* Check for BNAND header first. Then whinge if it's found
* but later checks fail.
*/
ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
ret = mtd->read(mtd, block * inftl->EraseSize,
SECTORSIZE, &retlen, buf);
/* We ignore ret in case the ECC of the MediaHeader is invalid
(which is apparently acceptable) */
......@@ -106,8 +112,9 @@ static int find_boot_record(struct INFTLrecord *inftl)
}
/* To be safer with BIOS, also use erase mark as discriminant */
if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +
SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {
if ((ret = inftl_read_oob(mtd, block * inftl->EraseSize +
SECTORSIZE + 8, 8, &retlen,
(char *)&h1) < 0)) {
printk(KERN_WARNING "INFTL: ANAND header found at "
"0x%x in mtd%d, but OOB data read failed "
"(err %d)\n", block * inftl->EraseSize,
......@@ -123,7 +130,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
/* Read the spare media header at offset 4096 */
MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
mtd->read(mtd, block * inftl->EraseSize + 4096,
SECTORSIZE, &retlen, buf);
if (retlen != SECTORSIZE) {
printk(KERN_WARNING "INFTL: Unable to read spare "
......@@ -233,7 +240,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
*/
instr->addr = ip->Reserved0 * inftl->EraseSize;
instr->len = inftl->EraseSize;
MTD_ERASE(inftl->mbd.mtd, instr);
mtd->erase(mtd, instr);
}
if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
printk(KERN_WARNING "INFTL: Media Header "
......@@ -350,21 +357,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
int len, int check_oob)
{
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
struct mtd_info *mtd = inftl->mbd.mtd;
size_t retlen;
int i;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
"address=0x%x,len=%d,check_oob=%d)\n", inftl,
address, len, check_oob);
for (i = 0; i < len; i += SECTORSIZE) {
if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
if(inftl_read_oob(mtd, address, mtd->oobsize,
&retlen, &buf[SECTORSIZE]) < 0)
return -1;
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
......@@ -387,6 +394,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
size_t retlen;
struct inftl_unittail uci;
struct erase_info *instr = &inftl->instr;
struct mtd_info *mtd = inftl->mbd.mtd;
int physblock;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
......@@ -404,8 +412,9 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
/* Erase one physical eraseblock at a time, even though the NAND api
allows us to group them. This way we if we have a failure, we can
mark only the failed block in the bbt. */
for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
MTD_ERASE(inftl->mbd.mtd, instr);
for (physblock = 0; physblock < inftl->EraseSize;
physblock += instr->len, instr->addr += instr->len) {
mtd->erase(inftl->mbd.mtd, instr);
if (instr->state == MTD_ERASE_FAILED) {
printk(KERN_WARNING "INFTL: error while formatting block %d\n",
......@@ -415,8 +424,8 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
/*
* Check the "freeness" of Erase Unit before updating metadata.
* FixMe: is this check really necessary? Since we have check the
* return code after the erase operation.
* FixMe: is this check really necessary? Since we have check
* the return code after the erase operation.
*/
if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
goto fail;
......@@ -429,8 +438,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
uci.Reserved[2] = 0;
uci.Reserved[3] = 0;
instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
8, 8, &retlen, (char *)&uci) < 0)
if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0)
goto fail;
return 0;
fail:
......@@ -549,6 +557,7 @@ void INFTL_dumpVUchains(struct INFTLrecord *s)
int INFTL_mount(struct INFTLrecord *s)
{
struct mtd_info *mtd = s->mbd.mtd;
unsigned int block, first_block, prev_block, last_block;
unsigned int first_logical_block, logical_block, erase_mark;
int chain_length, do_format_chain;
......@@ -607,10 +616,11 @@ int INFTL_mount(struct INFTLrecord *s)
break;
}
if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8,
if (inftl_read_oob(mtd, block * s->EraseSize + 8,
8, &retlen, (char *)&h0) < 0 ||
MTD_READOOB(s->mbd.mtd, block * s->EraseSize +
2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) {
inftl_read_oob(mtd, block * s->EraseSize +
2 * SECTORSIZE + 8, 8, &retlen,
(char *)&h1) < 0) {
/* Should never happen? */
do_format_chain++;
break;
......
......@@ -37,7 +37,7 @@ config MTD_PHYSMAP_START
config MTD_PHYSMAP_LEN
hex "Physical length of flash mapping"
depends on MTD_PHYSMAP
default "0x4000000"
default "0"
help
This is the total length of the mapping of the flash chips on
your particular board. If there is space, or aliases, in the
......@@ -78,7 +78,7 @@ config MTD_PNC2000
config MTD_SC520CDP
tristate "CFI Flash device mapped on AMD SC520 CDP"
depends on X86 && MTD_CFI
depends on X86 && MTD_CFI && MTD_CONCAT
help
The SC520 CDP board has two banks of CFI-compliant chips and one
Dual-in-line JEDEC chip. This 'mapping' driver supports that
......@@ -109,7 +109,7 @@ config MTD_TS5500
mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL.
Note that jumper 3 ("Write Enable Drive A") must be set
otherwise detection won't succeeed.
otherwise detection won't succeed.
config MTD_SBC_GXX
tristate "CFI Flash device mapped on Arcom SBC-GXx boards"
......@@ -200,8 +200,8 @@ config MTD_TSUNAMI
Support for the flash chip on Tsunami TIG bus.
config MTD_LASAT
tristate "Flash chips on LASAT board"
depends on LASAT
tristate "LASAT flash device"
depends on LASAT && MTD_CFI
help
Support for the flash chips on the Lasat 100 and 200 boards.
......@@ -561,7 +561,6 @@ config MTD_PCMCIA
config MTD_PCMCIA_ANONYMOUS
bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards"
depends on MTD_PCMCIA
default N
help
If this option is enabled, PCMCIA cards which do not report
anything about themselves are assumed to be MTD cards.
......
/*
* Copyright 2001 Flaga hf. Medical Devices, Kri Davsson <kd@flaga.is>
* Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
*
* $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $
*
......@@ -135,5 +135,5 @@ module_exit(cleanup_flagadm);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kri Davsson <kd@flaga.is>");
MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>");
MODULE_DESCRIPTION("MTD map driver for Flaga digital module");
......@@ -122,5 +122,5 @@ module_exit(cleanup_dbox2_flash);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kri Davsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");
......@@ -4,7 +4,7 @@
* $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
*
* (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
* (C) 2005 Jrn Engel <joern@wohnheim.fh-wedel.de>
* (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
*
*/
......
......@@ -20,6 +20,8 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/reboot.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/io.h>
/****************************************************************************/
......@@ -188,7 +190,7 @@ int nettel_eraseconfig(void)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
ret = MTD_ERASE(mtd, &nettel_erase);
ret = mtd->erase(mtd, &nettel_erase);
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
......
......@@ -713,6 +713,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link)
if(dev->mtd_info) {
del_mtd_device(dev->mtd_info);
map_destroy(dev->mtd_info);
info("mtd%d: Removed", dev->mtd_info->index);
}
......
......@@ -14,112 +14,229 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/config.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <asm/io.h>
static struct mtd_info *mymtd;
struct map_info physmap_map = {
.name = "phys_mapped_flash",
.phys = CONFIG_MTD_PHYSMAP_START,
.size = CONFIG_MTD_PHYSMAP_LEN,
.bankwidth = CONFIG_MTD_PHYSMAP_BANKWIDTH,
struct physmap_flash_info {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
#ifdef CONFIG_MTD_PARTITIONS
int nr_parts;
struct mtd_partition *parts;
#endif
};
static int physmap_flash_remove(struct platform_device *dev)
{
struct physmap_flash_info *info;
struct physmap_flash_data *physmap_data;
info = platform_get_drvdata(dev);
if (info == NULL)
return 0;
platform_set_drvdata(dev, NULL);
physmap_data = dev->dev.platform_data;
if (info->mtd != NULL) {
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition *mtd_parts;
static int mtd_parts_nb;
if (info->nr_parts) {
del_mtd_partitions(info->mtd);
kfree(info->parts);
} else if (physmap_data->nr_parts) {
del_mtd_partitions(info->mtd);
} else {
del_mtd_device(info->mtd);
}
#else
del_mtd_device(info->mtd);
#endif
map_destroy(info->mtd);
}
static int num_physmap_partitions;
static struct mtd_partition *physmap_partitions;
if (info->map.virt != NULL)
iounmap((void *)info->map.virt);
static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
if (info->res != NULL) {
release_resource(info->res);
kfree(info->res);
}
void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
{
physmap_partitions=parts;
num_physmap_partitions=num_parts;
return 0;
}
#endif /* CONFIG_MTD_PARTITIONS */
static int __init init_physmap(void)
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
#endif
static int physmap_flash_probe(struct platform_device *dev)
{
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
const char **type;
struct physmap_flash_data *physmap_data;
struct physmap_flash_info *info;
const char **probe_type;
int err;
physmap_data = dev->dev.platform_data;
if (physmap_data == NULL)
return -ENODEV;
printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
(unsigned long long)dev->resource->end - dev->resource->start + 1,
(unsigned long long)dev->resource->start);
info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto err_out;
}
memset(info, 0, sizeof(*info));
printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
physmap_map.virt = ioremap(physmap_map.phys, physmap_map.size);
platform_set_drvdata(dev, info);
info->res = request_mem_region(dev->resource->start,
dev->resource->end - dev->resource->start + 1,
dev->dev.bus_id);
if (info->res == NULL) {
dev_err(&dev->dev, "Could not reserve memory region\n");
err = -ENOMEM;
goto err_out;
}
if (!physmap_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
info->map.name = dev->dev.bus_id;
info->map.phys = dev->resource->start;
info->map.size = dev->resource->end - dev->resource->start + 1;
info->map.bankwidth = physmap_data->width;
info->map.set_vpp = physmap_data->set_vpp;
info->map.virt = ioremap(info->map.phys, info->map.size);
if (info->map.virt == NULL) {
dev_err(&dev->dev, "Failed to ioremap flash region\n");
err = EIO;
goto err_out;
}
simple_map_init(&physmap_map);
simple_map_init(&info->map);
mymtd = NULL;
type = rom_probe_types;
for(; !mymtd && *type; type++) {
mymtd = do_map_probe(*type, &physmap_map);
probe_type = rom_probe_types;
for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
info->mtd = do_map_probe(*probe_type, &info->map);
if (info->mtd == NULL) {
dev_err(&dev->dev, "map_probe failed\n");
err = -ENXIO;
goto err_out;
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
info->mtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes,
&mtd_parts, 0);
if (mtd_parts_nb > 0)
{
add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
if (err > 0) {
add_mtd_partitions(info->mtd, info->parts, err);
return 0;
}
if (num_physmap_partitions != 0)
{
printk(KERN_NOTICE
"Using physmap partition definition\n");
add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
if (physmap_data->nr_parts) {
printk(KERN_NOTICE "Using physmap partition information\n");
add_mtd_partitions(info->mtd, physmap_data->parts,
physmap_data->nr_parts);
return 0;
}
#endif
add_mtd_device(mymtd);
add_mtd_device(info->mtd);
return 0;
}
iounmap(physmap_map.virt);
return -ENXIO;
err_out:
physmap_flash_remove(dev);
return err;
}
static void __exit cleanup_physmap(void)
static struct platform_driver physmap_flash_driver = {
.probe = physmap_flash_probe,
.remove = physmap_flash_remove,
.driver = {
.name = "physmap-flash",
},
};
#ifdef CONFIG_MTD_PHYSMAP_LEN
#if CONFIG_MTD_PHYSMAP_LEN != 0
#warning using PHYSMAP compat code
#define PHYSMAP_COMPAT
#endif
#endif
#ifdef PHYSMAP_COMPAT
static struct physmap_flash_data physmap_flash_data = {
.width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
};
static struct resource physmap_flash_resource = {
.start = CONFIG_MTD_PHYSMAP_START,
.end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
.flags = IORESOURCE_MEM,
};
static struct platform_device physmap_flash = {
.name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &physmap_flash_data,
},
.num_resources = 1,
.resource = &physmap_flash_resource,
};
void physmap_configure(unsigned long addr, unsigned long size,
int bankwidth, void (*set_vpp)(struct map_info *, int))
{
physmap_flash_resource.start = addr;
physmap_flash_resource.end = addr + size - 1;
physmap_flash_data.width = bankwidth;
physmap_flash_data.set_vpp = set_vpp;
}
#ifdef CONFIG_MTD_PARTITIONS
if (mtd_parts_nb) {
del_mtd_partitions(mymtd);
kfree(mtd_parts);
} else if (num_physmap_partitions) {
del_mtd_partitions(mymtd);
} else {
del_mtd_device(mymtd);
}
#else
del_mtd_device(mymtd);
void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
{
physmap_flash_data.nr_parts = num_parts;
physmap_flash_data.parts = parts;
}
#endif
#endif
map_destroy(mymtd);
iounmap(physmap_map.virt);
physmap_map.virt = NULL;
static int __init physmap_init(void)
{
int err;
err = platform_driver_register(&physmap_flash_driver);
#ifdef PHYSMAP_COMPAT
if (err == 0)
platform_device_register(&physmap_flash);
#endif
return err;
}
module_init(init_physmap);
module_exit(cleanup_physmap);
static void __exit physmap_exit(void)
{
#ifdef PHYSMAP_COMPAT
platform_device_unregister(&physmap_flash);
#endif
platform_driver_unregister(&physmap_flash_driver);
}
module_init(physmap_init);
module_exit(physmap_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
......
......@@ -71,7 +71,7 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos,
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
ret = MTD_ERASE(mtd, &erase);
ret = mtd->erase(mtd, &erase);
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
......@@ -88,7 +88,7 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos,
* Next, writhe data to flash.
*/
ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
ret = mtd->write(mtd, pos, len, &retlen, buf);
if (ret)
return ret;
if (retlen != len)
......@@ -138,7 +138,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
mtd->name, pos, len);
if (!sect_size)
return MTD_WRITE (mtd, pos, len, &retlen, buf);
return mtd->write(mtd, pos, len, &retlen, buf);
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
......@@ -170,7 +170,8 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset != sect_start) {
/* fill the cache with the current sector */
mtdblk->cache_state = STATE_EMPTY;
ret = MTD_READ(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);
ret = mtd->read(mtd, sect_start, sect_size,
&retlen, mtdblk->cache_data);
if (ret)
return ret;
if (retlen != sect_size)
......@@ -207,7 +208,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
mtd->name, pos, len);
if (!sect_size)
return MTD_READ (mtd, pos, len, &retlen, buf);
return mtd->read(mtd, pos, len, &retlen, buf);
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
......@@ -226,7 +227,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset == sect_start) {
memcpy (buf, mtdblk->cache_data + offset, size);
} else {
ret = MTD_READ (mtd, pos, size, &retlen, buf);
ret = mtd->read(mtd, pos, size, &retlen, buf);
if (ret)
return ret;
if (retlen != size)
......@@ -288,8 +289,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
mutex_init(&mtdblk->cache_mutex);
mtdblk->cache_state = STATE_EMPTY;
if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&
mtdblk->mtd->erasesize) {
if ( !(mtdblk->mtd->flags & MTD_NO_ERASE) && mtdblk->mtd->erasesize) {
mtdblk->cache_size = mtdblk->mtd->erasesize;
mtdblk->cache_data = NULL;
}
......
......@@ -45,8 +45,6 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
dev->blksize = 512;
dev->size = mtd->size >> 9;
dev->tr = tr;
if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) !=
(MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE))
dev->readonly = 1;
add_mtd_blktrans_dev(dev);
......
This diff is collapsed.
This diff is collapsed.
......@@ -47,6 +47,7 @@ int add_mtd_device(struct mtd_info *mtd)
{
int i;
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
for (i=0; i < MAX_MTD_DEVICES; i++)
......@@ -254,37 +255,6 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
return ret;
}
/* default_mtd_readv - default mtd readv method for MTD devices that dont
* implement their own
*/
int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen)
{
unsigned long i;
size_t totlen = 0, thislen;
int ret = 0;
if(!mtd->read) {
ret = -EIO;
} else {
for (i=0; i<count; i++) {
if (!vecs[i].iov_len)
continue;
ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base);
totlen += thislen;
if (ret || thislen != vecs[i].iov_len)
break;
from += vecs[i].iov_len;
}
}
if (retlen)
*retlen = totlen;
return ret;
}
EXPORT_SYMBOL(add_mtd_device);
EXPORT_SYMBOL(del_mtd_device);
EXPORT_SYMBOL(get_mtd_device);
......@@ -292,7 +262,6 @@ EXPORT_SYMBOL(put_mtd_device);
EXPORT_SYMBOL(register_mtd_user);
EXPORT_SYMBOL(unregister_mtd_user);
EXPORT_SYMBOL(default_mtd_writev);
EXPORT_SYMBOL(default_mtd_readv);
#ifdef CONFIG_PROC_FS
......
......@@ -51,16 +51,21 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
int res;
if (from >= mtd->size)
len = 0;
else if (from + len > mtd->size)
len = mtd->size - from;
if (part->master->read_ecc == NULL)
return part->master->read (part->master, from + part->offset,
res = part->master->read (part->master, from + part->offset,
len, retlen, buf);
else
return part->master->read_ecc (part->master, from + part->offset,
len, retlen, buf, NULL, &mtd->oobinfo);
if (unlikely(res)) {
if (res == -EUCLEAN)
mtd->ecc_stats.corrected++;
if (res == -EBADMSG)
mtd->ecc_stats.failed++;
}
return res;
}
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
......@@ -74,6 +79,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
return part->master->point (part->master, from + part->offset,
len, retlen, buf);
}
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
{
struct mtd_part *part = PART(mtd);
......@@ -81,31 +87,25 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
part->master->unpoint (part->master, addr, from + part->offset, len);
}
static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
static int part_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
struct mtd_part *part = PART(mtd);
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
if (from >= mtd->size)
len = 0;
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->read_ecc (part->master, from + part->offset,
len, retlen, buf, eccbuf, oobsel);
}
int res;
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
len = 0;
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->read_oob (part->master, from + part->offset,
len, retlen, buf);
return -EINVAL;
if (from + ops->len > mtd->size)
return -EINVAL;
res = part->master->read_oob(part->master, from + part->offset, ops);
if (unlikely(res)) {
if (res == -EUCLEAN)
mtd->ecc_stats.corrected++;
if (res == -EBADMSG)
mtd->ecc_stats.failed++;
}
return res;
}
static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
......@@ -148,44 +148,23 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
len = 0;
else if (to + len > mtd->size)
len = mtd->size - to;
if (part->master->write_ecc == NULL)
return part->master->write (part->master, to + part->offset,
len, retlen, buf);
else
return part->master->write_ecc (part->master, to + part->offset,
len, retlen, buf, NULL, &mtd->oobinfo);
}
static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf,
u_char *eccbuf, struct nand_oobinfo *oobsel)
static int part_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
if (to >= mtd->size)
len = 0;
else if (to + len > mtd->size)
len = mtd->size - to;
return part->master->write_ecc (part->master, to + part->offset,
len, retlen, buf, eccbuf, oobsel);
}
static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (to >= mtd->size)
len = 0;
else if (to + len > mtd->size)
len = mtd->size - to;
return part->master->write_oob (part->master, to + part->offset,
len, retlen, buf);
return -EINVAL;
if (to + ops->len > mtd->size)
return -EINVAL;
return part->master->write_oob(part->master, to + part->offset, ops);
}
static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
......@@ -208,52 +187,8 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (part->master->writev_ecc == NULL)
return part->master->writev (part->master, vecs, count,
to + part->offset, retlen);
else
return part->master->writev_ecc (part->master, vecs, count,
to + part->offset, retlen,
NULL, &mtd->oobinfo);
}
static int part_readv (struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen)
{
struct mtd_part *part = PART(mtd);
if (part->master->readv_ecc == NULL)
return part->master->readv (part->master, vecs, count,
from + part->offset, retlen);
else
return part->master->readv_ecc (part->master, vecs, count,
from + part->offset, retlen,
NULL, &mtd->oobinfo);
}
static int part_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
return part->master->writev_ecc (part->master, vecs, count,
to + part->offset, retlen,
eccbuf, oobsel);
}
static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
return part->master->readv_ecc (part->master, vecs, count,
from + part->offset, retlen,
eccbuf, oobsel);
}
static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
......@@ -329,12 +264,17 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
{
struct mtd_part *part = PART(mtd);
int res;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (ofs >= mtd->size)
return -EINVAL;
ofs += part->offset;
return part->master->block_markbad(part->master, ofs);
res = part->master->block_markbad(part->master, ofs);
if (!res)
mtd->ecc_stats.badblocks++;
return res;
}
/*
......@@ -398,7 +338,7 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.type = master->type;
slave->mtd.flags = master->flags & ~parts[i].mask_flags;
slave->mtd.size = parts[i].size;
slave->mtd.oobblock = master->oobblock;
slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
slave->mtd.ecctype = master->ecctype;
slave->mtd.eccsize = master->eccsize;
......@@ -415,10 +355,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.unpoint = part_unpoint;
}
if (master->read_ecc)
slave->mtd.read_ecc = part_read_ecc;
if (master->write_ecc)
slave->mtd.write_ecc = part_write_ecc;
if (master->read_oob)
slave->mtd.read_oob = part_read_oob;
if (master->write_oob)
......@@ -443,12 +379,6 @@ int add_mtd_partitions(struct mtd_info *master,
}
if (master->writev)
slave->mtd.writev = part_writev;
if (master->readv)
slave->mtd.readv = part_readv;
if (master->writev_ecc)
slave->mtd.writev_ecc = part_writev_ecc;
if (master->readv_ecc)
slave->mtd.readv_ecc = part_readv_ecc;
if (master->lock)
slave->mtd.lock = part_lock;
if (master->unlock)
......@@ -528,8 +458,17 @@ int add_mtd_partitions(struct mtd_info *master,
parts[i].name);
}
/* copy oobinfo from master */
memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
slave->mtd.ecclayout = master->ecclayout;
if (master->block_isbad) {
uint32_t offs = 0;
while(offs < slave->mtd.size) {
if (master->block_isbad(master,
offs + slave->offset))
slave->mtd.ecc_stats.badblocks++;
offs += slave->mtd.erasesize;
}
}
if(parts[i].mtdp)
{ /* store the object pointer (caller may or may not register it */
......
......@@ -23,6 +23,14 @@ config MTD_NAND_VERIFY_WRITE
device thinks the write was successful, a bit could have been
flipped accidentaly due to device wear or something else.
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
depends on MTD_NAND
default n
help
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
config MTD_NAND_AUTCPU12
tristate "SmartMediaCard on autronix autcpu12 board"
depends on MTD_NAND && ARCH_AUTCPU12
......@@ -49,12 +57,24 @@ config MTD_NAND_SPIA
help
If you had to ask, you don't have one. Say 'N'.
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA && MTD_NAND
help
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_TOTO
tristate "NAND Flash device on TOTO board"
depends on ARCH_OMAP && MTD_NAND
depends on ARCH_OMAP && MTD_NAND && BROKEN
help
Support for NAND flash on Texas Instruments Toto platform.
config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX && MTD_NAND
help
Support for NAND flash on Technologic Systems TS-7250 platform.
config MTD_NAND_IDS
tristate
......@@ -76,7 +96,7 @@ config MTD_NAND_RTC_FROM4
config MTD_NAND_PPCHAMELEONEVB
tristate "NAND Flash device on PPChameleonEVB board"
depends on PPCHAMELEONEVB && MTD_NAND
depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
help
This enables the NAND flash driver on the PPChameleon EVB Board.
......@@ -87,7 +107,7 @@ config MTD_NAND_S3C2410
This enables the NAND flash controller on the S3C2410 and S3C2440
SoCs
No board specfic support is done by this driver, each board
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
......@@ -109,6 +129,22 @@ config MTD_NAND_S3C2410_HWECC
currently not be able to switch to software, as there is no
implementation for ECC method used by the S3C2410
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on MTD_NAND && 44x
help
NDFC Nand Flash Controllers are integrated in EP44x SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "S3C2410 NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on MTD_NAND && EXPERIMENTAL
......@@ -183,11 +219,24 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
help
The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC
capabilities; enabling this option will allow you to use
these. The driver will check the MSRs to verify that the
controller is enabled for NAND, and currently requires that
the controller be in MMIO mode.
If you say "m", the module will be called "cs553x_nand.ko".
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
depends on MTD_NAND && MTD_PARTITIONS
help
The simulator may simulate verious NAND flash chips for the
The simulator may simulate various NAND flash chips for the
MTD nand layer.
endmenu
......@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
......@@ -17,6 +18,9 @@ obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
nand-objs = nand_base.o nand_bbt.o
/*
* drivers/mtd/nand/ams-delta.c
*
* Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
*
* Derived from drivers/mtd/toto.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the NAND flash device found on the
* Amstrad E3 (Delta).
*/
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/sizes.h>
#include <asm/arch/gpio.h>
#include <asm/arch/board-ams-delta.h>
/*
* MTD structure for E3 (Delta)
*/
static struct mtd_info *ams_delta_mtd = NULL;
#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
/*
* Define partitions for flash devices
*/
static struct mtd_partition partition_info[] = {
{ .name = "Kernel",
.offset = 0,
.size = 3 * SZ_1M + SZ_512K },
{ .name = "u-boot",
.offset = 3 * SZ_1M + SZ_512K,
.size = SZ_256K },
{ .name = "u-boot params",
.offset = 3 * SZ_1M + SZ_512K + SZ_256K,
.size = SZ_256K },
{ .name = "Amstrad LDR",
.offset = 4 * SZ_1M,
.size = SZ_256K },
{ .name = "File system",
.offset = 4 * SZ_1M + 1 * SZ_256K,
.size = 27 * SZ_1M },
{ .name = "PBL reserved",
.offset = 32 * SZ_1M - 3 * SZ_256K,
.size = 3 * SZ_256K },
};
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{
struct nand_chip *this = mtd->priv;
omap_writew(0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
omap_writew(byte, this->IO_ADDR_W);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
ndelay(40);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
AMS_DELTA_LATCH2_NAND_NWE);
}
static u_char ams_delta_read_byte(struct mtd_info *mtd)
{
u_char res;
struct nand_chip *this = mtd->priv;
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
ndelay(40);
omap_writew(~0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
res = omap_readw(this->IO_ADDR_R);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
AMS_DELTA_LATCH2_NAND_NRE);
return res;
}
static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
int len)
{
int i;
for (i=0; i<len; i++)
ams_delta_write_byte(mtd, buf[i]);
}
static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
int i;
for (i=0; i<len; i++)
buf[i] = ams_delta_read_byte(mtd);
}
static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
int len)
{
int i;
for (i=0; i<len; i++)
if (buf[i] != ams_delta_read_byte(mtd))
return -EFAULT;
return 0;
}
/*
* Command control function
*
* ctrl:
* NAND_NCE: bit 0 -> bit 2
* NAND_CLE: bit 1 -> bit 7
* NAND_ALE: bit 2 -> bit 6
*/
static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
if (ctrl & NAND_CTRL_CHANGE) {
unsigned long bits;
bits = (~ctrl & NAND_NCE) << 2;
bits |= (ctrl & NAND_CLE) << 7;
bits |= (ctrl & NAND_ALE) << 6;
ams_delta_latch2_write(0xC2, bits);
}
if (cmd != NAND_CMD_NONE)
ams_delta_write_byte(mtd, cmd);
}
static int ams_delta_nand_ready(struct mtd_info *mtd)
{
return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
}
/*
* Main initialization routine
*/
static int __init ams_delta_init(void)
{
struct nand_chip *this;
int err = 0;
/* Allocate memory for MTD device structure and private data */
ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
sizeof(struct nand_chip), GFP_KERNEL);
if (!ams_delta_mtd) {
printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
ams_delta_mtd->owner = THIS_MODULE;
/* Get pointer to private data */
this = (struct nand_chip *) (&ams_delta_mtd[1]);
/* Initialize structures */
memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
ams_delta_mtd->priv = this;
/* Set address of NAND IO lines */
this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
this->read_byte = ams_delta_read_byte;
this->write_buf = ams_delta_write_buf;
this->read_buf = ams_delta_read_buf;
this->verify_buf = ams_delta_verify_buf;
this->cmd_ctrl = ams_delta_hwcontrol;
if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
this->dev_ready = ams_delta_nand_ready;
} else {
this->dev_ready = NULL;
printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
}
/* 25 us command delay time */
this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
/* Set chip enabled, but */
ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
AMS_DELTA_LATCH2_NAND_NWE |
AMS_DELTA_LATCH2_NAND_NCE |
AMS_DELTA_LATCH2_NAND_NWP);
/* Scan to find existance of the device */
if (nand_scan(ams_delta_mtd, 1)) {
err = -ENXIO;
goto out_mtd;
}
/* Register the partitions */
add_mtd_partitions(ams_delta_mtd, partition_info,
ARRAY_SIZE(partition_info));
goto out;
out_mtd:
kfree(ams_delta_mtd);
out:
return err;
}
module_init(ams_delta_init);
/*
* Clean up routine
*/
static void __exit ams_delta_cleanup(void)
{
/* Release resources, unregister device */
nand_release(ams_delta_mtd);
/* Free the MTD device structure */
kfree(ams_delta_mtd);
}
module_exit(ams_delta_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
This diff is collapsed.
......@@ -42,12 +42,7 @@
* MTD structure for AUTCPU12 board
*/
static struct mtd_info *autcpu12_mtd = NULL;
static int autcpu12_io_base = CS89712_VIRT_BASE;
static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
static void __iomem * autcpu12_fio_base;
static void __iomem *autcpu12_fio_base;
/*
* Define partitions for flash devices
......@@ -94,76 +89,88 @@ static struct mtd_partition partition_info128k[] = {
#define NUM_PARTITIONS128K 2
/*
* hardware specific access to control-lines
*/
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
*
* ALE bit 4 autcpu12_pedr
* CLE bit 5 autcpu12_pedr
* NCE bit 0 fio_ctrl
*
*/
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
switch(cmd){
case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break;
case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
if (ctrl & NAND_CTRL_CHANGE) {
void __iomem *addr
unsigned char bits;
case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break;
case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
bits = (ctrl & NAND_CLE) << 4;
bits |= (ctrl & NAND_ALE) << 2;
writeb((readb(addr) & ~0x30) | bits, addr);
case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
/*
* read device ready pin
*/
* read device ready pin
*/
int autcpu12_device_ready(struct mtd_info *mtd)
{
void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
return readb(addr) & AUTCPU12_SMC_RDY;
}
/*
* Main initialization routine
*/
int __init autcpu12_init (void)
static int __init autcpu12_init(void)
{
struct nand_chip *this;
int err = 0;
/* Allocate memory for MTD device structure and private data */
autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
GFP_KERNEL);
if (!autcpu12_mtd) {
printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
/* map physical adress */
autcpu12_fio_base = ioremap(autcpu12_fio_pbase,SZ_1K);
if(!autcpu12_fio_base){
autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
if (!autcpu12_fio_base) {
printk("Ioremap autcpu12 SmartMedia Card failed\n");
err = -EIO;
goto out_mtd;
}
/* Get pointer to private data */
this = (struct nand_chip *) (&autcpu12_mtd[1]);
this = (struct nand_chip *)(&autcpu12_mtd[1]);
/* Initialize structures */
memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info));
memset((char *) this, 0, sizeof(struct nand_chip));
memset(autcpu12_mtd, 0, sizeof(struct mtd_info));
memset(this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
autcpu12_mtd->priv = this;
autcpu12_mtd->owner = THIS_MODULE;
/* Set address of NAND IO lines */
this->IO_ADDR_R = autcpu12_fio_base;
this->IO_ADDR_W = autcpu12_fio_base;
this->hwcontrol = autcpu12_hwcontrol;
this->cmd_ctrl = autcpu12_hwcontrol;
this->dev_ready = autcpu12_device_ready;
/* 20 us command delay time */
this->chip_delay = 20;
this->eccmode = NAND_ECC_SOFT;
this->ecc.mode = NAND_ECC_SOFT;
/* Enable the following for a flash based bad block table */
/*
......@@ -172,30 +179,41 @@ int __init autcpu12_init (void)
this->options = NAND_USE_FLASH_BBT;
/* Scan to find existance of the device */
if (nand_scan (autcpu12_mtd, 1)) {
if (nand_scan(autcpu12_mtd, 1)) {
err = -ENXIO;
goto out_ior;
}
/* Register the partitions */
switch(autcpu12_mtd->size){
case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
default: {
printk ("Unsupported SmartMedia device\n");
switch (autcpu12_mtd->size) {
case SZ_16M:
add_mtd_partitions(autcpu12_mtd, partition_info16k,
NUM_PARTITIONS16K);
break;
case SZ_32M:
add_mtd_partitions(autcpu12_mtd, partition_info32k,
NUM_PARTITIONS32K);
break;
case SZ_64M:
add_mtd_partitions(autcpu12_mtd, partition_info64k,
NUM_PARTITIONS64K);
break;
case SZ_128M:
add_mtd_partitions(autcpu12_mtd, partition_info128k,
NUM_PARTITIONS128K);
break;
default:
printk("Unsupported SmartMedia device\n");
err = -ENXIO;
goto out_ior;
}
}
goto out;
out_ior:
iounmap((void *)autcpu12_fio_base);
out_mtd:
kfree (autcpu12_mtd);
out:
out_ior:
iounmap(autcpu12_fio_base);
out_mtd:
kfree(autcpu12_mtd);
out:
return err;
}
......@@ -204,20 +222,19 @@ module_init(autcpu12_init);
/*
* Clean up routine
*/
#ifdef MODULE
static void __exit autcpu12_cleanup (void)
static void __exit autcpu12_cleanup(void)
{
/* Release resources, unregister device */
nand_release (autcpu12_mtd);
nand_release(autcpu12_mtd);
/* unmap physical adress */
iounmap((void *)autcpu12_fio_base);
iounmap(autcpu12_fio_base);
/* Free the MTD device structure */
kfree (autcpu12_mtd);
kfree(autcpu12_mtd);
}
module_exit(autcpu12_cleanup);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -65,52 +65,63 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
/* These are the new chips with large page size. The pagesize
* and the erasesize is determined from the extended id bytes
/*
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/*512 Megabit */
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
/* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
* The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
* 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
* Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
* There are more speed improvements for reads and writes possible, but not implemented now
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
* 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page
* planes 1 block = 2 pages, but due to plane arrangement the blocks
* 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would
* increase the eraseblock size so we chose a combined one which can be
* erased in one go There are more speed improvements for reads and
* writes possible, but not implemented now
*/
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
BBT_AUTO_REFRESH
},
{NULL,}
};
......@@ -129,9 +140,9 @@ struct nand_manufacturers nand_manuf_ids[] = {
{0x0, "Unknown"}
};
EXPORT_SYMBOL (nand_manuf_ids);
EXPORT_SYMBOL (nand_flash_ids);
EXPORT_SYMBOL(nand_manuf_ids);
EXPORT_SYMBOL(nand_flash_ids);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION ("Nand device & manufacturer ID's");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION("Nand device & manufacturer IDs");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -29,6 +29,20 @@ config MTD_ONENAND_GENERIC
help
Support for OneNAND flash via platform device driver.
config MTD_ONENAND_OTP
bool "OneNAND OTP Support"
depends on MTD_ONENAND
help
One Block of the NAND Flash Array memory is reserved as
a One-Time Programmable Block memory area.
Also, 1st Block of NAND Flash Array can be used as OTP.
The OTP block can be read, programmed and locked using the same
operations as any other NAND Flash Array memory block.
OTP block cannot be erased.
OTP block is fully-guaranteed to be a valid block.
config MTD_ONENAND_SYNC_READ
bool "OneNAND Sync. Burst Read Support"
depends on ARCH_OMAP
......
This diff is collapsed.
......@@ -17,6 +17,9 @@
#include <linux/mtd/onenand.h>
#include <linux/mtd/compatmac.h>
extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
* @param buf the buffer to search
......@@ -87,13 +90,13 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
/* No need to read pages fully,
* just read required OOB bytes */
ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
readlen, &retlen, &buf[0]);
if (ret)
return ret;
if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -12,6 +12,9 @@ jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
jffs2-y += super.o debug.o
jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
jffs2-$(CONFIG_JFFS2_FS_XATTR) += xattr.o xattr_trusted.o xattr_user.o
jffs2-$(CONFIG_JFFS2_FS_SECURITY) += security.o
jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* This file provides the bit-probabilities for the input file */
#define BIT_DIVIDER 629
static int bits[9] = { 179,167,183,165,159,198,178,119,}; /* ia32 .so files */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment