From 15b5423757a750b2c7efabd77bb6ed8aa6ffb20e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 21 Oct 2004 00:55:08 +0100 Subject: Shared Reed-Solomon ECC library The attached patch contains a shared Reed-Solomon Library analogous to the shared zlib. (N)AND FLASH is gaining popularity and there are a lot of ASIC/SoC/FPGA controllers around which implement hardware support for Reed-Solomon error correction. As usual they use different implementations (polynomials etc.). So it's obvious to use a shared library for the common tasks of error correction. A short scan through the kernel revealed that at least the ftape driver uses Reed-Solomon error correction. It could be easily converted to use the shared library code. The encoder/decoder code is lifted from the GPL'd userspace RS-library written by Phil Karn. I modified/wrapped it to provide the different functions which we need in the MTD/NAND code. The library is tested in extenso under various MTD/NAND configurations. The lib should be usable for other purposes right out of the box. Adjustment for currently not implemented functionality is an easy task. I'm willing to take the maintainership of the library. Signed-Off-By: Thomas Gleixner Signed-Off-By: David Woodhouse "No objections at all. Just keep the authorship notices." -- Phil Karn --- include/linux/rslib.h | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 include/linux/rslib.h (limited to 'include/linux') diff --git a/include/linux/rslib.h b/include/linux/rslib.h new file mode 100644 index 000000000000..980c8f74d8dc --- /dev/null +++ b/include/linux/rslib.h @@ -0,0 +1,105 @@ +/* + * include/linux/rslib.h + * + * Overview: + * Generic Reed Solomon encoder / decoder library + * + * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) + * + * RS code lifted from reed solomon library written by Phil Karn + * Copyright 2002 Phil Karn, KA9Q + * + * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner Exp $ + * + * 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. + */ + +#ifndef _RSLIB_H_ +#define _RSLIB_H_ + +#include + +/** + * struct rs_control - rs control structure + * + * @mm: Bits per symbol + * @nn: Symbols per block (= (1<mm = number of bits per symbol + * rs->nn = (2^rs->mm) - 1 + * + * Simple arithmetic modulo would return a wrong result for values + * >= 3 * rs->nn +*/ +static inline int rs_modnn(struct rs_control *rs, int x) +{ + while (x >= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + +#endif -- cgit v1.2.3 From d0669b55e1f8e20ebeaafc7e1a6cb87578672f5e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 21 Oct 2004 01:23:38 +0100 Subject: MTD updates for __iomem Signed-Off-By: Thomas Gleixner Signed-Off-By: David Woodhouse --- drivers/mtd/maps/arctic-mtd.c | 4 ++-- drivers/mtd/maps/autcpu12-nvram.c | 6 ++--- drivers/mtd/maps/beech-mtd.c | 4 ++-- drivers/mtd/maps/cdb89712.c | 8 +++---- drivers/mtd/maps/ceiva.c | 6 ++--- drivers/mtd/maps/cfi_flagadm.c | 4 ++-- drivers/mtd/maps/cstm_mips_ixx.c | 4 ++-- drivers/mtd/maps/dbox2-flash.c | 4 ++-- drivers/mtd/maps/dc21285.c | 4 ++-- drivers/mtd/maps/dilnetpc.c | 4 ++-- drivers/mtd/maps/dmv182.c | 4 ++-- drivers/mtd/maps/edb7312.c | 14 +++++------ drivers/mtd/maps/elan-104nc.c | 6 ++--- drivers/mtd/maps/epxa10db-flash.c | 4 ++-- drivers/mtd/maps/fortunet.c | 4 ++-- drivers/mtd/maps/h720x-flash.c | 4 ++-- drivers/mtd/maps/impa7.c | 8 +++---- drivers/mtd/maps/integrator-flash.c | 4 ++-- drivers/mtd/maps/iq80310.c | 4 ++-- drivers/mtd/maps/ixp2000.c | 48 ++++++++++++++++++------------------- drivers/mtd/maps/ixp4xx.c | 8 +++---- drivers/mtd/maps/l440gx.c | 4 ++-- drivers/mtd/maps/lasat.c | 4 ++-- drivers/mtd/maps/mbx860.c | 4 ++-- drivers/mtd/maps/mpc1211.c | 4 ++-- drivers/mtd/maps/netsc520.c | 4 ++-- drivers/mtd/maps/nettel.c | 5 ++-- drivers/mtd/maps/ocelot.c | 6 ++--- drivers/mtd/maps/omap-toto-flash.c | 4 ++-- drivers/mtd/maps/pb1550-flash.c | 4 ++-- drivers/mtd/maps/pb1xxx-flash.c | 5 ++-- drivers/mtd/maps/physmap.c | 4 ++-- drivers/mtd/maps/pnc2000.c | 4 ++-- drivers/mtd/maps/redwood.c | 4 ++-- drivers/mtd/maps/rpxlite.c | 4 ++-- drivers/mtd/maps/sbc_gxx.c | 6 ++--- drivers/mtd/maps/sc520cdp.c | 4 ++-- drivers/mtd/maps/scb2_flash.c | 4 ++-- drivers/mtd/maps/scx200_docflash.c | 4 ++-- drivers/mtd/maps/solutionengine.c | 6 ++--- drivers/mtd/maps/sun_uflash.c | 4 ++-- drivers/mtd/maps/uclinux.c | 9 +++---- drivers/mtd/maps/wr_sbc82xx_flash.c | 4 ++-- include/linux/mtd/doc2000.h | 8 +++---- 44 files changed, 132 insertions(+), 133 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c index 2acf5b0b8cc3..36e3ff869ba4 100644 --- a/drivers/mtd/maps/arctic-mtd.c +++ b/drivers/mtd/maps/arctic-mtd.c @@ -1,5 +1,5 @@ /* - * $Id: arctic-mtd.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: arctic-mtd.c,v 1.12 2004/09/16 23:27:12 gleixner Exp $ * * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for * IBM 405LP Arctic boards. @@ -98,7 +98,7 @@ init_arctic_mtd(void) { printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); - arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + arctic_mtd_map.virt = (void __iomem *) ioremap(PADDR, SIZE); if (!arctic_mtd_map.virt) { printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index 31e9df6629c8..cd02989de726 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -2,7 +2,7 @@ * NV-RAM memory access on autcpu12 * (C) 2002 Thomas Gleixner (gleixner@autronix.de) * - * $Id: autcpu12-nvram.c,v 1.6 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: autcpu12-nvram.c,v 1.7 2004/09/16 23:27:12 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ static int __init init_autcpu12_sram (void) { int err, save0, save1; - autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K); + autcpu12_sram_map.virt = (void __iomem *)ioremap(0x12000000, SZ_128K); if (!autcpu12_sram_map.virt) { printk("Failed to ioremap autcpu12 NV-RAM space\n"); err = -EIO; @@ -76,7 +76,7 @@ static int __init init_autcpu12_sram (void) /* We have a 128K found, restore 0x10000 and set size * to 128K */ - ma[_write32(&autcpu12_sram_map,save1,0x10000); + map_write32(&autcpu12_sram_map,save1,0x10000); autcpu12_sram_map.size = SZ_128K; map: diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c index d8f737aa745d..56c7370fc544 100644 --- a/drivers/mtd/maps/beech-mtd.c +++ b/drivers/mtd/maps/beech-mtd.c @@ -1,5 +1,5 @@ /* - * $Id: beech-mtd.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: beech-mtd.c,v 1.9 2004/09/16 23:27:12 gleixner Exp $ * * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for * IBM 405LP Beech boards. @@ -74,7 +74,7 @@ init_beech_mtd(void) { printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); - beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + beech_mtd_map.virt = (void __iomem *) ioremap(PADDR, SIZE); if (!beech_mtd_map.virt) { printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index e8c984ee13e2..23b1289905d2 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c @@ -1,7 +1,7 @@ /* * Flash on Cirrus CDB89712 * - * $Id: cdb89712.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: cdb89712.c,v 1.9 2004/09/16 23:27:12 gleixner Exp $ */ #include @@ -44,7 +44,7 @@ static int __init init_cdb89712_flash (void) goto out; } - cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + cdb89712_flash_map.virt = (void __iomem *)ioremap(FLASH_START, FLASH_SIZE); if (!cdb89712_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); err = -EIO; @@ -114,7 +114,7 @@ static int __init init_cdb89712_sram (void) goto out; } - cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); + cdb89712_sram_map.virt = (void __iomem *)ioremap(SRAM_START, SRAM_SIZE); if (!cdb89712_sram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); err = -EIO; @@ -182,7 +182,7 @@ static int __init init_cdb89712_bootrom (void) goto out; } - cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); + cdb89712_bootrom_map.virt = (void __iomem *)ioremap(BOOTROM_START, BOOTROM_SIZE); if (!cdb89712_bootrom_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); err = -EIO; diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index e34420bb101d..da8584a662f4 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -11,7 +11,7 @@ * * (C) 2000 Nicolas Pitre * - * $Id: ceiva.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $ */ #include @@ -103,7 +103,7 @@ struct clps_info { unsigned long base; unsigned long size; int width; - void __iomem *vbase; + void *vbase; struct map_info *map; struct mtd_info *mtd; struct resource *res; @@ -150,7 +150,7 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info break; } - clps[i].map->virt = clps[i].vbase; + clps[i].map->virt = (void __iomem *)clps[i].vbase; clps[i].map->bankwidth = clps[i].width; clps[i].map->size = clps[i].size; diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 28d59ff7782d..f923e8b8cebc 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -1,7 +1,7 @@ /* * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíđsson * - * $Id: cfi_flagadm.c,v 1.12 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: cfi_flagadm.c,v 1.13 2004/09/16 23:27:12 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -96,7 +96,7 @@ int __init init_flagadm(void) FLASH_SIZE, FLASH_PHYS_ADDR); flagadm_map.phys = FLASH_PHYS_ADDR; - flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR, + flagadm_map.virt = (void __iomem *s)ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); if (!flagadm_map.virt) { diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c index 773b1ba9ac9d..c5b742df4e39 100644 --- a/drivers/mtd/maps/cstm_mips_ixx.c +++ b/drivers/mtd/maps/cstm_mips_ixx.c @@ -1,5 +1,5 @@ /* - * $Id: cstm_mips_ixx.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: cstm_mips_ixx.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $ * * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. * Config with both CFI and JEDEC device support. @@ -170,7 +170,7 @@ 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 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); + cstm_mips_ixx_map[i].virt = (void __iomem *)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); if (!cstm_mips_ixx_map[i].virt) { printk(KERN_WARNING "Failed to ioremap\n"); return -EIO; diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index 7c4de43c0ef1..e40465bfa482 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -1,5 +1,5 @@ /* - * $Id: dbox2-flash.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $ + * $Id: dbox2-flash.c,v 1.12 2004/09/16 23:27:12 gleixner Exp $ * * D-Box 2 flash driver */ @@ -75,7 +75,7 @@ struct map_info dbox2_flash_map = { int __init init_dbox2_flash(void) { printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); - dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + dbox2_flash_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!dbox2_flash_map.virt) { printk("Failed to ioremap\n"); diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index fc72bb5c5d22..5f61a6ef4036 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.20 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: dc21285.c,v 1.21 2004/09/16 23:27:13 gleixner Exp $ */ #include #include @@ -175,7 +175,7 @@ static int __init init_dc21285(void) dc21285_map.bankwidth*8); /* Let's map the flash area */ - dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024); + dc21285_map.map_priv_1 = (void __iomem *)ioremap(DC21285_FLASH, 16*1024*1024); if (!dc21285_map.map_priv_1) { printk("Failed to ioremap\n"); return -EIO; diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index feb38ba14f26..f69992c1ba1a 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: dilnetpc.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: dilnetpc.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $ * * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems * featuring the AMD Elan SC410 processor. There are two variants of this @@ -403,7 +403,7 @@ static int __init init_dnpc(void) printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); - dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size); + dnpc_map.virt = (void __iomem *)ioremap_nocache(dnpc_map.phys, dnpc_map.size); dnpc_map_flash(dnpc_map.phys, dnpc_map.size); diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index cdb9c1bc9c4e..124d02165cbc 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c @@ -4,7 +4,7 @@ * * Flash map driver for the Dy4 SVME182 board * - * $Id: dmv182.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $ + * $Id: dmv182.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $ * * Copyright 2003-2004, TimeSys Corporation * @@ -104,7 +104,7 @@ static int __init init_svme182(void) partitions = svme182_partitions; svme182_map.virt = - (unsigned long)ioremap(FLASH_BASE_ADDR, svme182_map.size); + (void __iomem *)ioremap(FLASH_BASE_ADDR, svme182_map.size); if (svme182_map.virt == 0) { printk("Failed to ioremap FLASH memory area.\n"); diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index b7fd849dc1fc..4a98dff01db3 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -1,5 +1,5 @@ /* - * $Id: edb7312.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $ + * $Id: edb7312.c,v 1.12 2004/09/16 23:27:13 gleixner Exp $ * * Handle mapping of the NOR flash on Cogent EDB7312 boards * @@ -71,19 +71,19 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif -static int mtd_parts_nb; -static struct mtd_partition *mtd_parts; +static int mtd_parts_nb = 0; +static struct mtd_partition *mtd_parts = 0; int __init init_edb7312nor(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = NULL; + const char *part_type = 0; printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.virt = (unsigned long) - ioremap(WINDOW_ADDR, WINDOW_SIZE); + edb7312nor_map.virt = (void __iomem *) + ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!edb7312nor_map.virt) { printk(MSG_PREFIX "failed to ioremap\n"); @@ -92,7 +92,7 @@ int __init init_edb7312nor(void) simple_map_init(&edb7312nor_map); - mymtd = NULL; + mymtd = 0; type = rom_probe_types; for(; !mymtd && *type; type++) { mymtd = do_map_probe(*type, &edb7312nor_map); diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c index 9410e1fb28d5..d39bfa633491 100644 --- a/drivers/mtd/maps/elan-104nc.c +++ b/drivers/mtd/maps/elan-104nc.c @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.21 2004/07/12 22:38:29 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.22 2004/09/16 23:27:13 gleixner Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. @@ -53,7 +53,7 @@ always fail. So we don't do it. I just hope it doesn't break anything. #define PAGE_IO_SIZE 2 static volatile int page_in_window = -1; // Current page in window. -static unsigned long iomapadr; +static void __iomem *iomapadr; static spinlock_t elan_104nc_spin = SPIN_LOCK_UNLOCKED; /* partition_info gives details on the logical partitions that the split the @@ -190,7 +190,7 @@ int __init init_elan_104nc(void) /* Urg! We use I/O port 0x22 without request_region()ing it, because it's already allocated to the PIC. */ - iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); + iomapadr = (void __iomem *)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", elan_104nc_map.name ); diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c index 545a398c47b9..4a4bf79e8a0c 100644 --- a/drivers/mtd/maps/epxa10db-flash.c +++ b/drivers/mtd/maps/epxa10db-flash.c @@ -5,7 +5,7 @@ * Copyright (C) 2001 Altera Corporation * Copyright (C) 2001 Red Hat, Inc. * - * $Id: epxa10db-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: epxa10db-flash.c,v 1.12 2004/09/16 23:27:13 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +62,7 @@ static int __init epxa_mtd_init(void) printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); - epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + epxa_map.virt = (void __iomem *)ioremap(FLASH_START, FLASH_SIZE); if (!epxa_map.virt) { printk("Failed to ioremap %s flash\n",BOARD_NAME); return -EIO; diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 50409efda9c9..a7dc9c3905d4 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -1,6 +1,6 @@ /* fortunet.c memory map * - * $Id: fortunet.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: fortunet.c,v 1.8 2004/09/16 23:27:13 gleixner Exp $ */ #include @@ -210,7 +210,7 @@ int __init init_fortunet(void) map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, map_regions[ix].map_info.virt = - (int)ioremap_nocache( + (void __iomem *)ioremap_nocache( map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); if(!map_regions[ix].map_info.virt) diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index e7cd7b022eb7..46e654786249 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -2,7 +2,7 @@ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based * evaluation boards * - * $Id: h720x-flash.c,v 1.9 2004/07/14 17:45:40 dwmw2 Exp $ + * $Id: h720x-flash.c,v 1.10 2004/09/16 23:27:13 gleixner Exp $ * * (C) 2002 Jungjun Kim * 2003 Thomas Gleixner @@ -73,7 +73,7 @@ int __init h720x_mtd_init(void) char *part_type = NULL; - h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE); + h720x_map.virt = (void __iomem *)ioremap(FLASH_PHYS, FLASH_SIZE); if (!h720x_map.virt) { printk(KERN_ERR "H720x-MTD: ioremap failed\n"); diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 7d2b42436958..34ed09fca8e2 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -1,5 +1,5 @@ /* - * $Id: impa7.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $ + * $Id: impa7.c,v 1.12 2004/09/16 23:27:13 gleixner Exp $ * * Handle mapping of the NOR flash on implementa A7 boards * @@ -77,7 +77,7 @@ int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = NULL; + const char *part_type = 0; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -91,7 +91,7 @@ int __init init_impa7(void) pt[i].size, pt[i].addr); impa7_map[i].phys = pt[i].addr; - impa7_map[i].virt = (unsigned long) + impa7_map[i].virt = (void __iomem *) ioremap(pt[i].addr, pt[i].size); if (!impa7_map[i].virt) { printk(MSG_PREFIX "failed to ioremap\n"); @@ -99,7 +99,7 @@ int __init init_impa7(void) } simple_map_init(&impa7_map[i]); - impa7_mtd[i] = NULL; + impa7_mtd[i] = 0; type = rom_probe_types; for(; !impa7_mtd[i] && *type; type++) { impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]); diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 1f23ab1cd882..710bec4c89ef 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -22,7 +22,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.16 2004/07/12 21:59:44 dwmw2 Exp $ + $Id: integrator-flash.c,v 1.17 2004/09/16 23:27:13 gleixner Exp $ ======================================================================*/ @@ -110,7 +110,7 @@ static int armflash_probe(struct device *_dev) info->map.size = size; info->map.bankwidth = plat->width; info->map.phys = res->start; - info->map.virt = (unsigned long) base; + info->map.virt = (void __iomem *) base; info->map.name = dev->dev.bus_id; info->map.set_vpp = armflash_set_vpp; diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c index 17d7c77594e4..977a084b60f8 100644 --- a/drivers/mtd/maps/iq80310.c +++ b/drivers/mtd/maps/iq80310.c @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.18 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: iq80310.c,v 1.19 2004/09/16 23:27:13 gleixner Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -68,7 +68,7 @@ static int __init init_iq80310(void) int parsed_nr_parts = 0; int ret; - iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + iq80310_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!iq80310_map.virt) { printk("Failed to ioremap\n"); return -EIO; diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 104488c0b188..6d3715c4219a 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -1,5 +1,5 @@ /* - * $Id: ixp2000.c,v 1.1 2004/09/02 00:13:41 dsaxena Exp $ + * $Id: ixp2000.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $ * * drivers/mtd/maps/ixp2000.c * @@ -14,7 +14,7 @@ * 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 @@ -44,8 +44,8 @@ struct ixp2000_flash_info { }; static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) -{ - unsigned long (*set_bank)(unsigned long) = +{ + unsigned long (*set_bank)(unsigned long) = (unsigned long(*)(unsigned long))map->map_priv_2; return (set_bank ? set_bank(ofs) : ofs); @@ -53,15 +53,15 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long #ifdef __ARMEB__ /* - * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which - * causes the lower address bits to be XORed with 0x11 on 8 bit accesses - * and XORed with 0x10 on 16 bit accesses. See the spec update, erratta 44. + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. */ -static int errata44_workaround = 0; +static int erratum44_workaround = 0; static inline unsigned long address_fix8_write(unsigned long addr) { - if (errata44_workaround) { + if (erratum44_workaround) { return (addr ^ 3); } return addr; @@ -88,7 +88,7 @@ static void ixp2000_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { from = flash_bank_setup(map, from); - while(len--) + while(len--) *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); } @@ -127,8 +127,8 @@ static int ixp2000_flash_remove(struct device *_dev) if (info->map.map_priv_1) iounmap((void *) info->map.map_priv_1); - if (info->partitions) - kfree(info->partitions); + if (info->partitions) { + kfree(info->partitions); } if (info->res) { release_resource(info->res); @@ -147,11 +147,11 @@ static int ixp2000_flash_probe(struct device *_dev) static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; struct platform_device *dev = to_platform_device(_dev); struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; - struct flash_platform_data *plat; + struct flash_platform_data *plat; struct ixp2000_flash_info *info; unsigned long window_size; int err = -1; - + if (!ixp_data) return -ENODEV; @@ -160,7 +160,7 @@ static int ixp2000_flash_probe(struct device *_dev) return -ENODEV; window_size = dev->resource->end - dev->resource->start + 1; - dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dM)\n", + dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", ixp_data->nr_banks, ((u32)window_size >> 20)); if (plat->width != 1) { @@ -173,7 +173,7 @@ static int ixp2000_flash_probe(struct device *_dev) if(!info) { err = -ENOMEM; goto Error; - } + } memzero(info, sizeof(struct ixp2000_flash_info)); dev_set_drvdata(&dev->dev, info); @@ -183,7 +183,7 @@ static int ixp2000_flash_probe(struct device *_dev) * not attempt to do a direct access on us. */ info->map.phys = NO_XIP; - + info->nr_banks = ixp_data->nr_banks; info->map.size = ixp_data->nr_banks * window_size; info->map.bankwidth = 1; @@ -191,7 +191,7 @@ static int ixp2000_flash_probe(struct device *_dev) /* * map_priv_2 is used to store a ptr to to the bank_setup routine */ - info->map.map_priv_2 = (u32) ixp_data->bank_setup; + info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup; info->map.name = dev->dev.bus_id; info->map.read = ixp2000_flash_read8; @@ -199,8 +199,8 @@ static int ixp2000_flash_probe(struct device *_dev) info->map.copy_from = ixp2000_flash_copy_from; info->map.copy_to = ixp2000_flash_copy_to; - info->res = request_mem_region(dev->resource->start, - dev->resource->end - dev->resource->start + 1, + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, dev->dev.bus_id); if (!info->res) { dev_err(_dev, "Could not reserve memory region\n"); @@ -209,7 +209,7 @@ static int ixp2000_flash_probe(struct device *_dev) } info->map.map_priv_1 = - (unsigned long) ioremap(dev->resource->start, + (void __iomem *) ioremap(dev->resource->start, dev->resource->end - dev->resource->start + 1); if (!info->map.map_priv_1) { dev_err(_dev, "Failed to ioremap flash region\n"); @@ -224,12 +224,12 @@ static int ixp2000_flash_probe(struct device *_dev) #if defined(__ARMEB__) /* - * Enable errata 44 workaround for NPUs with broken slowport + * Enable erratum 44 workaround for NPUs with broken slowport */ errata44_workaround = ixp2000_has_broken_slowport(); - dev_info(_dev, "Errata 44 workaround %s\n", - errata44_workaround ? "enabled" : "disabled"); + dev_info(_dev, "Erratum 44 workaround %s\n", + erratum44_workaround ? "enabled" : "disabled"); #endif info->mtd = do_map_probe(plat->map_name, &info->map); diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 1770b1acc2b9..ba874b8d07a4 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -69,7 +69,7 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, dest[len - 1] = BYTE0(src[i]); } -/* +/* * Unaligned writes are ignored, causing the 8-bit * probe to fail and proceed to the 16-bit probe (which succeeds). */ @@ -79,7 +79,7 @@ static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; } -/* +/* * Fast write16 function without the probing check above */ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) @@ -197,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev) } info->map.map_priv_1 = - (void __iomem *) ioremap(dev->resource->start, + (void __iomem *) ioremap(dev->resource->start, dev->resource->end - dev->resource->start + 1); if (!info->map.map_priv_1) { printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); @@ -212,7 +212,7 @@ static int ixp4xx_flash_probe(struct device *_dev) goto Error; } info->mtd->owner = THIS_MODULE; - + /* Use the fast version */ info->map.write = ixp4xx_write16, diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index 046f7efbd8e6..f8c5b0b2f8a0 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c @@ -1,5 +1,5 @@ /* - * $Id: l440gx.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: l440gx.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $ * * BIOS Flash chip on Intel 440GX board. * @@ -73,7 +73,7 @@ static int __init init_l440gx(void) return -ENODEV; } - l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); + l440gx_map.virt = (void __iomem *)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); if (!l440gx_map.virt) { printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); diff --git a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c index 2a2efaa42456..6451c7ead44a 100644 --- a/drivers/mtd/maps/lasat.c +++ b/drivers/mtd/maps/lasat.c @@ -7,7 +7,7 @@ * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * - * $Id: lasat.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: lasat.c,v 1.8 2004/09/16 23:27:13 gleixner Exp $ * */ @@ -50,7 +50,7 @@ static int __init init_lasat(void) ENABLE_VPP((&lasat_map)); lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); - lasat_map.virt = (unsigned long)ioremap_nocache( + lasat_map.virt = (void __iomem *)ioremap_nocache( lasat_map.phys, lasat_board_info.li_flash_size); lasat_map.size = lasat_board_info.li_flash_size; diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index 4c0f9e967cc8..0945f44375be 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c @@ -1,5 +1,5 @@ /* - * $Id: mbx860.c,v 1.6 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: mbx860.c,v 1.7 2004/09/16 23:27:13 gleixner Exp $ * * Handle mapping of the flash on MBX860 boards * @@ -60,7 +60,7 @@ struct map_info mbx_map = { int __init init_mbx(void) { printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); - mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + mbx_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); if (!mbx_map.virt) { printk("Failed to ioremap\n"); diff --git a/drivers/mtd/maps/mpc1211.c b/drivers/mtd/maps/mpc1211.c index cc55200a21e3..4685e8e13460 100644 --- a/drivers/mtd/maps/mpc1211.c +++ b/drivers/mtd/maps/mpc1211.c @@ -1,7 +1,7 @@ /* * Flash on MPC-1211 * - * $Id: mpc1211.c,v 1.3 2004/07/14 17:45:40 dwmw2 Exp $ + * $Id: mpc1211.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $ * * (C) 2002 Interface, Saito.K & Jeanne * @@ -44,7 +44,7 @@ static int __init init_mpc1211_maps(void) int nr_parts; mpc1211_flash_map.phys = 0; - mpc1211_flash_map.virt = P2SEGADDR(0); + mpc1211_flash_map.virt = (void __iomem *)P2SEGADDR(0); simple_map_init(&mpc1211_flash_map); diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index afdf6589bfbe..c91115868a15 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -3,7 +3,7 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.10 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: netsc520.c,v 1.11 2004/09/16 23:27:13 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -95,7 +95,7 @@ static struct mtd_info *mymtd; static int __init init_netsc520(void) { printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys); - netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size); + netsc520_map.virt = (void __iomem *)ioremap_nocache(netsc520_map.phys, netsc520_map.size); if (!netsc520_map.virt) { printk("Failed to ioremap_nocache\n"); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 38a81462ff4c..8541d9b75de6 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -6,7 +6,7 @@ * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) * - * $Id: nettel.c,v 1.5 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: nettel.c,v 1.7 2004/10/20 22:17:30 dwmw2 Exp $ */ /****************************************************************************/ @@ -273,8 +273,7 @@ int __init nettel_init(void) __asm__ ("wbinvd"); nettel_amd_map.phys = amdaddr; - nettel_amd_map.virt = (unsigned long) - ioremap_nocache(amdaddr, maxsize); + nettel_amd_map.virt = (void __iomem *) ioremap_nocache(amdaddr, maxsize); if (!nettel_amd_map.virt) { printk("SNAPGEAR: failed to ioremap() BOOTCS\n"); return(-EIO); diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c index 40c524d62047..eb5a00316b23 100644 --- a/drivers/mtd/maps/ocelot.c +++ b/drivers/mtd/maps/ocelot.c @@ -1,5 +1,5 @@ /* - * $Id: ocelot.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: ocelot.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $ * * Flash on Momenco Ocelot */ @@ -81,7 +81,7 @@ static int __init init_ocelot_maps(void) iounmap(pld); /* Now ioremap the NVRAM space */ - ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); + ocelot_nvram_map.virt = (void __iomem *)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); if (!ocelot_nvram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); return -EIO; @@ -101,7 +101,7 @@ static int __init init_ocelot_maps(void) nvram_mtd->write = ocelot_ram_write; /* Now map the flash space */ - ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); + ocelot_flash_map.virt = (void __iomem *)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); if (!ocelot_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); goto fail_2; diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index 4262f1c03c09..496109071cb1 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c @@ -5,7 +5,7 @@ * * (C) 2002 MontVista Software, Inc. * - * $Id: omap-toto-flash.c,v 1.2 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $ */ #include @@ -35,7 +35,7 @@ static struct map_info omap_toto_map_flash = { .name = "OMAP Toto flash", .bankwidth = 2, - .virt = OMAP_TOTO_FLASH_BASE, + .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, }; diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c index 4747fbc1fa79..ebc54a65f7ee 100644 --- a/drivers/mtd/maps/pb1550-flash.c +++ b/drivers/mtd/maps/pb1550-flash.c @@ -1,7 +1,7 @@ /* * Flash memory access on Alchemy Pb1550 board * - * $Id: pb1550-flash.c,v 1.4 2004/07/14 17:45:40 dwmw2 Exp $ + * $Id: pb1550-flash.c,v 1.5 2004/09/16 23:27:13 gleixner Exp $ * * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c: * (C) 2003 Pete Popov @@ -179,7 +179,7 @@ int __init pb1550_mtd_init(void) printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", pb1550_map.bankwidth*8); pb1550_map.virt = - (unsigned long)ioremap(window_addr, window_size); + (void __iomem *)ioremap(window_addr, window_size); mymtd = do_map_probe("cfi_probe", &pb1550_map); if (!mymtd) return -ENXIO; mymtd->owner = THIS_MODULE; diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c index b6b8ccf48d9f..1971208dc330 100644 --- a/drivers/mtd/maps/pb1xxx-flash.c +++ b/drivers/mtd/maps/pb1xxx-flash.c @@ -3,7 +3,7 @@ * * (C) 2001 Pete Popov * - * $Id: pb1xxx-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: pb1xxx-flash.c,v 1.13 2004/09/26 07:33:01 ppopov Exp $ */ #include @@ -17,7 +17,6 @@ #include #include -#include #ifdef DEBUG_RW #define DBG(x...) printk(x) @@ -150,7 +149,7 @@ int __init pb1xxx_mtd_init(void) */ printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", BUSWIDTH*8); - pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + pb1xxx_mtd_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE); simple_map_init(&pb1xxx_mtd_map); diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 5822ba99c195..a57a672884e9 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -1,5 +1,5 @@ /* - * $Id: physmap.c,v 1.34 2004/07/21 00:16:14 jwboyer Exp $ + * $Id: physmap.c,v 1.35 2004/09/16 23:27:13 gleixner Exp $ * * Normal mappings of chips in physical memory * @@ -51,7 +51,7 @@ static int __init init_physmap(void) const char **type; printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys); - physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size); + physmap_map.virt = (void __iomem *)ioremap(physmap_map.phys, physmap_map.size); if (!physmap_map.virt) { printk("Failed to ioremap\n"); diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c index b204786d52f8..3636d5a23c9a 100644 --- a/drivers/mtd/maps/pnc2000.c +++ b/drivers/mtd/maps/pnc2000.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: pnc2000.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: pnc2000.c,v 1.16 2004/09/16 23:27:13 gleixner Exp $ */ #include @@ -31,7 +31,7 @@ struct map_info pnc_map = { .size = WINDOW_SIZE, .bankwidth = 4, .phys = 0xFFFFFFFF, - .virt = WINDOW_ADDR, + .virt = (void __iomem *)WINDOW_ADDR, }; diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index acc3af90ad5c..00a518d43a88 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -1,5 +1,5 @@ /* - * $Id: redwood.c,v 1.8 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: redwood.c,v 1.9 2004/09/16 23:27:13 gleixner Exp $ * * drivers/mtd/maps/redwood.c * @@ -132,7 +132,7 @@ int __init init_redwood_flash(void) WINDOW_SIZE, WINDOW_ADDR); redwood_flash_map.virt = - (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!redwood_flash_map.virt) { printk("init_redwood_flash: failed to ioremap\n"); diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c index 837089a8f13d..24ca248dd460 100644 --- a/drivers/mtd/maps/rpxlite.c +++ b/drivers/mtd/maps/rpxlite.c @@ -1,5 +1,5 @@ /* - * $Id: rpxlite.c,v 1.20 2004/07/12 21:59:44 dwmw2 Exp $ + * $Id: rpxlite.c,v 1.21 2004/09/16 23:27:13 gleixner Exp $ * * Handle mapping of the flash on the RPX Lite and CLLF boards */ @@ -28,7 +28,7 @@ static struct map_info rpxlite_map = { int __init init_rpxlite(void) { printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); - rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + rpxlite_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); if (!rpxlite_map.virt) { printk("Failed to ioremap\n"); diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 7a9cb1d45348..bb1823121cf0 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.29 2004/07/12 22:38:29 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.30 2004/09/16 23:27:14 gleixner Exp $ The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. @@ -84,7 +84,7 @@ separate MTD devices. // Globals static volatile int page_in_window = -1; // Current page in window. -static unsigned long iomapadr; +static void __iomem *iomapadr; static spinlock_t sbc_gxx_spin = SPIN_LOCK_UNLOCKED; /* partition_info gives details on the logical partitions that the split the @@ -195,7 +195,7 @@ static void cleanup_sbc_gxx(void) int __init init_sbc_gxx(void) { - iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); + iomapadr = (void __iomem *)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", sbc_gxx_map.name ); diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 8269b6029c17..adb8f120b8dd 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.16 2004/07/12 21:59:45 dwmw2 Exp $ + * $Id: sc520cdp.c,v 1.17 2004/09/16 23:27:14 gleixner Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -241,7 +241,7 @@ static int __init init_sc520cdp(void) printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", sc520cdp_map[i].size, sc520cdp_map[i].phys); - sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); + sc520cdp_map[i].virt = (void __iomem *)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); if (!sc520cdp_map[i].virt) { printk("Failed to ioremap_nocache\n"); diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index ff2328dbbc8c..288e4e19eb72 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -1,6 +1,6 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $Id: scb2_flash.c,v 1.8 2004/07/12 21:59:45 dwmw2 Exp $ + * $Id: scb2_flash.c,v 1.9 2004/09/16 23:27:14 gleixner Exp $ * Copyright (C) 2002 Sun Microsystems, Inc. * Tim Hockin * @@ -163,7 +163,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) } scb2_map.phys = SCB2_ADDR; - scb2_map.virt = (unsigned long)scb2_ioaddr; + scb2_map.virt = (void __iomem *)scb2_ioaddr; scb2_map.size = SCB2_WINDOW; simple_map_init(&scb2_map); diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 58855a15e3eb..031ad2e83029 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c @@ -2,7 +2,7 @@ Copyright (c) 2001,2002 Christer Weinigel - $Id: scx200_docflash.c,v 1.6 2004/07/12 21:59:45 dwmw2 Exp $ + $Id: scx200_docflash.c,v 1.7 2004/09/16 23:27:14 gleixner Exp $ National Semiconductor SCx200 flash mapped with DOCCS */ @@ -180,7 +180,7 @@ int __init init_scx200_docflash(void) simple_map_init(&scx200_docflash_map); scx200_docflash_map.phys = docmem.start; - scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); + scx200_docflash_map.virt = (void __iomem *)ioremap(docmem.start, scx200_docflash_map.size); if (!scx200_docflash_map.virt) { printk(KERN_ERR NAME ": failed to ioremap the flash\n"); release_resource(&docmem); diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index 9b2eebe1b97b..8ce5d897645c 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.13 2004/07/12 21:59:45 dwmw2 Exp $ + * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -62,9 +62,9 @@ static int __init init_soleng_maps(void) /* First probe at offset 0 */ soleng_flash_map.phys = 0; - soleng_flash_map.virt = P2SEGADDR(0); + soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0); soleng_eprom_map.phys = 0x01000000; - soleng_eprom_map.virt = P1SEGADDR(0x01000000); + soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); simple_map_init(&soleng_eprom_map); simple_map_init(&soleng_flash_map); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 2a9932c50959..4398538ed07d 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -1,4 +1,4 @@ -/* $Id: sun_uflash.c,v 1.9 2004/07/12 21:59:45 dwmw2 Exp $ +/* $Id: sun_uflash.c,v 1.10 2004/09/16 23:27:14 gleixner Exp $ * * sun_uflash - Driver implementation for user-programmable flash * present on many Sun Microsystems SME boardsets. @@ -97,7 +97,7 @@ int uflash_devinit(struct linux_ebus_device* edev) } pdev->map.phys = edev->resource[0].start; pdev->map.virt = - (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size); + (void __iomem *)ioremap_nocache(edev->resource[0].start, pdev->map.size); if(0 == pdev->map.virt) { printk("%s: failed to map device\n", __FUNCTION__); kfree(pdev->name); diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index baff49bf7df3..27af674e0b03 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -5,7 +5,7 @@ * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) * - * $Id: uclinux.c,v 1.7 2004/07/12 21:59:45 dwmw2 Exp $ + * $Id: uclinux.c,v 1.8 2004/09/16 23:27:14 gleixner Exp $ */ /****************************************************************************/ @@ -69,9 +69,10 @@ int __init uclinux_mtd_init(void) printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", (int) mapp->map_priv_2, (int) mapp->size); - mapp->virt = ioremap_nocache(mapp->phys, mapp->size); + mapp->virt = (void __iomem *) + ioremap_nocache(mapp->phys, mapp->size); - if (!mapp->virt) { + if (mapp->virt == 0) { printk("uclinux[mtd]: ioremap_nocache() failed\n"); return(-EIO); } @@ -81,7 +82,7 @@ int __init uclinux_mtd_init(void) mtd = do_map_probe("map_ram", mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); - iounmap(mapp->virt); + iounmap((void *) mapp->virt); return(-ENXIO); } diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index b7fdece51650..02b1b56f4858 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -1,5 +1,5 @@ /* - * $Id: wr_sbc82xx_flash.c,v 1.5 2004/07/15 14:52:02 dwmw2 Exp $ + * $Id: wr_sbc82xx_flash.c,v 1.6 2004/09/16 23:27:14 gleixner Exp $ * * Map for flash chips on Wind River PowerQUICC II SBC82xx board. * @@ -116,7 +116,7 @@ int __init init_sbc82xx_flash(void) } printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); - sbc82xx_flash_map[i].virt = (unsigned long)ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); + sbc82xx_flash_map[i].virt = (void __iomem *)ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); if (!sbc82xx_flash_map[i].virt) { printk("Failed to ioremap\n"); diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 0fd8f49c649b..bc58c4f55ab0 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -6,7 +6,7 @@ * Copyright (C) 2002-2003 Greg Ungerer * Copyright (C) 2002-2003 SnapGear Inc * - * $Id: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $ + * $Id: doc2000.h,v 1.23 2004/09/16 23:26:08 gleixner Exp $ * * Released under GPL */ @@ -89,8 +89,8 @@ #define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x4000 #else -#define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg)) -#define WriteDOC_(d, adr, reg) writeb(d, ((unsigned long)adr) + (reg)) +#define ReadDOC_(adr, reg) readb((void __iomem *)(((unsigned long)adr) + (reg))) +#define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(((unsigned long)adr) + (reg))) #define DOC_IOREMAP_LEN 0x2000 #endif @@ -168,7 +168,7 @@ struct Nand { struct DiskOnChip { unsigned long physadr; - unsigned long virtadr; + void __iomem *virtadr; unsigned long totlen; unsigned char ChipID; /* Type of DiskOnChip */ int ioreg; -- cgit v1.2.3 From 8eb2a259ae800d553296d0a1b6b2cd6ebff6c569 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 21 Oct 2004 01:50:36 +0100 Subject: MTD map access: Fix calculation of the number of longs in a bus access Patch from Ben Dooks Signed-Off-By: David Woodhouse --- include/linux/mtd/map.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 278d0f30de20..a960be2cc33c 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.43 2004/07/14 13:30:27 dwmw2 Exp $ */ +/* $Id: map.h,v 1.45 2004/09/21 14:31:17 bjd Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,11 @@ #define map_bankwidth_is_4(map) (0) #endif +/* ensure we never evaluate anything shorted than an unsigned long + * to zero, and ensure we'll never miss the end of an comparison (bjd) */ + +#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long)) + #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 # ifdef map_bankwidth # undef map_bankwidth @@ -63,12 +69,12 @@ # undef map_bankwidth_is_large # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) # undef map_words -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # endif # else # define map_bankwidth(map) 8 # define map_bankwidth_is_large(map) (BITS_PER_LONG < 64) -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # endif #define map_bankwidth_is_8(map) (map_bankwidth(map) == 8) #undef MAX_MAP_BANKWIDTH @@ -84,11 +90,11 @@ # undef map_bankwidth_is_large # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) # undef map_words -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # else # define map_bankwidth(map) 16 # define map_bankwidth_is_large(map) (1) -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # endif #define map_bankwidth_is_16(map) (map_bankwidth(map) == 16) #undef MAX_MAP_BANKWIDTH @@ -104,11 +110,11 @@ # undef map_bankwidth_is_large # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) # undef map_words -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # else # define map_bankwidth(map) 32 # define map_bankwidth_is_large(map) (1) -# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long)) +# define map_words(map) map_calc_words(map) # endif #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32) #undef MAX_MAP_BANKWIDTH -- cgit v1.2.3 From 637465e067650cadceadd427af6b869a9a8fce70 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 21 Oct 2004 02:13:45 +0100 Subject: MTD: NOR flash chip driver updates Mostly from Eric Biederman for supporting BIOS flash. - Move support firmware hub style lock and unlock into fhw_lock.h (from cfi_cmdset_0002) - Move cfi_varsize_frob into cfi_util from cfi_cmdset_0001.c and cfi_cmdset_0002.c - reduce gen_probe probe failuers to a debug level message - Modify cfi_fixup to take a struct mtd_info instead of a struct map_info So that the fixup routines can modify the mtd functions. - Modify cfi_cmdset_0001() to allocate and initialize the mtd structure before calling cfi_fixup. - Modify cfi_cmdset_0002() to allocate and initialize the mtd structure before calling cfi_fixup. - Refactor the hard coded fixups in cfi_cmdset_0001 and cfi_cmdset_0002 so the improved cfi_fixup infrastructure. - Rewrote amd76xrom and ichxrom. They now report their starting physical address in their name. They now both handle multiple bankwidth configurations They both can create multipe mtd devices. They both now assume the rom windows are properly opened by the BIOS or whatever runs previous to them. Their code is now synchromized so it is almost identical, and could be a starting point for a x86_rom_probe. Signed-Off-By: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 283 ++++++++------------ drivers/mtd/chips/cfi_cmdset_0002.c | 504 ++++++++++-------------------------- drivers/mtd/chips/cfi_probe.c | 21 +- drivers/mtd/chips/cfi_util.c | 102 +++++++- drivers/mtd/chips/fwh_lock.h | 107 ++++++++ drivers/mtd/chips/gen_probe.c | 12 +- drivers/mtd/chips/jedec_probe.c | 178 ++++++++----- drivers/mtd/maps/amd76xrom.c | 382 +++++++++++++++------------ drivers/mtd/maps/ichxrom.c | 494 +++++++++++++++++------------------ include/linux/mtd/cfi.h | 40 ++- 10 files changed, 1067 insertions(+), 1056 deletions(-) create mode 100644 drivers/mtd/chips/fwh_lock.h (limited to 'include/linux') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c1e3536c2147..cca36dd074a5 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.154 2004/08/09 13:19:43 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.157 2004/10/15 20:00:26 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -39,6 +39,12 @@ // debugging, turns off buffer write mode if set to 1 #define FORCE_WORD_WRITE 0 +#define MANUFACTURER_INTEL 0x0089 +#define I82802AB 0x00ad +#define I82802AC 0x00ac +#define MANUFACTURER_ST 0x0020 +#define M50LPW080 0x002F + static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); //static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); //static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -55,7 +61,7 @@ static void cfi_intelext_destroy(struct mtd_info *); struct mtd_info *cfi_cmdset_0001(struct map_info *, int); -static struct mtd_info *cfi_intelext_setup (struct map_info *); +static struct mtd_info *cfi_intelext_setup (struct mtd_info *); static int cfi_intelext_partition_fixup(struct map_info *, struct cfi_private **); static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, @@ -63,6 +69,11 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len); +static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); +static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); +#include "fwh_lock.h" + + /* * *********** SETUP AND PROBE BITS *********** @@ -123,8 +134,9 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -static void fixup_intel_strataflash(struct map_info *map, void* param) +static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_amdstd *extp = cfi->cmdset_priv; @@ -134,16 +146,18 @@ static void fixup_intel_strataflash(struct map_info *map, void* param) } #endif -static void fixup_st_m28w320ct(struct map_info *map, void* param) +static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ } -static void fixup_st_m28w320cb(struct map_info *map, void* param) +static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; /* Note this is done after the region info is endian swapped */ @@ -151,24 +165,51 @@ static void fixup_st_m28w320cb(struct map_info *map, void* param) (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; }; -static struct cfi_fixup fixup_table[] = { +static void fixup_use_point(struct mtd_info *mtd, void *param) +{ + struct map_info *map = mtd->priv; + if (!mtd->point && map_is_linear(map)) { + mtd->point = cfi_intelext_point; + mtd->unpoint = cfi_intelext_unpoint; + } +} + +static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + if (cfi->cfiq->BufWriteTimeoutTyp) { + printk(KERN_INFO "Using buffer write method\n" ); + mtd->write = cfi_intelext_write_buffers; + } +} + +static struct cfi_fixup cfi_fixup_table[] = { #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - { - CFI_MFR_ANY, CFI_ID_ANY, - fixup_intel_strataflash, NULL - }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, #endif - { - 0x0020, /* STMicroelectronics */ - 0x00ba, /* M28W320CT */ - fixup_st_m28w320ct, NULL - }, { - 0x0020, /* STMicroelectronics */ - 0x00bb, /* M28W320CB */ - fixup_st_m28w320cb, NULL - }, { - 0, 0, NULL, NULL - } +#if !FORCE_WORD_WRITE + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, +#endif + { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, + { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, + { 0, 0, NULL, NULL } +}; + +static struct cfi_fixup jedec_fixup_table[] = { + { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, + { 0, 0, NULL, NULL } +}; +static struct cfi_fixup fixup_table[] = { + /* The CFI vendor ids and the JEDEC vendor IDs appear + * to be common. It is like the devices id's are as + * well. This table is to pick all cases where + * we know that is the case. + */ + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, + { 0, 0, NULL, NULL } }; /* This routine is made available to other mtd code via @@ -181,8 +222,30 @@ static struct cfi_fixup fixup_table[] = { struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; + struct mtd_info *mtd; int i; + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) { + printk(KERN_ERR "Failed to allocate memory for MTD device\n"); + return NULL; + } + memset(mtd, 0, sizeof(*mtd)); + mtd->priv = map; + mtd->type = MTD_NORFLASH; + + /* Fill in the default mtd operations */ + mtd->erase = cfi_intelext_erase_varsize; + mtd->read = cfi_intelext_read; + mtd->write = cfi_intelext_write_words; + mtd->sync = cfi_intelext_sync; + mtd->lock = cfi_intelext_lock; + mtd->unlock = cfi_intelext_unlock; + mtd->suspend = cfi_intelext_suspend; + mtd->resume = cfi_intelext_resume; + mtd->flags = MTD_CAP_NORFLASH; + mtd->name = map->name; + if (cfi->cfi_mode == CFI_MODE_CFI) { /* * It's a real CFI chip, not one for which the probe @@ -193,8 +256,10 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) struct cfi_pri_intelext *extp; extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp"); - if (!extp) + if (!extp) { + kfree(mtd); return NULL; + } /* Do some byteswapping if necessary */ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); @@ -204,7 +269,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) /* Install our own private info structure */ cfi->cmdset_priv = extp; - cfi_fixup(map, fixup_table); + cfi_fixup(mtd, cfi_fixup_table); #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ @@ -215,6 +280,12 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); } } + else if (cfi->cfi_mode == CFI_MODE_JEDEC) { + /* Apply jedec specific fixups */ + cfi_fixup(mtd, jedec_fixup_table); + } + /* Apply generic fixups */ + cfi_fixup(mtd, fixup_table); for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<cfiq->WordWriteTimeoutTyp; @@ -225,28 +296,19 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) map->fldrv = &cfi_intelext_chipdrv; - return cfi_intelext_setup(map); + return cfi_intelext_setup(mtd); } -static struct mtd_info *cfi_intelext_setup(struct map_info *map) +static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct mtd_info *mtd; unsigned long offset = 0; int i,j; unsigned long devsize = (1<cfiq->DevSize) * cfi->interleave; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); - if (!mtd) { - printk(KERN_ERR "Failed to allocate memory for MTD device\n"); - goto setup_err; - } - - memset(mtd, 0, sizeof(*mtd)); - mtd->priv = map; - mtd->type = MTD_NORFLASH; mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; @@ -286,34 +348,10 @@ static struct mtd_info *cfi_intelext_setup(struct map_info *map) mtd->eraseregions[i].numblocks); } - /* Also select the correct geometry setup too */ - mtd->erase = cfi_intelext_erase_varsize; - mtd->read = cfi_intelext_read; - - if (map_is_linear(map)) { - mtd->point = cfi_intelext_point; - mtd->unpoint = cfi_intelext_unpoint; - } - - if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { - printk(KERN_INFO "Using buffer write method\n" ); - mtd->write = cfi_intelext_write_buffers; - } else { - printk(KERN_INFO "Using word write method\n" ); - mtd->write = cfi_intelext_write_words; - } #if 0 mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; #endif - mtd->sync = cfi_intelext_sync; - mtd->lock = cfi_intelext_lock; - mtd->unlock = cfi_intelext_unlock; - mtd->suspend = cfi_intelext_suspend; - mtd->resume = cfi_intelext_resume; - mtd->flags = MTD_CAP_NORFLASH; - map->fldrv = &cfi_intelext_chipdrv; - mtd->name = map->name; /* This function has the potential to distort the reality a bit and therefore should be called last. */ @@ -515,7 +553,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr return 0; case FL_ERASING: - if (!(cfip->FeatureSupport & 2) || + if (!cfip || + !(cfip->FeatureSupport & 2) || !(mode == FL_READY || mode == FL_POINT || (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) goto sleep; @@ -884,7 +923,7 @@ static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, s int base_offst,reg_sz; /* Check that we actually have some protection registers */ - if(!(extp->FeatureSupport&64)){ + if(!extp || !(extp->FeatureSupport&64)){ printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); return 0; } @@ -903,7 +942,7 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, s int base_offst,reg_sz; /* Check that we actually have some protection registers */ - if(!(extp->FeatureSupport&64)){ + if(!extp || !(extp->FeatureSupport&64)){ printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); return 0; } @@ -1308,102 +1347,6 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, return 0; } -typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, - unsigned long adr, int len, void *thunk); - -static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, - loff_t ofs, size_t len, void *thunk) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr; - int chipnum, ret = 0; - int i, first; - struct mtd_erase_region_info *regions = mtd->eraseregions; - - if (ofs > mtd->size) - return -EINVAL; - - if ((len + ofs) > mtd->size) - return -EINVAL; - - /* Check that both start and end of the requested erase are - * aligned with the erasesize at the appropriate addresses. - */ - - i = 0; - - /* Skip all erase regions which are ended before the start of - the requested erase. Actually, to save on the calculations, - we skip to the first erase region which starts after the - start of the requested erase, and then go back one. - */ - - while (i < mtd->numeraseregions && ofs >= regions[i].offset) - i++; - i--; - - /* OK, now i is pointing at the erase region in which this - erase request starts. Check the start of the requested - erase range is aligned with the erase size which is in - effect here. - */ - - if (ofs & (regions[i].erasesize-1)) - return -EINVAL; - - /* Remember the erase region we start on */ - first = i; - - /* Next, check that the end of the requested erase is aligned - * with the erase region at that address. - */ - - while (inumeraseregions && (ofs + len) >= regions[i].offset) - i++; - - /* As before, drop back one to point at the region in which - the address actually falls - */ - i--; - - if ((ofs + len) & (regions[i].erasesize-1)) - return -EINVAL; - - chipnum = ofs >> cfi->chipshift; - adr = ofs - (chipnum << cfi->chipshift); - - i=first; - - while(len) { - unsigned long chipmask; - int size = regions[i].erasesize; - - ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); - - if (ret) - return ret; - - adr += size; - len -= size; - - chipmask = (1 << cfi->chipshift) - 1; - if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask)) - i++; - - if (adr >> cfi->chipshift) { - adr = 0; - chipnum++; - - if (chipnum >= cfi->numchips) - break; - } - } - - return 0; -} - - static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { @@ -1550,7 +1493,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) ofs = instr->addr; len = instr->len; - ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); + ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); if (ret) return ret; @@ -1695,18 +1638,18 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); - cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + cfi_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif - ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, - ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); + ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, + ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); - cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + cfi_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif return ret; @@ -1719,18 +1662,18 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", __FUNCTION__, ofs, len); - cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + cfi_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif - ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, + ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); - cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, - ofs, len, 0); + cfi_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif return ret; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 5bd15f548f22..1f9fe2ae780b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -13,7 +13,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.106 2004/08/09 14:02:32 dwmw2 Exp $ + * $Id: cfi_cmdset_0002.c,v 1.110 2004/09/24 04:26:04 eric Exp $ * */ @@ -40,13 +40,15 @@ #define MAX_WORD_RETRIES 3 +#define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_SST 0x00BF +#define SST49LF004B 0x0060 + static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); -static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t); -static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t); static void cfi_amdstd_sync (struct mtd_info *); static int cfi_amdstd_suspend (struct mtd_info *); static void cfi_amdstd_resume (struct mtd_info *); @@ -55,8 +57,11 @@ static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u static void cfi_amdstd_destroy(struct mtd_info *); struct mtd_info *cfi_cmdset_0002(struct map_info *, int); -static struct mtd_info *cfi_amdstd_setup (struct map_info *); +static struct mtd_info *cfi_amdstd_setup (struct mtd_info *); +static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); +static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); +#include "fwh_lock.h" static struct mtd_chip_driver cfi_amdstd_chipdrv = { .probe = NULL, /* Not usable directly */ @@ -66,7 +71,6 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = { }; -/* #define DEBUG_LOCK_BITS */ /* #define DEBUG_CFI_FEATURES */ @@ -122,8 +126,9 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) #ifdef AMD_BOOTLOC_BUG /* Wheee. Bring me the head of someone at AMD. */ -static void fixup_amd_bootblock(struct map_info *map, void* param) +static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_amdstd *extp = cfi->cmdset_priv; __u8 major = extp->MajorVersion; @@ -141,25 +146,92 @@ static void fixup_amd_bootblock(struct map_info *map, void* param) } #endif -static struct cfi_fixup fixup_table[] = { +static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + if (cfi->cfiq->BufWriteTimeoutTyp) { + DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); + mtd->write = cfi_amdstd_write_buffers; + } +} + +static void fixup_use_secsi(struct mtd_info *mtd, void *param) +{ + /* Setup for chips with a secsi area */ + mtd->read_user_prot_reg = cfi_amdstd_secsi_read; + mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; +} + +static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + if ((cfi->cfiq->NumEraseRegions == 1) && + ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { + mtd->erase = cfi_amdstd_erase_chip; + } + +} + +static struct cfi_fixup cfi_fixup_table[] = { #ifdef AMD_BOOTLOC_BUG - { - 0x0001, /* AMD */ - CFI_ID_ANY, - fixup_amd_bootblock, NULL - }, + { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, +#endif + { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, +#if !FORCE_WORD_WRITE + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, #endif { 0, 0, NULL, NULL } }; +static struct cfi_fixup jedec_fixup_table[] = { + { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, + { 0, 0, NULL, NULL } +}; + +static struct cfi_fixup fixup_table[] = { + /* The CFI vendor ids and the JEDEC vendor IDs appear + * to be common. It is like the devices id's are as + * well. This table is to pick all cases where + * we know that is the case. + */ + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, + { 0, 0, NULL, NULL } +}; struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; - unsigned char bootloc; + struct mtd_info *mtd; int i; + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) { + printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); + return NULL; + } + memset(mtd, 0, sizeof(*mtd)); + mtd->priv = map; + mtd->type = MTD_NORFLASH; + + /* Fill in the default mtd operations */ + mtd->erase = cfi_amdstd_erase_varsize; + mtd->write = cfi_amdstd_write_words; + mtd->read = cfi_amdstd_read; + mtd->sync = cfi_amdstd_sync; + mtd->suspend = cfi_amdstd_suspend; + mtd->resume = cfi_amdstd_resume; + mtd->flags = MTD_CAP_NORFLASH; + mtd->name = map->name; + if (cfi->cfi_mode==CFI_MODE_CFI){ + unsigned char bootloc; /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature @@ -169,13 +241,16 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) struct cfi_pri_amdstd *extp; extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); - if (!extp) + if (!extp) { + kfree(mtd); return NULL; + } /* Install our own private info structure */ cfi->cmdset_priv = extp; - cfi_fixup(map, fixup_table); + /* Apply cfi device specific fixups */ + cfi_fixup(mtd, cfi_fixup_table); #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ @@ -201,43 +276,28 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) cfi->cfiq->EraseRegionInfo[j] = swap; } } - /* - * These might already be setup (more correctly) by - * jedec_probe.c - still need it for cfi_probe.c path. - */ - if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) { - switch (cfi->device_type) { - case CFI_DEVICETYPE_X8: - cfi->addr_unlock1 = 0x555; - cfi->addr_unlock2 = 0x2aa; - break; - case CFI_DEVICETYPE_X16: - cfi->addr_unlock1 = 0xaaa; - if (map_bankwidth(map) == cfi_interleave(cfi)) { - /* X16 chip(s) in X8 mode */ - cfi->addr_unlock2 = 0x555; - } else { - cfi->addr_unlock2 = 0x554; - } - break; - case CFI_DEVICETYPE_X32: - cfi->addr_unlock1 = 0x1554; - if (map_bankwidth(map) == cfi_interleave(cfi)*2) { - /* X32 chip(s) in X16 mode */ - cfi->addr_unlock1 = 0xaaa; - } else { - cfi->addr_unlock2 = 0xaa8; - } - break; - default: - printk(KERN_WARNING - "MTD %s(): Unsupported device type %d\n", - __func__, cfi->device_type); - return NULL; - } + /* Set the default CFI lock/unlock addresses */ + cfi->addr_unlock1 = 0x555; + cfi->addr_unlock2 = 0x2aa; + /* Modify the unlock address if we are in compatibility mode */ + if ( /* x16 in x8 mode */ + ((cfi->device_type == CFI_DEVICETYPE_X8) && + (cfi->cfiq->InterfaceDesc == 2)) || + /* x32 in x16 mode */ + ((cfi->device_type == CFI_DEVICETYPE_X16) && + (cfi->cfiq->InterfaceDesc == 4))) + { + cfi->addr_unlock1 = 0xaaa; + cfi->addr_unlock2 = 0x555; } } /* CFI mode */ + else if (cfi->cfi_mode == CFI_MODE_JEDEC) { + /* Apply jedec specific fixups */ + cfi_fixup(mtd, jedec_fixup_table); + } + /* Apply generic fixups */ + cfi_fixup(mtd, fixup_table); for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<cfiq->WordWriteTimeoutTyp; @@ -246,32 +306,22 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) } map->fldrv = &cfi_amdstd_chipdrv; - - return cfi_amdstd_setup(map); + + return cfi_amdstd_setup(mtd); } -static struct mtd_info *cfi_amdstd_setup(struct map_info *map) +static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - struct mtd_info *mtd; unsigned long devsize = (1<cfiq->DevSize) * cfi->interleave; unsigned long offset = 0; int i,j; - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); - - if (!mtd) { - printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); - goto setup_err; - } - - memset(mtd, 0, sizeof(*mtd)); - mtd->priv = map; - mtd->type = MTD_NORFLASH; - /* Also select the correct geometry setup too */ + /* Select the correct geometry setup */ mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; @@ -312,54 +362,10 @@ static struct mtd_info *cfi_amdstd_setup(struct map_info *map) } #endif - if (mtd->numeraseregions == 1 - && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) { - mtd->erase = cfi_amdstd_erase_chip; - } else { - mtd->erase = cfi_amdstd_erase_varsize; - mtd->lock = cfi_amdstd_lock_varsize; - mtd->unlock = cfi_amdstd_unlock_varsize; - } - - if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { - DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); - mtd->write = cfi_amdstd_write_buffers; - } else { - DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" ); - mtd->write = cfi_amdstd_write_words; - } - - mtd->read = cfi_amdstd_read; - /* FIXME: erase-suspend-program is broken. See http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n"); - /* does this chip have a secsi area? */ - if(cfi->mfr==1){ - - switch(cfi->id){ - case 0x50: - case 0x53: - case 0x55: - case 0x56: - case 0x5C: - case 0x5F: - /* Yes */ - mtd->read_user_prot_reg = cfi_amdstd_secsi_read; - mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; - default: - ; - } - } - - - mtd->sync = cfi_amdstd_sync; - mtd->suspend = cfi_amdstd_suspend; - mtd->resume = cfi_amdstd_resume; - mtd->flags = MTD_CAP_NORFLASH; - map->fldrv = &cfi_amdstd_chipdrv; - mtd->name = map->name; __module_get(THIS_MODULE); return mtd; @@ -434,6 +440,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr goto sleep; if (!(mode == FL_READY || mode == FL_POINT + || !cfip || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)) || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)))) goto sleep; @@ -624,14 +631,12 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi chip->state = FL_READY; - /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); map_copy_from(map, buf, adr, len); - /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -732,17 +737,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned ENABLE_VPP(map); retry: - /* - * The CFI_DEVICETYPE_X8 argument is needed even when - * cfi->device_type != CFI_DEVICETYPE_X8. The addresses for - * command sequences don't scale even when the device is - * wider. This is the case for many of the cfi_send_gen_cmd() - * below. I'm not sure, however, why some use - * cfi->device_type. - */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); map_write(map, datum, adr); chip->state = FL_WRITING; @@ -958,7 +955,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; /* see comments in do_write_oneword() regarding uWriteTimeo. */ - static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; + unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; int ret = -EIO; unsigned long cmd_adr; int z, words; @@ -980,9 +977,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, __func__, adr, datum.x[0] ); ENABLE_VPP(map); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); /* Write Buffer Load */ map_write(map, CMD(0x25), cmd_adr); @@ -1081,8 +1078,8 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, size_t local_len = (-ofs)&(map_bankwidth(map)-1); if (local_len > len) local_len = len; - ret = cfi_amdstd_write_words(mtd, to, local_len, - retlen, buf); + ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<chipshift), + local_len, retlen, buf); if (ret) return ret; ofs += local_len; @@ -1128,7 +1125,8 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, if (len) { size_t retlen_dregs = 0; - ret = cfi_amdstd_write_words(mtd, to, len, &retlen_dregs, buf); + ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<chipshift), + len, &retlen_dregs, buf); *retlen += retlen_dregs; return ret; @@ -1163,12 +1161,12 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) __func__, chip->start ); ENABLE_VPP(map); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); chip->state = FL_ERASING; chip->erase_suspended = 0; @@ -1229,100 +1227,7 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } -typedef int (*frob_t)(struct map_info *map, struct flchip *chip, - unsigned long adr, void *thunk); - - -static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob, - loff_t ofs, size_t len, void *thunk) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr; - int chipnum, ret = 0; - int i, first; - struct mtd_erase_region_info *regions = mtd->eraseregions; - - if (ofs > mtd->size) - return -EINVAL; - - if ((len + ofs) > mtd->size) - return -EINVAL; - - /* Check that both start and end of the requested erase are - * aligned with the erasesize at the appropriate addresses. - */ - - i = 0; - - /* Skip all erase regions which are ended before the start of - the requested erase. Actually, to save on the calculations, - we skip to the first erase region which starts after the - start of the requested erase, and then go back one. - */ - - while (i < mtd->numeraseregions && ofs >= regions[i].offset) - i++; - i--; - - /* OK, now i is pointing at the erase region in which this - erase request starts. Check the start of the requested - erase range is aligned with the erase size which is in - effect here. - */ - - if (ofs & (regions[i].erasesize-1)) - return -EINVAL; - - /* Remember the erase region we start on */ - first = i; - - /* Next, check that the end of the requested erase is aligned - * with the erase region at that address. - */ - - while (inumeraseregions && (ofs + len) >= regions[i].offset) - i++; - - /* As before, drop back one to point at the region in which - the address actually falls - */ - i--; - - if ((ofs + len) & (regions[i].erasesize-1)) - return -EINVAL; - - chipnum = ofs >> cfi->chipshift; - adr = ofs - (chipnum << cfi->chipshift); - - i=first; - - while (len) { - ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk); - - if (ret) - return ret; - - adr += regions[i].erasesize; - len -= regions[i].erasesize; - - if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) - i++; - - if (adr >> cfi->chipshift) { - adr = 0; - chipnum++; - - if (chipnum >= cfi->numchips) - break; - } - } - - return 0; -} - - -static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) +static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -1342,11 +1247,11 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u __func__, adr ); ENABLE_VPP(map); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); map_write(map, CMD(0x30), adr); chip->state = FL_ERASING; @@ -1415,7 +1320,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) ofs = instr->addr; len = instr->len; - ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); + ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); if (ret) return ret; @@ -1588,137 +1493,6 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) } } - -#ifdef DEBUG_LOCK_BITS - -static int do_printlockstatus_oneblock(struct map_info *map, - struct flchip *chip, - unsigned long adr, - void *thunk) -{ - struct cfi_private *cfi = map->fldrv_priv; - int ofs_factor = cfi->interleave * cfi->device_type; - - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); - printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", - adr, cfi_read_query(map, adr+(2*ofs_factor))); - cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); - - return 0; -} - - -#define debug_dump_locks(mtd, frob, ofs, len, thunk) \ - cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk)) - -#else - -#define debug_dump_locks(...) - -#endif /* DEBUG_LOCK_BITS */ - - -struct xxlock_thunk { - uint8_t val; - flstate_t state; -}; - - -#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING}) -#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING}) - - -/* - * FIXME - this is *very* specific to a particular chip. It likely won't - * work for all chips that require unlock. It also hasn't been tested - * with interleaved chips. - */ -static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) -{ - struct cfi_private *cfi = map->fldrv_priv; - struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk; - int ret; - - /* - * This is easy because these are writes to registers and not writes - * to flash memory - that means that we don't have to check status - * and timeout. - */ - - adr += chip->start; - /* - * lock block registers: - * - on 64k boundariesand - * - bit 1 set high - * - block lock registers are 4MiB lower - overflow subtract (danger) - */ - adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff; - - cfi_spin_lock(chip->mutex); - ret = get_chip(map, chip, adr, FL_LOCKING); - if (ret) { - cfi_spin_unlock(chip->mutex); - return ret; - } - - chip->state = xxlt->state; - map_write(map, CMD(xxlt->val), adr); - - /* Done and happy. */ - chip->state = FL_READY; - put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); - return 0; -} - - -static int cfi_amdstd_lock_varsize(struct mtd_info *mtd, - loff_t ofs, - size_t len) -{ - int ret; - - DEBUG(MTD_DEBUG_LEVEL3, - "%s: lock status before, ofs=0x%08llx, len=0x%08zX\n", - __func__, ofs, len); - debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); - - ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, - (void *)&DO_XXLOCK_ONEBLOCK_LOCK); - - DEBUG(MTD_DEBUG_LEVEL3, - "%s: lock status after, ret=%d\n", - __func__, ret); - - debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); - - return ret; -} - - -static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd, - loff_t ofs, - size_t len) -{ - int ret; - - DEBUG(MTD_DEBUG_LEVEL3, - "%s: lock status before, ofs=0x%08llx, len=0x%08zX\n", - __func__, ofs, len); - debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); - - ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, - (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK); - - DEBUG(MTD_DEBUG_LEVEL3, - "%s: lock status after, ret=%d\n", - __func__, ret); - debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); - - return ret; -} - - static void cfi_amdstd_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index 071be4220417..be55c6f2f670 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: cfi_probe.c,v 1.77 2004/07/14 08:38:44 dwmw2 Exp $ + $Id: cfi_probe.c,v 1.79 2004/10/20 23:04:01 dwmw2 Exp $ */ #include @@ -243,12 +243,27 @@ static char *vendorname(__u16 vendor) case P_ID_AMD_EXT: return "AMD/Fujitsu Extended"; + + case P_ID_WINBOND: + return "Winbond Standard"; + case P_ID_ST_ADV: + return "ST Advanced"; + case P_ID_MITSUBISHI_STD: return "Mitsubishi Standard"; case P_ID_MITSUBISHI_EXT: return "Mitsubishi Extended"; + + case P_ID_SST_PAGE: + return "SST Page Write"; + + case P_ID_INTEL_PERFORMANCE: + return "Intel Performance Code"; + + case P_ID_INTEL_DATA: + return "Intel Data"; case P_ID_RESERVED: return "Not Allowed / Reserved for Future Use"; @@ -327,6 +342,10 @@ static void print_cfi_ident(struct cfi_ident *cfip) printk(" - x32-only asynchronous interface\n"); break; + case 4: + printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); + break; + case 65535: printk(" - Not Allowed / Reserved\n"); break; diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index d1a785628c49..49c97bc96bba 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -7,7 +7,7 @@ * * This code is covered by the GPL. * - * $Id: cfi_util.c,v 1.4 2004/07/14 08:38:44 dwmw2 Exp $ + * $Id: cfi_util.c,v 1.5 2004/08/12 06:40:23 eric Exp $ * */ @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -74,19 +75,114 @@ out: EXPORT_SYMBOL(cfi_read_pri); -void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups) +void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) { + struct map_info *map = mtd->priv; 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); + f->fixup(mtd, f->param); } } } EXPORT_SYMBOL(cfi_fixup); +int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, + loff_t ofs, size_t len, void *thunk) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long adr; + int chipnum, ret = 0; + int i, first; + struct mtd_erase_region_info *regions = mtd->eraseregions; + + if (ofs > mtd->size) + return -EINVAL; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + /* Check that both start and end of the requested erase are + * aligned with the erasesize at the appropriate addresses. + */ + + i = 0; + + /* Skip all erase regions which are ended before the start of + the requested erase. Actually, to save on the calculations, + we skip to the first erase region which starts after the + start of the requested erase, and then go back one. + */ + + while (i < mtd->numeraseregions && ofs >= regions[i].offset) + i++; + i--; + + /* OK, now i is pointing at the erase region in which this + erase request starts. Check the start of the requested + erase range is aligned with the erase size which is in + effect here. + */ + + if (ofs & (regions[i].erasesize-1)) + return -EINVAL; + + /* Remember the erase region we start on */ + first = i; + + /* Next, check that the end of the requested erase is aligned + * with the erase region at that address. + */ + + while (inumeraseregions && (ofs + len) >= regions[i].offset) + i++; + + /* As before, drop back one to point at the region in which + the address actually falls + */ + i--; + + if ((ofs + len) & (regions[i].erasesize-1)) + return -EINVAL; + + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); + + i=first; + + while(len) { + unsigned long chipmask; + int size = regions[i].erasesize; + + ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); + + if (ret) + return ret; + + adr += size; + len -= size; + + chipmask = (1 << cfi->chipshift) - 1; + if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask)) + i++; + + if (adr >> cfi->chipshift) { + adr = 0; + chipnum++; + + if (chipnum >= cfi->numchips) + break; + } + } + + return 0; +} + +EXPORT_SYMBOL(cfi_varsize_frob); + MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h new file mode 100644 index 000000000000..fbf44708a861 --- /dev/null +++ b/drivers/mtd/chips/fwh_lock.h @@ -0,0 +1,107 @@ +#ifndef FWH_LOCK_H +#define FWH_LOCK_H + + +enum fwh_lock_state { + FWH_UNLOCKED = 0, + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +struct fwh_xxlock_thunk { + enum fwh_lock_state val; + flstate_t state; +}; + + +#define FWH_XXLOCK_ONEBLOCK_LOCK ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING}) +#define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED, FL_UNLOCKING}) + +/* + * This locking/unlock is specific to firmware hub parts. Only one + * is known that supports the Intel command set. Firmware + * hub parts cannot be interleaved as they are on the LPC bus + * so this code has not been tested with interleaved chips, + * and will likely fail in that context. + */ +static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk; + int ret; + + /* Refuse the operation if the we cannot look behind the chip */ + if (chip->start < 0x400000) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): chip->start: %lx wanted >= 0x400000\n", + __func__, chip->start ); + return -EIO; + } + /* + * lock block registers: + * - on 64k boundariesand + * - bit 1 set high + * - block lock registers are 4MiB lower - overflow subtract (danger) + * + * The address manipulation is first done on the logical address + * which is 0 at the start of the chip, and then the offset of + * the individual chip is addted to it. Any other order a weird + * map offset could cause problems. + */ + adr = (adr & ~0xffffUL) | 0x2; + adr += chip->start - 0x400000; + + /* + * This is easy because these are writes to registers and not writes + * to flash memory - that means that we don't have to check status + * and timeout. + */ + cfi_spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_LOCKING); + if (ret) { + cfi_spin_unlock(chip->mutex); + return ret; + } + + chip->state = xxlt->state; + map_write(map, CMD(xxlt->val), adr); + + /* Done and happy. */ + chip->state = FL_READY; + put_chip(map, chip, adr); + cfi_spin_unlock(chip->mutex); + return 0; +} + + +static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; + + ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, + (void *)&FWH_XXLOCK_ONEBLOCK_LOCK); + + return ret; +} + + +static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; + + ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, + (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); + + return ret; +} + +static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) +{ + printk(KERN_NOTICE "using fwh lock/unlock method\n"); + /* Setup for the chips with the fwh lock method */ + mtd->lock = fwh_lock_varsize; + mtd->unlock = fwh_unlock_varsize; +} +#endif /* FWH_LOCK_H */ diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 3615fd815aef..fc982c4671f0 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -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.19 2004/07/13 22:33:32 dwmw2 Exp $ + * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $ */ #include @@ -64,7 +64,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi interleave and device type, etc. */ if (!genprobe_new_chip(map, cp, &cfi)) { /* The probe didn't like it */ - printk(KERN_WARNING "%s: Found no %s device at location zero\n", + printk(KERN_DEBUG "%s: Found no %s device at location zero\n", cp->name, map->name); return NULL; } @@ -169,8 +169,12 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, cfi->interleave = nr_chips; - for (type = 0; type < 3; type++) { - cfi->device_type = 1<device_type = type; if (cp->probe_chip(map, 0, NULL, cfi)) return 1; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 8fb85f079111..250d038d2775 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.51 2004/07/14 14:44:30 thayne Exp $ + $Id: jedec_probe.c,v 1.57 2004/09/17 11:45:05 eric Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -107,6 +107,7 @@ #define I82802AC 0x00ac /* Macronix */ +#define MX29LV040C 0x004F #define MX29LV160T 0x22C4 #define MX29LV160B 0x2249 #define MX29F016 0x00AD @@ -128,6 +129,7 @@ #define M50FW040 0x002C #define M50FW080 0x002D #define M50FW016 0x002E +#define M50LPW080 0x002F /* SST */ #define SST29EE020 0x0010 @@ -181,8 +183,8 @@ enum uaddr { struct unlock_addr { - int addr1; - int addr2; + u32 addr1; + u32 addr2; }; @@ -512,12 +514,12 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x10000,8), } }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29F002T, - .name = "AMD AM29F002T", - .DevSize = SIZE_256KiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,3), + mfr_id: MANUFACTURER_AMD, + dev_id: AM29F002T, + name: "AMD AM29F002T", + DevSize: SIZE_256KiB, + NumEraseRegions: 4, + regions: {ERASEINFO(0x10000,3), ERASEINFO(0x08000,1), ERASEINFO(0x02000,2), ERASEINFO(0x04000,1) @@ -768,12 +770,12 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x04000,1) } }, { - .mfr_id = MANUFACTURER_HYUNDAI, - .dev_id = HY29F002T, - .name = "Hyundai HY29F002T", - .DevSize = SIZE_256KiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,3), + mfr_id: MANUFACTURER_HYUNDAI, + dev_id: HY29F002T, + name: "Hyundai HY29F002T", + DevSize: SIZE_256KiB, + NumEraseRegions: 4, + regions: {ERASEINFO(0x10000,3), ERASEINFO(0x08000,1), ERASEINFO(0x02000,2), ERASEINFO(0x04000,1) @@ -1082,6 +1084,19 @@ static const struct amd_flash_info jedec_table[] = { .regions = { ERASEINFO(0x10000,16), } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29LV040C, + .name = "Macronix MX29LV040C", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } }, { .mfr_id = MANUFACTURER_MACRONIX, .dev_id = MX29LV160T, @@ -1162,12 +1177,12 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x10000,7), } }, { - .mfr_id = MANUFACTURER_MACRONIX, - .dev_id = MX29F002T, - .name = "Macronix MX29F002T", - .DevSize = SIZE_256KiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,3), + mfr_id: MANUFACTURER_MACRONIX, + dev_id: MX29F002T, + name: "Macronix MX29F002T", + DevSize: SIZE_256KiB, + NumEraseRegions: 4, + regions: {ERASEINFO(0x10000,3), ERASEINFO(0x08000,1), ERASEINFO(0x02000,2), ERASEINFO(0x04000,1) @@ -1247,7 +1262,7 @@ static const struct amd_flash_info jedec_table[] = { .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - .regions = {ERASEINFO(0x01000,64), + regions: {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1259,7 +1274,7 @@ static const struct amd_flash_info jedec_table[] = { .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - .regions = {ERASEINFO(0x01000,64), + regions: {ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1379,6 +1394,22 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x01000,256), } }, { + .mfr_id = MANUFACTURER_SST, /* should be CFI */ + .dev_id = SST39LF160, + .name = "SST 39LF160", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x1000,256), + ERASEINFO(0x1000,256) + } + + }, { .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ .dev_id = M29W800DT, .name = "ST M29W800DT", @@ -1498,6 +1529,19 @@ static const struct amd_flash_info jedec_table[] = { .regions = { ERASEINFO(0x10000,32), } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M50LPW080, + .name = "ST M50LPW080", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } }, { .mfr_id = MANUFACTURER_TOSHIBA, .dev_id = TC58FVT160, @@ -1624,20 +1668,20 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, { map_word result; unsigned long mask; + u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type); mask = (1 << (cfi->device_type * 8)) -1; - result = map_read(map, base); + result = map_read(map, base + ofs); return result.x[0] & mask; } static inline u32 jedec_read_id(struct map_info *map, __u32 base, struct cfi_private *cfi) { - int osf; map_word result; unsigned long mask; - osf = cfi->interleave *cfi->device_type; + u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type); mask = (1 << (cfi->device_type * 8)) -1; - result = map_read(map, base + osf); + result = map_read(map, base + ofs); return result.x[0] & mask; } @@ -1653,9 +1697,11 @@ static inline void jedec_reset(u32 base, struct map_info *map, * as they will ignore the writes and dont care what address * the F0 is written to */ if(cfi->addr_unlock1) { - /*printk("reset unlock called %x %x \n",cfi->addr_unlock1,cfi->addr_unlock2);*/ - cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + DEBUG( MTD_DEBUG_LEVEL3, + "reset unlock called %x %x \n", + cfi->addr_unlock1,cfi->addr_unlock2); + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); } cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); @@ -1700,7 +1746,6 @@ static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_ty static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) { int i,num_erase_regions; - unsigned long mask; __u8 uaddr; printk("Found: %s\n",jedec_table[index].name); @@ -1736,9 +1781,8 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) } /* Mask out address bits which are smaller than the device type */ - mask = ~(p_cfi->device_type-1); - p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask; - p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask; + p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1; + p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2; return 1; /* ok */ } @@ -1759,7 +1803,6 @@ static inline int jedec_match( __u32 base, int rc = 0; /* failure until all tests pass */ u32 mfr, id; __u8 uaddr; - unsigned long mask; /* * The IDs must match. For X16 and X32 devices operating in @@ -1797,7 +1840,7 @@ static inline int jedec_match( __u32 base, DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) ); - if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) { + if ( base + cfi_interleave(cfi) * ( 1 << finfo->DevSize ) > map->size ) { DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", __func__, finfo->mfr_id, finfo->dev_id, @@ -1810,18 +1853,16 @@ static inline int jedec_match( __u32 base, goto match_done; } - mask = ~(cfi->device_type-1); - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr - && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 || - (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) { + && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 || + unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) { DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4lx 0x%.4lx did not match\n", - __func__, - unlock_addrs[uaddr].addr1 & mask, - unlock_addrs[uaddr].addr2 & mask); + "MTD %s(): 0x%.4x 0x%.4x did not match\n", + __func__, + unlock_addrs[uaddr].addr1, + unlock_addrs[uaddr].addr2); goto match_done; } @@ -1857,10 +1898,10 @@ static inline int jedec_match( __u32 base, */ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); if(cfi->addr_unlock1) { - cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); } - cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); /* FIXME - should have a delay before continuing */ match_done: @@ -1873,19 +1914,18 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, { int i; enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED; + u32 probe_offset1, probe_offset2; retry: if (!cfi->numchips) { - unsigned long mask = ~(cfi->device_type-1); - uaddr_idx++; if (MTD_UADDR_UNNECESSARY == uaddr_idx) return 0; /* Mask out address bits which are smaller than the device type */ - cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask; - cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask; + cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1; + cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2; } /* Make certain we aren't probing past the end of map */ @@ -1896,30 +1936,30 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, return 0; } - if ((base + cfi->addr_unlock1) >= map->size) { - printk(KERN_NOTICE - "Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n", - base, cfi->addr_unlock1, map->size -1); - - return 0; + /* Ensure the unlock addresses we try stay inside the map */ + probe_offset1 = cfi_build_cmd_addr( + cfi->addr_unlock1, + cfi_interleave(cfi), + cfi->device_type); + probe_offset2 = cfi_build_cmd_addr( + cfi->addr_unlock1, + cfi_interleave(cfi), + cfi->device_type); + if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || + ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) + { + goto retry; } - if ((base + cfi->addr_unlock2) >= map->size) { - printk(KERN_NOTICE - "Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n", - base, cfi->addr_unlock2, map->size -1); - return 0; - } - /* Reset */ jedec_reset(base, map, cfi); /* Autoselect Mode */ if(cfi->addr_unlock1) { - cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); } - cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); /* FIXME - should have a delay before continuing */ if (!cfi->numchips) { @@ -1930,7 +1970,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, cfi->id = jedec_read_id(map, base, cfi); DEBUG(MTD_DEBUG_LEVEL3, "Search for id:(%02x %02x) interleave(%d) type(%d)\n", - cfi->mfr, cfi->id, cfi->interleave, cfi->device_type); + cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); for (i=0; iname, cfi->interleave, cfi->device_type*8, base, + map->name, cfi_interleave(cfi), cfi->device_type*8, base, map->bankwidth*8); return 1; diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index b43312731270..cde413dbd846 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -2,7 +2,7 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.12 2004/07/14 14:44:31 thayne Exp $ + * $Id: amd76xrom.c,v 1.17 2004/09/18 01:59:56 eric Exp $ */ #include @@ -12,61 +12,73 @@ #include #include #include +#include +#include #include #include #include +#include #define xstr(s) str(s) #define str(s) #s #define MOD_NAME xstr(KBUILD_BASENAME) -#define MTD_DEV_NAME_LENGTH 16 +#define ADDRESS_NAME_LEN 18 + +#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ + +struct amd76xrom_window { + void __iomem *virt; + unsigned long phys; + unsigned long size; + struct list_head maps; + struct resource rsrc; + struct pci_dev *pdev; +}; struct amd76xrom_map_info { + struct list_head list; struct map_info map; struct mtd_info *mtd; - void __iomem * window_addr; - u32 window_start, window_size; - struct pci_dev *pdev; - struct resource window_rsrc; - struct resource rom_rsrc; - char mtd_name[MTD_DEV_NAME_LENGTH]; + struct resource rsrc; + char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; }; - -static struct amd76xrom_map_info amd76xrom_map = { - .map = { - .name = MOD_NAME, - .size = 0, - .bankwidth = 1, - } - /* remaining fields of structure are initialized to 0 */ +static struct amd76xrom_window amd76xrom_window = { + .maps = LIST_HEAD_INIT(amd76xrom_window.maps), }; - -static void amd76xrom_cleanup(struct amd76xrom_map_info *info) +static void amd76xrom_cleanup(struct amd76xrom_window *window) { + struct amd76xrom_map_info *map, *scratch; u8 byte; - /* Disable writes through the rom window */ - pci_read_config_byte(info->pdev, 0x40, &byte); - pci_write_config_byte(info->pdev, 0x40, byte & ~1); + if (window->pdev) { + /* Disable writes through the rom window */ + pci_read_config_byte(window->pdev, 0x40, &byte); + pci_write_config_byte(window->pdev, 0x40, byte & ~1); + } - if (info->mtd) { - del_mtd_device(info->mtd); - map_destroy(info->mtd); - info->mtd = NULL; - info->map.virt = NULL; + /* Free all of the mtd devices */ + list_for_each_entry_safe(map, scratch, &window->maps, list) { + if (map->rsrc.parent) { + release_resource(&map->rsrc); + } + del_mtd_device(map->mtd); + map_destroy(map->mtd); + list_del(&map->list); + kfree(map); } - if (info->rom_rsrc.parent) - release_resource(&info->rom_rsrc); - if (info->window_rsrc.parent) - release_resource(&info->window_rsrc); - - if (info->window_addr) { - iounmap(info->window_addr); - info->window_addr = NULL; + if (window->rsrc.parent) + release_resource(&window->rsrc); + + if (window->virt) { + iounmap(window->virt); + window->virt = NULL; + window->phys = 0; + window->size = 0; + window->pdev = NULL; } } @@ -74,167 +86,196 @@ static void amd76xrom_cleanup(struct amd76xrom_map_info *info) static int __devinit amd76xrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - struct rom_window { - u32 start; - u32 size; - u8 segen_bits; - }; - static struct rom_window rom_window[] = { - /* - * Need the 5MiB window for chips that have block lock/unlock - * registers located below 4MiB window. - */ - { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, - { 0xffc00000, 4*1024*1024, (1<<7), }, - { 0xffff0000, 64*1024, 0 }, - { 0 , 0, 0 }, - }; - static const u32 rom_probe_sizes[] = { - 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, - 256*1024, 128*1024, 64*1024, 0}; static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; u8 byte; - struct amd76xrom_map_info *info = &amd76xrom_map; - struct rom_window *window; - int i; - u32 rom_size; - - info->pdev = pdev; - window = &rom_window[0]; - - while (window->size) { - /* - * Try to reserve the window mem region. If this fails then - * it is likely due to a fragment of the window being - * "reseved" by the BIOS. In the case that the - * request_mem_region() fails then once the rom size is - * discovered we will try to reserve the unreserved fragment. - */ - info->window_rsrc.name = MOD_NAME; - info->window_rsrc.start = window->start; - info->window_rsrc.end = window->start + window->size - 1; - info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&iomem_resource, &info->window_rsrc)) { - info->window_rsrc.parent = NULL; - printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource" - " 0x%.08lx-0x%.08lx - kernel bug?\n", - __func__, - info->window_rsrc.start, info->window_rsrc.end); - } + struct amd76xrom_window *window = &amd76xrom_window; + struct amd76xrom_map_info *map = 0; + unsigned long map_top; + + /* Remember the pci dev I find the window in */ + window->pdev = pdev; - /* Enable the selected rom window */ - pci_read_config_byte(pdev, 0x43, &byte); - pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + /* Assume the rom window is properly setup, and find it's size */ + pci_read_config_byte(pdev, 0x43, &byte); + if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) { + window->phys = 0xffb00000; /* 5MiB */ + } + else if ((byte & (1<<7)) == (1<<7)) { + window->phys = 0xffc00000; /* 4MiB */ + } + else { + window->phys = 0xffff0000; /* 64KiB */ + } + window->size = 0xffffffffUL - window->phys + 1UL; + + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to a fragment of the window being + * "reseved" by the BIOS. In the case that the + * request_mem_region() fails then once the rom size is + * discovered we will try to reserve the unreserved fragment. + */ + window->rsrc.name = MOD_NAME; + window->rsrc.start = window->phys; + window->rsrc.end = window->phys + window->size - 1; + window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &window->rsrc)) { + window->rsrc.parent = NULL; + printk(KERN_ERR MOD_NAME + " %s(): Unable to register resource" + " 0x%.08lx-0x%.08lx - kernel bug?\n", + __func__, + window->rsrc.start, window->rsrc.end); + } - /* Enable writes through the rom window */ - pci_read_config_byte(pdev, 0x40, &byte); - pci_write_config_byte(pdev, 0x40, byte | 1); +#if 0 - /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits); +#endif - printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", - window->size, window->start); - /* For write accesses caches are useless */ - info->window_addr = ioremap_nocache(window->start, - window->size); + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + /* For write accesses caches are useless */ + window->virt = ioremap_nocache(window->phys, window->size); + if (!window->virt) { + printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n", + window->phys, window->size); + goto out; + } - if (!info->window_addr) { - printk(KERN_ERR "Failed to ioremap\n"); - continue; + /* Get the first address to look for an rom chip at */ + map_top = window->phys; +#if 1 + /* The probe sequence run over the firmware hub lock + * registers sets them to 0x7 (no access). + * Probe at most the last 4M of the address space. + */ + if (map_top < 0xffc00000) { + map_top = 0xffc00000; + } +#endif + /* Loop through and look for rom chips */ + while((map_top - 1) < 0xffffffffUL) { + struct cfi_private *cfi; + unsigned long offset; + int i; + + if (!map) { + map = kmalloc(sizeof(*map), GFP_KERNEL); + } + if (!map) { + printk(KERN_ERR MOD_NAME ": kmalloc failed"); + goto out; } + memset(map, 0, sizeof(*map)); + INIT_LIST_HEAD(&map->list); + map->map.name = map->map_name; + map->map.phys = map_top; + offset = map_top - window->phys; + map->map.virt = (void __iomem *) + (((unsigned long)(window->virt)) + offset); + map->map.size = 0xffffffffUL - map_top + 1UL; + /* Set the name of the map to the address I am trying */ + sprintf(map->map_name, "%s @%08lx", + MOD_NAME, map->map.phys); + + /* There is no generic VPP support */ + for(map->map.bankwidth = 32; map->map.bankwidth; + map->map.bankwidth >>= 1) + { + char **probe_type; + /* Skip bankwidths that are not supported */ + if (!map_bankwidth_supported(map->map.bankwidth)) + continue; - info->mtd = NULL; + /* Setup the map methods */ + simple_map_init(&map->map); - for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { - char **chip_type; - if (rom_size > window->size) { - continue; - } - info->map.phys = window->start + window->size - rom_size; - info->map.virt = - info->window_addr + window->size - rom_size; - info->map.size = rom_size; - simple_map_init(&info->map); - chip_type = rom_probe_types; - for(; !info->mtd && *chip_type; chip_type++) { - info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map); + /* Try all of the probe methods */ + probe_type = rom_probe_types; + for(; *probe_type; probe_type++) { + map->mtd = do_map_probe(*probe_type, &map->map); + if (map->mtd) + goto found; } - if (info->mtd) goto found_mtd; } - iounmap(info->window_addr); - info->window_addr = NULL; - - /* Disable writes through the rom window */ - pci_read_config_byte(pdev, 0x40, &byte); - pci_write_config_byte(pdev, 0x40, byte & ~1); - - window++; - } - goto failed; - - found_mtd: - printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n", - window->size - rom_size); - - info->mtd->owner = THIS_MODULE; - - if (!info->window_rsrc.parent) { - /* failed to reserve entire window - try fragments */ - info->window_rsrc.name = MOD_NAME; - info->window_rsrc.start = window->start; - info->window_rsrc.end = window->start + window->size - rom_size - 1; - info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&iomem_resource, &info->window_rsrc)) { - printk(KERN_ERR MOD_NAME - ": cannot reserve window resource fragment\n"); -#if 0 + map_top += ROM_PROBE_STEP_SIZE; + continue; + found: + /* Trim the size if we are larger than the map */ + if (map->mtd->size > map->map.size) { + printk(KERN_WARNING MOD_NAME + " rom(%u) larger than window(%lu). fixing...\n", + map->mtd->size, map->map.size); + map->mtd->size = map->map.size; + } + if (window->rsrc.parent) { /* - * The BIOS e820 usually reserves this so it isn't - * usually an error. + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. */ - goto failed; -#endif + map->rsrc.name = map->map_name; + map->rsrc.start = map->map.phys; + map->rsrc.end = map->map.phys + map->mtd->size - 1; + map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&window->rsrc, &map->rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + map->rsrc.parent = NULL; + } } - } - add_mtd_device(info->mtd); - info->window_start = window->start; - info->window_size = window->size; - - if (info->window_rsrc.parent) { - /* - * Registering the MTD device in iomem may not be possible - * if there is a BIOS "reserved" and BUSY range. If this - * fails then continue anyway. - */ - snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, - "mtd%d", info->mtd->index); - - info->rom_rsrc.name = info->mtd_name; - info->rom_rsrc.start = window->start + window->size - rom_size; - info->rom_rsrc.end = window->start + window->size - 1; - info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { - printk(KERN_ERR MOD_NAME - ": cannot reserve MTD resource\n"); - info->rom_rsrc.parent = NULL; + /* Make the whole region visible in the map */ + map->map.virt = window->virt; + map->map.phys = window->phys; + cfi = map->map.fldrv_priv; + for(i = 0; i < cfi->numchips; i++) { + cfi->chips[i].start += offset; } + + /* Now that the mtd devices is complete claim and export it */ + map->mtd->owner = THIS_MODULE; + if (add_mtd_device(map->mtd)) { + map_destroy(map->mtd); + map->mtd = 0; + goto out; + } + + + /* Calculate the new value of map_top */ + map_top += map->mtd->size; + + /* File away the map structure */ + list_add(&map->list, &window->maps); + map = 0; } + out: + /* Free any left over map structures */ + if (map) { + kfree(map); + } + /* See if I have any map structures */ + if (list_empty(&window->maps)) { + amd76xrom_cleanup(window); + return -ENODEV; + } return 0; - - failed: - amd76xrom_cleanup(info); - return -ENODEV; } static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) { - struct amd76xrom_map_info *info = &amd76xrom_map; + struct amd76xrom_window *window = &amd76xrom_window; - amd76xrom_cleanup(info); + amd76xrom_cleanup(window); } static struct pci_device_id amd76xrom_pci_tbl[] = { @@ -269,7 +310,6 @@ int __init init_amd76xrom(void) } } if (pdev) { - amd76xrom_map.pdev = pdev; return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]); } return -ENXIO; @@ -280,7 +320,7 @@ int __init init_amd76xrom(void) static void __exit cleanup_amd76xrom(void) { - amd76xrom_remove_one(amd76xrom_map.pdev); + amd76xrom_remove_one(amd76xrom_window.pdev); } module_init(init_amd76xrom); diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index a26cc3af5e1f..03a5d772f56a 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.8 2004/07/16 17:43:11 dwmw2 Exp $ + * $Id: ichxrom.c,v 1.14 2004/09/18 01:59:56 eric Exp $ */ #include @@ -12,187 +12,87 @@ #include #include #include +#include +#include #include #include #include -#include +#include #define xstr(s) str(s) #define str(s) #s #define MOD_NAME xstr(KBUILD_BASENAME) -#define MTD_DEV_NAME_LENGTH 16 - -#define RESERVE_MEM_REGION 0 - +#define ADDRESS_NAME_LEN 18 -#define MANUFACTURER_INTEL 0x0089 -#define I82802AB 0x00ad -#define I82802AC 0x00ac +#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ -#define ICHX_FWH_REGION_START 0xFF000000UL -#define ICHX_FWH_REGION_SIZE 0x01000000UL #define BIOS_CNTL 0x4e #define FWH_DEC_EN1 0xE3 #define FWH_DEC_EN2 0xF0 #define FWH_SEL1 0xE8 #define FWH_SEL2 0xEE -struct ichxrom_map_info { - struct map_info map; - struct mtd_info *mtd; - unsigned long window_addr; +struct ichxrom_window { + void __iomem* virt; + unsigned long phys; + unsigned long size; + struct list_head maps; + struct resource rsrc; struct pci_dev *pdev; - struct resource window_rsrc; - struct resource rom_rsrc; - char mtd_name[MTD_DEV_NAME_LENGTH]; }; -static inline unsigned long addr(struct map_info *map, unsigned long ofs) -{ - unsigned long offset; - offset = ((8*1024*1024) - map->size) + ofs; - if (offset >= (4*1024*1024)) { - offset += 0x400000; - } - return map->map_priv_1 + 0x400000 + offset; -} - -static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) -{ - return addr - map->map_priv_1 + ICHX_FWH_REGION_START; -} - -static map_word ichxrom_read(struct map_info *map, unsigned long ofs) -{ - map_word val; - int i; - switch(map->bankwidth) { - case 1: val.x[0] = __raw_readb(addr(map, ofs)); break; - case 2: val.x[0] = __raw_readw(addr(map, ofs)); break; - case 4: val.x[0] = __raw_readl(addr(map, ofs)); break; -#if BITS_PER_LONG >= 64 - case 8: val.x[0] = __raw_readq(addr(map, ofs)); break; -#endif - default: val.x[0] = 0; break; - } - for(i = 1; i < map_words(map); i++) { - val.x[i] = 0; - } - return val; -} - -static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, addr(map, from), len); -} - -static void ichxrom_write(struct map_info *map, map_word d, unsigned long ofs) -{ - switch(map->bankwidth) { - case 1: __raw_writeb(d.x[0], addr(map,ofs)); break; - case 2: __raw_writew(d.x[0], addr(map,ofs)); break; - case 4: __raw_writel(d.x[0], addr(map,ofs)); break; -#if BITS_PER_LONG >= 64 - case 8: __raw_writeq(d.x[0], addr(map,ofs)); break; -#endif - } - mb(); -} - -static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(addr(map, to), from, len); -} - -static struct ichxrom_map_info ichxrom_map = { - .map = { - .name = MOD_NAME, - .phys = NO_XIP, - .size = 0, - .bankwidth = 1, - .read = ichxrom_read, - .copy_from = ichxrom_copy_from, - .write = ichxrom_write, - .copy_to = ichxrom_copy_to, - /* Firmware hubs only use vpp when being programmed - * in a factory setting. So in-place programming - * needs to use a different method. - */ - }, - /* remaining fields of structure are initialized to 0 */ +struct ichxrom_map_info { + struct list_head list; + struct map_info map; + struct mtd_info *mtd; + struct resource rsrc; + char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; }; -enum fwh_lock_state { - FWH_DENY_WRITE = 1, - FWH_IMMUTABLE = 2, - FWH_DENY_READ = 4, +static struct ichxrom_window ichxrom_window = { + .maps = LIST_HEAD_INIT(ichxrom_window.maps), }; -static void ichxrom_cleanup(struct ichxrom_map_info *info) +static void ichxrom_cleanup(struct ichxrom_window *window) { + struct ichxrom_map_info *map, *scratch; u16 word; /* Disable writes through the rom window */ - pci_read_config_word(info->pdev, BIOS_CNTL, &word); - pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1); - - if (info->mtd) { - del_mtd_device(info->mtd); - map_destroy(info->mtd); - info->mtd = NULL; - info->map.virt = 0; + pci_read_config_word(window->pdev, BIOS_CNTL, &word); + pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1); + + /* Free all of the mtd devices */ + list_for_each_entry_safe(map, scratch, &window->maps, list) { + if (map->rsrc.parent) + release_resource(&map->rsrc); + del_mtd_device(map->mtd); + map_destroy(map->mtd); + list_del(&map->list); + kfree(map); } - if (info->rom_rsrc.parent) - release_resource(&info->rom_rsrc); - if (info->window_rsrc.parent) - release_resource(&info->window_rsrc); - - if (info->window_addr) { - iounmap((void *)(info->window_addr)); - info->window_addr = 0; - } -} - - -static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, - enum fwh_lock_state state) -{ - struct map_info *map = mtd->priv; - unsigned long start = ofs; - unsigned long end = start + len -1; - - /* FIXME do I need to guard against concurrency here? */ - /* round down to 64K boundaries */ - start = start & ~0xFFFF; - end = end & ~0xFFFF; - while (start <= end) { - unsigned long ctrl_addr; - ctrl_addr = addr(map, start) - 0x400000 + 2; - writeb(state, ctrl_addr); - start = start + 0x10000; + if (window->rsrc.parent) + release_resource(&window->rsrc); + if (window->virt) { + iounmap(window->virt); + window->virt = NULL; + window->phys = 0; + window->size = 0; + window->pdev = NULL; } - return 0; } -static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) -{ - return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); -} - -static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) -{ - return ichxrom_set_lock_state(mtd, ofs, len, 0); -} static int __devinit ichxrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; + struct ichxrom_window *window = &ichxrom_window; + struct ichxrom_map_info *map = 0; + unsigned long map_top; + u8 byte; u16 word; - struct ichxrom_map_info *info = &ichxrom_map; - unsigned long map_size; - static char *probes[] = { "cfi_probe", "jedec_probe" }; - struct cfi_private *cfi; /* For now I just handle the ichx and I assume there * are not a lot of resources up at the top of the address @@ -204,26 +104,56 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, * Also you can page firmware hubs if an 8MB window isn't enough * but don't currently handle that case either. */ + window->pdev = pdev; + + /* Find a region continuous to the end of the ROM window */ + window->phys = 0; + pci_read_config_byte(pdev, FWH_DEC_EN1, &byte); + if (byte == 0xff) { + window->phys = 0xffc00000; + pci_read_config_byte(pdev, FWH_DEC_EN2, &byte); + if ((byte & 0x0f) == 0x0f) { + window->phys = 0xff400000; + } + else if ((byte & 0x0e) == 0x0e) { + window->phys = 0xff500000; + } + else if ((byte & 0x0c) == 0x0c) { + window->phys = 0xff600000; + } + else if ((byte & 0x08) == 0x08) { + window->phys = 0xff700000; + } + } + else if ((byte & 0xfe) == 0xfe) { + window->phys = 0xffc80000; + } + else if ((byte & 0xfc) == 0xfc) { + window->phys = 0xffd00000; + } + else if ((byte & 0xf8) == 0xf8) { + window->phys = 0xffd80000; + } + else if ((byte & 0xf0) == 0xf0) { + window->phys = 0xffe00000; + } + else if ((byte & 0xe0) == 0xe0) { + window->phys = 0xffe80000; + } + else if ((byte & 0xc0) == 0xc0) { + window->phys = 0xfff00000; + } + else if ((byte & 0x80) == 0x80) { + window->phys = 0xfff80000; + } - info->pdev = pdev; - - /* - * Try to reserve the window mem region. If this fails then - * it is likely due to the window being "reseved" by the BIOS. - */ - info->window_rsrc.name = MOD_NAME; - info->window_rsrc.start = ICHX_FWH_REGION_START; - info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1; - info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&iomem_resource, &info->window_rsrc)) { - info->window_rsrc.parent = NULL; - printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource" - " 0x%.08lx-0x%.08lx - kernel bug?\n", - __func__, - info->window_rsrc.start, info->window_rsrc.end); + if (window->phys == 0) { + printk(KERN_ERR MOD_NAME ": Rom window is closed\n"); + goto out; } - + window->phys -= 0x400000UL; + window->size = (0xffffffffUL - window->phys) + 1UL; + /* Enable writes through the rom window */ pci_read_config_word(pdev, BIOS_CNTL, &word); if (!(word & 1) && (word & (1<<1))) { @@ -231,119 +161,167 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, * this device, so don't even try. */ printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n"); - goto failed; + goto out; } pci_write_config_word(pdev, BIOS_CNTL, word | 1); + /* + * Try to reserve the window mem region. If this fails then + * it is likely due to the window being "reseved" by the BIOS. + */ + window->rsrc.name = MOD_NAME; + window->rsrc.start = window->phys; + window->rsrc.end = window->phys + window->size - 1; + window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, &window->rsrc)) { + window->rsrc.parent = NULL; + printk(KERN_DEBUG MOD_NAME + ": %s(): Unable to register resource" + " 0x%.08lx-0x%.08lx - kernel bug?\n", + __func__, + window->rsrc.start, window->rsrc.end); + } /* Map the firmware hub into my address space. */ - /* Does this use too much virtual address space? */ - info->window_addr = (unsigned long)ioremap( - ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); - if (!info->window_addr) { - printk(KERN_ERR "Failed to ioremap\n"); - goto failed; + window->virt = ioremap_nocache(window->phys, window->size); + if (!window->virt) { + printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n", + window->phys, window->size); + goto out; } - /* For now assume the firmware has setup all relevant firmware - * windows. We don't have enough information to handle this case - * intelligently. + /* Get the first address to look for an rom chip at */ + map_top = window->phys; + if ((window->phys & 0x3fffff) != 0) { + map_top = window->phys + 0x400000; + } +#if 1 + /* The probe sequence run over the firmware hub lock + * registers sets them to 0x7 (no access). + * Probe at most the last 4M of the address space. */ + if (map_top < 0xffc00000) { + map_top = 0xffc00000; + } +#endif + /* Loop through and look for rom chips */ + while((map_top - 1) < 0xffffffffUL) { + struct cfi_private *cfi; + unsigned long offset; + int i; + + if (!map) { + map = kmalloc(sizeof(*map), GFP_KERNEL); + } + if (!map) { + printk(KERN_ERR MOD_NAME ": kmalloc failed"); + goto out; + } + memset(map, 0, sizeof(*map)); + INIT_LIST_HEAD(&map->list); + map->map.name = map->map_name; + map->map.phys = map_top; + offset = map_top - window->phys; + map->map.virt = (void __iomem *) + (((unsigned long)(window->virt)) + offset); + map->map.size = 0xffffffffUL - map_top + 1UL; + /* Set the name of the map to the address I am trying */ + sprintf(map->map_name, "%s @%08lx", + MOD_NAME, map->map.phys); - /* FIXME select the firmware hub and enable a window to it. */ - - info->mtd = NULL; - info->map.map_priv_1 = info->window_addr; - - /* Loop through the possible bankwidths */ - for(ichxrom_map.map.bankwidth = 4; ichxrom_map.map.bankwidth; ichxrom_map.map.bankwidth >>= 1) { - map_size = ICHX_FWH_REGION_SIZE; - while(!info->mtd && (map_size > 0)) { - int i; - info->map.size = map_size; - for(i = 0; i < sizeof(probes)/sizeof(char *); i++) { - info->mtd = do_map_probe(probes[i], &ichxrom_map.map); - if (info->mtd) - break; + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in-place programming + * needs to use a different method. + */ + for(map->map.bankwidth = 32; map->map.bankwidth; + map->map.bankwidth >>= 1) + { + char **probe_type; + /* Skip bankwidths that are not supported */ + if (!map_bankwidth_supported(map->map.bankwidth)) + continue; + + /* Setup the map methods */ + simple_map_init(&map->map); + + /* Try all of the probe methods */ + probe_type = rom_probe_types; + for(; *probe_type; probe_type++) { + map->mtd = do_map_probe(*probe_type, &map->map); + if (map->mtd) + goto found; } - map_size -= 512*1024; } - if (info->mtd) - break; - } - if (!info->mtd) { - goto failed; - } - cfi = ichxrom_map.map.fldrv_priv; - if ((cfi->mfr == MANUFACTURER_INTEL) && ( - (cfi->id == I82802AB) || - (cfi->id == I82802AC))) - { - /* If it is a firmware hub put in the special lock - * and unlock routines. - */ - info->mtd->lock = ichxrom_lock; - info->mtd->unlock = ichxrom_unlock; - } - if (info->mtd->size > info->map.size) { - printk(KERN_WARNING MOD_NAME " rom(%u) larger than window(%lu). fixing...\n", - info->mtd->size, info->map.size); - info->mtd->size = info->map.size; - } + map_top += ROM_PROBE_STEP_SIZE; + continue; + found: + /* Trim the size if we are larger than the map */ + if (map->mtd->size > map->map.size) { + printk(KERN_WARNING MOD_NAME + " rom(%u) larger than window(%lu). fixing...\n", + map->mtd->size, map->map.size); + map->mtd->size = map->map.size; + } + if (window->rsrc.parent) { + /* + * Registering the MTD device in iomem may not be possible + * if there is a BIOS "reserved" and BUSY range. If this + * fails then continue anyway. + */ + map->rsrc.name = map->map_name; + map->rsrc.start = map->map.phys; + map->rsrc.end = map->map.phys + map->mtd->size - 1; + map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&window->rsrc, &map->rsrc)) { + printk(KERN_ERR MOD_NAME + ": cannot reserve MTD resource\n"); + map->rsrc.parent = NULL; + } + } + + /* Make the whole region visible in the map */ + map->map.virt = window->virt; + map->map.phys = window->phys; + cfi = map->map.fldrv_priv; + for(i = 0; i < cfi->numchips; i++) { + cfi->chips[i].start += offset; + } - info->mtd->owner = THIS_MODULE; - add_mtd_device(info->mtd); - - if (info->window_rsrc.parent) { - /* - * Registering the MTD device in iomem may not be possible - * if there is a BIOS "reserved" and BUSY range. If this - * fails then continue anyway. - */ - snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, - "mtd%d", info->mtd->index); - - info->rom_rsrc.name = info->mtd_name; - info->rom_rsrc.start = ICHX_FWH_REGION_START - + ICHX_FWH_REGION_SIZE - map_size; - info->rom_rsrc.end = ICHX_FWH_REGION_START - + ICHX_FWH_REGION_SIZE; - info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { - printk(KERN_ERR MOD_NAME - ": cannot reserve MTD resource\n"); - info->rom_rsrc.parent = NULL; + /* Now that the mtd devices is complete claim and export it */ + map->mtd->owner = THIS_MODULE; + if (add_mtd_device(map->mtd)) { + map_destroy(map->mtd); + map->mtd = 0; + goto out; } + + + /* Calculate the new value of map_top */ + map_top += map->mtd->size; + + /* File away the map structure */ + list_add(&map->list, &window->maps); + map = 0; } + out: + /* Free any left over map structures */ + if (map) { + kfree(map); + } + /* See if I have any map structures */ + if (list_empty(&window->maps)) { + ichxrom_cleanup(window); + return -ENODEV; + } return 0; - - failed: - ichxrom_cleanup(info); - return -ENODEV; } static void __devexit ichxrom_remove_one (struct pci_dev *pdev) { - struct ichxrom_map_info *info = &ichxrom_map; - u16 word; - - del_mtd_device(info->mtd); - map_destroy(info->mtd); - info->mtd = NULL; - info->map.map_priv_1 = 0; - - iounmap((void *)(info->window_addr)); - info->window_addr = 0; - - /* Disable writes through the rom window */ - pci_read_config_word(pdev, BIOS_CNTL, &word); - pci_write_config_word(pdev, BIOS_CNTL, word & ~1); - -#if RESERVE_MEM_REGION - release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); -#endif + struct ichxrom_window *window = &ichxrom_window; + ichxrom_cleanup(window); } static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { @@ -371,7 +349,6 @@ static struct pci_driver ichxrom_driver = { }; #endif -static struct pci_dev *mydev; int __init init_ichxrom(void) { struct pci_dev *pdev; @@ -385,7 +362,6 @@ int __init init_ichxrom(void) } } if (pdev) { - mydev = pdev; return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]); } return -ENXIO; @@ -396,7 +372,7 @@ int __init init_ichxrom(void) static void __exit cleanup_ichxrom(void) { - ichxrom_remove_one(mydev); + ichxrom_remove_one(ichxrom_window.pdev); } module_init(init_ichxrom); diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index a3efae0cd9a2..284f24851f1d 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.45 2004/07/20 02:44:27 dwmw2 Exp $ + * $Id: cfi.h,v 1.48 2004/10/20 23:08:05 dwmw2 Exp $ */ #ifndef __MTD_CFI_H__ @@ -177,16 +177,19 @@ struct cfi_bri_query { uint32_t ConfField[1]; /* Not host ordered */ } __attribute__((packed)); -#define P_ID_NONE 0 -#define P_ID_INTEL_EXT 1 -#define P_ID_AMD_STD 2 -#define P_ID_INTEL_STD 3 -#define P_ID_AMD_EXT 4 -#define P_ID_ST_ADV 32 -#define P_ID_MITSUBISHI_STD 256 -#define P_ID_MITSUBISHI_EXT 257 -#define P_ID_SST_PAGE 258 -#define P_ID_RESERVED 65535 +#define P_ID_NONE 0x0000 +#define P_ID_INTEL_EXT 0x0001 +#define P_ID_AMD_STD 0x0002 +#define P_ID_INTEL_STD 0x0003 +#define P_ID_AMD_EXT 0x0004 +#define P_ID_WINBOND 0x0006 +#define P_ID_ST_ADV 0x0020 +#define P_ID_MITSUBISHI_STD 0x0100 +#define P_ID_MITSUBISHI_EXT 0x0101 +#define P_ID_SST_PAGE 0x0102 +#define P_ID_INTEL_PERFORMANCE 0x0200 +#define P_ID_INTEL_DATA 0x0210 +#define P_ID_RESERVED 0xffff #define CFI_MODE_CFI 1 @@ -350,17 +353,26 @@ static inline void cfi_spin_unlock(spinlock_t *mutex) struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, const char* name); - struct cfi_fixup { uint16_t mfr; uint16_t id; - void (*fixup)(struct map_info *map, void* param); + void (*fixup)(struct mtd_info *mtd, void* param); void* param; }; #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff -void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups); +#define CFI_MFR_AMD 0x0001 +#define CFI_MFR_ST 0x0020 /* STMicroelectronics */ + +void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); + +typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk); + +int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, + loff_t ofs, size_t len, void *thunk); + #endif /* __MTD_CFI_H__ */ -- cgit v1.2.3 From ce9ef9d9bdd861fbcd221d1722deb5ce13ded23e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 21 Oct 2004 02:35:05 +0100 Subject: MTD: NAND flash driver updates. - Use new RS library for ECC - Add support for new NAND flash chips - New board support: - iPAQ H1910 - Renesas AG-AND devel board - Simtec S3C210 - Support for shared controllers on multiple chips. Signed-Off-By: Thomas Gleixner Signed-Off-By: David Woodhouse --- drivers/mtd/nand/Kconfig | 49 ++- drivers/mtd/nand/Makefile | 5 +- drivers/mtd/nand/au1550nd.c | 420 ++++++++++++++--------- drivers/mtd/nand/autcpu12.c | 6 +- drivers/mtd/nand/diskonchip.c | 234 ++++++++++--- drivers/mtd/nand/edb7312.c | 27 +- drivers/mtd/nand/h1910.c | 208 +++++++++++ drivers/mtd/nand/nand_base.c | 147 ++++---- drivers/mtd/nand/nand_bbt.c | 5 +- drivers/mtd/nand/ppchameleonevb.c | 51 ++- drivers/mtd/nand/rtc_from4.c | 561 ++++++++++++++++++++++++++++++ drivers/mtd/nand/s3c2410.c | 704 ++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/spia.c | 23 +- drivers/mtd/nand/toto.c | 24 +- drivers/mtd/nand/tx4925ndfmc.c | 30 +- drivers/mtd/nand/tx4938ndfmc.c | 22 +- include/linux/mtd/nand.h | 20 +- 17 files changed, 2101 insertions(+), 435 deletions(-) create mode 100644 drivers/mtd/nand/h1910.c create mode 100644 drivers/mtd/nand/rtc_from4.c create mode 100644 drivers/mtd/nand/s3c2410.c (limited to 'include/linux') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index ed085292c57d..89ab7da160f1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.17 2004/08/10 14:24:07 dwmw2 Exp $ +# $Id: Kconfig,v 1.22 2004/10/05 22:11:46 gleixner Exp $ menu "NAND Flash Device Drivers" depends on MTD!=n @@ -36,6 +36,12 @@ config MTD_NAND_EDB7312 This enables the driver for the Cirrus Logic EBD7312 evaluation board to access the onboard NAND Flash. +config MTD_NAND_H1900 + tristate "iPAQ H1900 flash" + depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS + help + This enables the driver for the iPAQ h1900 flash. + config MTD_NAND_SPIA tristate "NAND Flash device on SPIA board" depends on ARM && ARCH_P720T && MTD_NAND @@ -74,15 +80,54 @@ config MTD_NAND_AU1550 This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. +config MTD_NAND_RTC_FROM4 + tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" + depends on MTD_NAND && SH_SOLUTION_ENGINE + select REED_SOLOMON + select REED_SOLOMON_DEC8 + help + This enables the driver for the Renesas Technology AG-AND + flash interface board (FROM_BOARD4) + config MTD_NAND_PPCHAMELEONEVB tristate "NAND Flash device on PPChameleonEVB board" depends on PPCHAMELEONEVB && MTD_NAND help - This enables the NAND flash driver on the PPChameleon EVB Board. + This enables the NAND flash driver on the PPChameleon EVB Board. + +config MTD_NAND_S3C2410 + tristate "NAND Flash support for S3C2410 SoC" + depends on ARCH_S3C2410 && MTD_NAND + help + This enables the NAND flash controller on the S3C2410. + + No board specfic support is done by this driver, each board + must advertise a platform_device for the driver to attach. + +config MTD_NAND_S3C2410_DEBUG + bool "S3C2410 NAND driver debug" + depends on MTD_NAND_S3C2410 + help + Enable debugging of the S3C2410 NAND driver + +config MTD_NAND_S3C2410_HWECC + bool "S3C2410 NAND Hardware ECC" + depends on MTD_NAND_S3C2410 + help + Enable the use of the S3C2410's internal ECC generator when + using NAND. Early versions of the chip have had problems with + incorrect ECC generation, and if using these, the default of + software ECC is preferable. + + If you lay down a device with the hardware ECC, then you will + currently not be able to switch to software, as there is no + implementation for ECC method used by the S3C2410 config MTD_NAND_DISKONCHIP tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" depends on MTD_NAND && EXPERIMENTAL + select REED_SOLOMON + select REED_SOLOMON_DEC16 help This is a reimplementation of M-Systems DiskOnChip 2000, Millennium and Millennium Plus as a standard NAND device driver, diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index db19399398ad..a0b6c60528da 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile.common,v 1.9 2004/07/12 16:07:31 dwmw2 Exp $ +# $Id: Makefile.common,v 1.13 2004/09/28 22:04:23 bjd Exp $ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o @@ -14,6 +14,9 @@ obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o +obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o +obj-$(CONFIG_MTD_NAND_H1900) += h1910.o +obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o nand-objs = nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 8e4da650603f..196d1f20a47b 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Embedded Edge, LLC * - * $Id: au1550nd.c,v 1.5 2004/05/17 07:19:35 ppopov Exp $ + * $Id: au1550nd.c,v 1.9 2004/10/20 05:58:30 ppopov Exp $ * * 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 @@ -18,6 +18,17 @@ #include #include #include + +/* fixme: this is ugly */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) +#include +#ifdef CONFIG_MIPS_PB1550 +#include +#endif +#ifdef CONFIG_MIPS_DB1550 +#include +#endif +#else #include #ifdef CONFIG_MIPS_PB1550 #include @@ -25,18 +36,16 @@ #ifdef CONFIG_MIPS_DB1550 #include #endif - +#endif /* * MTD structure for NAND controller */ static struct mtd_info *au1550_mtd = NULL; -static volatile u32 p_nand; -static int nand_width = 1; /* default, only x8 supported for now */ +static void __iomem *p_nand; +static int nand_width = 1; /* default x8*/ -/* Internal buffers. Page buffer and oob buffer for one block*/ -static u_char data_buf[512 + 16]; -static u_char oob_buf[16 * 32]; +#define NAND_CS 1 /* * Define partitions for flash device @@ -70,183 +79,262 @@ const static struct mtd_partition partition_info[] = { #endif }; -static inline void write_cmd_reg(u8 cmd) + +/** + * au_read_byte - read one byte from the chip + * @mtd: MTD device structure + * + * read function for 8bit buswith + */ +static u_char au_read_byte(struct mtd_info *mtd) { - if (nand_width) - *((volatile u8 *)(p_nand + MEM_STNAND_CMD)) = cmd; - else - *((volatile u16 *)(p_nand + MEM_STNAND_CMD)) = cmd; + struct nand_chip *this = mtd->priv; + u_char ret = readb(this->IO_ADDR_R); au_sync(); + return ret; } -static inline void write_addr_reg(u8 addr) +/** + * au_write_byte - write one byte to the chip + * @mtd: MTD device structure + * @byte: pointer to data byte to write + * + * write function for 8it buswith + */ +static void au_write_byte(struct mtd_info *mtd, u_char byte) { - if (nand_width) - *((volatile u8 *)(p_nand + MEM_STNAND_ADDR)) = addr; - else - *((volatile u16 *)(p_nand + MEM_STNAND_ADDR)) = addr; + struct nand_chip *this = mtd->priv; + writeb(byte, this->IO_ADDR_W); au_sync(); } -static inline void write_data_reg(u8 data) +/** + * au_read_byte16 - read one byte endianess aware from the chip + * @mtd: MTD device structure + * + * read function for 16bit buswith with + * endianess conversion + */ +static u_char au_read_byte16(struct mtd_info *mtd) { - if (nand_width) - *((volatile u8 *)(p_nand + MEM_STNAND_DATA)) = data; - else - *((volatile u16 *)(p_nand + MEM_STNAND_DATA)) = data; + struct nand_chip *this = mtd->priv; + u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R)); au_sync(); + return ret; } -static inline u32 read_data_reg(void) +/** + * au_write_byte16 - write one byte endianess aware to the chip + * @mtd: MTD device structure + * @byte: pointer to data byte to write + * + * write function for 16bit buswith with + * endianess conversion + */ +static void au_write_byte16(struct mtd_info *mtd, u_char byte) { - u32 data; - if (nand_width) { - data = *((volatile u8 *)(p_nand + MEM_STNAND_DATA)); - au_sync(); - } - else { - data = *((volatile u16 *)(p_nand + MEM_STNAND_DATA)); - au_sync(); - } - return data; + struct nand_chip *this = mtd->priv; + writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); + au_sync(); } -void au1550_hwcontrol(struct mtd_info *mtd, int cmd) +/** + * au_read_word - read one word from the chip + * @mtd: MTD device structure + * + * read function for 16bit buswith without + * endianess conversion + */ +static u16 au_read_word(struct mtd_info *mtd) { + struct nand_chip *this = mtd->priv; + u16 ret = readw(this->IO_ADDR_R); + au_sync(); + return ret; } -int au1550_device_ready(struct mtd_info *mtd) +/** + * au_write_word - write one word to the chip + * @mtd: MTD device structure + * @word: data word to write + * + * write function for 16bit buswith without + * endianess conversion + */ +static void au_write_word(struct mtd_info *mtd, u16 word) { - int ready; - ready = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0; - return ready; + struct nand_chip *this = mtd->priv; + writew(word, this->IO_ADDR_W); + au_sync(); } -static u_char au1550_nand_read_byte(struct mtd_info *mtd) +/** + * au_write_buf - write buffer to chip + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + * + * write function for 8bit buswith + */ +static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { - u_char ret; - ret = read_data_reg(); - return ret; -} + int i; + struct nand_chip *this = mtd->priv; -static void au1550_nand_write_byte(struct mtd_info *mtd, u_char byte) -{ - write_data_reg((u8)byte); + for (i=0; iIO_ADDR_W); + au_sync(); + } } -static void -au1550_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +/** + * au_read_buf - read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + * + * read function for 8bit buswith + */ +static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) { int i; + struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R); + au_sync(); + } } -static void -au1550_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +/** + * au_verify_buf - Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + * + * verify function for 8bit buswith + */ +static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { int i; + struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R)) + return -EFAULT; + au_sync(); + } + + return 0; } -static int -au1550_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +/** + * au_write_buf16 - write buffer to chip + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + * + * write function for 16bit buswith + */ +static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) { int i; + struct nand_chip *this = mtd->priv; + u16 *p = (u16 *) buf; + len >>= 1; + + for (i=0; iIO_ADDR_W); + au_sync(); + } + +} - for (i=0; ipriv; + u16 *p = (u16 *) buf; + len >>= 1; - return 0; + for (i=0; iIO_ADDR_R); + au_sync(); + } } -static void au1550_nand_select_chip(struct mtd_info *mtd, int chip) +/** + * au_verify_buf16 - Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + * + * verify function for 16bit buswith + */ +static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) { - switch(chip) { - case -1: - /* deassert chip enable */ - au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL); - break; - case 0: - /* assert (force assert) chip enable */ - au_writel(au_readl(MEM_STNDCTL) | 0x20 , MEM_STNDCTL); - break; + int i; + struct nand_chip *this = mtd->priv; + u16 *p = (u16 *) buf; + len >>= 1; - default: - BUG(); + for (i=0; iIO_ADDR_R)) + return -EFAULT; + au_sync(); } + return 0; } -static void au1550_nand_command (struct mtd_info *mtd, unsigned command, - int column, int page_addr) + +static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) { register struct nand_chip *this = mtd->priv; - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - write_cmd_reg(readcmd); - } - write_cmd_reg(command); - - if (column != -1 || page_addr != -1) { - - /* Serially input address */ - if (column != -1) - write_addr_reg(column); - if (page_addr != -1) { - write_addr_reg((unsigned char) (page_addr & 0xff)); - write_addr_reg(((page_addr >> 8) & 0xff)); - /* One more address cycle for higher density devices */ - if (mtd->size & 0x0c000000) - write_addr_reg((unsigned char) ((page_addr >> 16) & 0x0f)); - } - } - - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: + switch(cmd){ + + case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break; + case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; + + case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; + case NAND_CTL_CLRALE: + this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + /* FIXME: Nobody knows why this is neccecary, + * but it works only that way */ + udelay(1); break; - case NAND_CMD_RESET: - if (this->dev_ready) - break; - udelay(this->chip_delay); - write_cmd_reg(NAND_CMD_STATUS); - while ( !(read_data_reg() & 0x40)); - return; - - /* This applies to read commands */ - default: - udelay (this->chip_delay); + case NAND_CTL_SETNCE: + /* assert (force assert) chip enable */ + au_writel(au_readl(MEM_STNDCTL) | (1<<(4+NAND_CS)) , MEM_STNDCTL); + break; + + case NAND_CTL_CLRNCE: + /* deassert chip enable */ + au_writel(au_readl(MEM_STNDCTL) & ~(1<<(4+NAND_CS)), MEM_STNDCTL); + break; } + + this->IO_ADDR_R = this->IO_ADDR_W; - /* wait until command is processed */ - while (!this->dev_ready(mtd)); + /* Drain the writebuffer */ + au_sync(); } +int au1550_device_ready(struct mtd_info *mtd) +{ + int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0; + au_sync(); + return ret; +} /* * Main initialization routine @@ -255,7 +343,7 @@ int __init au1550_init (void) { struct nand_chip *this; u16 boot_swapboot = 0; /* default value */ - u32 mem_time; + int retval; /* Allocate memory for MTD device structure and private data */ au1550_mtd = kmalloc (sizeof(struct mtd_info) + @@ -275,9 +363,10 @@ int __init au1550_init (void) /* Link the private data with the MTD structure */ au1550_mtd->priv = this; + + /* MEM_STNDCTL: disable ints, disable nand boot */ /* disable interrupts */ au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); - /* disable NAND boot */ au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); @@ -295,7 +384,6 @@ int __init au1550_init (void) case 0xD: /* x16 NAND Flash */ nand_width = 0; - printk("Pb1550 NAND: 16-bit NAND not supported by MTD\n"); break; case 1: case 9: @@ -307,62 +395,62 @@ int __init au1550_init (void) break; default: printk("Pb1550 NAND: bad boot:swap\n"); - kfree(au1550_mtd); - return 1; + retval = -EINVAL; + goto outmem; } +#endif /* Configure RCE1 - should be done by YAMON */ - au_writel(0x5 | (nand_width << 22), MEM_STCFG1); - au_writel(NAND_TIMING, MEM_STTIME1); - mem_time = au_readl(MEM_STTIME1); + au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */ + au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */ au_sync(); - /* setup and enable chip select */ + /* setup and enable chip select, MEM_STADDR1 */ /* we really need to decode offsets only up till 0x20 */ au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), MEM_STADDR1); au_sync(); -#endif -#ifdef CONFIG_MIPS_DB1550 - /* Configure RCE1 - should be done by YAMON */ - au_writel(0x00400005, MEM_STCFG1); - au_writel(0x00007774, MEM_STTIME1); - au_writel(0x12000FFF, MEM_STADDR1); -#endif - - p_nand = (volatile struct nand_regs *)ioremap(NAND_PHYS_ADDR, 0x1000); + p_nand = (void __iomem *)ioremap(NAND_PHYS_ADDR, 0x1000); /* Set address of hardware control function */ this->hwcontrol = au1550_hwcontrol; this->dev_ready = au1550_device_ready; /* 30 us command delay time */ this->chip_delay = 30; - - this->cmdfunc = au1550_nand_command; - this->select_chip = au1550_nand_select_chip; - this->write_byte = au1550_nand_write_byte; - this->read_byte = au1550_nand_read_byte; - this->write_buf = au1550_nand_write_buf; - this->read_buf = au1550_nand_read_buf; - this->verify_buf = au1550_nand_verify_buf; this->eccmode = NAND_ECC_SOFT; - /* Set internal data buffer */ - this->data_buf = data_buf; - this->oob_buf = oob_buf; + this->options = NAND_NO_AUTOINCR; + + if (!nand_width) + this->options |= NAND_BUSWIDTH_16; + + this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; + this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; + this->write_word = au_write_word; + this->read_word = au_read_word; + this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; + this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; + this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf; /* Scan to find existence of the device */ if (nand_scan (au1550_mtd, 1)) { - kfree (au1550_mtd); - return -ENXIO; + retval = -ENXIO; + goto outio; } /* Register the partitions */ add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS); return 0; + + outio: + iounmap ((void *)p_nand); + + outmem: + kfree (au1550_mtd); + return retval; } module_init(au1550_init); @@ -375,16 +463,14 @@ static void __exit au1550_cleanup (void) { struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1]; - iounmap ((void *)p_nand); - - /* Unregister partitions */ - del_mtd_partitions(au1550_mtd); - - /* Unregister the device */ - del_mtd_device (au1550_mtd); + /* Release resources, unregister device */ + nand_release (au1550_mtd); /* Free the MTD device structure */ kfree (au1550_mtd); + + /* Unmap */ + iounmap ((void *)p_nand); } module_exit(au1550_cleanup); #endif diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 33779a8dadf4..eb101b47c9ce 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: autcpu12.c,v 1.20 2004/07/20 02:44:26 dwmw2 Exp $ + * $Id: autcpu12.c,v 1.21 2004/09/16 23:27:14 gleixner Exp $ * * 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 @@ -48,7 +48,7 @@ static int autcpu12_io_base = CS89712_VIRT_BASE; static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC; static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET; static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET; -static int autcpu12_fio_base; +static void __iomem * autcpu12_fio_base; #ifdef MODULE MODULE_PARM(autcpu12_fio_pbase, "i"); @@ -150,7 +150,7 @@ int __init autcpu12_init (void) } /* map physical adress */ - autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K); + autcpu12_fio_base=(void __iomem *)ioremap(autcpu12_fio_pbase,SZ_1K); if(!autcpu12_fio_base){ printk("Ioremap autcpu12 SmartMedia Card failed\n"); err = -EIO; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0f7dedd6b88e..a94cca472f81 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -8,16 +8,22 @@ * Author: David Woodhouse * Additional Diskonchip 2000 and Millennium support by Dan Brown * Diskonchip Millennium Plus support by Kalev Lember - * + * + * Error correction code lifted from the old docecc code + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Copyright (C) 2000 Netgem S.A. + * converted to the generic Reed-Solomon library by Thomas Gleixner + * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.34 2004/08/09 19:41:12 dbrown Exp $ + * $Id: diskonchip.c,v 1.38 2004/10/05 22:11:46 gleixner Exp $ */ #include #include #include #include +#include #include #include @@ -62,7 +68,7 @@ static unsigned long __initdata doc_locations[] = { static struct mtd_info *doclist = NULL; struct doc_priv { - unsigned long virtadr; + void __iomem *virtadr; unsigned long physadr; u_char ChipID; u_char CDSNControl; @@ -104,8 +110,10 @@ MODULE_PARM(try_dword, "i"); static int no_ecc_failures=0; MODULE_PARM(no_ecc_failures, "i"); +#ifdef CONFIG_MTD_PARTITIONS static int no_autopart=0; MODULE_PARM(no_autopart, "i"); +#endif #ifdef MTD_NAND_DISKONCHIP_BBTWRITE static int inftl_bbt_write=1; @@ -118,6 +126,112 @@ static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; MODULE_PARM(doc_config_location, "l"); MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); + +/* Sector size for HW ECC */ +#define SECTOR_SIZE 512 +/* The sector bytes are packed into NB_DATA 10 bit words */ +#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10) +/* Number of roots */ +#define NROOTS 4 +/* First consective root */ +#define FCR 510 +/* Number of symbols */ +#define NN 1023 + +/* the Reed Solomon control structure */ +static struct rs_control *rs_decoder; + +/* + * The HW decoder in the DoC ASIC's provides us a error syndrome, + * which we must convert to a standard syndrom usable by the generic + * Reed-Solomon library code. + * + * Fabrice Bellard figured this out in the old docecc code. I added + * some comments, improved a minor bit and converted it to make use + * of the generic Reed-Solomon libary. tglx + */ +static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) +{ + int i, j, nerr, errpos[8]; + uint8_t parity; + uint16_t ds[4], s[5], tmp, errval[8], syn[4]; + + /* Convert the ecc bytes into words */ + ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8); + ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6); + ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4); + ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); + parity = ecc[1]; + + /* Initialize the syndrom buffer */ + for (i = 0; i < NROOTS; i++) + s[i] = ds[0]; + /* + * Evaluate + * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] + * where x = alpha^(FCR + i) + */ + for(j = 1; j < NROOTS; j++) { + if(ds[j] == 0) + continue; + tmp = rs->index_of[ds[j]]; + for(i = 0; i < NROOTS; i++) + s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)]; + } + + /* Calc s[i] = s[i] / alpha^(v + i) */ + for (i = 0; i < NROOTS; i++) { + if (syn[i]) + syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); + } + /* Call the decoder library */ + nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval); + + /* Incorrectable errors ? */ + if (nerr < 0) + return nerr; + + /* + * Correct the errors. The bitpositions are a bit of magic, + * but they are given by the design of the de/encoder circuit + * in the DoC ASIC's. + */ + for(i = 0;i < nerr; i++) { + int index, bitpos, pos = 1015 - errpos[i]; + uint8_t val; + if (pos >= NB_DATA && pos < 1019) + continue; + if (pos < NB_DATA) { + /* extract bit position (MSB first) */ + pos = 10 * (NB_DATA - 1 - pos) - 6; + /* now correct the following 10 bits. At most two bytes + can be modified since pos is even */ + index = (pos >> 3) ^ 1; + bitpos = pos & 7; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = (uint8_t) (errval[i] >> (2 + bitpos)); + parity ^= val; + if (index < SECTOR_SIZE) + data[index] ^= val; + } + index = ((pos >> 3) + 1) ^ 1; + bitpos = (bitpos + 10) & 7; + if (bitpos == 0) + bitpos = 8; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = (uint8_t)(errval[i] << (8 - bitpos)); + parity ^= val; + if (index < SECTOR_SIZE) + data[index] ^= val; + } + } + } + /* If the parity is wrong, no rescue possible */ + return parity ? -1 : nerr; +} + static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) { volatile char dummy; @@ -139,7 +253,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ static int _DoC_WaitReady(struct doc_priv *doc) { - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); if(debug) printk("_DoC_WaitReady...\n"); @@ -169,7 +283,7 @@ static int _DoC_WaitReady(struct doc_priv *doc) static inline int DoC_WaitReady(struct doc_priv *doc) { - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int ret = 0; if (DoC_is_MillenniumPlus(doc)) { @@ -195,7 +309,7 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; if(debug)printk("write_byte %02x\n", datum); WriteDOC(datum, docptr, CDSNSlowIO); @@ -206,7 +320,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; ReadDOC(docptr, CDSNSlowIO); @@ -221,7 +335,7 @@ static void doc2000_writebuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("writebuf of %d bytes: ", len); for (i=0; i < len; i++) { @@ -237,7 +351,7 @@ static void doc2000_readbuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("readbuf of %d bytes: ", len); @@ -252,7 +366,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug) printk("readbuf_dword of %d bytes: ", len); @@ -273,7 +387,7 @@ static int doc2000_verifybuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; for (i=0; i < len; i++) @@ -305,7 +419,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) uint32_t dword; uint8_t byte[4]; } ident; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); doc2000_write_byte(mtd, NAND_CMD_READID); @@ -364,7 +478,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; WriteDOC(datum, docptr, CDSNSlowIO); WriteDOC(datum, docptr, Mil_CDSN_IO); @@ -375,7 +489,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; //ReadDOC(docptr, CDSNSlowIO); /* 11.4.5 -- delay twice to allow extended length cycle */ @@ -390,7 +504,7 @@ static void doc2001_writebuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; for (i=0; i < len; i++) @@ -404,7 +518,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ @@ -422,7 +536,7 @@ static int doc2001_verifybuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ @@ -442,7 +556,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; ReadDOC(docptr, Mplus_ReadPipeInit); @@ -457,7 +571,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("writebuf of %d bytes: ", len); @@ -474,7 +588,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("readbuf of %d bytes: ", len); @@ -504,7 +618,7 @@ static int doc2001plus_verifybuf(struct mtd_info *mtd, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("verifybuf of %d bytes: ", len); @@ -530,7 +644,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; if(debug)printk("select chip (%d)\n", chip); @@ -556,7 +670,7 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; if(debug)printk("select chip (%d)\n", chip); @@ -583,7 +697,7 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; switch(cmd) { case NAND_CTL_SETNCE: @@ -621,7 +735,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* * Must terminate write pipeline before sending any commands @@ -725,7 +839,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; if (DoC_is_MillenniumPlus(doc)) { /* 11.4.2 -- must NOP four times before checking FR/B# */ @@ -763,7 +877,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ switch(mode) { @@ -782,7 +896,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ switch(mode) { @@ -803,7 +917,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; int emptymatch = 1; @@ -861,7 +975,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ int i, ret = 0; struct nand_chip *this = mtd->priv; struct doc_priv *doc = (void *)this->priv; - unsigned long docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; volatile u_char dummy; int emptymatch = 1; @@ -914,7 +1028,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ erased block, in which case the ECC will not come out right. We'll suppress the error and tell the caller everything's OK. Because it is. */ - if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc); + if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); if (ret > 0) printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); } @@ -1385,13 +1499,13 @@ static inline int __init doc_probe(unsigned long physadr) struct mtd_info *mtd; struct nand_chip *nand; struct doc_priv *doc; - unsigned long virtadr; + void __iomem *virtadr; unsigned char save_control; unsigned char tmp, tmpb, tmpc; int reg, len, numchips; int ret = 0; - virtadr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN); + virtadr = (void __iomem *)ioremap(physadr, DOC_IOREMAP_LEN); if (!virtadr) { printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); return -EIO; @@ -1518,7 +1632,7 @@ static inline int __init doc_probe(unsigned long physadr) sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); - mtd = kmalloc(len, GFP_KERNEL); + mtd = kmalloc(len, GFP_KERNEL); if (!mtd) { printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); ret = -ENOMEM; @@ -1543,7 +1657,7 @@ static inline int __init doc_probe(unsigned long physadr) nand->enable_hwecc = doc200x_enable_hwecc; nand->calculate_ecc = doc200x_calculate_ecc; nand->correct_data = doc200x_correct_data; - //nand->data_buf + nand->autooob = &doc200x_oobinfo; nand->eccmode = NAND_ECC_HW6_512; nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME; @@ -1589,6 +1703,23 @@ fail: return ret; } +static void release_nanddoc(void) +{ + struct mtd_info *mtd, *nextmtd; + struct nand_chip *nand; + struct doc_priv *doc; + + for (mtd = doclist; mtd; mtd = nextmtd) { + nand = mtd->priv; + doc = (void *)nand->priv; + + nextmtd = doc->nextdoc; + nand_release(mtd); + iounmap((void *)doc->virtadr); + kfree(mtd); + } +} + int __init init_nanddoc(void) { int i; @@ -1607,23 +1738,34 @@ int __init init_nanddoc(void) printk(KERN_INFO "No valid DiskOnChip devices found\n"); return -ENODEV; } + + /* We could create the decoder on demand, if memory is a concern. + * This way we have it handy, if an error happens + * + * Symbolsize is 10 (bits) + * Primitve polynomial is x^10+x^3+1 + * first consecutive root is 510 + * primitve element to generate roots = 1 + * generator polinomial degree = 4 + */ + rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); + if (!rs_decoder) { + printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); + release_nanddoc(); + return -ENOMEM; + } + return 0; } void __exit cleanup_nanddoc(void) { - struct mtd_info *mtd, *nextmtd; - struct nand_chip *nand; - struct doc_priv *doc; - - for (mtd = doclist; mtd; mtd = nextmtd) { - nand = mtd->priv; - doc = (void *)nand->priv; + /* Cleanup the nand/DoC resources */ + release_nanddoc(); - nextmtd = doc->nextdoc; - nand_release(mtd); - iounmap((void *)doc->virtadr); - kfree(mtd); + /* Free the reed solomon resources */ + if (rs_decoder) { + free_rs(rs_decoder); } } diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 797794069103..805102e000bd 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: edb7312.c,v 1.8 2004/07/12 15:03:26 dwmw2 Exp $ + * $Id: edb7312.c,v 1.10 2004/10/05 13:50:20 gleixner Exp $ * * 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 @@ -53,9 +53,9 @@ static struct mtd_info *ep7312_mtd = NULL; * Module stuff */ -static int ep7312_fio_pbase = EP7312_FIO_PBASE; -static int ep7312_pxdr = EP7312_PXDR; -static int ep7312_pxddr = EP7312_PXDDR; +static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; +static void __iomem * ep7312_pxdr = (void __iomem *) EP7312_PXDR; +static void __iomem * ep7312_pxddr = (void __iomem *) EP7312_PXDDR; #ifdef MODULE MODULE_PARM(ep7312_fio_pbase, "i"); @@ -131,7 +131,7 @@ static int __init ep7312_init (void) const char *part_type = 0; int mtd_parts_nb = 0; struct mtd_partition *mtd_parts = 0; - int ep7312_fio_base; + void __iomem * ep7312_fio_base; /* Allocate memory for MTD device structure and private data */ ep7312_mtd = kmalloc(sizeof(struct mtd_info) + @@ -143,7 +143,7 @@ static int __init ep7312_init (void) } /* map physical adress */ - ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K); + ep7312_fio_base = (void __iomem *)ioremap(ep7312_fio_pbase, SZ_1K); if(!ep7312_fio_base) { printk("ioremap EDB7312 NAND flash failed\n"); kfree(ep7312_mtd); @@ -181,16 +181,7 @@ static int __init ep7312_init (void) return -ENXIO; } - /* Allocate memory for internal data buffer */ - this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL); - if (!this->data_buf) { - printk("Unable to allocate NAND data buffer for EDB7312.\n"); - iounmap((void *)ep7312_fio_base); - kfree (ep7312_mtd); - return -ENOMEM; - } - -#ifdef CONFIG_PARTITIONS +#ifdef CONFIG_MTD_PARTITIONS ep7312_mtd->name = "edb7312-nand"; mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); @@ -221,8 +212,8 @@ static void __exit ep7312_cleanup (void) { struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; - /* Unregister the device */ - del_mtd_device (ep7312_mtd); + /* Release resources, unregister device */ + nand_release (ap7312_mtd); /* Free internal data buffer */ kfree (this->data_buf); diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c new file mode 100644 index 000000000000..5d284f68d706 --- /dev/null +++ b/drivers/mtd/nand/h1910.c @@ -0,0 +1,208 @@ +/* + * drivers/mtd/nand/h1910.c + * + * Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com) + * + * Derived from drivers/mtd/nand/edb7312.c + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * $Id: h1910.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is + * a 128Mibit (16MiB x 8 bits) NAND flash device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* for CLPS7111_VIRT_BASE */ +#include +#include +#include + +/* + * MTD structure for EDB7312 board + */ +static struct mtd_info *h1910_nand_mtd = NULL; + +/* + * Module stuff + */ + +#ifdef CONFIG_MTD_PARTITIONS +/* + * Define static partitions for flash device + */ +static struct mtd_partition partition_info[] = { + { name: "h1910 NAND Flash", + offset: 0, + size: 16*1024*1024 } +}; +#define NUM_PARTITIONS 1 + +#endif + + +/* + * hardware specific access to control-lines + */ +static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip* this = (struct nand_chip *) (mtd->priv); + + switch(cmd) { + + case NAND_CTL_SETCLE: + this->IO_ADDR_R |= (1 << 2); + this->IO_ADDR_W |= (1 << 2); + break; + case NAND_CTL_CLRCLE: + this->IO_ADDR_R &= ~(1 << 2); + this->IO_ADDR_W &= ~(1 << 2); + break; + + case NAND_CTL_SETALE: + this->IO_ADDR_R |= (1 << 3); + this->IO_ADDR_W |= (1 << 3); + break; + case NAND_CTL_CLRALE: + this->IO_ADDR_R &= ~(1 << 3); + this->IO_ADDR_W &= ~(1 << 3); + break; + + case NAND_CTL_SETNCE: + break; + case NAND_CTL_CLRNCE: + break; + } +} + +/* + * read device ready pin + */ +#if 0 +static int h1910_device_ready(struct mtd_info *mtd) +{ + return (GPLR(55) & GPIO_bit(55)); +} +#endif + +/* + * Main initialization routine + */ +static int __init h1910_init (void) +{ + struct nand_chip *this; + const char *part_type = 0; + int mtd_parts_nb = 0; + struct mtd_partition *mtd_parts = 0; + void __iomem *nandaddr; + + if (!machine_is_h1900()) + return -ENODEV; + + nandaddr = (void __iomem *)__ioremap(0x08000000, 0x1000, 0, 1); + if (!nandaddr) { + printk("Failed to ioremap nand flash.\n"); + return -ENOMEM; + } + + /* Allocate memory for MTD device structure and private data */ + h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + + sizeof(struct nand_chip), + GFP_KERNEL); + if (!h1910_nand_mtd) { + printk("Unable to allocate h1910 NAND MTD device structure.\n"); + iounmap ((void *) nandaddr); + return -ENOMEM; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&h1910_nand_mtd[1]); + + /* Initialize structures */ + memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + h1910_nand_mtd->priv = this; + + /* + * Enable VPEN + */ + GPSR(37) = GPIO_bit(37); + + /* insert callbacks */ + this->IO_ADDR_R = nandaddr; + this->IO_ADDR_W = nandaddr; + this->hwcontrol = h1910_hwcontrol; + this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ + /* 15 us command delay time */ + this->chip_delay = 50; + this->eccmode = NAND_ECC_SOFT; + this->options = NAND_NO_AUTOINCR; + + /* Scan to find existence of the device */ + if (nand_scan (h1910_nand_mtd, 1)) { + printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); + kfree (h1910_nand_mtd); + iounmap ((void *) nandaddr); + return -ENXIO; + } + +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, + "h1910-nand"); + if (mtd_parts_nb > 0) + part_type = "command line"; + else + mtd_parts_nb = 0; +#endif + if (mtd_parts_nb == 0) + { + mtd_parts = partition_info; + mtd_parts_nb = NUM_PARTITIONS; + part_type = "static"; + } + + /* Register the partitions */ + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); + + /* Return happy */ + return 0; +} +module_init(h1910_init); + +/* + * Clean up routine + */ +static void __exit h1910_cleanup (void) +{ + struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; + + /* Release resources, unregister device */ + nand_release (h1910_nand_mtd); + + /* Release io resource */ + iounmap ((void *) this->IO_ADDR_W); + + /* Free the MTD device structure */ + kfree (h1910_nand_mtd); +} +module_exit(h1910_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joshua Wise "); +MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910"); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ff6adf43f73a..181b95275352 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -24,6 +24,10 @@ * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * + * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared + * among multiple independend devices. Suggestions and initial patch + * from Ben Dooks + * * Credits: * David Woodhouse for adding multichip support * @@ -37,7 +41,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.115 2004/08/09 13:19:45 dwmw2 Exp $ + * $Id: nand_base.c,v 1.121 2004/10/06 19:53:11 gleixner Exp $ * * 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 @@ -131,25 +135,31 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int #define nand_verify_pages(...) (0) #endif -static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state); +static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); /** - * nand_release_chip - [GENERIC] release chip + * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */ -static void nand_release_chip (struct mtd_info *mtd) +static void nand_release_device (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* De-select the NAND device */ this->select_chip(mtd, -1); + /* Do we have a hardware controller ? */ + if (this->controller) { + spin_lock(&this->controller->lock); + this->controller->active = NULL; + spin_unlock(&this->controller->lock); + } /* Release the chip */ - spin_lock_bh (&this->chip_lock); + spin_lock (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); + spin_unlock (&this->chip_lock); } /** @@ -388,7 +398,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) chipnr = (int)(ofs >> this->chip_shift); /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_READING); + nand_get_device (this, mtd, FL_READING); /* Select the NAND device */ this->select_chip(mtd, chipnr); @@ -410,7 +420,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) if (getchip) { /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); } return res; @@ -533,8 +543,8 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) + /* One more address cycle for devices > 32MiB */ + if (this->chipsize > (32 << 20)) this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); } /* Latch in address */ @@ -689,15 +699,16 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, } /** - * nand_get_chip - [GENERIC] Get chip for selected access + * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ -static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state) +static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { + struct nand_chip *active = this; DECLARE_WAITQUEUE (wait, current); @@ -705,19 +716,29 @@ static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new * Grab the lock and see if the device is available */ retry: - spin_lock_bh (&this->chip_lock); - - if (this->state == FL_READY) { - this->state = new_state; - spin_unlock_bh (&this->chip_lock); - return; + /* Hardware controller shared among independend devices */ + if (this->controller) { + spin_lock (&this->controller->lock); + if (this->controller->active) + active = this->controller->active; + else + this->controller->active = this; + spin_unlock (&this->controller->lock); } - + + if (active == this) { + spin_lock (&this->chip_lock); + if (this->state == FL_READY) { + this->state = new_state; + spin_unlock (&this->chip_lock); + return; + } + } set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); + add_wait_queue (&active->wq, &wait); + spin_unlock (&active->chip_lock); schedule (); - remove_wait_queue (&this->wq, &wait); + remove_wait_queue (&active->wq, &wait); goto retry; } @@ -747,7 +768,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * any case on any machine. */ ndelay (100); - spin_lock_bh (&this->chip_lock); if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); else @@ -755,24 +775,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ - if (this->state != state) { - spin_unlock_bh (&this->chip_lock); + if (this->state != state) return 0; - } + if (this->dev_ready) { if (this->dev_ready(mtd)) + break; + } else { + if (this->read_byte(mtd) & NAND_STATUS_READY) break; } - if (this->read_byte(mtd) & NAND_STATUS_READY) - break; - - spin_unlock_bh (&this->chip_lock); yield (); - spin_lock_bh (&this->chip_lock); } status = (int) this->read_byte(mtd); - spin_unlock_bh (&this->chip_lock); - return status; } @@ -1051,7 +1066,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd ,FL_READING); + nand_get_device (this, mtd ,FL_READING); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1281,7 +1296,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG @@ -1328,7 +1343,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd , FL_READING); + nand_get_device (this, mtd , FL_READING); /* Select the NAND device */ this->select_chip(mtd, chipnr); @@ -1379,7 +1394,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t } /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); /* Return happy */ *retlen = len; @@ -1413,7 +1428,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd , FL_READING); + nand_get_device (this, mtd , FL_READING); this->select_chip (mtd, chip); @@ -1442,7 +1457,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); return 0; } @@ -1564,7 +1579,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_WRITING); + nand_get_device (this, mtd, FL_WRITING); /* Calculate chipnr */ chipnr = (int)(to >> this->chip_shift); @@ -1669,7 +1684,7 @@ cmp: out: /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); return ret; } @@ -1709,7 +1724,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_WRITING); + nand_get_device (this, mtd, FL_WRITING); /* Select the NAND device */ this->select_chip(mtd, chipnr); @@ -1771,7 +1786,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret = 0; out: /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); return ret; } @@ -1838,7 +1853,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig } /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_WRITING); + nand_get_device (this, mtd, FL_WRITING); /* Get the current chip-nr */ chipnr = (int) (to >> this->chip_shift); @@ -1952,7 +1967,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig ret = 0; out: /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); *retlen = written; return ret; @@ -2041,7 +2056,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb instr->fail_addr = 0xffffffff; /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_ERASING); + nand_get_device (this, mtd, FL_ERASING); /* Shift to get first page */ page = (int) (instr->addr >> this->page_shift); @@ -2112,7 +2127,7 @@ erase_exit: mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ - nand_release_chip(mtd); + nand_release_device(mtd); /* Return more or less happy */ return ret; @@ -2127,43 +2142,13 @@ erase_exit: static void nand_sync (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE (wait, current); DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); -retry: - /* Grab the spinlock */ - spin_lock_bh (&this->chip_lock); - - /* See what's going on */ - switch (this->state) { - case FL_READY: - case FL_SYNCING: - this->state = FL_SYNCING; - spin_unlock_bh (&this->chip_lock); - break; - - default: - /* Not an idle state */ - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule (); - - remove_wait_queue (&this->wq, &wait); - goto retry; - } - - /* Lock the device */ - spin_lock_bh (&this->chip_lock); - - /* Set the device to be ready again */ - if (this->state == FL_SYNCING) { - this->state = FL_READY; - wake_up (&this->wq); - } - - /* Unlock the device */ - spin_unlock_bh (&this->chip_lock); + /* Grab the lock and see if the device is available */ + nand_get_device (this, mtd, FL_SYNCING); + /* Release it and go back */ + nand_release_device (mtd); } diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 2642e11516e7..77f08d1ee14f 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,7 +6,7 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.24 2004/06/28 08:25:35 gleixner Exp $ + * $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 gleixner Exp $ * * 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 @@ -114,6 +114,7 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des * @num: the number of bbt descriptors to read * @bits: number of bits per block * @offs: offset in the memory table + * @reserved_block_code: Pattern to identify reserved blocks * * Read the bad block table starting from page. * @@ -796,7 +797,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate memory (2bit per block) */ - this->bbt = (uint8_t *) kmalloc (len, GFP_KERNEL); + this->bbt = kmalloc (len, GFP_KERNEL); if (!this->bbt) { printk (KERN_ERR "nand_scan_bbt: Out of memory\n"); return -ENOMEM; diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 9c356a0a78ec..d024a5b9a1a8 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/edb7312.c * * - * $Id: ppchameleonevb.c,v 1.2 2004/05/05 22:09:54 gleixner Exp $ + * $Id: ppchameleonevb.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ * * 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 @@ -74,12 +74,6 @@ MODULE_PARM(ppchameleonevb_fio_pbase, "i"); __setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase); #endif -/* Internal buffers. Page buffer and oob buffer for one block */ -static u_char data_buf[2048 + 64]; -static u_char oob_buf[64 * 64]; -static u_char data_buf_evb[512 + 16]; -static u_char oob_buf_evb[16 * 32]; - #ifdef CONFIG_MTD_PARTITIONS /* * Define static partitions for flash devices @@ -196,8 +190,8 @@ static int __init ppchameleonevb_init (void) const char *part_type = 0; int mtd_parts_nb = 0; struct mtd_partition *mtd_parts = 0; - int ppchameleon_fio_base; - int ppchameleonevb_fio_base; + void __iomem *ppchameleon_fio_base; + void __iomem *ppchameleonevb_fio_base; /********************************* @@ -205,15 +199,14 @@ static int __init ppchameleonevb_init (void) *********************************/ /* Allocate memory for MTD device structure and private data */ ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), - GFP_KERNEL); + sizeof(struct nand_chip), GFP_KERNEL); if (!ppchameleon_mtd) { printk("Unable to allocate PPChameleon NAND MTD device structure.\n"); return -ENOMEM; } /* map physical address */ - ppchameleon_fio_base = (unsigned long)ioremap(ppchameleon_fio_pbase, SZ_4M); + ppchameleon_fio_base = (void __iomem *) ioremap(ppchameleon_fio_pbase, SZ_4M); if(!ppchameleon_fio_base) { printk("ioremap PPChameleon NAND flash failed\n"); kfree(ppchameleon_mtd); @@ -264,10 +257,6 @@ static int __init ppchameleonevb_init (void) /* ECC mode */ this->eccmode = NAND_ECC_SOFT; - /* Set internal data buffer */ - this->data_buf = data_buf; - this->oob_buf = oob_buf; - /* Scan to find existence of the device (it could not be mounted) */ if (nand_scan (ppchameleon_mtd, 1)) { iounmap((void *)ppchameleon_fio_base); @@ -309,15 +298,14 @@ nand_evb_init: ****************************/ /* Allocate memory for MTD device structure and private data */ ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), - GFP_KERNEL); + sizeof(struct nand_chip), GFP_KERNEL); if (!ppchameleonevb_mtd) { printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n"); return -ENOMEM; } /* map physical address */ - ppchameleonevb_fio_base = (unsigned long)ioremap(ppchameleonevb_fio_pbase, SZ_4M); + ppchameleonevb_fio_base = (void __iomem *)ioremap(ppchameleonevb_fio_pbase, SZ_4M); if(!ppchameleonevb_fio_base) { printk("ioremap PPChameleonEVB NAND flash failed\n"); kfree(ppchameleonevb_mtd); @@ -349,7 +337,8 @@ nand_evb_init: out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); /* enable output driver */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); + out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | + NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); #ifdef USE_READY_BUSY_PIN /* three-state select */ out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC); @@ -359,7 +348,6 @@ nand_evb_init: out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001); #endif - /* insert callbacks */ this->IO_ADDR_R = ppchameleonevb_fio_base; this->IO_ADDR_W = ppchameleonevb_fio_base; @@ -372,10 +360,6 @@ nand_evb_init: /* ECC mode */ this->eccmode = NAND_ECC_SOFT; - /* Set internal data buffer */ - this->data_buf = data_buf_evb; - this->oob_buf = oob_buf_evb; - /* Scan to find existence of the device */ if (nand_scan (ppchameleonevb_mtd, 1)) { iounmap((void *)ppchameleonevb_fio_base); @@ -412,15 +396,20 @@ module_init(ppchameleonevb_init); */ static void __exit ppchameleonevb_cleanup (void) { - struct nand_chip *this = (struct nand_chip *) &ppchameleonevb_mtd[1]; - - /* Unregister the device */ - del_mtd_device (ppchameleonevb_mtd); + struct nand_chip *this; - /* Free internal data buffer */ - kfree (this->data_buf); + /* Release resources, unregister device(s) */ + nand_release (ppchameleon_mtd); + nand_release (ppchameleonevb_mtd); + + /* Release iomaps */ + this = (struct nand_chip *) &ppchameleon_mtd[1]; + iounmap((void *) this->IO_ADDR_R; + this = (struct nand_chip *) &ppchameleonevb_mtd[1]; + iounmap((void *) this->IO_ADDR_R; /* Free the MTD device structure */ + kfree (ppchameleon_mtd); kfree (ppchameleonevb_mtd); } module_exit(ppchameleonevb_cleanup); diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c new file mode 100644 index 000000000000..2d65fa7ce0d1 --- /dev/null +++ b/drivers/mtd/nand/rtc_from4.c @@ -0,0 +1,561 @@ +/* + * drivers/mtd/nand/rtc_from4.c + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Derived from drivers/mtd/nand/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * + * $Id: rtc_from4.c,v 1.6 2004/10/05 22:11:46 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the AG-AND flash device found on the + * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), + * which utilizes the Renesas HN29V1G91T-30 part. + * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MTD structure for Renesas board + */ +static struct mtd_info *rtc_from4_mtd = NULL; + +#define RTC_FROM4_MAX_CHIPS 2 + +/* HS77x9 processor register defines */ +#define SH77X9_BCR1 ((volatile unsigned short *)(0xFFFFFF60)) +#define SH77X9_BCR2 ((volatile unsigned short *)(0xFFFFFF62)) +#define SH77X9_WCR1 ((volatile unsigned short *)(0xFFFFFF64)) +#define SH77X9_WCR2 ((volatile unsigned short *)(0xFFFFFF66)) +#define SH77X9_MCR ((volatile unsigned short *)(0xFFFFFF68)) +#define SH77X9_PCR ((volatile unsigned short *)(0xFFFFFF6C)) +#define SH77X9_FRQCR ((volatile unsigned short *)(0xFFFFFF80)) + +/* + * Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor) + */ +/* Address where flash is mapped */ +#define RTC_FROM4_FIO_BASE 0x14000000 + +/* CLE and ALE are tied to address lines 5 & 4, respectively */ +#define RTC_FROM4_CLE (1 << 5) +#define RTC_FROM4_ALE (1 << 4) + +/* address lines A24-A22 used for chip selection */ +#define RTC_FROM4_NAND_ADDR_SLOT3 (0x00800000) +#define RTC_FROM4_NAND_ADDR_SLOT4 (0x00C00000) +#define RTC_FROM4_NAND_ADDR_FPGA (0x01000000) +/* mask address lines A24-A22 used for chip selection */ +#define RTC_FROM4_NAND_ADDR_MASK (RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA) + +/* FPGA status register for checking device ready (bit zero) */ +#define RTC_FROM4_FPGA_SR (RTC_FROM4_NAND_ADDR_FPGA | 0x00000002) +#define RTC_FROM4_DEVICE_READY 0x0001 + +/* FPGA Reed-Solomon ECC Control register */ + +#define RTC_FROM4_RS_ECC_CTL (RTC_FROM4_NAND_ADDR_FPGA | 0x00000050) +#define RTC_FROM4_RS_ECC_CTL_CLR (1 << 7) +#define RTC_FROM4_RS_ECC_CTL_GEN (1 << 6) +#define RTC_FROM4_RS_ECC_CTL_FD_E (1 << 5) + +/* FPGA Reed-Solomon ECC code base */ +#define RTC_FROM4_RS_ECC (RTC_FROM4_NAND_ADDR_FPGA | 0x00000060) +#define RTC_FROM4_RS_ECCN (RTC_FROM4_NAND_ADDR_FPGA | 0x00000080) + +/* FPGA Reed-Solomon ECC check register */ +#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) +#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) + +/* Undefine for software ECC */ +#define RTC_FROM4_HWECC 1 + +/* + * Module stuff + */ +static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE); + +MODULE_PARM(rtc_from4_fio_base, "i"); + +const static struct mtd_partition partition_info[] = { + { + .name = "Renesas flash partition 1", + .offset = 0, + .size = MTDPART_SIZ_FULL + }, +}; +#define NUM_PARTITIONS 1 + +/* + * hardware specific flash bbt decriptors + * Note: this is to allow debugging by disabling + * NAND_BBT_CREATE and/or NAND_BBT_WRITE + * + */ +static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr rtc_from4_bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 40, + .len = 4, + .veroffs = 44, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 40, + .len = 4, + .veroffs = 44, + .maxblocks = 4, + .pattern = mirror_pattern +}; + + + +#ifdef RTC_FROM4_HWECC + +/* the Reed Solomon control structure */ +static struct rs_control *rs_decoder; + +/* + * hardware specific Out Of Band information + */ +static struct nand_oobinfo rtc_from4_nand_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 32, + .eccpos = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31}, + .oobfree = { {32, 32} } +}; + +/* Aargh. I missed the reversed bit order, when I + * was talking to Renesas about the FPGA. + * + * The table is used for bit reordering and inversion + * of the ecc byte which we get from the FPGA + */ +static uint8_t revbits[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +#endif + + + +/* + * rtc_from4_hwcontrol - hardware specific access to control-lines + * @mtd: MTD device structure + * @cmd: hardware control command + * + * Address lines (A5 and A4) are used to control Command and Address Latch + * Enable on this board, so set the read/write address appropriately. + * + * Chip Enable is also controlled by the Chip Select (CS5) and + * Address lines (A24-A22), so no action is required here. + * + */ +static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip* this = (struct nand_chip *) (mtd->priv); + + switch(cmd) { + + case NAND_CTL_SETCLE: + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); + break; + case NAND_CTL_CLRCLE: + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); + break; + + case NAND_CTL_SETALE: + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); + break; + case NAND_CTL_CLRALE: + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); + break; + + case NAND_CTL_SETNCE: + break; + case NAND_CTL_CLRNCE: + break; + + } +} + + +/* + * rtc_from4_nand_select_chip - hardware specific chip select + * @mtd: MTD device structure + * @chip: Chip to select (0 == slot 3, 1 == slot 4) + * + * The chip select is based on address lines A24-A22. + * This driver uses flash slots 3 and 4 (A23-A22). + * + */ +static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK); + + switch(chip) { + + case 0: /* select slot 3 chip */ + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3); + break; + case 1: /* select slot 4 chip */ + this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4); + this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4); + break; + + } +} + + + +/* + * rtc_from4_nand_device_ready - hardware specific ready/busy check + * @mtd: MTD device structure + * + * This board provides the Ready/Busy state in the status register + * of the FPGA. Bit zero indicates the RDY(1)/BSY(0) signal. + * + */ +static int rtc_from4_nand_device_ready(struct mtd_info *mtd) +{ + unsigned short status; + + status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR)); + + return (status & RTC_FROM4_DEVICE_READY); + +} + +#ifdef RTC_FROM4_HWECC +/* + * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function + * @mtd: MTD device structure + * @mode: I/O mode; read or write + * + * enable hardware ECC for data read or write + * + */ +static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) +{ + volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL); + unsigned short status; + + switch (mode) { + case NAND_ECC_READ : + status = RTC_FROM4_RS_ECC_CTL_CLR + | RTC_FROM4_RS_ECC_CTL_FD_E; + + *rs_ecc_ctl = status; + break; + + case NAND_ECC_READSYN : + status = 0x00; + + *rs_ecc_ctl = status; + break; + + case NAND_ECC_WRITE : + status = RTC_FROM4_RS_ECC_CTL_CLR + | RTC_FROM4_RS_ECC_CTL_GEN + | RTC_FROM4_RS_ECC_CTL_FD_E; + + *rs_ecc_ctl = status; + break; + + default: + BUG(); + break; + } + +} + +/* + * rtc_from4_calculate_ecc - hardware specific code to read ECC code + * @mtd: MTD device structure + * @dat: buffer containing the data to generate ECC codes + * @ecc_code ECC codes calculated + * + * The ECC code is calculated by the FPGA. All we have to do is read the values + * from the FPGA registers. + * + * Note: We read from the inverted registers, since data is inverted before + * the code is calculated. So all 0xff data (blank page) results in all 0xff rs code + * + */ +static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN); + unsigned short value; + int i; + + for (i = 0; i < 8; i++) { + value = *rs_eccn; + ecc_code[i] = (unsigned char)value; + rs_eccn++; + } + ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ +} + +/* + * rtc_from4_correct_data - hardware specific code to correct data using ECC code + * @mtd: MTD device structure + * @buf: buffer containing the data to generate ECC codes + * @ecc1 ECC codes read + * @ecc2 ECC codes calculated + * + * The FPGA tells us fast, if there's an error or not. If no, we go back happy + * else we read the ecc results from the fpga and call the rs library to decode + * and hopefully correct the error + * + * For now I use the code, which we read from the FLASH to use the RS lib, + * as the syndrom conversion has a unresolved issue. + */ +static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) +{ + int i, j, res; + unsigned short status; + uint16_t par[6], syn[6], tmp; + uint8_t ecc[8]; + volatile unsigned short *rs_ecc; + + status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK)); + + if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR)) { + return 0; + } + + /* Read the syndrom pattern from the FPGA and correct the bitorder */ + rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); + for (i = 0; i < 8; i++) { + ecc[i] = revbits[(*rs_ecc) & 0xFF]; + rs_ecc++; + } + + /* convert into 6 10bit syndrome fields */ + par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | + (((uint16_t)ecc[1] << 8) & 0x300)]; + par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | + (((uint16_t)ecc[2] << 6) & 0x3c0)]; + par[3] = rs_decoder->index_of[(((uint16_t)ecc[2] >> 4) & 0x00f) | + (((uint16_t)ecc[3] << 4) & 0x3f0)]; + par[2] = rs_decoder->index_of[(((uint16_t)ecc[3] >> 6) & 0x003) | + (((uint16_t)ecc[4] << 2) & 0x3fc)]; + par[1] = rs_decoder->index_of[(((uint16_t)ecc[5] >> 0) & 0x0ff) | + (((uint16_t)ecc[6] << 8) & 0x300)]; + par[0] = (((uint16_t)ecc[6] >> 2) & 0x03f) | (((uint16_t)ecc[7] << 6) & 0x3c0); + + /* Convert to computable syndrome */ + for (i = 0; i < 6; i++) { + syn[i] = par[0]; + for (j = 1; j < 6; j++) + if (par[j] != rs_decoder->nn) + syn[i] ^= rs_decoder->alpha_to[rs_modnn(rs_decoder, par[j] + i * j)]; + + /* Convert to index form */ + syn[i] = rs_decoder->index_of[syn[i]]; + } + + /* Let the library code do its magic.*/ + res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL); + if (res > 0) { + DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " + "ECC corrected %d errors on read\n", res); + } + return res; +} +#endif + +/* + * Main initialization routine + */ +int __init rtc_from4_init (void) +{ + struct nand_chip *this; + unsigned short bcr1, bcr2, wcr2; + + /* Allocate memory for MTD device structure and private data */ + rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), + GFP_KERNEL); + if (!rtc_from4_mtd) { + printk ("Unable to allocate Renesas NAND MTD device structure.\n"); + return -ENOMEM; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&rtc_from4_mtd[1]); + + /* Initialize structures */ + memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + rtc_from4_mtd->priv = this; + + /* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */ + bcr1 = *SH77X9_BCR1 & ~0x0002; + bcr1 |= 0x0002; + *SH77X9_BCR1 = bcr1; + + /* set */ + bcr2 = *SH77X9_BCR2 & ~0x0c00; + bcr2 |= 0x0800; + *SH77X9_BCR2 = bcr2; + + /* set area 5 wait states */ + wcr2 = *SH77X9_WCR2 & ~0x1c00; + wcr2 |= 0x1c00; + *SH77X9_WCR2 = wcr2; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = rtc_from4_fio_base; + this->IO_ADDR_W = rtc_from4_fio_base; + /* Set address of hardware control function */ + this->hwcontrol = rtc_from4_hwcontrol; + /* Set address of chip select function */ + this->select_chip = rtc_from4_nand_select_chip; + /* command delay time (in us) */ + this->chip_delay = 100; + /* return the status of the Ready/Busy line */ + this->dev_ready = rtc_from4_nand_device_ready; + +#ifdef RTC_FROM4_HWECC + printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n"); + + this->eccmode = NAND_ECC_HW8_512; + this->options |= NAND_HWECC_SYNDROME; + /* set the nand_oobinfo to support FPGA H/W error detection */ + this->autooob = &rtc_from4_nand_oobinfo; + this->enable_hwecc = rtc_from4_enable_hwecc; + this->calculate_ecc = rtc_from4_calculate_ecc; + this->correct_data = rtc_from4_correct_data; +#else + printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n"); + + this->eccmode = NAND_ECC_SOFT; +#endif + + /* set the bad block tables to support debugging */ + this->bbt_td = &rtc_from4_bbt_main_descr; + this->bbt_md = &rtc_from4_bbt_mirror_descr; + + /* Scan to find existence of the device */ + if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) { + kfree(rtc_from4_mtd); + return -ENXIO; + } + + /* Register the partitions */ + add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); + +#ifdef RTC_FROM4_HWECC + /* We could create the decoder on demand, if memory is a concern. + * This way we have it handy, if an error happens + * + * Symbolsize is 10 (bits) + * Primitve polynomial is x^10+x^3+1 + * first consecutive root is 0 + * primitve element to generate roots = 1 + * generator polinomial degree = 6 + */ + rs_decoder = init_rs(10, 0x409, 0, 1, 6); + if (!rs_decoder) { + printk (KERN_ERR "Could not create a RS decoder\n"); + nand_release(rtc_from4_mtd); + kfree(rtc_from4_mtd); + return -ENOMEM; + } +#endif + /* Return happy */ + return 0; +} +module_init(rtc_from4_init); + + +/* + * Clean up routine + */ +#ifdef MODULE +static void __exit rtc_from4_cleanup (void) +{ + /* Release resource, unregister partitions */ + nand_release(rtc_from4_mtd); + + /* Free the MTD device structure */ + kfree (rtc_from4_mtd); + +#ifdef RTC_FROM4_HWECC + /* Free the reed solomon resources */ + if (rs_decoder) { + free_rs(rs_decoder); + } +#endif +} +module_exit(rtc_from4_cleanup); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("d.marlin + * + * Samsung S3C2410 NAND driver + * + * Changelog: + * 21-Sep-2004 BJD Initial version + * 23-Sep-2004 BJD Mulitple device support + * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode + * 12-Oct-2004 BJD Fixed errors in use of platform data + * + * $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include + +#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define PFX "s3c2410-nand: " + +#ifdef CONFIG_MTD_NAND_S3C2410_HWECC +static int hardware_ecc = 1; +#else +static int hardware_ecc = 0; +#endif + +/* new oob placement block for use with hardware ecc generation + */ + +static struct nand_oobinfo nand_hw_eccoob = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 3, + .eccpos = {0, 1, 2 }, + .oobfree = { {8, 8} } +}; + +/* controller and mtd information */ + +struct s3c2410_nand_info; + +struct s3c2410_nand_mtd { + struct mtd_info mtd; + struct nand_chip chip; + struct s3c2410_nand_set *set; + struct s3c2410_nand_info *info; + int scan_res; +}; + +/* overview of the s3c2410 nand state */ + +struct s3c2410_nand_info { + /* mtd info */ + struct nand_hw_control controller; + struct s3c2410_nand_mtd *mtds; + struct s3c2410_platform_nand *platform; + + /* device info */ + struct device *device; + struct resource *area; + struct clk *clk; + void *regs; + int mtd_count; +}; + +/* conversion functions */ + +static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd) +{ + return container_of(mtd, struct s3c2410_nand_mtd, mtd); +} + +static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd) +{ + return s3c2410_nand_mtd_toours(mtd)->info; +} + +static struct s3c2410_nand_info *to_nand_info(struct device *dev) +{ + return (struct s3c2410_nand_info *)dev_get_drvdata(dev); +} + +static struct s3c2410_platform_nand *to_nand_plat(struct device *dev) +{ + return (struct s3c2410_platform_nand *)dev->platform_data; +} + +/* timing calculations */ + +#define NS_IN_KHZ 10000000 + +static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) +{ + int result; + + result = (wanted * NS_IN_KHZ) / clk; + result++; + + pr_debug("result %d from %ld, %d\n", result, clk, wanted); + + if (result > max) { + printk("%d ns is too big for current clock rate %ld\n", + wanted, clk); + return -1; + } + + if (result < 1) + result = 1; + + return result; +} + +#define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ) + +/* controller setup */ + +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, + struct device *dev) +{ + struct s3c2410_platform_nand *plat = to_nand_plat(dev); + unsigned int tacls, twrph0, twrph1; + unsigned long clkrate = clk_get_rate(info->clk); + unsigned long cfg; + + /* calculate the timing information for the controller */ + + if (plat != NULL) { + tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8); + twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); + twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); + } else { + /* default timings */ + tacls = 8; + twrph0 = 8; + twrph1 = 8; + } + + if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { + printk(KERN_ERR PFX "cannot get timings suitable for board\n"); + return -EINVAL; + } + + printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n", + to_ns(tacls, clkrate), + to_ns(twrph0, clkrate), + to_ns(twrph1, clkrate)); + + cfg = S3C2410_NFCONF_EN; + cfg |= S3C2410_NFCONF_TACLS(tacls-1); + cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); + cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); + + pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); + + writel(cfg, info->regs + S3C2410_NFCONF); + return 0; +} + +/* select chip */ + +static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct s3c2410_nand_info *info; + struct s3c2410_nand_mtd *nmtd; + struct nand_chip *this = mtd->priv; + unsigned long cur; + + nmtd = (struct s3c2410_nand_mtd *)this->priv; + info = nmtd->info; + + cur = readl(info->regs + S3C2410_NFCONF); + + if (chip == -1) { + cur |= S3C2410_NFCONF_nFCE; + } else { + if (chip > nmtd->set->nr_chips) { + printk(KERN_ERR PFX "chip %d out of range\n", chip); + return; + } + + if (info->platform != NULL) { + if (info->platform->select_chip != NULL) + (info->platform->select_chip)(nmtd->set, chip); + } + + cur &= ~S3C2410_NFCONF_nFCE; + } + + writel(cur, info->regs + S3C2410_NFCONF); +} + +/* command and control functions */ + +static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long cur; + + switch (cmd) { + case NAND_CTL_SETNCE: + cur = readl(info->regs + S3C2410_NFCONF); + cur &= ~S3C2410_NFCONF_nFCE; + writel(cur, info->regs + S3C2410_NFCONF); + break; + + case NAND_CTL_CLRNCE: + cur = readl(info->regs + S3C2410_NFCONF); + cur |= S3C2410_NFCONF_nFCE; + writel(cur, info->regs + S3C2410_NFCONF); + break; + + /* we don't need to implement these */ + case NAND_CTL_SETCLE: + case NAND_CTL_CLRCLE: + case NAND_CTL_SETALE: + case NAND_CTL_CLRALE: + pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd); + break; + } +} + +/* s3c2410_nand_command + * + * This function implements sending commands and the relevant address + * information to the chip, via the hardware controller. Since the + * S3C2410 generates the correct ALE/CLE signaling automatically, we + * do not need to use hwcontrol. +*/ + +static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + register struct nand_chip *this = mtd->priv; + + /* + * Write out the command to the device. + */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->oobblock) { + /* OOB area */ + column -= mtd->oobblock; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + + writeb(readcmd, info->regs + S3C2410_NFCMD); + } + writeb(command, info->regs + S3C2410_NFCMD); + + /* Set ALE and clear CLE to start address cycle */ + + if (column != -1 || page_addr != -1) { + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (this->options & NAND_BUSWIDTH_16) + column >>= 1; + writeb(column, info->regs + S3C2410_NFADDR); + } + if (page_addr != -1) { + writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR); + writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR); + /* One more address cycle for higher density devices */ + if (this->chipsize & 0x0c000000) + writeb((unsigned char) ((page_addr >> 16) & 0x0f), + info->regs + S3C2410_NFADDR); + } + /* Latch in address */ + } + + /* + * program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; + + case NAND_CMD_RESET: + if (this->dev_ready) + break; + + udelay(this->chip_delay); + writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD); + + while ( !(this->read_byte(mtd) & 0x40)); + return; + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!this->dev_ready) { + udelay (this->chip_delay); + return; + } + } + + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay (100); + /* wait until command is processed */ + while (!this->dev_ready(mtd)); +} + + +/* s3c2410_nand_devready() + * + * returns 0 if the nand is busy, 1 if it is ready +*/ + +static int s3c2410_nand_devready(struct mtd_info *mtd) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + + return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; +} + +/* ECC handling functions */ + +static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", + mtd, dat, read_ecc, calc_ecc); + + pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n", + read_ecc[0], read_ecc[1], read_ecc[2], + calc_ecc[0], calc_ecc[1], calc_ecc[2]); + + if (read_ecc[0] == calc_ecc[0] && + read_ecc[1] == calc_ecc[1] && + read_ecc[2] == calc_ecc[2]) + return 0; + + /* we curently have no method for correcting the error */ + + return -1; +} + +static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long ctrl; + + ctrl = readl(info->regs + S3C2410_NFCONF); + ctrl |= S3C2410_NFCONF_INITECC; + writel(ctrl, info->regs + S3C2410_NFCONF); +} + +static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + + ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0); + ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); + ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); + + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", + ecc_code[0], ecc_code[1], ecc_code[2]); + + return 0; +} + + +/* over-ride the standard functions for a little more speed? */ + +static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *this = (struct nand_chip *)mtd->priv; + readsb(this->IO_ADDR_R, buf, len); +} + +static void s3c2410_nand_write_buf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = (struct nand_chip *)mtd->priv; + writesb(this->IO_ADDR_W, buf, len); +} + +/* device management functions */ + +static int s3c2410_nand_remove(struct device *dev) +{ + struct s3c2410_nand_info *info = to_nand_info(dev); + + dev_set_drvdata(dev, NULL); + + if (info == NULL) + return 0; + + /* first thing we need to do is release all our mtds + * and their partitions, then go through freeing the + * resources used + */ + + if (info->mtds != NULL) { + struct s3c2410_nand_mtd *ptr = info->mtds; + int mtdno; + + for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) { + pr_debug("releasing mtd %d (%p)\n", mtdno, ptr); + nand_release(&ptr->mtd); + } + + kfree(info->mtds); + } + + /* free the common resources */ + + if (info->clk != NULL && !IS_ERR(info->clk)) { + clk_disable(info->clk); + clk_unuse(info->clk); + clk_put(info->clk); + } + + if (info->regs != NULL) { + iounmap(info->regs); + info->regs = NULL; + } + + if (info->area != NULL) { + release_resource(info->area); + kfree(info->area); + info->area = NULL; + } + + kfree(info); + + return 0; +} + +#ifdef CONFIG_MTD_PARTITIONS +static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, + struct s3c2410_nand_mtd *mtd, + struct s3c2410_nand_set *set) +{ + if (set == NULL) + return add_mtd_device(&mtd->mtd); + + if (set->nr_partitions > 0 && set->partitions != NULL) { + return add_mtd_partitions(&mtd->mtd, + set->partitions, + set->nr_partitions); + } + + return add_mtd_device(&mtd->mtd); +} +#else +static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, + struct s3c2410_nand_mtd *mtd, + struct s3c2410_nand_set *set) +{ + return add_mtd_device(&mtd->mtd); +} +#endif + +/* s3c2410_nand_init_chip + * + * init a single instance of an chip +*/ + +static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, + struct s3c2410_nand_mtd *nmtd, + struct s3c2410_nand_set *set) +{ + struct nand_chip *chip = &nmtd->chip; + + chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA; + chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA; + chip->hwcontrol = s3c2410_nand_hwcontrol; + chip->dev_ready = s3c2410_nand_devready; + chip->cmdfunc = s3c2410_nand_command; + chip->write_buf = s3c2410_nand_write_buf; + chip->read_buf = s3c2410_nand_read_buf; + chip->select_chip = s3c2410_nand_select_chip; + chip->chip_delay = 50; + chip->priv = nmtd; + chip->options = 0; + chip->controller = &info->controller; + + nmtd->info = info; + nmtd->mtd.priv = chip; + nmtd->set = set; + + if (hardware_ecc) { + chip->correct_data = s3c2410_nand_correct_data; + chip->enable_hwecc = s3c2410_nand_enable_hwecc; + chip->calculate_ecc = s3c2410_nand_calculate_ecc; + chip->eccmode = NAND_ECC_HW3_512; + chip->autooob = &nand_hw_eccoob; + } else { + chip->eccmode = NAND_ECC_SOFT; + } +} + +/* s3c2410_nand_probe + * + * called by device layer when it finds a device matching + * one our driver can handled. This code checks to see if + * it can allocate all necessary resources then calls the + * nand layer to look for devices +*/ + +static int s3c2410_nand_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c2410_platform_nand *plat = to_nand_plat(dev); + struct s3c2410_nand_info *info; + struct s3c2410_nand_mtd *nmtd; + struct s3c2410_nand_set *sets; + struct resource *res; + int err = 0; + int size; + int nr_sets; + int setno; + + pr_debug("s3c2410_nand_probe(%p)\n", dev); + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + printk(KERN_ERR PFX "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info, sizeof(*info)); + dev_set_drvdata(dev, info); + + spin_lock_init(&info->controller.lock); + + /* get the clock source and enable it */ + + info->clk = clk_get(dev, "nand"); + if (IS_ERR(info->clk)) { + printk(KERN_ERR PFX "failed to get clock"); + err = -ENOENT; + goto exit_error; + } + + clk_use(info->clk); + clk_enable(info->clk); + + /* allocate and map the resource */ + + res = pdev->resource; /* assume that the flash has one resource */ + size = res->end - res->start + 1; + + info->area = request_mem_region(res->start, size, pdev->name); + + if (info->area == NULL) { + printk(KERN_ERR PFX "cannot reserve register region\n"); + err = -ENOENT; + goto exit_error; + } + + info->device = dev; + info->platform = plat; + info->regs = ioremap(res->start, size); + + if (info->regs == NULL) { + printk(KERN_ERR PFX "cannot reserve register region\n"); + err = -EIO; + goto exit_error; + } + + printk(KERN_INFO PFX "mapped registers at %p\n", info->regs); + + /* initialise the hardware */ + + err = s3c2410_nand_inithw(info, dev); + if (err != 0) + goto exit_error; + + sets = (plat != NULL) ? plat->sets : NULL; + nr_sets = (plat != NULL) ? plat->nr_sets : 1; + + info->mtd_count = nr_sets; + + /* allocate our information */ + + size = nr_sets * sizeof(*info->mtds); + info->mtds = kmalloc(size, GFP_KERNEL); + if (info->mtds == NULL) { + printk(KERN_ERR PFX "failed to allocate mtd storage\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info->mtds, size); + + /* initialise all possible chips */ + + nmtd = info->mtds; + + for (setno = 0; setno < nr_sets; setno++, nmtd++) { + pr_debug("initialising set %d (%p, info %p)\n", + setno, nmtd, info); + + s3c2410_nand_init_chip(info, nmtd, sets); + + nmtd->scan_res = nand_scan(&nmtd->mtd, + (sets) ? sets->nr_chips : 1); + + if (nmtd->scan_res == 0) { + s3c2410_nand_add_partition(info, nmtd, sets); + } + + if (sets != NULL) + sets++; + } + + pr_debug("initialised ok\n"); + return 0; + + exit_error: + s3c2410_nand_remove(dev); + + if (err == 0) + err = -EINVAL; + return err; +} + +static struct device_driver s3c2410_nand_driver = { + .name = "s3c2410-nand", + .bus = &platform_bus_type, + .probe = s3c2410_nand_probe, + .remove = s3c2410_nand_remove, +}; + +static int __init s3c2410_nand_init(void) +{ + printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n"); + return driver_register(&s3c2410_nand_driver); +} + +static void __exit s3c2410_nand_exit(void) +{ + driver_unregister(&s3c2410_nand_driver); +} + +module_init(s3c2410_nand_init); +module_exit(s3c2410_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("S3C2410 MTD NAND driver"); diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index acf6fc808b76..b0de249628f2 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -8,7 +8,7 @@ * to controllines (due to change in nand.c) * page_cache added * - * $Id: spia.c,v 1.21 2003/07/11 15:12:29 dwmw2 Exp $ + * $Id: spia.c,v 1.23 2004/10/05 13:50:20 gleixner Exp $ * * 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 @@ -132,8 +132,8 @@ int __init spia_init (void) (*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07; /* Set address of NAND IO lines */ - this->IO_ADDR_R = spia_fio_base; - this->IO_ADDR_W = spia_fio_base; + this->IO_ADDR_R = (void __iomem *) spia_fio_base; + this->IO_ADDR_W = (void __iomem *) spia_fio_base; /* Set address of hardware control function */ this->hwcontrol = spia_hwcontrol; /* 15 us command delay time */ @@ -145,14 +145,6 @@ int __init spia_init (void) return -ENXIO; } - /* Allocate memory for internal data buffer */ - this->data_buf = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL); - if (!this->data_buf) { - printk ("Unable to allocate NAND data buffer for SPIA.\n"); - kfree (spia_mtd); - return -ENOMEM; - } - /* Register the partitions */ add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS); @@ -167,13 +159,8 @@ module_init(spia_init); #ifdef MODULE static void __exit spia_cleanup (void) { - struct nand_chip *this = (struct nand_chip *) &spia_mtd[1]; - - /* Unregister the device */ - del_mtd_device (spia_mtd); - - /* Free internal data buffer */ - kfree (this->data_buf); + /* Release resources, unregister device */ + nand_release (spia_mtd); /* Free the MTD device structure */ kfree (spia_mtd); diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index ecb9f3dc8805..52c808fb5fa9 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -15,7 +15,7 @@ * This is a device driver for the NAND flash device found on the * TI fido board. It supports 32MiB and 64MiB cards * - * $Id: toto.c,v 1.2 2003/10/21 10:04:58 dwmw2 Exp $ + * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ */ #include @@ -37,7 +37,7 @@ */ static struct mtd_info *toto_mtd = NULL; -static int toto_io_base = OMAP_FLASH_1_BASE; +static unsigned long toto_io_base = OMAP_FLASH_1_BASE; #define CONFIG_NAND_WORKAROUND 1 @@ -155,14 +155,6 @@ int __init toto_init (void) goto out_mtd; } - /* Allocate memory for internal data buffer */ - this->data_buf = kmalloc (sizeof(u_char) * (toto_mtd->oobblock + toto_mtd->oobsize), GFP_KERNEL); - if (!this->data_buf) { - printk (KERN_WARNING "Unable to allocate NAND data buffer for toto.\n"); - err = -ENOMEM; - goto out_mtd; - } - /* Register the partitions */ switch(toto_mtd->size){ case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; @@ -194,16 +186,8 @@ module_init(toto_init); */ static void __exit toto_cleanup (void) { - struct nand_chip *this = (struct nand_chip *) &toto_mtd[1]; - - /* Unregister partitions */ - del_mtd_partitions(toto_mtd); - - /* Unregister the device */ - del_mtd_device (toto_mtd); - - /* Free internal data buffers */ - kfree (this->data_buf); + /* Release resources, unregister device */ + nand_release (toto_mtd); /* Free the MTD device structure */ kfree (toto_mtd); diff --git a/drivers/mtd/nand/tx4925ndfmc.c b/drivers/mtd/nand/tx4925ndfmc.c index 5f6a2f5ed138..bba688830c9b 100644 --- a/drivers/mtd/nand/tx4925ndfmc.c +++ b/drivers/mtd/nand/tx4925ndfmc.c @@ -11,7 +11,7 @@ * Derived from drivers/mtd/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: tx4925ndfmc.c,v 1.3 2004/07/20 02:44:26 dwmw2 Exp $ + * $Id: tx4925ndfmc.c,v 1.5 2004/10/05 13:50:20 gleixner Exp $ * * Copyright (C) 2001 Toshiba Corporation * @@ -340,8 +340,8 @@ int __init tx4925ndfmc_init (void) tx4925ndfmc_mtd->priv = this; /* Set address of NAND IO lines */ - this->IO_ADDR_R = (unsigned long)&(tx4925_ndfmcptr->dtr); - this->IO_ADDR_W = (unsigned long)&(tx4925_ndfmcptr->dtr); + this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr); + this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr); this->hwcontrol = tx4925ndfmc_hwcontrol; this->enable_hwecc = tx4925ndfmc_enable_hwecc; this->calculate_ecc = tx4925ndfmc_readecc; @@ -363,14 +363,6 @@ int __init tx4925ndfmc_init (void) goto out_ior; } - /* Allocate memory for internal data buffer */ - this->data_buf = kmalloc (sizeof(u_char) * (tx4925ndfmc_mtd->oobblock + tx4925ndfmc_mtd->oobsize), GFP_KERNEL); - if (!this->data_buf) { - printk ("Unable to allocate NAND data buffer for RBTX4925.\n"); - err = -ENOMEM; - goto out_ior; - } - /* Register the partitions */ #ifdef CONFIG_MTD_CMDLINE_PARTS { @@ -391,14 +383,12 @@ int __init tx4925ndfmc_init (void) default: { printk ("Unsupported SmartMedia device\n"); err = -ENXIO; - goto out_buf; + goto out_ior; } } #endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */ goto out; -out_buf: - kfree (this->data_buf); out_ior: out: return err; @@ -412,16 +402,8 @@ module_init(tx4925ndfmc_init); #ifdef MODULE static void __exit tx4925ndfmc_cleanup (void) { - struct nand_chip *this = (struct nand_chip *) &tx4925ndfmc_mtd[1]; - - /* Unregister partitions */ - del_mtd_partitions(tx4925ndfmc_mtd); - - /* Unregister the device */ - del_mtd_device (tx4925ndfmc_mtd); - - /* Free internal data buffers */ - kfree (this->data_buf); + /* Release resources, unregister device */ + nand_release (tx4925ndfmc_mtd); /* Free the MTD device structure */ kfree (tx4925ndfmc_mtd); diff --git a/drivers/mtd/nand/tx4938ndfmc.c b/drivers/mtd/nand/tx4938ndfmc.c index f2375b24187c..df26e58820b3 100644 --- a/drivers/mtd/nand/tx4938ndfmc.c +++ b/drivers/mtd/nand/tx4938ndfmc.c @@ -10,7 +10,7 @@ * * Based on spia.c by Steven J. Hill * - * $Id: tx4938ndfmc.c,v 1.2 2004/03/27 19:55:53 gleixner Exp $ + * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ * * Copyright (C) 2000-2001 Toshiba Corporation * @@ -365,14 +365,6 @@ int __init tx4938ndfmc_init (void) return -ENXIO; } - /* Allocate memory for internal data buffer */ - this->data_buf = kmalloc (sizeof(u_char) * (tx4938ndfmc_mtd->oobblock + tx4938ndfmc_mtd->oobsize), GFP_KERNEL); - if (!this->data_buf) { - printk ("Unable to allocate NAND data buffer for TX4938.\n"); - kfree (tx4938ndfmc_mtd); - return -ENOMEM; - } - if (protected) { printk(KERN_INFO "TX4938 NDFMC: write protected.\n"); tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE); @@ -401,19 +393,11 @@ module_init(tx4938ndfmc_init); */ static void __exit tx4938ndfmc_cleanup (void) { - struct nand_chip *this = (struct nand_chip *) tx4938ndfmc_mtd->priv; - - /* Unregister the device */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - del_mtd_partitions(tx4938ndfmc_mtd); -#endif - del_mtd_device (tx4938ndfmc_mtd); + /* Release resources, unregister device */ + nand_release (tx4938ndfmc_mtd); /* Free the MTD device structure */ kfree (tx4938ndfmc_mtd); - - /* Free internal data buffer */ - kfree (this->data_buf); } module_exit(tx4938ndfmc_cleanup); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 7de9f8dfa8ab..9453cb58c683 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.63 2004/07/07 16:29:43 gleixner Exp $ + * $Id: nand.h,v 1.66 2004/10/02 10:07:08 gleixner Exp $ * * 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 @@ -212,6 +212,18 @@ typedef enum { FL_CACHEDPRG, } nand_state_t; +/* Keep gcc happy */ +struct nand_chip; + +/** + * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices + * @lock: protection lock + * @active: the mtd device which holds the controller currently + */ +struct nand_hw_control { + spinlock_t lock; + struct nand_chip *active; +}; /** * struct nand_chip - NAND Private Flash Chip Data @@ -265,12 +277,13 @@ typedef enum { * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup * @bbt_md: [REPLACEABLE] bad block table mirror descriptor + * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date */ struct nand_chip { - unsigned long IO_ADDR_R; - unsigned long IO_ADDR_W; + void __iomem *IO_ADDR_R; + void __iomem *IO_ADDR_W; u_char (*read_byte)(struct mtd_info *mtd); void (*write_byte)(struct mtd_info *mtd, u_char byte); @@ -317,6 +330,7 @@ struct nand_chip { uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; + struct nand_hw_control *controller; void *priv; }; -- cgit v1.2.3