Commit 506a6f1c authored by David Woodhouse's avatar David Woodhouse

Merge linux-mtd@bkbits.net:mtd-2.6

into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6
parents 1140b22f 67d4878e
......@@ -1090,6 +1090,10 @@ E: jbglaw@lug-owl.de
D: SRM environment driver (for Alpha systems)
P: 1024D/8399E1BB 250D 3BCF 7127 0D8C A444 A961 1DBD 5E75 8399 E1BB
N: Thomas Gleixner
E: tglx@linutronix.de
D: NAND flash hardware support, JFFS2 on NAND flash
N: Richard E. Gooch
E: rgooch@atnf.csiro.au
D: parent process death signal to children
......
# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $
# $Id: Kconfig,v 1.5 2004/06/04 15:59:32 gleixner Exp $
menu "Memory Technology Devices (MTD)"
......@@ -68,9 +68,23 @@ config MTD_REDBOOT_PARTS
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
config MTD_REDBOOT_PARTS_UNALLOCATED
bool " Include unallocated flash regions"
depends on MTD_REDBOOT_PARTS
help
If you need to register each unallocated flash region as a MTD
'partition', enable this option.
config MTD_REDBOOT_PARTS_READONLY
bool " Force read-only for RedBoot system images"
depends on MTD_REDBOOT_PARTS
help
If you need to force read-only for 'RedBoot', 'RedBoot Config' and
'FIS directory' images, enable this option.
config MTD_CMDLINE_PARTS
tristate "Command line partition table parsing"
depends on MTD_PARTITIONS
bool "Command line partition table parsing"
depends on MTD_PARTITIONS = "y"
---help---
Allow generic configuration of the MTD paritition tables via the kernel
command line. Multiple flash resources are supported for hardware where
......
#
# Makefile for the memory technology device drivers.
#
# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $
# *** BIG UGLY NOTE ***
#
# The shiny new inter_module_xxx has introduced yet another ugly link
# order dependency, which I'd previously taken great care to avoid.
# We now have to ensure that the chip drivers are initialised before the
# map drivers, and that the doc200[01] drivers are initialised before
# docprobe.
#
# We'll hopefully merge the doc200[01] drivers and docprobe back into
# a single driver some time soon, but the CFI drivers are going to have
# to stay like that.
#
# Urgh.
#
# dwmw2 21/11/0
# $Id: Makefile.common,v 1.3 2004/07/12 16:07:30 dwmw2 Exp $
# Core functionality.
obj-$(CONFIG_MTD) += mtdcore.o
......
......@@ -21,7 +21,7 @@
This is access code for flashes using ARM's flash partitioning
standards.
$Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $
$Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
======================================================================*/
......
# drivers/mtd/chips/Kconfig
# $Id: Kconfig,v 1.3 2003/05/28 15:13:24 dwmw2 Exp $
# $Id: Kconfig,v 1.8 2004/07/13 22:32:02 dwmw2 Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
......@@ -85,59 +85,72 @@ config MTD_CFI_GEOMETRY
arrangements of CFI chips. If unsure, say 'N' and all options
which are supported by the current code will be enabled.
config MTD_CFI_B1
bool "Support 8-bit buswidth"
depends on MTD_CFI_GEOMETRY
config MTD_MAP_BANK_WIDTH_1
bool "Support 8-bit buswidth" if MTD_CFI_GEOMETRY
default y
help
If you wish to support CFI devices on a physical bus which is
8 bits wide, say 'Y'.
config MTD_CFI_B2
bool "Support 16-bit buswidth"
depends on MTD_CFI_GEOMETRY
config MTD_MAP_BANK_WIDTH_2
bool "Support 16-bit buswidth" if MTD_CFI_GEOMETRY
default y
help
If you wish to support CFI devices on a physical bus which is
16 bits wide, say 'Y'.
config MTD_CFI_B4
bool "Support 32-bit buswidth"
depends on MTD_CFI_GEOMETRY
config MTD_MAP_BANK_WIDTH_4
bool "Support 32-bit buswidth" if MTD_CFI_GEOMETRY
default y
help
If you wish to support CFI devices on a physical bus which is
32 bits wide, say 'Y'.
config MTD_CFI_B8
bool "Support 64-bit buswidth"
depends on MTD_CFI_GEOMETRY
config MTD_MAP_BANK_WIDTH_8
bool "Support 64-bit buswidth" if MTD_CFI_GEOMETRY
default n
help
If you wish to support CFI devices on a physical bus which is
64 bits wide, say 'Y'.
config MTD_MAP_BANK_WIDTH_16
bool "Support 128-bit buswidth" if MTD_CFI_GEOMETRY
default n
help
If you wish to support CFI devices on a physical bus which is
128 bits wide, say 'Y'.
config MTD_MAP_BANK_WIDTH_32
bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
default n
help
If you wish to support CFI devices on a physical bus which is
256 bits wide, say 'Y'.
config MTD_CFI_I1
bool "Support 1-chip flash interleave" if !MTD_CFI_B1
depends on MTD_CFI_GEOMETRY
default y if MTD_CFI_B1
bool "Support 1-chip flash interleave" if MTD_CFI_GEOMETRY
default y
help
If your flash chips are not interleaved - i.e. you only have one
flash chip addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I2
bool "Support 2-chip flash interleave"
depends on MTD_CFI_GEOMETRY
bool "Support 2-chip flash interleave" if MTD_CFI_GEOMETRY
default y
help
If your flash chips are interleaved in pairs - i.e. you have two
flash chips addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I4
bool "Support 4-chip flash interleave"
depends on MTD_CFI_GEOMETRY
bool "Support 4-chip flash interleave" if MTD_CFI_GEOMETRY
default n
help
If your flash chips are interleaved in fours - i.e. you have four
flash chips addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I8
bool "Support 8-chip flash interleave"
depends on MTD_CFI_GEOMETRY
bool "Support 8-chip flash interleave" if MTD_CFI_GEOMETRY
default n
help
If your flash chips are interleaved in eights - i.e. you have eight
flash chips addressed by each bus cycle, then say 'Y'.
......@@ -160,6 +173,27 @@ config MTD_CFI_AMDSTD
provides support for one of those command sets, used on chips
including the AMD Am29LV320.
config MTD_CFI_AMDSTD_RETRY
int "Retry failed commands (erase/program)"
depends on MTD_CFI_AMDSTD
default "0"
help
Some chips, when attached to a shared bus, don't properly filter
bus traffic that is destined to other devices. This broken
behavior causes erase and program sequences to be aborted when
the sequences are mixed with traffic for other devices.
SST49LF040 (and related) chips are know to be broken.
config MTD_CFI_AMDSTD_RETRY_MAX
int "Max retries of failed commands (erase/program)"
depends on MTD_CFI_AMDSTD_RETRY
default "0"
help
If you have an SST49LF040 (or related chip) then this value should
be set to at least 1. This can also be adjusted at driver load
time with the retry_cmd_max module parameter.
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
......@@ -168,6 +202,11 @@ config MTD_CFI_STAA
sets which a CFI-compliant chip may claim to implement. This code
provides support for one of those command sets.
config MTD_CFI_UTIL
tristate
default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
config MTD_RAM
tristate "Support for RAM chips in bus mapping"
depends on MTD
......
#
# linux/drivers/chips/Makefile
#
# $Id: Makefile.common,v 1.1 2003/05/21 15:00:01 dwmw2 Exp $
# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 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 cfi_probe.o
# 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
obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o
obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
......
......@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $
* $Id: amd_flash.c,v 1.24 2004/07/12 13:34:30 dwmw2 Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id: cfi_probe.c,v 1.71 2003/05/28 12:51:48 dwmw2 Exp $
$Id: cfi_probe.c,v 1.77 2004/07/14 08:38:44 dwmw2 Exp $
*/
#include <linux/config.h>
......@@ -26,7 +26,7 @@ static void print_cfi_ident(struct cfi_ident *);
#endif
static int cfi_probe_chip(struct map_info *map, __u32 base,
struct flchip *chips, struct cfi_private *cfi);
unsigned long *chip_map, struct cfi_private *cfi);
static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
struct mtd_info *cfi_probe(struct map_info *map);
......@@ -35,21 +35,36 @@ struct mtd_info *cfi_probe(struct map_info *map);
in: interleave,type,mode
ret: table index, <0 for error
*/
static inline int qry_present(struct map_info *map, __u32 base,
static int qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
int osf = cfi->interleave * cfi->device_type; // scale factor
map_word val;
map_word qry;
if (cfi_read(map,base+osf*0x10)==cfi_build_cmd('Q',map,cfi) &&
cfi_read(map,base+osf*0x11)==cfi_build_cmd('R',map,cfi) &&
cfi_read(map,base+osf*0x12)==cfi_build_cmd('Y',map,cfi))
return 1; // ok !
qry = cfi_build_cmd('Q', map, cfi);
val = map_read(map, base + osf*0x10);
return 0; // nothing found
if (!map_word_equal(map, qry, val))
return 0;
qry = cfi_build_cmd('R', map, cfi);
val = map_read(map, base + osf*0x11);
if (!map_word_equal(map, qry, val))
return 0;
qry = cfi_build_cmd('Y', map, cfi);
val = map_read(map, base + osf*0x12);
if (!map_word_equal(map, qry, val))
return 0;
return 1; // nothing found
}
static int cfi_probe_chip(struct map_info *map, __u32 base,
struct flchip *chips, struct cfi_private *cfi)
unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
......@@ -66,6 +81,7 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
return 0;
}
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
if (!qry_present(map,base,cfi))
......@@ -78,18 +94,25 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
}
/* Check each previous chip to see if it's an alias */
for (i=0; i<cfi->numchips; i++) {
for (i=0; i < (base >> cfi->chipshift); i++) {
unsigned long start;
if(!test_bit(i, chip_map)) {
/* Skip location; no valid chip at this address */
continue;
}
start = i << cfi->chipshift;
/* This chip should be in read mode if it's one
we've already touched. */
if (qry_present(map,chips[i].start,cfi)) {
if (qry_present(map, start, cfi)) {
/* Eep. This chip also had the QRY marker.
* Is it an alias for the new one? */
cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
/* If the QRY marker goes away, it's an alias */
if (!qry_present(map, chips[i].start, cfi)) {
if (!qry_present(map, start, cfi)) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, chips[i].start);
map->name, base, start);
return 0;
}
/* Yes, it's actually got QRY for data. Most
......@@ -97,10 +120,11 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
* too and if it's the same, assume it's an alias. */
/* FIXME: Use other modes to do a proper check */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
if (qry_present(map, base, cfi)) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, chips[i].start);
map->name, base, start);
return 0;
}
}
......@@ -108,21 +132,16 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
/* OK, if we got to here, then none of the previous chips appear to
be aliases for the current one. */
if (cfi->numchips == MAX_CFI_CHIPS) {
printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
/* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
return -1;
}
chips[cfi->numchips].start = base;
chips[cfi->numchips].state = FL_READY;
set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
cfi->numchips++;
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
map->buswidth*8);
map->bankwidth*8);
return 1;
}
......@@ -150,7 +169,6 @@ static int cfi_chip_setup(struct map_info *map,
memset(cfi->cfiq,0,sizeof(struct cfi_ident));
cfi->cfi_mode = CFI_MODE_CFI;
cfi->fast_prog=1; /* CFI supports fast programming */
/* Read the CFI info structure */
for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
......@@ -180,8 +198,29 @@ static int cfi_chip_setup(struct map_info *map,
(cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
#endif
}
/* Note we put the device back into Read Mode BEFORE going into Auto
* Select Mode, as some devices support nesting of modes, others
* don't. This way should always work.
* On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
* so should be treated as nops or illegal (and so put the device
* back into Read Mode, which is a nop in this case).
*/
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi->mfr = cfi_read_query(map, base);
cfi->id = cfi_read_query(map, base + ofs_factor);
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
/* ... even if it's an Intel chip */
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
map->bankwidth*8);
return 1;
}
......@@ -241,11 +280,11 @@ static void print_cfi_ident(struct cfi_ident *cfip)
printk("No Alternate Algorithm Table\n");
printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
if (cfip->VppMin) {
printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
}
else
printk("No Vpp line\n");
......
/*
* Common Flash Interface support:
* Generic utility functions not dependant on command set
*
* Copyright (C) 2002 Red Hat
* Copyright (C) 2003 STMicroelectronics Limited
*
* This code is covered by the GPL.
*
* $Id: cfi_util.c,v 1.4 2004/07/14 08:38:44 dwmw2 Exp $
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/compatmac.h>
struct cfi_extquery *
cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
{
struct cfi_private *cfi = map->fldrv_priv;
__u32 base = 0; // cfi->chips[0].start;
int ofs_factor = cfi->interleave * cfi->device_type;
int i;
struct cfi_extquery *extp = NULL;
printk(" %s Extended Query Table at 0x%4.4X\n", name, adr);
if (!adr)
goto out;
/* Switch it into Query Mode */
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
extp = kmalloc(size, GFP_KERNEL);
if (!extp) {
printk(KERN_ERR "Failed to allocate memory\n");
goto out;
}
/* Read in the Extended Query Table */
for (i=0; i<size; i++) {
((unsigned char *)extp)[i] =
cfi_read_query(map, base+((adr+i)*ofs_factor));
}
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
printk(KERN_WARNING " Unknown %s Extended Query "
"version %c.%c.\n", name, extp->MajorVersion,
extp->MinorVersion);
kfree(extp);
extp = NULL;
goto out;
}
out:
/* Make sure it's in read mode */
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
return extp;
}
EXPORT_SYMBOL(cfi_read_pri);
void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups)
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_fixup *f;
for (f=fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
f->fixup(map, f->param);
}
}
}
EXPORT_SYMBOL(cfi_fixup);
MODULE_LICENSE("GPL");
/*
* $Id: chipreg.c,v 1.15 2003/05/21 15:15:05 dwmw2 Exp $
* $Id: chipreg.c,v 1.16 2003/05/29 09:36:15 dwmw2 Exp $
*
* Registration for chip drivers
*
......
......@@ -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.13 2003/06/25 11:50:37 dwmw2 Exp $
* $Id: gen_probe.c,v 1.19 2004/07/13 22:33:32 dwmw2 Exp $
*/
#include <linux/kernel.h>
......@@ -50,16 +50,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
EXPORT_SYMBOL(mtd_do_chip_probe);
struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
{
unsigned long base=0;
struct cfi_private cfi;
struct cfi_private *retcfi;
struct flchip chip[MAX_CFI_CHIPS];
int i;
unsigned long *chip_map;
int i, j, mapsize;
int max_chips;
memset(&cfi, 0, sizeof(cfi));
memset(&chip[0], 0, sizeof(chip));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
......@@ -80,46 +79,47 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
return NULL;
}
#endif
chip[0].start = 0;
chip[0].state = FL_READY;
cfi.chipshift = cfi.cfiq->DevSize;
switch(cfi.interleave) {
#ifdef CFIDEV_INTERLEAVE_1
case 1:
break;
#endif
#ifdef CFIDEV_INTERLEAVE_2
case 2:
if (cfi_interleave_is_1(&cfi)) {
;
} else if (cfi_interleave_is_2(&cfi)) {
cfi.chipshift++;
break;
#endif
#ifdef CFIDEV_INTERLEAVE_4
case 4:
cfi.chipshift+=2;
break;
#endif
default:
} else if (cfi_interleave_is_4((&cfi))) {
cfi.chipshift += 2;
} else if (cfi_interleave_is_8(&cfi)) {
cfi.chipshift += 3;
} else {
BUG();
}
cfi.numchips = 1;
/*
* Allocate memory for bitmap of valid chips.
* Align bitmap storage size to full byte.
*/
max_chips = map->size >> cfi.chipshift;
mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
chip_map = kmalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
kfree(cfi.cfiq);
return NULL;
}
memset (chip_map, 0, mapsize);
set_bit(0, chip_map); /* Mark first chip valid */
/*
* Now probe for other chips, checking sensibly for aliases while
* we're at it. The new_chip probe above should have let the first
* chip in read mode.
*
* NOTE: Here, we're checking if there is room for another chip
* the same size within the mapping. Therefore,
* base + chipsize <= map->size is the correct thing to do,
* because, base + chipsize would be the _first_ byte of the
* next chip, not the one we're currently pondering.
*/
for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
base += (1<<cfi.chipshift))
cp->probe_chip(map, base, &chip[0], &cfi);
for (i = 1; i < max_chips; i++) {
cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
}
/*
* Now allocate the space for the structures we need to return to
......@@ -131,19 +131,26 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
if (!retcfi) {
printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
kfree(cfi.cfiq);
kfree(chip_map);
return NULL;
}
memcpy(retcfi, &cfi, sizeof(cfi));
memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
/* Fix up the stuff that breaks when you move it */
for (i=0; i< retcfi->numchips; i++) {
init_waitqueue_head(&retcfi->chips[i].wq);
spin_lock_init(&retcfi->chips[i]._spinlock);
retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
if(test_bit(i, chip_map)) {
struct flchip *pchip = &retcfi->chips[j++];
pchip->start = (i << cfi.chipshift);
pchip->state = FL_READY;
init_waitqueue_head(&pchip->wq);
spin_lock_init(&pchip->_spinlock);
pchip->mutex = &pchip->_spinlock;
}
}
kfree(chip_map);
return retcfi;
}
......@@ -151,131 +158,27 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi)
{
switch (map->buswidth) {
#ifdef CFIDEV_BUSWIDTH_1
case CFIDEV_BUSWIDTH_1:
cfi->interleave = CFIDEV_INTERLEAVE_1;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
break;
#endif /* CFIDEV_BUSWITDH_1 */
#ifdef CFIDEV_BUSWIDTH_2
case CFIDEV_BUSWIDTH_2:
#ifdef CFIDEV_INTERLEAVE_1
cfi->interleave = CFIDEV_INTERLEAVE_1;
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_1 */
#ifdef CFIDEV_INTERLEAVE_2
cfi->interleave = CFIDEV_INTERLEAVE_2;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_2 */
break;
#endif /* CFIDEV_BUSWIDTH_2 */
#ifdef CFIDEV_BUSWIDTH_4
case CFIDEV_BUSWIDTH_4:
#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
cfi->interleave = CFIDEV_INTERLEAVE_1;
cfi->device_type = CFI_DEVICETYPE_X32;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_1 */
#ifdef CFIDEV_INTERLEAVE_2
cfi->interleave = CFIDEV_INTERLEAVE_2;
#ifdef SOMEONE_ACTUALLY_MAKES_THESE
cfi->device_type = CFI_DEVICETYPE_X32;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_2 */
#ifdef CFIDEV_INTERLEAVE_4
cfi->interleave = CFIDEV_INTERLEAVE_4;
#ifdef SOMEONE_ACTUALLY_MAKES_THESE
cfi->device_type = CFI_DEVICETYPE_X32;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_4 */
break;
#endif /* CFIDEV_BUSWIDTH_4 */
#ifdef CFIDEV_BUSWIDTH_8
case CFIDEV_BUSWIDTH_8:
#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
cfi->interleave = CFIDEV_INTERLEAVE_2;
cfi->device_type = CFI_DEVICETYPE_X32;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_2 */
#ifdef CFIDEV_INTERLEAVE_4
cfi->interleave = CFIDEV_INTERLEAVE_4;
#ifdef SOMEONE_ACTUALLY_MAKES_THESE
cfi->device_type = CFI_DEVICETYPE_X32;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_4 */
#ifdef CFIDEV_INTERLEAVE_8
cfi->interleave = CFIDEV_INTERLEAVE_8;
cfi->device_type = CFI_DEVICETYPE_X16;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
#endif /* CFIDEV_INTERLEAVE_8 */
break;
#endif /* CFIDEV_BUSWIDTH_8 */
default:
printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
return 0;
int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
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) {
if (!cfi_interleave_supported(nr_chips))
continue;
cfi->interleave = nr_chips;
for (type = 0; type < 3; type++) {
cfi->device_type = 1<<type;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
}
}
return 0;
}
typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
extern cfi_cmdset_fn_t cfi_cmdset_0001;
......
......@@ -11,7 +11,7 @@
* not going to guess how to send commands to them, plus I expect they will
* all speak CFI..
*
* $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $
* $Id: jedec.c,v 1.20 2004/07/12 14:03:01 dwmw2 Exp $
*/
#include <linux/init.h>
......
This diff is collapsed.
/*
* Common code to handle map devices which are simple RAM
* (C) 2000 Red Hat. GPL'd.
* $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $
* $Id: map_ram.c,v 1.19 2004/07/12 21:58:44 dwmw2 Exp $
*/
#include <linux/module.h>
......@@ -104,10 +104,15 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
/* Yeah, it's inefficient. Who cares? It's faster than a _real_
flash erase. */
struct map_info *map = (struct map_info *)mtd->priv;
map_word allff;
unsigned long i;
for (i=0; i<instr->len; i++)
map_write8(map, 0xFF, instr->addr + i);
allff = map_word_ff(map);
for (i=0; i<instr->len; i += map_bankwidth(map))
map_write(map, allff, instr->addr + i);
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
......
/*
* Common code to handle map devices which are simple ROM
* (C) 2000 Red Hat. GPL'd.
* $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $
* $Id: map_rom.c,v 1.21 2004/07/12 14:06:01 dwmw2 Exp $
*/
#include <linux/module.h>
......
......@@ -4,7 +4,7 @@
* Copyright 2000,2001 David A. Schleef <ds@schleef.org>
* 2000,2001 Lineo, Inc.
*
* $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $
* $Id: sharp.c,v 1.13 2004/07/12 14:06:34 dwmw2 Exp $
*
* Devices supported:
* LH28F016SCT Symmetrical block flash memory, 2Mx8
......
/*
* $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $
* $Id: cmdlinepart.c,v 1.14 2004/07/12 12:34:23 dwmw2 Exp $
*
* Read flash partition table from command line
*
......@@ -10,7 +10,7 @@
* mtdparts=<mtddef>[;<mtddef]
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
* <partdef> := <size>[@offset][<name>][ro]
* <mtd-id> := unique id used in mapping driver/device
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
* <size> := standard linux memsize OR "-" to denote all remaining space
* <name> := '(' NAME ')'
*
......@@ -358,14 +358,7 @@ static int __init cmdline_parser_init(void)
return register_mtd_parser(&cmdline_parser);
}
static void __exit cmdline_parser_exit(void)
{
deregister_mtd_parser(&cmdline_parser);
}
module_init(cmdline_parser_init);
module_exit(cmdline_parser_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
......
# drivers/mtd/maps/Kconfig
# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $
# $Id: Kconfig,v 1.10 2004/07/15 00:34:49 dwmw2 Exp $
menu "Self-contained MTD device drivers"
depends on MTD!=n
......@@ -9,9 +9,9 @@ config MTD_PMC551
depends on MTD && PCI
---help---
This provides a MTD device driver for the Ramix PMC551 RAM PCI card
from Ramix Inc. <http://www.ramix.com/products/>. These devices come
in memory configurations from 32M - 1G. If you have one, you
probably want to enable this.
from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
These devices come in memory configurations from 32M - 1G. If you
have one, you probably want to enable this.
If this driver is compiled as a module you get the ability to select
the size of the aperture window pointing into the devices memory.
......@@ -40,9 +40,12 @@ config MTD_PMC551_DEBUG
config MTD_MS02NV
tristate "DEC MS02-NV NVRAM module support"
depends on CONFIG_MACH_DECSTATION
depends on MTD && MACH_DECSTATION
help
Support for NVRAM module on DECstation.
This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
backed-up NVRAM module. The module was originally meant as an NFS
accelerator. Say Y here if you have a DECstation 5000/2x0 or a
DECsystem 5900 equipped with such a module.
config MTD_SLRAM
tristate "Uncached system RAM"
......@@ -52,6 +55,16 @@ config MTD_SLRAM
you can still use it for storage or swap by using this driver to
present it to the system as a Memory Technology Device.
config MTD_PHRAM
tristate "Physical system RAM"
depends on MTD
help
This is a re-implementation of the slram driver above.
Use this driver to access physical memory that the kernel proper
doesn't have access to, memory beyond the mem=xxx limit, nvram,
memory on the video card, etc...
config MTD_LART
tristate "28F160xx flash driver for LART"
depends on SA1100_LART && MTD
......@@ -161,11 +174,18 @@ config MTD_DOC2001PLUS
config MTD_DOCPROBE
tristate
default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m)
default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
help
This isn't a real config option, it's derived.
config MTD_DOCECC
tristate
default m if MTD_DOCPROBE!=y && MTD_NAND_DISKONCHIP!=y && (MTD_DOCPROBE=m || MTD_NAND_DISKONCHIP=m)
default y if MTD_DOCPROBE=y || MTD_NAND_DISKONCHIP=y
help
This isn't a real config option, it's derived.
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_DOCPROBE
......
#
# linux/drivers/devices/Makefile
#
# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $
# $Id: Makefile.common,v 1.6 2004/07/12 16:07:30 dwmw2 Exp $
# *** BIG UGLY NOTE ***
#
......@@ -13,8 +13,10 @@
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o
obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o
obj-$(CONFIG_MTD_DOCECC) += docecc.o
obj-$(CONFIG_MTD_SLRAM) += slram.o
obj-$(CONFIG_MTD_PHRAM) += phram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
......
/*
* $Id: blkmtd-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
* $Id: blkmtd-25.c,v 1.6 2004/07/15 15:09:15 dwmw2 Exp $
*
* blkmtd.c - use a block device as a fake MTD
*
......@@ -39,7 +39,7 @@
/* Default erase size in K, always make it a multiple of PAGE_SIZE */
#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
#define VERSION "$Revision: 1.5 $"
#define VERSION "$Revision: 1.6 $"
/* Info for the block device */
struct blkmtd_dev {
......
This diff is collapsed.
......@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
* $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $
* $Id: doc2001.c,v 1.42 2004/04/04 12:36:45 gleixner Exp $
*/
#include <linux/kernel.h>
......@@ -19,6 +19,7 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
......@@ -37,12 +38,9 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
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 *unused);
size_t *retlen, u_char *buf, u_char *eccbuf, int 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 *unused);
size_t *retlen, const u_char *buf, u_char *eccbuf, int 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,
......@@ -229,7 +227,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
doc->mfr = mfr;
doc->id = id;
doc->chipshift = nand_flash_ids[i].chipshift;
doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
break;
}
}
......@@ -406,12 +404,11 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
/* Just a special case of doc_read_ecc */
return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
}
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 *unused)
size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
{
int i, ret;
volatile char dummy;
......@@ -533,12 +530,11 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
char eccbuf[6];
return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
}
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 *unused)
size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
{
int i,ret = 0;
volatile char dummy;
......
This diff is collapsed.
This diff is collapsed.
......@@ -2,7 +2,7 @@
/*
* MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
*
* $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
* $Id: lart.c,v 1.6 2004/07/14 17:21:38 dwmw2 Exp $
*
* Author: Abraham vd Merwe <abraham@2d3d.co.za>
*
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
* $Id: pmc551.c,v 1.26 2004/07/14 17:25:07 dwmw2 Exp $
*
* PMC551 PCI Mezzanine Ram Device
*
......
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
* $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
* $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $
*
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
......@@ -1093,7 +1093,7 @@ struct mtd_blktrans_ops ftl_tr = {
int init_ftl(void)
{
DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
DEBUG(0, "$Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n");
return register_mtd_blktrans(&ftl_tr);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* $Id: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $
* $Id: arctic-mtd.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $
*
* drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
* IBM 405LP Arctic boards.
......@@ -72,7 +72,7 @@
static struct map_info arctic_mtd_map = {
.name = NAME,
.size = SIZE,
.buswidth = BUSWIDTH,
.bankwidth = BUSWIDTH,
.phys = PADDR,
};
......
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.
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.
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.
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