Commit a48178a2 authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.infradead.org/mtd-2.6:
  Remove accidentally-added include/linux/utsrelease.h
  Revert "[MTD] blkdev helper code: fix printk format warning"
  [MTD] Add SSFDC (SmartMedia) read-only translation layer
  [MTD] pmc551 pci cleanup
  [MTD] pmc551 use kzalloc
  [MTD] pmc551 whitespace cleanup
  [MTD] Remove iq80310 map driver
  [MTD NAND] Fix in typo ndfc.c causing wrong ECC layout
  [MTD] physmap: add power management support
  ioremap balanced with iounmap for drivers/mtd subsystem
  [MTD] Switch to pci_get_device and do ref counting
  [MTD] blkdev helper code: fix printk format warning
  [MTD] Fix ixp4xx partition parsing.
  [JFFS2] Remove unneeded ifdefs from jffs2_fs_i.h
  [MTD NAND] Remove old code in au1550nd.c
  [MTD] Unlock NOR flash automatically where necessary
parents 14d1adfc 734a5628
......@@ -263,6 +263,14 @@ config RFD_FTL
http://www.gensw.com/pages/prod/bios/rfd.htm
config SSFDC
bool "NAND SSFDC (SmartMedia) read only translation layer"
depends on MTD
default n
help
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
......
......@@ -212,6 +212,7 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
{
mtd->lock = cfi_atmel_lock;
mtd->unlock = cfi_atmel_unlock;
mtd->flags |= MTD_STUPID_LOCK;
}
static struct cfi_fixup cfi_fixup_table[] = {
......
......@@ -4,82 +4,82 @@
* PMC551 PCI Mezzanine Ram Device
*
* Author:
* Mark Ferrell <mferrell@mvista.com>
* Copyright 1999,2000 Nortel Networks
* Mark Ferrell <mferrell@mvista.com>
* Copyright 1999,2000 Nortel Networks
*
* License:
* As part of this driver was derived from the slram.c driver it
* falls under the same license, which is GNU General Public
* License v2
* As part of this driver was derived from the slram.c driver it
* falls under the same license, which is GNU General Public
* License v2
*
* Description:
* This driver is intended to support the PMC551 PCI Ram device
* from Ramix Inc. The PMC551 is a PMC Mezzanine module for
* cPCI embedded systems. The device contains a single SROM
* that initially programs the V370PDC chipset onboard the
* device, and various banks of DRAM/SDRAM onboard. This driver
* implements this PCI Ram device as an MTD (Memory Technology
* Device) so that it can be used to hold a file system, or for
* added swap space in embedded systems. Since the memory on
* this board isn't as fast as main memory we do not try to hook
* it into main memory as that would simply reduce performance
* on the system. Using it as a block device allows us to use
* it as high speed swap or for a high speed disk device of some
* sort. Which becomes very useful on diskless systems in the
* embedded market I might add.
* This driver is intended to support the PMC551 PCI Ram device
* from Ramix Inc. The PMC551 is a PMC Mezzanine module for
* cPCI embedded systems. The device contains a single SROM
* that initially programs the V370PDC chipset onboard the
* device, and various banks of DRAM/SDRAM onboard. This driver
* implements this PCI Ram device as an MTD (Memory Technology
* Device) so that it can be used to hold a file system, or for
* added swap space in embedded systems. Since the memory on
* this board isn't as fast as main memory we do not try to hook
* it into main memory as that would simply reduce performance
* on the system. Using it as a block device allows us to use
* it as high speed swap or for a high speed disk device of some
* sort. Which becomes very useful on diskless systems in the
* embedded market I might add.
*
* Notes:
* Due to what I assume is more buggy SROM, the 64M PMC551 I
* have available claims that all 4 of it's DRAM banks have 64M
* of ram configured (making a grand total of 256M onboard).
* This is slightly annoying since the BAR0 size reflects the
* aperture size, not the dram size, and the V370PDC supplies no
* other method for memory size discovery. This problem is
* mostly only relevant when compiled as a module, as the
* unloading of the module with an aperture size smaller then
* the ram will cause the driver to detect the onboard memory
* size to be equal to the aperture size when the module is
* reloaded. Soooo, to help, the module supports an msize
* option to allow the specification of the onboard memory, and
* an asize option, to allow the specification of the aperture
* size. The aperture must be equal to or less then the memory
* size, the driver will correct this if you screw it up. This
* problem is not relevant for compiled in drivers as compiled
* in drivers only init once.
* Due to what I assume is more buggy SROM, the 64M PMC551 I
* have available claims that all 4 of it's DRAM banks have 64M
* of ram configured (making a grand total of 256M onboard).
* This is slightly annoying since the BAR0 size reflects the
* aperture size, not the dram size, and the V370PDC supplies no
* other method for memory size discovery. This problem is
* mostly only relevant when compiled as a module, as the
* unloading of the module with an aperture size smaller then
* the ram will cause the driver to detect the onboard memory
* size to be equal to the aperture size when the module is
* reloaded. Soooo, to help, the module supports an msize
* option to allow the specification of the onboard memory, and
* an asize option, to allow the specification of the aperture
* size. The aperture must be equal to or less then the memory
* size, the driver will correct this if you screw it up. This
* problem is not relevant for compiled in drivers as compiled
* in drivers only init once.
*
* Credits:
* Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
* initial example code of how to initialize this device and for
* help with questions I had concerning operation of the device.
* Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
* initial example code of how to initialize this device and for
* help with questions I had concerning operation of the device.
*
* Most of the MTD code for this driver was originally written
* for the slram.o module in the MTD drivers package which
* allows the mapping of system memory into an MTD device.
* Since the PMC551 memory module is accessed in the same
* fashion as system memory, the slram.c code became a very nice
* fit to the needs of this driver. All we added was PCI
* detection/initialization to the driver and automatically figure
* out the size via the PCI detection.o, later changes by Corey
* Minyard set up the card to utilize a 1M sliding apature.
* Most of the MTD code for this driver was originally written
* for the slram.o module in the MTD drivers package which
* allows the mapping of system memory into an MTD device.
* Since the PMC551 memory module is accessed in the same
* fashion as system memory, the slram.c code became a very nice
* fit to the needs of this driver. All we added was PCI
* detection/initialization to the driver and automatically figure
* out the size via the PCI detection.o, later changes by Corey
* Minyard set up the card to utilize a 1M sliding apature.
*
* Corey Minyard <minyard@nortelnetworks.com>
* * Modified driver to utilize a sliding aperture instead of
* mapping all memory into kernel space which turned out to
* be very wasteful.
* * Located a bug in the SROM's initialization sequence that
* made the memory unusable, added a fix to code to touch up
* the DRAM some.
* Corey Minyard <minyard@nortelnetworks.com>
* * Modified driver to utilize a sliding aperture instead of
* mapping all memory into kernel space which turned out to
* be very wasteful.
* * Located a bug in the SROM's initialization sequence that
* made the memory unusable, added a fix to code to touch up
* the DRAM some.
*
* Bugs/FIXME's:
* * MUST fix the init function to not spin on a register
* waiting for it to set .. this does not safely handle busted
* devices that never reset the register correctly which will
* cause the system to hang w/ a reboot being the only chance at
* recover. [sort of fixed, could be better]
* * Add I2C handling of the SROM so we can read the SROM's information
* about the aperture size. This should always accurately reflect the
* onboard memory size.
* * Comb the init routine. It's still a bit cludgy on a few things.
* * MUST fix the init function to not spin on a register
* waiting for it to set .. this does not safely handle busted
* devices that never reset the register correctly which will
* cause the system to hang w/ a reboot being the only chance at
* recover. [sort of fixed, could be better]
* * Add I2C handling of the SROM so we can read the SROM's information
* about the aperture size. This should always accurately reflect the
* onboard memory size.
* * Comb the init routine. It's still a bit cludgy on a few things.
*/
#include <linux/kernel.h>
......@@ -105,74 +105,77 @@
static struct mtd_info *pmc551list;
static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
size_t retlen;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr,
(long)instr->len);
#endif
end = instr->addr + instr->len - 1;
end = instr->addr + instr->len - 1;
/* Is it past the end? */
if ( end > mtd->size ) {
/* Is it past the end? */
if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n", (long)end, (long)mtd->size);
printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n",
(long)end, (long)mtd->size);
#endif
return -EINVAL;
}
eoff_hi = end & ~(priv->asize - 1);
soff_hi = instr->addr & ~(priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
pmc551_point (mtd, instr->addr, instr->len, &retlen, &ptr);
if ( soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot
will do it. */
memset(ptr, 0xff, instr->len);
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
return -EINVAL;
}
eoff_hi = end & ~(priv->asize - 1);
soff_hi = instr->addr & ~(priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot
will do it. */
memset(ptr, 0xff, instr->len);
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk( KERN_DEBUG "pmc551_erase() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
printk(KERN_DEBUG "pmc551_erase() soff_hi: %ld, "
"eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
memset(ptr, 0xff, priv->asize);
if (soff_hi + priv->asize >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point (mtd,(priv->base_map0|soff_hi),
priv->asize, &retlen, &ptr);
}
memset (ptr, 0xff, eoff_lo);
}
out:
memset(ptr, 0xff, priv->asize);
if (soff_hi + priv->asize >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi),
priv->asize, &retlen, &ptr);
}
memset(ptr, 0xff, eoff_lo);
}
out:
instr->state = MTD_ERASE_DONE;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_erase() done\n");
#endif
mtd_erase_callback(instr);
return 0;
mtd_erase_callback(instr);
return 0;
}
static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char ** mtdbuf)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi;
u32 soff_lo;
struct mypriv *priv = mtd->priv;
u32 soff_hi;
u32 soff_lo;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
......@@ -180,18 +183,19 @@ static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *
if (from + len > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n", (long)from+len, (long)mtd->size);
printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n",
(long)from + len, (long)mtd->size);
#endif
return -EINVAL;
}
soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
/* Cheap hack optimization */
if( priv->curr_map0 != from ) {
pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
(priv->base_map0 | soff_hi) );
if (priv->curr_map0 != from) {
pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
(priv->base_map0 | soff_hi));
priv->curr_map0 = soff_hi;
}
......@@ -200,137 +204,144 @@ static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *
return 0;
}
static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
size_t len)
{
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n");
#endif
}
static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
u_char *copyto = buf;
u_char *copyto = buf;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n", (long)from, (long)len, (long)priv->asize);
printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n",
(long)from, (long)len, (long)priv->asize);
#endif
end = from + len - 1;
end = from + len - 1;
/* Is it past the end? */
if (end > mtd->size) {
/* Is it past the end? */
if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n", (long) end, (long)mtd->size);
printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n",
(long)end, (long)mtd->size);
#endif
return -EINVAL;
}
soff_hi = from & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point (mtd, from, len, retlen, &ptr);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
will do it. */
memcpy(copyto, ptr, len);
copyto += len;
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
return -EINVAL;
}
soff_hi = from & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, from, len, retlen, &ptr);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
will do it. */
memcpy(copyto, ptr, len);
copyto += len;
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk( KERN_DEBUG "pmc551_read() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
printk(KERN_DEBUG "pmc551_read() soff_hi: %ld, "
"eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
memcpy(copyto, ptr, priv->asize);
copyto += priv->asize;
if (soff_hi + priv->asize >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
}
memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo;
}
out:
memcpy(copyto, ptr, priv->asize);
copyto += priv->asize;
if (soff_hi + priv->asize >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
}
memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo;
}
out:
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_read() done\n");
#endif
*retlen = copyto - buf;
return 0;
*retlen = copyto - buf;
return 0;
}
static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
u_char *ptr;
const u_char *copyfrom = buf;
const u_char *copyfrom = buf;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n", (long)to, (long)len, (long)priv->asize);
printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n",
(long)to, (long)len, (long)priv->asize);
#endif
end = to + len - 1;
/* Is it past the end? or did the u32 wrap? */
if (end > mtd->size ) {
end = to + len - 1;
/* Is it past the end? or did the u32 wrap? */
if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, size: %ld, to: %ld)\n", (long) end, (long)mtd->size, (long)to);
printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, "
"size: %ld, to: %ld)\n", (long)end, (long)mtd->size,
(long)to);
#endif
return -EINVAL;
}
soff_hi = to & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point (mtd, to, len, retlen, &ptr);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
will do it. */
memcpy(ptr, copyfrom, len);
copyfrom += len;
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
return -EINVAL;
}
soff_hi = to & ~(priv->asize - 1);
eoff_hi = end & ~(priv->asize - 1);
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, to, len, retlen, &ptr);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
will do it. */
memcpy(ptr, copyfrom, len);
copyfrom += len;
} else {
/* We have to do multiple writes to get all the data
written. */
while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
printk( KERN_DEBUG "pmc551_write() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
printk(KERN_DEBUG "pmc551_write() soff_hi: %ld, "
"eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
memcpy(ptr, copyfrom, priv->asize);
copyfrom += priv->asize;
if (soff_hi >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
}
memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo;
}
out:
memcpy(ptr, copyfrom, priv->asize);
copyfrom += priv->asize;
if (soff_hi >= mtd->size) {
goto out;
}
soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
}
memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo;
}
out:
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_write() done\n");
#endif
*retlen = copyfrom - buf;
return 0;
*retlen = copyfrom - buf;
return 0;
}
/*
......@@ -345,58 +356,58 @@ static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *re
* mechanism
* returns the size of the memory region found.
*/
static u32 fixup_pmc551 (struct pci_dev *dev)
static u32 fixup_pmc551(struct pci_dev *dev)
{
#ifdef CONFIG_MTD_PMC551_BUGFIX
u32 dram_data;
u32 dram_data;
#endif
u32 size, dcmd, cfg, dtmp;
u16 cmd, tmp, i;
u32 size, dcmd, cfg, dtmp;
u16 cmd, tmp, i;
u8 bcmd, counter;
/* Sanity Check */
if(!dev) {
return -ENODEV;
}
/* Sanity Check */
if (!dev) {
return -ENODEV;
}
/*
* Attempt to reset the card
* FIXME: Stop Spinning registers
*/
counter=0;
counter = 0;
/* unlock registers */
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5);
/* read in old data */
pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
/* bang the reset line up and down for a few */
for(i=0;i<10;i++) {
counter=0;
for (i = 0; i < 10; i++) {
counter = 0;
bcmd &= ~0x80;
while(counter++ < 100) {
while (counter++ < 100) {
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
}
counter=0;
counter = 0;
bcmd |= 0x80;
while(counter++ < 100) {
while (counter++ < 100) {
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
}
}
bcmd |= (0x40|0x20);
bcmd |= (0x40 | 0x20);
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
/*
/*
* Take care and turn off the memory on the device while we
* tweak the configurations
*/
pci_read_config_word(dev, PCI_COMMAND, &cmd);
tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
pci_write_config_word(dev, PCI_COMMAND, tmp);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
pci_write_config_word(dev, PCI_COMMAND, tmp);
/*
* Disable existing aperture before probing memory size
*/
pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
dtmp = (dcmd | PMC551_PCI_MEM_MAP_ENABLE | PMC551_PCI_MEM_MAP_REG_EN);
pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
/*
* Grab old BAR0 config so that we can figure out memory size
......@@ -407,220 +418,230 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
* then write all 1's to the memory space, read back the result into
* "size", and then write back all the old config.
*/
pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &cfg);
#ifndef CONFIG_MTD_PMC551_BUGFIX
pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
size = (size&PCI_BASE_ADDRESS_MEM_MASK);
size &= ~(size-1);
pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ~0);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &size);
size = (size & PCI_BASE_ADDRESS_MEM_MASK);
size &= ~(size - 1);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, cfg);
#else
/*
* Get the size of the memory by reading all the DRAM size values
* and adding them up.
*
* KLUDGE ALERT: the boards we are using have invalid column and
* row mux values. We fix them here, but this will break other
* memory configurations.
*/
pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
/*
* Oops .. something went wrong
*/
if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
return -ENODEV;
}
#endif /* CONFIG_MTD_PMC551_BUGFIX */
if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
return -ENODEV;
/*
* Get the size of the memory by reading all the DRAM size values
* and adding them up.
*
* KLUDGE ALERT: the boards we are using have invalid column and
* row mux values. We fix them here, but this will break other
* memory configurations.
*/
pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
/*
* Oops .. something went wrong
*/
if ((size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
return -ENODEV;
}
#endif /* CONFIG_MTD_PMC551_BUGFIX */
if ((cfg & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
return -ENODEV;
}
/*
* Precharge Dram
*/
pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
/*
* Wait until command has gone through
* FIXME: register spinning issue
*/
do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
if(counter++ > 100)break;
} while ( (PCI_COMMAND_IO) & cmd );
/*
/*
* Precharge Dram
*/
pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0400);
pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x00bf);
/*
* Wait until command has gone through
* FIXME: register spinning issue
*/
do {
pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
if (counter++ > 100)
break;
} while ((PCI_COMMAND_IO) & cmd);
/*
* Turn on auto refresh
* The loop is taken directly from Ramix's example code. I assume that
* this must be held high for some duration of time, but I can find no
* documentation refrencing the reasons why.
*/
for ( i = 1; i<=8 ; i++) {
pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
/*
* Make certain command has gone through
* FIXME: register spinning issue
*/
counter=0;
do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
if(counter++ > 100)break;
} while ( (PCI_COMMAND_IO) & cmd );
}
pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
/*
* Wait until command completes
* FIXME: register spinning issue
*/
counter=0;
do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
if(counter++ > 100)break;
} while ( (PCI_COMMAND_IO) & cmd );
pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
dcmd |= 0x02000000;
pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
/*
* Check to make certain fast back-to-back, if not
* then set it so
*/
pci_read_config_word( dev, PCI_STATUS, &cmd);
if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
cmd |= PCI_COMMAND_FAST_BACK;
pci_write_config_word( dev, PCI_STATUS, cmd);
}
/*
* Check to make certain the DEVSEL is set correctly, this device
* has a tendancy to assert DEVSEL and TRDY when a write is performed
* to the memory when memory is read-only
*/
if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
cmd &= ~PCI_STATUS_DEVSEL_MASK;
pci_write_config_word( dev, PCI_STATUS, cmd );
}
/*
* Set to be prefetchable and put everything back based on old cfg.
*/
for (i = 1; i <= 8; i++) {
pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0df);
/*
* Make certain command has gone through
* FIXME: register spinning issue
*/
counter = 0;
do {
pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
if (counter++ > 100)
break;
} while ((PCI_COMMAND_IO) & cmd);
}
pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0020);
pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0ff);
/*
* Wait until command completes
* FIXME: register spinning issue
*/
counter = 0;
do {
pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
if (counter++ > 100)
break;
} while ((PCI_COMMAND_IO) & cmd);
pci_read_config_dword(dev, PMC551_DRAM_CFG, &dcmd);
dcmd |= 0x02000000;
pci_write_config_dword(dev, PMC551_DRAM_CFG, dcmd);
/*
* Check to make certain fast back-to-back, if not
* then set it so
*/
pci_read_config_word(dev, PCI_STATUS, &cmd);
if ((cmd & PCI_COMMAND_FAST_BACK) == 0) {
cmd |= PCI_COMMAND_FAST_BACK;
pci_write_config_word(dev, PCI_STATUS, cmd);
}
/*
* Check to make certain the DEVSEL is set correctly, this device
* has a tendancy to assert DEVSEL and TRDY when a write is performed
* to the memory when memory is read-only
*/
if ((cmd & PCI_STATUS_DEVSEL_MASK) != 0x0) {
cmd &= ~PCI_STATUS_DEVSEL_MASK;
pci_write_config_word(dev, PCI_STATUS, cmd);
}
/*
* Set to be prefetchable and put everything back based on old cfg.
* it's possible that the reset of the V370PDC nuked the original
* setup
*/
*/
/*
cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
*/
/*
cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
*/
/*
* Turn PCI memory and I/O bus access back on
*/
pci_write_config_word( dev, PCI_COMMAND,
PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
* Turn PCI memory and I/O bus access back on
*/
pci_write_config_word(dev, PCI_COMMAND,
PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
#ifdef CONFIG_MTD_PMC551_DEBUG
/*
* Some screen fun
*/
printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%llx\n",
(size<1024)?size:(size<1048576)?size>>10:size>>20,
(size<1024)?'B':(size<1048576)?'K':'M',
size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
(unsigned long long)((dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK));
/*
* Check to see the state of the memory
*/
pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
"pmc551: DRAM_BLK0 Size: %d at %d\n"
"pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
(((0x1<<1)&dcmd) == 0)?"RW":"RO",
(((0x1<<0)&dcmd) == 0)?"Off":"On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
"pmc551: DRAM_BLK1 Size: %d at %d\n"
"pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
(((0x1<<1)&dcmd) == 0)?"RW":"RO",
(((0x1<<0)&dcmd) == 0)?"Off":"On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
"pmc551: DRAM_BLK2 Size: %d at %d\n"
"pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
(((0x1<<1)&dcmd) == 0)?"RW":"RO",
(((0x1<<0)&dcmd) == 0)?"Off":"On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
"pmc551: DRAM_BLK3 Size: %d at %d\n"
"pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
(((0x1<<1)&dcmd) == 0)?"RW":"RO",
(((0x1<<0)&dcmd) == 0)?"Off":"On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
pci_read_config_word( dev, PCI_COMMAND, &cmd );
printk( KERN_DEBUG "pmc551: Memory Access %s\n",
(((0x1<<1)&cmd) == 0)?"off":"on" );
printk( KERN_DEBUG "pmc551: I/O Access %s\n",
(((0x1<<0)&cmd) == 0)?"off":"on" );
pci_read_config_word( dev, PCI_STATUS, &cmd );
printk( KERN_DEBUG "pmc551: Devsel %s\n",
((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
"pmc551: System Control Register is %slocked to PCI access\n"
"pmc551: System Control Register is %slocked to EEPROM access\n",
(bcmd&0x1)?"software":"hardware",
(bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
/*
* Some screen fun
*/
printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
"0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
size >> 10 : size >> 20,
(size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
(unsigned long long)pci_resource_start(dev, 0));
/*
* Check to see the state of the memory
*/
pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dcmd);
printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
"pmc551: DRAM_BLK0 Size: %d at %d\n"
"pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
((dcmd >> 9) & 0xF));
pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dcmd);
printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
"pmc551: DRAM_BLK1 Size: %d at %d\n"
"pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
((dcmd >> 9) & 0xF));
pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dcmd);
printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
"pmc551: DRAM_BLK2 Size: %d at %d\n"
"pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
((dcmd >> 9) & 0xF));
pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dcmd);
printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
"pmc551: DRAM_BLK3 Size: %d at %d\n"
"pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
PMC551_DRAM_BLK_GET_SIZE(dcmd),
((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
((dcmd >> 9) & 0xF));
pci_read_config_word(dev, PCI_COMMAND, &cmd);
printk(KERN_DEBUG "pmc551: Memory Access %s\n",
(((0x1 << 1) & cmd) == 0) ? "off" : "on");
printk(KERN_DEBUG "pmc551: I/O Access %s\n",
(((0x1 << 0) & cmd) == 0) ? "off" : "on");
pci_read_config_word(dev, PCI_STATUS, &cmd);
printk(KERN_DEBUG "pmc551: Devsel %s\n",
((PCI_STATUS_DEVSEL_MASK & cmd) == 0x000) ? "Fast" :
((PCI_STATUS_DEVSEL_MASK & cmd) == 0x200) ? "Medium" :
((PCI_STATUS_DEVSEL_MASK & cmd) == 0x400) ? "Slow" : "Invalid");
printk(KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
((PCI_COMMAND_FAST_BACK & cmd) == 0) ? "Not " : "");
pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
printk(KERN_DEBUG "pmc551: EEPROM is under %s control\n"
"pmc551: System Control Register is %slocked to PCI access\n"
"pmc551: System Control Register is %slocked to EEPROM access\n",
(bcmd & 0x1) ? "software" : "hardware",
(bcmd & 0x20) ? "" : "un", (bcmd & 0x40) ? "" : "un");
#endif
return size;
return size;
}
/*
* Kernel version specific module stuffages
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
MODULE_DESCRIPTION(PMC551_VERSION);
......@@ -628,11 +649,11 @@ MODULE_DESCRIPTION(PMC551_VERSION);
/*
* Stuff these outside the ifdef so as to not bust compiled in driver support
*/
static int msize=0;
static int msize = 0;
#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE
#else
static int asize=0;
static int asize = 0;
#endif
module_param(msize, int, 0);
......@@ -645,164 +666,174 @@ MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
*/
static int __init init_pmc551(void)
{
struct pci_dev *PCI_Device = NULL;
struct mypriv *priv;
int count, found=0;
struct mtd_info *mtd;
u32 length = 0;
if(msize) {
msize = (1 << (ffs(msize) - 1))<<20;
if (msize > (1<<30)) {
printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n", msize);
struct pci_dev *PCI_Device = NULL;
struct mypriv *priv;
int count, found = 0;
struct mtd_info *mtd;
u32 length = 0;
if (msize) {
msize = (1 << (ffs(msize) - 1)) << 20;
if (msize > (1 << 30)) {
printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n",
msize);
return -EINVAL;
}
}
if(asize) {
asize = (1 << (ffs(asize) - 1))<<20;
if (asize > (1<<30) ) {
printk(KERN_NOTICE "pmc551: Invalid aperture size [%d]\n", asize);
if (asize) {
asize = (1 << (ffs(asize) - 1)) << 20;
if (asize > (1 << 30)) {
printk(KERN_NOTICE "pmc551: Invalid aperture size "
"[%d]\n", asize);
return -EINVAL;
}
}
printk(KERN_INFO PMC551_VERSION);
/*
* PCU-bus chipset probe.
*/
for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
if ((PCI_Device = pci_find_device(PCI_VENDOR_ID_V3_SEMI,
PCI_DEVICE_ID_V3_SEMI_V370PDC,
PCI_Device ) ) == NULL) {
break;
}
printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
(unsigned long long)PCI_Device->resource[0].start);
/*
* The PMC551 device acts VERY weird if you don't init it
* first. i.e. it will not correctly report devsel. If for
* some reason the sdram is in a wrote-protected state the
* device will DEVSEL when it is written to causing problems
* with the oldproc.c driver in
* some kernels (2.2.*)
*/
if((length = fixup_pmc551(PCI_Device)) <= 0) {
printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
break;
}
printk(KERN_INFO PMC551_VERSION);
/*
* PCU-bus chipset probe.
*/
for (count = 0; count < MAX_MTD_DEVICES; count++) {
if ((PCI_Device = pci_get_device(PCI_VENDOR_ID_V3_SEMI,
PCI_DEVICE_ID_V3_SEMI_V370PDC,
PCI_Device)) == NULL) {
break;
}
printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
(unsigned long long)pci_resource_start(PCI_Device, 0));
/*
* The PMC551 device acts VERY weird if you don't init it
* first. i.e. it will not correctly report devsel. If for
* some reason the sdram is in a wrote-protected state the
* device will DEVSEL when it is written to causing problems
* with the oldproc.c driver in
* some kernels (2.2.*)
*/
if ((length = fixup_pmc551(PCI_Device)) <= 0) {
printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
break;
}
/*
* This is needed until the driver is capable of reading the
* onboard I2C SROM to discover the "real" memory size.
*/
if(msize) {
if (msize) {
length = msize;
printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
printk(KERN_NOTICE "pmc551: Using specified memory "
"size 0x%x\n", length);
} else {
msize = length;
}
mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd) {
printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
break;
}
memset(mtd, 0, sizeof(struct mtd_info));
priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
if (!priv) {
printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
kfree(mtd);
break;
}
memset(priv, 0, sizeof(*priv));
mtd->priv = priv;
priv->dev = PCI_Device;
if(asize > length) {
printk(KERN_NOTICE "pmc551: reducing aperture size to fit %dM\n",length>>20);
mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd) {
printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
"device.\n");
break;
}
priv = kzalloc(sizeof(struct mypriv), GFP_KERNEL);
if (!priv) {
printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
"device.\n");
kfree(mtd);
break;
}
mtd->priv = priv;
priv->dev = PCI_Device;
if (asize > length) {
printk(KERN_NOTICE "pmc551: reducing aperture size to "
"fit %dM\n", length >> 20);
priv->asize = asize = length;
} else if (asize == 0 || asize == length) {
printk(KERN_NOTICE "pmc551: Using existing aperture size %dM\n", length>>20);
printk(KERN_NOTICE "pmc551: Using existing aperture "
"size %dM\n", length >> 20);
priv->asize = asize = length;
} else {
printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
printk(KERN_NOTICE "pmc551: Using specified aperture "
"size %dM\n", asize >> 20);
priv->asize = asize;
}
priv->start = ioremap(((PCI_Device->resource[0].start)
& PCI_BASE_ADDRESS_MEM_MASK),
priv->asize);
priv->start = pci_iomap(PCI_Device, 0, priv->asize);
if (!priv->start) {
printk(KERN_NOTICE "pmc551: Unable to map IO space\n");
kfree(mtd->priv);
kfree(mtd);
kfree(mtd->priv);
kfree(mtd);
break;
}
#ifdef CONFIG_MTD_PMC551_DEBUG
printk( KERN_DEBUG "pmc551: setting aperture to %d\n",
ffs(priv->asize>>20)-1);
printk(KERN_DEBUG "pmc551: setting aperture to %d\n",
ffs(priv->asize >> 20) - 1);
#endif
priv->base_map0 = ( PMC551_PCI_MEM_MAP_REG_EN
| PMC551_PCI_MEM_MAP_ENABLE
| (ffs(priv->asize>>20)-1)<<4 );
priv->curr_map0 = priv->base_map0;
pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
priv->curr_map0 );
priv->base_map0 = (PMC551_PCI_MEM_MAP_REG_EN
| PMC551_PCI_MEM_MAP_ENABLE
| (ffs(priv->asize >> 20) - 1) << 4);
priv->curr_map0 = priv->base_map0;
pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
priv->curr_map0);
#ifdef CONFIG_MTD_PMC551_DEBUG
printk( KERN_DEBUG "pmc551: aperture set to %d\n",
(priv->base_map0 & 0xF0)>>4 );
printk(KERN_DEBUG "pmc551: aperture set to %d\n",
(priv->base_map0 & 0xF0) >> 4);
#endif
mtd->size = msize;
mtd->flags = MTD_CAP_RAM;
mtd->erase = pmc551_erase;
mtd->read = pmc551_read;
mtd->write = pmc551_write;
mtd->point = pmc551_point;
mtd->unpoint = pmc551_unpoint;
mtd->type = MTD_RAM;
mtd->name = "PMC551 RAM board";
mtd->erasesize = 0x10000;
mtd->writesize = 1;
mtd->owner = THIS_MODULE;
if (add_mtd_device(mtd)) {
printk(KERN_NOTICE "pmc551: Failed to register new device\n");
iounmap(priv->start);
kfree(mtd->priv);
kfree(mtd);
break;
}
printk(KERN_NOTICE "Registered pmc551 memory device.\n");
printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
priv->asize>>20,
priv->start,
priv->start + priv->asize);
printk(KERN_NOTICE "Total memory is %d%c\n",
(length<1024)?length:
(length<1048576)?length>>10:length>>20,
(length<1024)?'B':(length<1048576)?'K':'M');
mtd->size = msize;
mtd->flags = MTD_CAP_RAM;
mtd->erase = pmc551_erase;
mtd->read = pmc551_read;
mtd->write = pmc551_write;
mtd->point = pmc551_point;
mtd->unpoint = pmc551_unpoint;
mtd->type = MTD_RAM;
mtd->name = "PMC551 RAM board";
mtd->erasesize = 0x10000;
mtd->writesize = 1;
mtd->owner = THIS_MODULE;
if (add_mtd_device(mtd)) {
printk(KERN_NOTICE "pmc551: Failed to register new "
"device\n");
pci_iounmap(PCI_Device, priv->start);
kfree(mtd->priv);
kfree(mtd);
break;
}
/* Keep a reference as the add_mtd_device worked */
pci_dev_get(PCI_Device);
printk(KERN_NOTICE "Registered pmc551 memory device.\n");
printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
priv->asize >> 20,
priv->start, priv->start + priv->asize);
printk(KERN_NOTICE "Total memory is %d%c\n",
(length < 1024) ? length :
(length < 1048576) ? length >> 10 : length >> 20,
(length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
priv->nextpmc551 = pmc551list;
pmc551list = mtd;
found++;
}
}
/* Exited early, reference left over */
if (PCI_Device)
pci_dev_put(PCI_Device);
if( !pmc551list ) {
printk(KERN_NOTICE "pmc551: not detected\n");
return -ENODEV;
} else {
if (!pmc551list) {
printk(KERN_NOTICE "pmc551: not detected\n");
return -ENODEV;
} else {
printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
return 0;
return 0;
}
}
......@@ -811,23 +842,24 @@ static int __init init_pmc551(void)
*/
static void __exit cleanup_pmc551(void)
{
int found=0;
struct mtd_info *mtd;
int found = 0;
struct mtd_info *mtd;
struct mypriv *priv;
while((mtd=pmc551list)) {
while ((mtd = pmc551list)) {
priv = mtd->priv;
pmc551list = priv->nextpmc551;
if(priv->start) {
printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n",
priv->asize>>20, priv->start);
iounmap (priv->start);
if (priv->start) {
printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
"0x%p\n", priv->asize >> 20, priv->start);
pci_iounmap(priv->dev, priv->start);
}
pci_dev_put(priv->dev);
kfree (mtd->priv);
del_mtd_device (mtd);
kfree (mtd);
kfree(mtd->priv);
del_mtd_device(mtd);
kfree(mtd);
found++;
}
......
......@@ -447,14 +447,6 @@ config MTD_DC21285
21285 bridge used with Intel's StrongARM processors. More info at
<http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
config MTD_IQ80310
tristate "CFI Flash device mapped on the XScale IQ80310 board"
depends on MTD_CFI && ARCH_IQ80310
help
This enables access routines for the flash chips on the Intel XScale
IQ80310 evaluation board. If you have one of these boards and would
like to use the flash chips on it, say 'Y'.
config MTD_IXP4XX
tristate "CFI Flash device mapped on Intel IXP4xx based systems"
depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
......
......@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
......
......@@ -57,6 +57,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
/* Disable writes through the rom window */
pci_read_config_byte(window->pdev, 0x40, &byte);
pci_write_config_byte(window->pdev, 0x40, byte & ~1);
pci_dev_put(window->pdev);
}
/* Free all of the mtd devices */
......@@ -91,7 +92,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
struct amd76xrom_map_info *map = NULL;
unsigned long map_top;
/* Remember the pci dev I find the window in */
/* Remember the pci dev I find the window in - already have a ref */
window->pdev = pdev;
/* Assume the rom window is properly setup, and find it's size */
......@@ -302,7 +303,7 @@ static int __init init_amd76xrom(void)
struct pci_device_id *id;
pdev = NULL;
for(id = amd76xrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
......
......@@ -96,6 +96,8 @@ static struct mtd_partition arctic_partitions[PARTITIONS] = {
static int __init
init_arctic_mtd(void)
{
int err = 0;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
arctic_mtd_map.virt = ioremap(PADDR, SIZE);
......@@ -109,12 +111,20 @@ init_arctic_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
if (!arctic_mtd)
if (!arctic_mtd) {
iounmap((void *) arctic_mtd_map.virt);
return -ENXIO;
}
arctic_mtd->owner = THIS_MODULE;
return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
iounmap((void *) arctic_mtd_map.virt);
}
return err;
}
static void __exit
......
......@@ -72,6 +72,8 @@ static struct mtd_partition beech_partitions[2] = {
static int __init
init_beech_mtd(void)
{
int err = 0;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
beech_mtd_map.virt = ioremap(PADDR, SIZE);
......@@ -86,12 +88,20 @@ init_beech_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
if (!beech_mtd)
if (!beech_mtd) {
iounmap((void *) beech_mtd_map.virt);
return -ENXIO;
}
beech_mtd->owner = THIS_MODULE;
return add_mtd_partitions(beech_mtd, beech_partitions, 2);
err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
iounmap((void *) beech_mtd_map.virt);
}
return err;
}
static void __exit
......
......@@ -171,7 +171,14 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
if (!cstm_mips_ixx_map[i].virt) {
int j = 0;
printk(KERN_WARNING "Failed to ioremap\n");
for (j = 0; j < i; j++) {
if (cstm_mips_ixx_map[j].virt) {
iounmap((void *)cstm_mips_ixx_map[j].virt);
cstm_mips_ixx_map[j].virt = 0;
}
}
return -EIO;
}
cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
......@@ -204,8 +211,15 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
}
else
return -ENXIO;
else {
for (i = 0; i < PHYSMAP_NUMBER; i++) {
if (cstm_mips_ixx_map[i].virt) {
iounmap((void *)cstm_mips_ixx_map[i].virt);
cstm_mips_ixx_map[i].virt = 0;
}
}
return -ENXIO;
}
}
return 0;
}
......
......@@ -108,6 +108,7 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_small_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ebony_small_map.virt);
return -ENXIO;
}
......@@ -117,6 +118,7 @@ int __init init_ebony(void)
if (!ebony_large_map.virt) {
printk("Failed to ioremap flash\n");
iounmap(ebony_small_map.virt);
return -EIO;
}
......@@ -129,6 +131,8 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_large_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ebony_small_map.virt);
iounmap(ebony_large_map.virt);
return -ENXIO;
}
......
......@@ -218,8 +218,11 @@ int __init init_fortunet(void)
map_regions[ix].map_info.size);
if(!map_regions[ix].map_info.virt)
{
int j = 0;
printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
map_regions[ix].map_info.name);
for (j = 0 ; j < ix; j++)
iounmap(map_regions[j].map_info.virt);
return -ENXIO;
}
simple_map_init(&map_regions[ix].map_info);
......
......@@ -61,6 +61,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
/* Disable writes through the rom window */
pci_read_config_word(window->pdev, BIOS_CNTL, &word);
pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
pci_dev_put(window->pdev);
/* Free all of the mtd devices */
list_for_each_entry_safe(map, scratch, &window->maps, list) {
......@@ -355,7 +356,7 @@ static int __init init_ichxrom(void)
pdev = NULL;
for (id = ichxrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
......
/*
* $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
*
* Mapping for the Intel XScale IQ80310 evaluation board
*
* Author: Nicolas Pitre
* Copyright: (C) 2001 MontaVista Software Inc.
*
* 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.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#define WINDOW_ADDR 0
#define WINDOW_SIZE 8*1024*1024
#define BUSWIDTH 1
static struct mtd_info *mymtd;
static struct map_info iq80310_map = {
.name = "IQ80310 flash",
.size = WINDOW_SIZE,
.bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR
};
static struct mtd_partition iq80310_partitions[4] = {
{
.name = "Firmware",
.size = 0x00080000,
.offset = 0,
.mask_flags = MTD_WRITEABLE /* force read-only */
},{
.name = "Kernel",
.size = 0x000a0000,
.offset = 0x00080000,
},{
.name = "Filesystem",
.size = 0x00600000,
.offset = 0x00120000
},{
.name = "RedBoot",
.size = 0x000e0000,
.offset = 0x00720000,
.mask_flags = MTD_WRITEABLE
}
};
static struct mtd_info *mymtd;
static struct mtd_partition *parsed_parts;
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static int __init init_iq80310(void)
{
struct mtd_partition *parts;
int nb_parts = 0;
int parsed_nr_parts = 0;
int ret;
iq80310_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!iq80310_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&iq80310_map);
mymtd = do_map_probe("cfi_probe", &iq80310_map);
if (!mymtd) {
iounmap((void *)iq80310_map.virt);
return -ENXIO;
}
mymtd->owner = THIS_MODULE;
ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
if (ret > 0)
parsed_nr_parts = ret;
if (parsed_nr_parts > 0) {
parts = parsed_parts;
nb_parts = parsed_nr_parts;
} else {
parts = iq80310_partitions;
nb_parts = ARRAY_SIZE(iq80310_partitions);
}
add_mtd_partitions(mymtd, parts, nb_parts);
return 0;
}
static void __exit cleanup_iq80310(void)
{
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
kfree(parsed_parts);
}
if (iq80310_map.virt)
iounmap((void *)iq80310_map.virt);
}
module_init(init_iq80310);
module_exit(cleanup_iq80310);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80310 evaluation board");
......@@ -253,7 +253,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
/* Use the fast version */
info->map.write = ixp4xx_write16,
err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
if (err > 0) {
err = add_mtd_partitions(info->mtd, info->partitions, err);
if(err)
......
......@@ -61,14 +61,17 @@ static int __init init_l440gx(void)
struct resource *pm_iobase;
__u16 word;
dev = pci_find_device(PCI_VENDOR_ID_INTEL,
dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
pm_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
pci_dev_put(dev);
if (!dev || !pm_dev) {
printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
pci_dev_put(pm_dev);
return -ENODEV;
}
......@@ -76,6 +79,7 @@ static int __init init_l440gx(void)
if (!l440gx_map.virt) {
printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
pci_dev_put(pm_dev);
return -ENOMEM;
}
simple_map_init(&l440gx_map);
......@@ -99,8 +103,12 @@ static int __init init_l440gx(void)
pm_iobase->start += iobase & ~1;
pm_iobase->end += iobase & ~1;
pci_dev_put(pm_dev);
/* Allocate the resource region */
if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
pci_dev_put(dev);
pci_dev_put(pm_dev);
printk(KERN_WARNING "Could not allocate pm iobase resource\n");
iounmap(l440gx_map.virt);
return -ENXIO;
......
......@@ -79,6 +79,7 @@ static int __init init_lasat(void)
return 0;
}
iounmap(lasat_map.virt);
return -ENXIO;
}
......@@ -89,6 +90,7 @@ static void __exit cleanup_lasat(void)
map_destroy(lasat_mtd);
}
if (lasat_map.virt) {
iounmap(lasat_map.virt);
lasat_map.virt = 0;
}
}
......
......@@ -277,6 +277,7 @@ int __init nettel_init(void)
nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
if (!nettel_amd_map.virt) {
printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
iounmap(nettel_mmcrp);
return(-EIO);
}
simple_map_init(&nettel_amd_map);
......@@ -337,7 +338,8 @@ int __init nettel_init(void)
nettel_amd_map.virt = NULL;
#else
/* Only AMD flash supported */
return(-ENXIO);
rc = -ENXIO;
goto out_unmap2;
#endif
}
......@@ -361,14 +363,15 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
return(-EIO);
rc = -EIO;
goto out_unmap2;
}
simple_map_init(&nettel_intel_map);
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (!intel_mtd) {
iounmap(nettel_intel_map.virt);
return(-ENXIO);
rc = -ENXIO;
goto out_unmap1;
}
/* Set PAR to the detected size */
......@@ -394,13 +397,14 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
return(-EIO);
rc = -EIO;
goto out_unmap2;
}
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (! intel_mtd) {
iounmap((void *) nettel_intel_map.virt);
return(-ENXIO);
rc = -ENXIO;
goto out_unmap1;
}
intel1size = intel_mtd->size - intel0size;
......@@ -456,6 +460,18 @@ int __init nettel_init(void)
#endif
return(rc);
#ifdef CONFIG_MTD_CFI_INTELEXT
out_unmap1:
iounmap((void *) nettel_intel_map.virt);
#endif
out_unmap2:
iounmap(nettel_mmcrp);
iounmap(nettel_amd_map.virt);
return(rc);
}
/****************************************************************************/
......@@ -469,6 +485,10 @@ void __exit nettel_cleanup(void)
del_mtd_partitions(amd_mtd);
map_destroy(amd_mtd);
}
if (nettel_mmcrp) {
iounmap(nettel_mmcrp);
nettel_mmcrp = NULL;
}
if (nettel_amd_map.virt) {
iounmap(nettel_amd_map.virt);
nettel_amd_map.virt = NULL;
......
......@@ -97,6 +97,7 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_small_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ocotea_small_map.virt);
return -ENXIO;
}
......@@ -106,6 +107,7 @@ int __init init_ocotea(void)
if (!ocotea_large_map.virt) {
printk("Failed to ioremap flash\n");
iounmap(ocotea_small_map.virt);
return -EIO;
}
......@@ -118,6 +120,8 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_large_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(ocotea_small_map.virt);
iounmap(ocotea_large_map.virt);
return -ENXIO;
}
......
......@@ -602,6 +602,10 @@ static int pcmciamtd_config(struct pcmcia_device *link)
ret = pcmcia_request_configuration(link, &link->conf);
if(ret != CS_SUCCESS) {
cs_error(link, RequestConfiguration, ret);
if (dev->win_base) {
iounmap(dev->win_base);
dev->win_base = NULL;
}
return -ENODEV;
}
......
......@@ -158,9 +158,42 @@ static int physmap_flash_probe(struct platform_device *dev)
return err;
}
#ifdef CONFIG_PM
static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
int ret = 0;
if (info)
ret = info->mtd->suspend(info->mtd);
return ret;
}
static int physmap_flash_resume(struct platform_device *dev)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
if (info)
info->mtd->resume(info->mtd);
return 0;
}
static void physmap_flash_shutdown(struct platform_device *dev)
{
struct physmap_flash_info *info = platform_get_drvdata(dev);
if (info && info->mtd->suspend(info->mtd) == 0)
info->mtd->resume(info->mtd);
}
#endif
static struct platform_driver physmap_flash_driver = {
.probe = physmap_flash_probe,
.remove = physmap_flash_remove,
#ifdef CONFIG_PM
.suspend = physmap_flash_suspend,
.resume = physmap_flash_resume,
.shutdown = physmap_flash_shutdown,
#endif
.driver = {
.name = "physmap-flash",
},
......
......@@ -126,6 +126,8 @@ static struct mtd_info *redwood_mtd;
int __init init_redwood_flash(void)
{
int err = 0;
printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
WINDOW_SIZE, WINDOW_ADDR);
......@@ -141,11 +143,18 @@ int __init init_redwood_flash(void)
if (redwood_mtd) {
redwood_mtd->owner = THIS_MODULE;
return add_mtd_partitions(redwood_mtd,
err = add_mtd_partitions(redwood_mtd,
redwood_flash_partitions,
NUM_REDWOOD_FLASH_PARTITIONS);
if (err) {
printk("init_redwood_flash: add_mtd_partitions failed\n");
iounmap(redwood_flash_map.virt);
}
return err;
}
iounmap(redwood_flash_map.virt);
return -ENXIO;
}
......
......@@ -156,7 +156,7 @@ int __init init_sbc8240_mtd (void)
};
int devicesfound = 0;
int i;
int i,j;
for (i = 0; i < NUM_FLASH_BANKS; i++) {
printk (KERN_NOTICE MSG_PREFIX
......@@ -166,6 +166,10 @@ int __init init_sbc8240_mtd (void)
(unsigned long) ioremap (pt[i].addr, pt[i].size);
if (!sbc8240_map[i].map_priv_1) {
printk (MSG_PREFIX "failed to ioremap\n");
for (j = 0; j < i; j++) {
iounmap((void *) sbc8240_map[j].map_priv_1);
sbc8240_map[j].map_priv_1 = 0;
}
return -EIO;
}
simple_map_init(&sbc8240_mtd[i]);
......@@ -175,6 +179,11 @@ int __init init_sbc8240_mtd (void)
if (sbc8240_mtd[i]) {
sbc8240_mtd[i]->module = THIS_MODULE;
devicesfound++;
} else {
if (sbc8240_map[i].map_priv_1) {
iounmap((void *) sbc8240_map[i].map_priv_1);
sbc8240_map[i].map_priv_1 = 0;
}
}
}
......
......@@ -87,19 +87,23 @@ static int __init init_scx200_docflash(void)
printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
if ((bridge = pci_find_device(PCI_VENDOR_ID_NS,
if ((bridge = pci_get_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SCx200_BRIDGE,
NULL)) == NULL)
return -ENODEV;
/* check that we have found the configuration block */
if (!scx200_cb_present())
if (!scx200_cb_present()) {
pci_dev_put(bridge);
return -ENODEV;
}
if (probe) {
/* Try to use the present flash mapping if any */
pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
pci_dev_put(bridge);
pmr = inl(scx200_cb_base + SCx200_PMR);
if (base == 0
......@@ -127,6 +131,7 @@ static int __init init_scx200_docflash(void)
return -ENOMEM;
}
} else {
pci_dev_put(bridge);
for (u = size; u > 1; u >>= 1)
;
if (u != 1) {
......
......@@ -68,6 +68,7 @@ int __init init_walnut(void)
if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
printk("The on-board flash is disabled (U79 sw 5)!");
iounmap(fpga_status_adr);
return -EIO;
}
if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
......@@ -81,6 +82,7 @@ int __init init_walnut(void)
if (!walnut_map.virt) {
printk("Failed to ioremap flash.\n");
iounmap(fpga_status_adr);
return -EIO;
}
......@@ -93,9 +95,11 @@ int __init init_walnut(void)
ARRAY_SIZE(walnut_partitions));
} else {
printk("map probe failed for flash\n");
iounmap(fpga_status_adr);
return -ENXIO;
}
iounmap(fpga_status_adr);
return 0;
}
......
......@@ -57,6 +57,16 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
/* Some chips always power up locked. Unlock them now */
if ((mtd->flags & MTD_WRITEABLE)
&& (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
if (mtd->unlock(mtd, 0, mtd->size))
printk(KERN_WARNING
"%s: unlock failed, "
"writes may not work\n",
mtd->name);
}
DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
......
......@@ -21,18 +21,7 @@
#include <linux/version.h>
#include <asm/io.h>
/* fixme: this is ugly */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#include <asm/mach-au1x00/au1xxx.h>
#else
#include <asm/au1000.h>
#ifdef CONFIG_MIPS_PB1550
#include <asm/pb1550.h>
#endif
#ifdef CONFIG_MIPS_DB1550
#include <asm/db1x00.h>
#endif
#endif
/*
* MTD structure for NAND controller
......
......@@ -198,6 +198,9 @@ static void __exit ep7312_cleanup(void)
/* Release resources, unregister device */
nand_release(ap7312_mtd);
/* Release io resource */
iounmap((void *)this->IO_ADDR_R);
/* Free the MTD device structure */
kfree(ep7312_mtd);
}
......
......@@ -168,7 +168,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecclayout = mtd->pl_chip->ecclayout;
chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
mtd->mtd.priv = chip;
mtd->mtd.owner = THIS_MODULE;
}
......
......@@ -276,6 +276,7 @@ static int __init ppchameleonevb_init(void)
/* Scan to find existence of the device (it could not be mounted) */
if (nand_scan(ppchameleon_mtd, 1)) {
iounmap((void *)ppchameleon_fio_base);
ppchameleon_fio_base = NULL;
kfree(ppchameleon_mtd);
goto nand_evb_init;
}
......@@ -314,6 +315,8 @@ static int __init ppchameleonevb_init(void)
ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleonevb_mtd) {
printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENOMEM;
}
......@@ -322,6 +325,8 @@ static int __init ppchameleonevb_init(void)
if (!ppchameleonevb_fio_base) {
printk("ioremap PPChameleonEVB NAND flash failed\n");
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -EIO;
}
......@@ -378,6 +383,8 @@ static int __init ppchameleonevb_init(void)
if (nand_scan(ppchameleonevb_mtd, 1)) {
iounmap((void *)ppchameleonevb_fio_base);
kfree(ppchameleonevb_mtd);
if (ppchameleon_fio_base)
iounmap(ppchameleon_fio_base);
return -ENXIO;
}
#ifdef CONFIG_MTD_PARTITIONS
......
/*
* Linux driver for SSFDC Flash Translation Layer (Read only)
* (c) 2005 Eptar srl
* Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
*
* Based on NTFL and MTDBLOCK_RO drivers
*
* 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.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/hdreg.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/blktrans.h>
struct ssfdcr_record {
struct mtd_blktrans_dev mbd;
int usecount;
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
int cis_block; /* block n. containing CIS/IDI */
int erase_size; /* phys_block_size */
unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on
the 128MB) */
int map_len; /* n. phys_blocks on the card */
};
#define SSFDCR_MAJOR 257
#define SSFDCR_PARTN_BITS 3
#define SECTOR_SIZE 512
#define SECTOR_SHIFT 9
#define OOB_SIZE 16
#define MAX_LOGIC_BLK_PER_ZONE 1000
#define MAX_PHYS_BLK_PER_ZONE 1024
#define KB(x) ( (x) * 1024L )
#define MB(x) ( KB(x) * 1024L )
/** CHS Table
1MB 2MB 4MB 8MB 16MB 32MB 64MB 128MB
NCylinder 125 125 250 250 500 500 500 500
NHead 4 4 4 4 4 8 8 16
NSector 4 8 8 16 16 16 32 32
SumSector 2,000 4,000 8,000 16,000 32,000 64,000 128,000 256,000
SectorSize 512 512 512 512 512 512 512 512
**/
typedef struct {
unsigned long size;
unsigned short cyl;
unsigned char head;
unsigned char sec;
} chs_entry_t;
/* Must be ordered by size */
static const chs_entry_t chs_table[] = {
{ MB( 1), 125, 4, 4 },
{ MB( 2), 125, 4, 8 },
{ MB( 4), 250, 4, 8 },
{ MB( 8), 250, 4, 16 },
{ MB( 16), 500, 4, 16 },
{ MB( 32), 500, 8, 16 },
{ MB( 64), 500, 8, 32 },
{ MB(128), 500, 16, 32 },
{ 0 },
};
static int get_chs(unsigned long size, unsigned short *cyl, unsigned char *head,
unsigned char *sec)
{
int k;
int found = 0;
k = 0;
while (chs_table[k].size > 0 && size > chs_table[k].size)
k++;
if (chs_table[k].size > 0) {
if (cyl)
*cyl = chs_table[k].cyl;
if (head)
*head = chs_table[k].head;
if (sec)
*sec = chs_table[k].sec;
found = 1;
}
return found;
}
/* These bytes are the signature for the CIS/IDI sector */
static const uint8_t cis_numbers[] = {
0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
};
/* Read and check for a valid CIS sector */
static int get_valid_cis_sector(struct mtd_info *mtd)
{
int ret, k, cis_sector;
size_t retlen;
loff_t offset;
uint8_t sect_buf[SECTOR_SIZE];
/*
* Look for CIS/IDI sector on the first GOOD block (give up after 4 bad
* blocks). If the first good block doesn't contain CIS number the flash
* is not SSFDC formatted
*/
cis_sector = -1;
for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) {
if (!mtd->block_isbad(mtd, offset)) {
ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen,
sect_buf);
/* CIS pattern match on the sector buffer */
if ( ret < 0 || retlen != SECTOR_SIZE ) {
printk(KERN_WARNING
"SSFDC_RO:can't read CIS/IDI sector\n");
} else if ( !memcmp(sect_buf, cis_numbers,
sizeof(cis_numbers)) ) {
/* Found */
cis_sector = (int)(offset >> SECTOR_SHIFT);
} else {
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: CIS/IDI sector not found"
" on %s (mtd%d)\n", mtd->name,
mtd->index);
}
break;
}
}
return cis_sector;
}
/* Read physical sector (wrapper to MTD_READ) */
static int read_physical_sector(struct mtd_info *mtd, uint8_t *sect_buf,
int sect_no)
{
int ret;
size_t retlen;
loff_t offset = (loff_t)sect_no << SECTOR_SHIFT;
ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, sect_buf);
if (ret < 0 || retlen != SECTOR_SIZE)
return -1;
return 0;
}
/* Read redundancy area (wrapper to MTD_READ_OOB */
static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
{
struct mtd_oob_ops ops;
int ret;
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.len = OOB_SIZE;
ops.oobbuf = buf;
ops.datbuf = NULL;
ret = mtd->read_oob(mtd, offs, &ops);
if (ret < 0 || ops.retlen != OOB_SIZE)
return -1;
return 0;
}
/* Parity calculator on a word of n bit size */
static int get_parity(int number, int size)
{
int k;
int parity;
parity = 1;
for (k = 0; k < size; k++) {
parity += (number >> k);
parity &= 1;
}
return parity;
}
/* Read and validate the logical block address field stored in the OOB */
static int get_logical_address(uint8_t *oob_buf)
{
int block_address, parity;
int offset[2] = {6, 11}; /* offset of the 2 address fields within OOB */
int j;
int ok = 0;
/*
* Look for the first valid logical address
* Valid address has fixed pattern on most significant bits and
* parity check
*/
for (j = 0; j < ARRAY_SIZE(offset); j++) {
block_address = ((int)oob_buf[offset[j]] << 8) |
oob_buf[offset[j]+1];
/* Check for the signature bits in the address field (MSBits) */
if ((block_address & ~0x7FF) == 0x1000) {
parity = block_address & 0x01;
block_address &= 0x7FF;
block_address >>= 1;
if (get_parity(block_address, 10) != parity) {
DEBUG(MTD_DEBUG_LEVEL0,
"SSFDC_RO: logical address field%d"
"parity error(0x%04X)\n", j+1,
block_address);
} else {
ok = 1;
break;
}
}
}
if ( !ok )
block_address = -2;
DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n",
block_address);
return block_address;
}
/* Build the logic block map */
static int build_logical_block_map(struct ssfdcr_record *ssfdc)
{
unsigned long offset;
uint8_t oob_buf[OOB_SIZE];
int ret, block_address, phys_block;
struct mtd_info *mtd = ssfdc->mbd.mtd;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
ssfdc->map_len, (unsigned long)ssfdc->map_len *
ssfdc->erase_size / 1024 );
/* Scan every physical block, skip CIS block */
for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
phys_block++) {
offset = (unsigned long)phys_block * ssfdc->erase_size;
if (mtd->block_isbad(mtd, offset))
continue; /* skip bad blocks */
ret = read_raw_oob(mtd, offset, oob_buf);
if (ret < 0) {
DEBUG(MTD_DEBUG_LEVEL0,
"SSFDC_RO: mtd read_oob() failed at %lu\n",
offset);
return -1;
}
block_address = get_logical_address(oob_buf);
/* Skip invalid addresses */
if (block_address >= 0 &&
block_address < MAX_LOGIC_BLK_PER_ZONE) {
int zone_index;
zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
ssfdc->logic_block_map[block_address] =
(unsigned short)phys_block;
DEBUG(MTD_DEBUG_LEVEL2,
"SSFDC_RO: build_block_map() phys_block=%d,"
"logic_block_addr=%d, zone=%d\n",
phys_block, block_address, zone_index);
}
}
return 0;
}
static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
struct ssfdcr_record *ssfdc;
int cis_sector;
/* Check for small page NAND flash */
if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE)
return;
/* Check for SSDFC format by reading CIS/IDI sector */
cis_sector = get_valid_cis_sector(mtd);
if (cis_sector == -1)
return;
ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL);
if (!ssfdc) {
printk(KERN_WARNING
"SSFDC_RO: out of memory for data structures\n");
return;
}
ssfdc->mbd.mtd = mtd;
ssfdc->mbd.devnum = -1;
ssfdc->mbd.blksize = SECTOR_SIZE;
ssfdc->mbd.tr = tr;
ssfdc->mbd.readonly = 1;
ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
ssfdc->erase_size = mtd->erasesize;
ssfdc->map_len = mtd->size / mtd->erasesize;
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
(ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) /
MAX_PHYS_BLK_PER_ZONE);
/* Set geometry */
ssfdc->heads = 16;
ssfdc->sectors = 32;
get_chs( mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) /
((long)ssfdc->sectors * (long)ssfdc->heads));
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
(long)ssfdc->cylinders * (long)ssfdc->heads *
(long)ssfdc->sectors );
ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
(long)ssfdc->sectors;
/* Allocate logical block map */
ssfdc->logic_block_map = kmalloc( sizeof(ssfdc->logic_block_map[0]) *
ssfdc->map_len, GFP_KERNEL);
if (!ssfdc->logic_block_map) {
printk(KERN_WARNING
"SSFDC_RO: out of memory for data structures\n");
goto out_err;
}
memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) *
ssfdc->map_len);
/* Build logical block map */
if (build_logical_block_map(ssfdc) < 0)
goto out_err;
/* Register device + partitions */
if (add_mtd_blktrans_dev(&ssfdc->mbd))
goto out_err;
printk(KERN_INFO "SSFDC_RO: Found ssfdc%c on mtd%d (%s)\n",
ssfdc->mbd.devnum + 'a', mtd->index, mtd->name);
return;
out_err:
kfree(ssfdc->logic_block_map);
kfree(ssfdc);
}
static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
del_mtd_blktrans_dev(dev);
kfree(ssfdc->logic_block_map);
kfree(ssfdc);
}
static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
unsigned long logic_sect_no, char *buf)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
int sectors_per_block, offset, block_address;
sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
offset = (int)(logic_sect_no % sectors_per_block);
block_address = (int)(logic_sect_no / sectors_per_block);
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
" block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
block_address);
if (block_address >= ssfdc->map_len)
BUG();
block_address = ssfdc->logic_block_map[block_address];
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
block_address);
if (block_address < 0xffff) {
unsigned long sect_no;
sect_no = (unsigned long)block_address * sectors_per_block +
offset;
DEBUG(MTD_DEBUG_LEVEL3,
"SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
sect_no);
if (read_physical_sector( ssfdc->mbd.mtd, buf, sect_no ) < 0)
return -EIO;
} else {
memset(buf, 0xff, SECTOR_SIZE);
}
return 0;
}
static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
{
struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
geo->heads = ssfdc->heads;
geo->sectors = ssfdc->sectors;
geo->cylinders = ssfdc->cylinders;
return 0;
}
/****************************************************************************
*
* Module stuff
*
****************************************************************************/
static struct mtd_blktrans_ops ssfdcr_tr = {
.name = "ssfdc",
.major = SSFDCR_MAJOR,
.part_bits = SSFDCR_PARTN_BITS,
.getgeo = ssfdcr_getgeo,
.readsect = ssfdcr_readsect,
.add_mtd = ssfdcr_add_mtd,
.remove_dev = ssfdcr_remove_dev,
.owner = THIS_MODULE,
};
static int __init init_ssfdcr(void)
{
printk(KERN_INFO "SSFDC read-only Flash Translation layer\n");
return register_mtd_blktrans(&ssfdcr_tr);
}
static void __exit cleanup_ssfdcr(void)
{
deregister_mtd_blktrans(&ssfdcr_tr);
}
module_init(init_ssfdcr);
module_exit(cleanup_ssfdcr);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>");
MODULE_DESCRIPTION("Flash Translation Layer for read-only SSFDC SmartMedia card");
......@@ -41,11 +41,7 @@ struct jffs2_inode_info {
uint16_t flags;
uint8_t usercompr;
#if !defined (__ECOS)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
struct inode vfs_inode;
#endif
#endif
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
struct posix_acl *i_acl_access;
struct posix_acl *i_acl_default;
......
......@@ -34,6 +34,7 @@ struct mtd_oob_buf {
#define MTD_WRITEABLE 0x400 /* Device is writeable */
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
......
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