Commit 200d481f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6

parents f43a64c5 97f927a4
# drivers/mtd/chips/Kconfig
# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
......@@ -155,6 +155,31 @@ config MTD_CFI_I8
If your flash chips are interleaved in eights - i.e. you have eight
flash chips addressed by each bus cycle, then say 'Y'.
config MTD_OTP
bool "Protection Registers aka one-time programmable (OTP) bits"
depends on MTD_CFI_ADV_OPTIONS
default n
help
This enables support for reading, writing and locking so called
"Protection Registers" present on some flash chips.
A subset of them are pre-programmed at the factory with a
unique set of values. The rest is user-programmable.
The user-programmable Protection Registers contain one-time
programmable (OTP) bits; when programmed, register bits cannot be
erased. Each Protection Register can be accessed multiple times to
program individual bits, as long as the register remains unlocked.
Each Protection Register has an associated Lock Register bit. When a
Lock Register bit is programmed, the associated Protection Register
can only be read; it can no longer be programmed. Additionally,
because the Lock Register bits themselves are OTP, when programmed,
Lock Register bits cannot be erased. Therefore, when a Protection
Register is locked, it cannot be unlocked.
This feature should therefore be used with extreme care. Any mistake
in the programming of OTP bits will waste them.
config MTD_CFI_INTELEXT
tristate "Support for Intel/Sharp flash chips"
depends on MTD_GEN_PROBE
......@@ -275,7 +300,7 @@ config MTD_JEDEC
config MTD_XIP
bool "XIP aware MTD support"
depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL
default y if XIP_KERNEL
help
This allows MTD support to work with flash memory which is also
......
......@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
* $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
......@@ -67,7 +67,6 @@
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
#define AM29BDS643D 0x227E
/* Atmel */
#define AT49xV16x 0x00C0
......@@ -617,17 +616,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
{ .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
}
}, {
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29BDS643D,
.name = "AMD AM29BDS643D",
.size = 0x00800000,
.numeraseregions = 3,
.regions = {
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
{ .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
{ .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
}
}, {
.mfr_id = MANUFACTURER_ATMEL,
.dev_id = AT49xV16x,
......
This diff is collapsed.
This diff is collapsed.
......@@ -58,10 +58,10 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
* to flash memory - that means that we don't have to check status
* and timeout.
*/
cfi_spin_lock(chip->mutex);
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) {
cfi_spin_unlock(chip->mutex);
spin_unlock(chip->mutex);
return ret;
}
......@@ -71,7 +71,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
/* Done and happy. */
chip->state = FL_READY;
put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
spin_unlock(chip->mutex);
return 0;
}
......
......@@ -2,7 +2,7 @@
* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
* $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
* $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
*/
#include <linux/kernel.h>
......@@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
if (!cfi_interleave_supported(nr_chips))
continue;
......
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
$Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
......@@ -142,6 +142,7 @@
#define SST29LE512 0x003d
#define SST39LF800 0x2781
#define SST39LF160 0x2782
#define SST39VF1601 0x234b
#define SST39LF512 0x00D4
#define SST39LF010 0x00D5
#define SST39LF020 0x00D6
......@@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256),
ERASEINFO(0x1000,256)
}
}, {
.mfr_id = MANUFACTURER_SST, /* should be CFI */
.dev_id = SST39VF1601,
.name = "SST 39VF1601",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
[1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
},
.DevSize = SIZE_2MiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 2,
.regions = {
ERASEINFO(0x1000,256),
ERASEINFO(0x1000,256)
}
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
......@@ -1856,6 +1872,16 @@ static inline int jedec_match( __u32 base,
case CFI_DEVICETYPE_X8:
mfr = (__u8)finfo->mfr_id;
id = (__u8)finfo->dev_id;
/* bjd: it seems that if we do this, we can end up
* detecting 16bit flashes as an 8bit device, even though
* there aren't.
*/
if (finfo->dev_id > 0xff) {
DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
__func__);
goto match_done;
}
break;
case CFI_DEVICETYPE_X16:
mfr = (__u16)finfo->mfr_id;
......
/*
* $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
* $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $
*
* Read flash partition table from command line
*
......@@ -239,7 +239,8 @@ static int mtdpart_setup_real(char *s)
&num_parts, /* out: number of parts */
0, /* first partition */
(unsigned char**)&this_mtd, /* out: extra mem */
mtd_id_len + 1 + sizeof(*this_mtd));
mtd_id_len + 1 + sizeof(*this_mtd) +
sizeof(void*)-1 /*alignment*/);
if(!parts)
{
/*
......@@ -252,6 +253,9 @@ static int mtdpart_setup_real(char *s)
return 0;
}
/* align this_mtd */
this_mtd = (struct cmdline_mtd_partition *)
ALIGN((unsigned long)this_mtd, sizeof(void*));
/* enter results */
this_mtd->parts = parts;
this_mtd->num_parts = num_parts;
......
/*
* $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $
* $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
*
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
* Copyright (C) 2004 Gareth Bult <Gareth@Encryptec.net>
* Copyright (C) 2004,2005 Jrn Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
......@@ -20,7 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/buffer_head.h>
#define VERSION "$Revision: 1.23 $"
#define VERSION "$Revision: 1.28 $"
#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
......@@ -89,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index)
static struct page* page_readahead(struct address_space *mapping, int index)
{
filler_t *filler = (filler_t*)mapping->a_ops->readpage;
//do_page_cache_readahead(mapping, index, XXX, 64);
cache_readahead(mapping, index);
return read_cache_page(mapping, index, filler, NULL);
}
......@@ -157,7 +155,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
struct block2mtd_dev *dev = mtd->priv;
struct page *page;
int index = from >> PAGE_SHIFT;
int offset = from & (PAGE_SHIFT-1);
int offset = from & (PAGE_SIZE-1);
int cpylen;
if (from > mtd->size)
......@@ -370,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
}
static int parse_num32(u32 *num32, const char *token)
static int parse_num(size_t *num, const char *token)
{
char *endp;
unsigned long n;
size_t n;
n = ustrtoul(token, &endp, 0);
n = (size_t) ustrtoul(token, &endp, 0);
if (*endp)
return -EINVAL;
*num32 = n;
*num = n;
return 0;
}
......@@ -422,7 +420,7 @@ 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 *token[2];
char *name;
u32 erase_size = PAGE_SIZE;
size_t erase_size = PAGE_SIZE;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
......@@ -449,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
return 0;
if (token[1]) {
ret = parse_num32(&erase_size, token[1]);
ret = parse_num(&erase_size, token[1]);
if (ret)
parse_err("illegal erase size");
}
......
......@@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $
* $Id: ms02-nv.c,v 1.10 2005/06/20 12:24:41 macro Exp $
*/
#include <linux/init.h>
......@@ -99,8 +99,8 @@ static inline uint ms02nv_probe_one(ulong addr)
* The firmware writes MS02NV_ID at MS02NV_MAGIC and also
* a diagnostic status at MS02NV_DIAG.
*/
ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG));
ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC));
ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG));
ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC));
err = get_dbe(ms02nv_magic, ms02nv_magicp);
if (err)
return 0;
......@@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr)
goto err_out_csr_res;
}
printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n",
mtd->index, ms02nv_name, addr, size >> 20);
mp->next = root_ms02nv_mtd;
......
/*
* mtdram - a test mtd device
* $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
* $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
* Author: Alexander Larsson <alex@cendio.se>
*
* Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
* Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
*
* This code is GPL
*
......@@ -18,213 +19,140 @@
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
#ifndef CONFIG_MTDRAM_ABS_POS
#define CONFIG_MTDRAM_ABS_POS 0
#endif
#if CONFIG_MTDRAM_ABS_POS > 0
#include <asm/io.h>
#endif
#ifdef MODULE
static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
module_param(total_size,ulong,0);
MODULE_PARM_DESC(total_size, "Total device size in KiB");
module_param(erase_size,ulong,0);
MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
#define MTDRAM_TOTAL_SIZE (total_size * 1024)
#define MTDRAM_ERASE_SIZE (erase_size * 1024)
#else
#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
#endif
#ifdef MODULE
module_param(total_size, ulong, 0);
MODULE_PARM_DESC(total_size, "Total device size in KiB");
module_param(erase_size, ulong, 0);
MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
#endif
// We could store these in the mtd structure, but we only support 1 device..
static struct mtd_info *mtd_info;
static int
ram_erase(struct mtd_info *mtd, struct erase_info *instr)
static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
if (instr->addr + instr->len > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
return -EINVAL;
}
memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return 0;
if (instr->addr + instr->len > mtd->size)
return -EINVAL;
memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return 0;
}
static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf)
{
if (from + len > mtd->size)
return -EINVAL;
*mtdbuf = mtd->priv + from;
*retlen = len;
return 0;
if (from + len > mtd->size)
return -EINVAL;
*mtdbuf = mtd->priv + from;
*retlen = len;
return 0;
}
static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
size_t len)
static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
size_t len)
{
DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
}
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
size_t *retlen, u_char *buf)
{
DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
if (from + len > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
return -EINVAL;
}
if (from + len > mtd->size)
return -EINVAL;
memcpy(buf, mtd->priv + from, len);
memcpy(buf, mtd->priv + from, len);
*retlen=len;
return 0;
*retlen = len;
return 0;
}
static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
size_t *retlen, const u_char *buf)
{
DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
if (to + len > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
return -EINVAL;
}
if (to + len > mtd->size)
return -EINVAL;
memcpy ((char *)mtd->priv + to, buf, len);
memcpy((char *)mtd->priv + to, buf, len);
*retlen=len;
return 0;
*retlen = len;
return 0;
}
static void __exit cleanup_mtdram(void)
{
if (mtd_info) {
del_mtd_device(mtd_info);
#if CONFIG_MTDRAM_TOTAL_SIZE > 0
if (mtd_info->priv)
#if CONFIG_MTDRAM_ABS_POS > 0
iounmap(mtd_info->priv);
#else
vfree(mtd_info->priv);
#endif
#endif
kfree(mtd_info);
}
}
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
unsigned long size, char *name)
{
memset(mtd, 0, sizeof(*mtd));
/* Setup the MTD structure */
mtd->name = name;
mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM;
mtd->size = size;
mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address;
mtd->owner = THIS_MODULE;
mtd->erase = ram_erase;
mtd->point = ram_point;
mtd->unpoint = ram_unpoint;
mtd->read = ram_read;
mtd->write = ram_write;
if (add_mtd_device(mtd)) {
return -EIO;
}
return 0;
}
#if CONFIG_MTDRAM_TOTAL_SIZE > 0
#if CONFIG_MTDRAM_ABS_POS > 0
static int __init init_mtdram(void)
{
void *addr;
int err;
/* Allocate some memory */
mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd_info)
return -ENOMEM;
addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
if (!addr) {
DEBUG(MTD_DEBUG_LEVEL1,
"Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n",
(long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
kfree(mtd_info);
mtd_info = NULL;
return -ENOMEM;
}
err = mtdram_init_device(mtd_info, addr,
MTDRAM_TOTAL_SIZE, "mtdram test device");
if (err)
{
iounmap(addr);
kfree(mtd_info);
mtd_info = NULL;
return err;
}
memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
return err;
if (mtd_info) {
del_mtd_device(mtd_info);
if (mtd_info->priv)
vfree(mtd_info->priv);
kfree(mtd_info);
}
}
#else /* CONFIG_MTDRAM_ABS_POS > 0 */
static int __init init_mtdram(void)
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
unsigned long size, char *name)
{
void *addr;
int err;
/* Allocate some memory */
mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd_info)
return -ENOMEM;
addr = vmalloc(MTDRAM_TOTAL_SIZE);
if (!addr) {
DEBUG(MTD_DEBUG_LEVEL1,
"Failed to vmalloc memory region of size %ld\n",
(long)MTDRAM_TOTAL_SIZE);
kfree(mtd_info);
mtd_info = NULL;
return -ENOMEM;
}
err = mtdram_init_device(mtd_info, addr,
MTDRAM_TOTAL_SIZE, "mtdram test device");
if (err)
{
vfree(addr);
kfree(mtd_info);
mtd_info = NULL;
return err;
}
memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
return err;
memset(mtd, 0, sizeof(*mtd));
/* Setup the MTD structure */
mtd->name = name;
mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM;
mtd->size = size;
mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address;
mtd->owner = THIS_MODULE;
mtd->erase = ram_erase;
mtd->point = ram_point;
mtd->unpoint = ram_unpoint;
mtd->read = ram_read;
mtd->write = ram_write;
if (add_mtd_device(mtd)) {
return -EIO;
}
return 0;
}
#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
static int __init init_mtdram(void)
{
return 0;
void *addr;
int err;
if (!total_size)
return -EINVAL;
/* Allocate some memory */
mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd_info)
return -ENOMEM;
addr = vmalloc(MTDRAM_TOTAL_SIZE);
if (!addr) {
kfree(mtd_info);
mtd_info = NULL;
return -ENOMEM;
}