diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/chips/Makefile linux-2.5/drivers/mtd/chips/Makefile --- bk-linus/drivers/mtd/chips/Makefile 2002-11-21 02:15:54.000000000 +0000 +++ linux-2.5/drivers/mtd/chips/Makefile 2002-11-21 17:59:04.000000000 +0000 @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $ +# $Id: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ export-objs := chipreg.o gen_probe.o @@ -18,7 +18,6 @@ obj-$(CONFIG_MTD_CFI) += cfi_probe.o obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o -obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/chips/amd_flash.c linux-2.5/drivers/mtd/chips/amd_flash.c --- bk-linus/drivers/mtd/chips/amd_flash.c 2002-11-21 02:15:54.000000000 +0000 +++ linux-2.5/drivers/mtd/chips/amd_flash.c 2002-11-21 17:59:04.000000000 +0000 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -52,6 +52,7 @@ /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_SST 0x00BF @@ -67,6 +68,9 @@ #define AM29BDS323D 0x22D1 #define AM29BDS643D 0x227E +/* Atmel */ +#define AT49xV16x 0x00C0 +#define AT49xV16xT 0x00C2 /* Fujitsu */ #define MBM29LV160TE 0x22C4 @@ -613,6 +617,26 @@ static struct mtd_info *amd_flash_probe( { offset: 0x600000, erasesize: 0x10000, numblocks: 31 }, { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 }, } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16x, + name: "Atmel AT49xV16x", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x02000, numblocks: 8 }, + { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } + } + }, { + mfr_id: MANUFACTURER_ATMEL, + dev_id: AT49xV16xT, + name: "Atmel AT49xV16xT", + size: 0x00200000, + numeraseregions: 2, + regions: { + { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, + { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 } + } } }; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/chips/jedec.c linux-2.5/drivers/mtd/chips/jedec.c --- bk-linus/drivers/mtd/chips/jedec.c 2002-11-21 02:15:55.000000000 +0000 +++ linux-2.5/drivers/mtd/chips/jedec.c 2002-11-21 17:59:05.000000000 +0000 @@ -11,7 +11,7 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ + * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $ */ #include @@ -738,6 +738,7 @@ static int flash_erase(struct mtd_info * } //printk("done\n"); + instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); return 0; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/devices/Makefile linux-2.5/drivers/mtd/devices/Makefile --- bk-linus/drivers/mtd/devices/Makefile 2002-11-21 02:15:55.000000000 +0000 +++ linux-2.5/drivers/mtd/devices/Makefile 2002-11-21 17:59:05.000000000 +0000 @@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_DOC2001) += doc2001.o obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o +obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/devices/doc1000.c linux-2.5/drivers/mtd/devices/doc1000.c --- bk-linus/drivers/mtd/devices/doc1000.c 2002-11-21 02:15:55.000000000 +0000 +++ linux-2.5/drivers/mtd/devices/doc1000.c 2002-11-21 17:59:06.000000000 +0000 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: doc1000.c,v 1.15 2001/10/02 15:05:13 dwmw2 Exp $ + $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $ ======================================================================*/ @@ -482,7 +482,7 @@ static void flashcard_periodic(unsigned else priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING; } - else if (erase->time + erase_timeout < jiffies) + else if (time_after(jiffies, erase->time + erase_timeout)) { printk("Flash erase timed out. The world is broken.\n"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/devices/ms02-nv.c linux-2.5/drivers/mtd/devices/ms02-nv.c --- bk-linus/drivers/mtd/devices/ms02-nv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/devices/ms02-nv.c 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2001 Maciej W. Rozycki + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ms02-nv.h" + + +static char version[] __initdata = + "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n"; + +MODULE_AUTHOR("Maciej W. Rozycki "); +MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver"); +MODULE_LICENSE("GPL"); + + +/* + * Addresses we probe for an MS02-NV at. Modules may be located + * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB + * boundary within a 0MB up to 448MB range. We don't support a module + * at 0MB, though. + */ +static ulong ms02nv_addrs[] __initdata = { + 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000, + 0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000, + 0x02000000, 0x01800000, 0x01000000, 0x00800000 +}; + +static const char ms02nv_name[] = "DEC MS02-NV NVRAM"; +static const char ms02nv_res_diag_ram[] = "Diagnostic RAM"; +static const char ms02nv_res_user_ram[] = "General-purpose RAM"; +static const char ms02nv_res_csr[] = "Control and status register"; + +static struct mtd_info *root_ms02nv_mtd; + + +static int ms02nv_read(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + if (from + len > mtd->size) + return -EINVAL; + + memcpy(buf, mp->uaddr + from, len); + *retlen = len; + + return 0; +} + +static int ms02nv_write(struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, const u_char *buf) +{ + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + if (to + len > mtd->size) + return -EINVAL; + + memcpy(mp->uaddr + to, buf, len); + *retlen = len; + + return 0; +} + + +static inline uint ms02nv_probe_one(ulong addr) +{ + ms02nv_uint *ms02nv_diagp; + ms02nv_uint *ms02nv_magicp; + uint ms02nv_diag; + uint ms02nv_magic; + size_t size; + + int err; + + /* + * The firmware writes MS02NV_ID at MS02NV_MAGIC and also + * a diagnostic status at MS02NV_DIAG. + */ + ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG)); + ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC)); + err = get_dbe(ms02nv_magic, ms02nv_magicp); + if (err) + return 0; + if (ms02nv_magic != MS02NV_ID) + return 0; + + ms02nv_diag = *ms02nv_diagp; + size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT; + if (size > MS02NV_CSR) + size = MS02NV_CSR; + + return size; +} + +static int __init ms02nv_init_one(ulong addr) +{ + struct mtd_info *mtd; + struct ms02nv_private *mp; + struct resource *mod_res; + struct resource *diag_res; + struct resource *user_res; + struct resource *csr_res; + ulong fixaddr; + size_t size, fixsize; + + static int version_printed; + + int ret = -ENODEV; + + /* The module decodes 8MB of address space. */ + mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL); + if (!mod_res) + return -ENOMEM; + + memset(mod_res, 0, sizeof(*mod_res)); + mod_res->name = ms02nv_name; + mod_res->start = addr; + mod_res->end = addr + MS02NV_SLOT_SIZE - 1; + mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, mod_res) < 0) + goto err_out_mod_res; + + size = ms02nv_probe_one(addr); + if (!size) + goto err_out_mod_res_rel; + + if (!version_printed) { + printk(KERN_INFO "%s", version); + version_printed = 1; + } + + ret = -ENOMEM; + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) + goto err_out_mod_res_rel; + memset(mtd, 0, sizeof(*mtd)); + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) + goto err_out_mtd; + memset(mp, 0, sizeof(*mp)); + + mtd->priv = mp; + mp->resource.module = mod_res; + + /* Firmware's diagnostic NVRAM area. */ + diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL); + if (!diag_res) + goto err_out_mp; + + memset(diag_res, 0, sizeof(*diag_res)); + diag_res->name = ms02nv_res_diag_ram; + diag_res->start = addr; + diag_res->end = addr + MS02NV_RAM - 1; + diag_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, diag_res); + + mp->resource.diag_ram = diag_res; + + /* User-available general-purpose NVRAM area. */ + user_res = kmalloc(sizeof(*user_res), GFP_KERNEL); + if (!user_res) + goto err_out_diag_res; + + memset(user_res, 0, sizeof(*user_res)); + user_res->name = ms02nv_res_user_ram; + user_res->start = addr + MS02NV_RAM; + user_res->end = addr + size - 1; + user_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, user_res); + + mp->resource.user_ram = user_res; + + /* Control and status register. */ + csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL); + if (!csr_res) + goto err_out_user_res; + + memset(csr_res, 0, sizeof(*csr_res)); + csr_res->name = ms02nv_res_csr; + csr_res->start = addr + MS02NV_CSR; + csr_res->end = addr + MS02NV_CSR + 3; + csr_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, csr_res); + + mp->resource.csr = csr_res; + + mp->addr = phys_to_virt(addr); + mp->size = size; + + /* + * Hide the firmware's diagnostic area. It may get destroyed + * upon a reboot. Take paging into account for mapping support. + */ + fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1); + mp->uaddr = phys_to_virt(fixaddr); + + mtd->type = MTD_RAM; + mtd->flags = MTD_CAP_RAM | MTD_XIP; + mtd->size = fixsize; + mtd->name = (char *)ms02nv_name; + mtd->module = THIS_MODULE; + mtd->read = ms02nv_read; + mtd->write = ms02nv_write; + + ret = -EIO; + if (add_mtd_device(mtd)) { + printk(KERN_ERR + "ms02-nv: Unable to register MTD device, aborting!\n"); + goto err_out_csr_res; + } + + printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n", + mtd->index, ms02nv_name, addr, size >> 20); + + mp->next = root_ms02nv_mtd; + root_ms02nv_mtd = mtd; + + return 0; + + +err_out_csr_res: + release_resource(csr_res); + kfree(csr_res); +err_out_user_res: + release_resource(user_res); + kfree(user_res); +err_out_diag_res: + release_resource(diag_res); + kfree(diag_res); +err_out_mp: + kfree(mp); +err_out_mtd: + kfree(mtd); +err_out_mod_res_rel: + release_resource(mod_res); +err_out_mod_res: + kfree(mod_res); + return ret; +} + +static void __exit ms02nv_remove_one(void) +{ + struct mtd_info *mtd = root_ms02nv_mtd; + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + root_ms02nv_mtd = mp->next; + + del_mtd_device(mtd); + + release_resource(mp->resource.csr); + kfree(mp->resource.csr); + release_resource(mp->resource.user_ram); + kfree(mp->resource.user_ram); + release_resource(mp->resource.diag_ram); + kfree(mp->resource.diag_ram); + release_resource(mp->resource.module); + kfree(mp->resource.module); + kfree(mp); + kfree(mtd); +} + + +static int __init ms02nv_init(void) +{ + volatile u32 *csr; + uint stride = 0; + int count = 0; + int i; + + switch (mips_machtype) { + case MACH_DS5000_200: + csr = (volatile u32 *)KN02_CSR_ADDR; + if (*csr & KN02_CSR_BNK32M) + stride = 2; + break; + case MACH_DS5000_2X0: + csr = (volatile u32 *)KN03_MCR_BASE; + if (*csr & KN03_MCR_BNK32M) + stride = 2; + break; + default: + return -ENODEV; + break; + } + + for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++) + if (!ms02nv_init_one(ms02nv_addrs[i] << stride)) + count++; + + return (count > 0) ? 0 : -ENODEV; +} + +static void __exit ms02nv_cleanup(void) +{ + while (root_ms02nv_mtd) + ms02nv_remove_one(); +} + + +module_init(ms02nv_init); +module_exit(ms02nv_cleanup); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/devices/ms02-nv.h linux-2.5/drivers/mtd/devices/ms02-nv.h --- bk-linus/drivers/mtd/devices/ms02-nv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/devices/ms02-nv.h 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2001 Maciej W. Rozycki + * + * 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. + */ + +#include +#include + +/* MS02-NV iomem register offsets. */ +#define MS02NV_CSR 0x400000 /* control & status register */ + +/* MS02-NV memory offsets. */ +#define MS02NV_DIAG 0x0003f8 /* diagnostic status */ +#define MS02NV_MAGIC 0x0003fc /* MS02-NV magic ID */ +#define MS02NV_RAM 0x000400 /* general-purpose RAM start */ + +/* MS02-NV diagnostic status constants. */ +#define MS02NV_DIAG_SIZE_MASK 0xf0 /* RAM size mask */ +#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* RAM size shift (left) */ + +/* MS02-NV general constants. */ +#define MS02NV_ID 0x03021966 /* MS02-NV magic ID value */ +#define MS02NV_SLOT_SIZE 0x800000 /* size of the address space + decoded by the module */ + +typedef volatile u32 ms02nv_uint; + +struct ms02nv_private { + struct mtd_info *next; + struct { + struct resource *module; + struct resource *diag_ram; + struct resource *user_ram; + struct resource *csr; + } resource; + u_char *addr; + size_t size; + u_char *uaddr; +}; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/devices/mtdram.c linux-2.5/drivers/mtd/devices/mtdram.c --- bk-linus/drivers/mtd/devices/mtdram.c 2002-11-21 02:15:56.000000000 +0000 +++ linux-2.5/drivers/mtd/devices/mtdram.c 2002-11-21 17:59:07.000000000 +0000 @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $ * Author: Alexander Larsson * * Copyright (c) 1999 Alexander Larsson @@ -123,7 +123,7 @@ int __init init_mtdram(void) // Allocate some memory mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); if (!mtd_info) - return 0; + return -ENOMEM; memset(mtd_info, 0, sizeof(*mtd_info)); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/amd766rom.c linux-2.5/drivers/mtd/maps/amd766rom.c --- bk-linus/drivers/mtd/maps/amd766rom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/amd766rom.c 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,245 @@ +/* + * amd766rom.c + * + * Normal mappings of chips in physical memory + * $Id: amd766rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct amd766rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; + u32 window_start, window_size; + struct pci_dev *pdev; +}; + +static __u8 amd766rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 amd766rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 amd766rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void amd766rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +static void amd766rom_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void amd766rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->map_priv_1 + to, from, len); +} + +static struct amd766rom_map_info amd766rom_map = { + map: { + name: "AMD766 rom", + size: 0, + buswidth: 1, + read8: amd766rom_read8, + read16: amd766rom_read16, + read32: amd766rom_read32, + copy_from: amd766rom_copy_from, + write8: amd766rom_write8, + write16: amd766rom_write16, + write32: amd766rom_write32, + copy_to: amd766rom_copy_to, + /* The standard rom socket is for single power supply chips + * that don't have an extra vpp. + */ + }, + mtd: 0, + window_addr: 0, +}; + +static int __devinit amd766rom_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[] = { + { 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", 0 }; + u8 byte; + struct amd766rom_map_info *info = &amd766rom_map; + struct rom_window *window; + int i; + u32 rom_size; + + window = &rom_window[0]; + while(window->size) { + if (request_mem_region(window->start, window->size, "amd766rom")) { + break; + } + window++; + } + if (!window->size) { + printk(KERN_ERR "amd766rom: cannot reserve rom window"); + goto err_out_none; + } + + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + + /* 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 */ + + printk(KERN_NOTICE "amd766rom window : %x at %x\n", + window->size, window->start); + /* For write accesses caches are useless */ + info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); + + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + info->mtd = 0; + for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { + char **chip_type; + if (rom_size > window->size) { + continue; + } + info->map.map_priv_1 = + info->window_addr + window->size - rom_size; + info->map.size = rom_size; + chip_type = rom_probe_types; + for(; !info->mtd && *chip_type; chip_type++) { + info->mtd = do_map_probe(*chip_type, &amd766rom_map.map); + } + if (info->mtd) { + break; + } + } + if (!info->mtd) { + goto err_out_iounmap; + } + printk(KERN_NOTICE "amd766rom chip at offset: %x\n", + window->size - rom_size); + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + info->window_start = window->start; + info->window_size = window->size; + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: + release_mem_region(window->start, window->size); +err_out_none: + return -ENODEV; +} + + +static void __devexit amd766rom_remove_one (struct pci_dev *pdev) +{ + struct amd766rom_map_info *info = &amd766rom_map; + u8 byte; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte & ~1); + + release_mem_region(info->window_start, info->window_size); +} + +static struct pci_device_id amd766rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, amd766rom_pci_tbl); + +#if 0 +static struct pci_driver amd766rom_driver = { + name: "amd766rom", + id_table: amd766rom_pci_tbl, + probe: amd766rom_init_one, + remove: amd766rom_remove_one, +}; +#endif + +int __init init_amd766rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0); + if (pdev) { + amd766rom_map.pdev = pdev; + return amd766rom_init_one(pdev, &amd766rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&amd766rom_driver); +#endif +} + +static void __exit cleanup_amd766rom(void) +{ + amd766rom_remove_one(amd766rom_map.pdev); +} + +module_init(init_amd766rom); +module_exit(cleanup_amd766rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD766 southbridge"); + diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/dilnetpc.c linux-2.5/drivers/mtd/maps/dilnetpc.c --- bk-linus/drivers/mtd/maps/dilnetpc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/dilnetpc.c 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,540 @@ +/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP" + * + * 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 + * + * $Id: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser 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 + * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash + * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs + * flash and 16 megs of RAM. + * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + * and http://www.ssv-embedded.de/ssv/pc104/p170.htm + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +** The DIL/NetPC keeps it's BIOS in two distinct flash blocks. +** Destroying any of these blocks transforms the DNPC into +** a paperweight (albeit not a very useful one, considering +** it only weighs a few grams). +** +** Therefore, the BIOS blocks must never be erased or written to +** except by people who know exactly what they are doing (e.g. +** to install a BIOS update). These partitions are marked read-only +** by default, but can be made read/write by undefining +** DNPC_BIOS_BLOCKS_WRITEPROTECTED: +*/ +#define DNPC_BIOS_BLOCKS_WRITEPROTECTED + +/* +** The ID string (in ROM) is checked to determine whether we +** are running on a DNP/1486 or ADNP/1486 +*/ +#define BIOSID_BASE 0x000fe100 + +#define ID_DNPC "DNP1486" +#define ID_ADNP "ADNP1486" + +/* +** Address where the flash should appear in CPU space +*/ +#define FLASH_BASE 0x2000000 + +/* +** Chip Setup and Control (CSC) indexed register space +*/ +#define CSC_INDEX 0x22 +#define CSC_DATA 0x23 + +#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */ +#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */ + +#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */ + +#define CSC_CR 0xd0 /* internal I/O device disable/Echo */ + /* Z-bus/configuration register */ + +#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */ + + +/* +** PC Card indexed register space: +*/ + +#define PCC_INDEX 0x3e0 +#define PCC_DATA 0x3e1 + +#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */ +#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */ +#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */ +#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */ +#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */ +#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */ +#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */ + + +/* +** Access to SC4x0's Chip Setup and Control (CSC) +** and PC Card (PCC) indexed registers: +*/ +static inline void setcsc(int reg, unsigned char data) +{ + outb(reg, CSC_INDEX); + outb(data, CSC_DATA); +} + +static inline unsigned char getcsc(int reg) +{ + outb(reg, CSC_INDEX); + return(inb(CSC_DATA)); +} + +static inline void setpcc(int reg, unsigned char data) +{ + outb(reg, PCC_INDEX); + outb(data, PCC_DATA); +} + +static inline unsigned char getpcc(int reg) +{ + outb(reg, PCC_INDEX); + return(inb(PCC_DATA)); +} + + +/* +************************************************************ +** Enable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size) +{ + unsigned long flash_end = flash_base + flash_size - 1; + + /* + ** enable setup of MMS windows C-F: + */ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + /* - set PC Card controller to operate in standard mode */ + setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1); + + /* + ** Program base address and end address of window + ** where the flash ROM should appear in CPU address space + */ + setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff); + setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f); + setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff); + setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f); + + /* program offset of first flash location to appear in this window (0) */ + setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff); + setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f); + + /* set attributes for MMS window C: non-cacheable, write-enabled */ + setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11); + + /* select physical device ROMCS0 (i.e. flash) for MMS Window C */ + setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03); + + /* enable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +/* +************************************************************ +** Disable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_unmap_flash(void) +{ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + + /* disable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +static __u8 dnpc_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +static __u16 dnpc_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +static __u32 dnpc_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +/* +************************************************************ +** Enable/Disable VPP to write to flash +************************************************************ +*/ + +static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED; +static int vpp_counter = 0; +/* +** This is what has to be done for the DNP board .. +*/ +static void dnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + +/* +** .. and this the ADNP version: +*/ +static void adnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + + + +#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ +#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ +#define WINDOW_ADDR FLASH_BASE + +static struct map_info dnpc_map = { + name: "ADNP Flash Bank", + size: ADNP_WINDOW_SIZE, + buswidth: 1, + read8: dnpc_read8, + read16: dnpc_read16, + read32: dnpc_read32, + copy_from: dnpc_copy_from, + write8: dnpc_write8, + write16: dnpc_write16, + write32: dnpc_write32, + copy_to: dnpc_copy_to, + set_vpp: adnp_set_vpp, + map_priv_2: WINDOW_ADDR +}; + +/* +** The layout of the flash is somewhat "strange": +** +** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data +** 2. 64 KiB (1 block) : System BIOS +** 3. 960 KiB (15 blocks) : User Data (DNP model) or +** 3. 3008 KiB (47 blocks) : User Data (ADNP model) +** 4. 64 KiB (1 block) : System BIOS Entry +*/ + +static struct mtd_partition partition_info[]= +{ + { + name: "ADNP boot", + offset: 0, + size: 0xf0000, + }, + { + name: "ADNP system BIOS", + offset: MTDPART_OFS_NXTBLK, + size: 0x10000, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, + { + name: "ADNP file system", + offset: MTDPART_OFS_NXTBLK, + size: 0x2f0000, + }, + { + name: "ADNP system BIOS entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) + +static struct mtd_info *mymtd; +static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; +static struct mtd_info *merged_mtd; + +/* +** "Highlevel" partition info: +** +** Using the MTD concat layer, we can re-arrange partitions to our +** liking: we construct a virtual MTD device by concatenating the +** partitions, specifying the sequence such that the boot block +** is immediately followed by the filesystem block (i.e. the stupid +** system BIOS block is mapped to a different place). When re-partitioning +** this concatenated MTD device, we can set the boot block size to +** an arbitrary (though erase block aligned) value i.e. not one that +** is dictated by the flash's physical layout. We can thus set the +** boot block to be e.g. 64 KB (which is fully sufficient if we want +** to boot an etherboot image) or to -say- 1.5 MB if we want to boot +** a large kernel image. In all cases, the remainder of the flash +** is available as file system space. +*/ + +static struct mtd_partition higlvl_partition_info[]= +{ + { + name: "ADNP boot block", + offset: 0, + size: CONFIG_MTD_DILNETPC_BOOTSIZE, + }, + { + name: "ADNP file system space", + offset: MTDPART_OFS_NXTBLK, + size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + }, + { + name: "ADNP system BIOS + BIOS Entry", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + mask_flags: MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0])) + + +static int dnp_adnp_probe(void) +{ + char *biosid, rc = -1; + + biosid = (char*)ioremap(BIOSID_BASE, 16); + if(biosid) + { + if(!strcmp(biosid, ID_DNPC)) + rc = 1; /* this is a DNPC */ + else if(!strcmp(biosid, ID_ADNP)) + rc = 0; /* this is a ADNPC */ + } + iounmap((void *)biosid); + return(rc); +} + + +static int __init init_dnpc(void) +{ + int is_dnp; + + /* + ** determine hardware (DNP/ADNP/invalid) + */ + if((is_dnp = dnp_adnp_probe()) < 0) + return -ENXIO; + + /* + ** Things are set up for ADNP by default + ** -> modify all that needs to be different for DNP + */ + if(is_dnp) + { /* + ** Adjust window size, select correct set_vpp function. + ** The partitioning scheme is identical on both DNP + ** and ADNP except for the size of the third partition. + */ + int i; + dnpc_map.size = DNP_WINDOW_SIZE; + dnpc_map.set_vpp = dnp_set_vpp; + partition_info[2].size = 0xf0000; + + /* + ** increment all string pointers so the leading 'A' gets skipped, + ** thus turning all occurrences of "ADNP ..." into "DNP ..." + */ + ++dnpc_map.name; + for(i = 0; i < NUM_PARTITIONS; i++) + ++partition_info[i].name; + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; + for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) + ++higlvl_partition_info[i].name; + } + + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2); + + dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size); + + dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size); + + if (!dnpc_map.map_priv_1) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + + printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1); + + mymtd = do_map_probe("jedec_probe", &dnpc_map); + + if (!mymtd) + mymtd = do_map_probe("cfi_probe", &dnpc_map); + + /* + ** If flash probes fail, try to make flashes accessible + ** at least as ROM. Ajust erasesize in this case since + ** the default one (128M) will break our partitioning + */ + if (!mymtd) + if((mymtd = do_map_probe("map_rom", &dnpc_map))) + mymtd->erasesize = 0x10000; + + if (!mymtd) { + iounmap((void *)dnpc_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* + ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() + ** -> add_mtd_partitions() will _not_ register MTD devices for + ** the partitions, but will instead store pointers to the MTD + ** objects it creates into our lowlvl_parts[] array. + ** NOTE: we arrange the pointers such that the sequence of the + ** partitions gets re-arranged: partition #2 follows + ** partition #0. + */ + partition_info[0].mtdp = &lowlvl_parts[0]; + partition_info[1].mtdp = &lowlvl_parts[2]; + partition_info[2].mtdp = &lowlvl_parts[1]; + partition_info[3].mtdp = &lowlvl_parts[3]; + + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + + /* + ** now create a virtual MTD device by concatenating the for partitions + ** (in the sequence given by the lowlvl_parts[] array. + */ + merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated"); + if(merged_mtd) + { /* + ** now partition the new device the way we want it. This time, + ** we do not supply mtd pointers in higlvl_partition_info, so + ** add_mtd_partitions() will register the devices. + */ + add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS); + } + + return 0; +} + +static void __exit cleanup_dnpc(void) +{ + if(merged_mtd) { + del_mtd_partitions(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (dnpc_map.map_priv_1) { + iounmap((void *)dnpc_map.map_priv_1); + dnpc_unmap_flash(); + dnpc_map.map_priv_1 = 0; + } +} + +module_init(init_dnpc); +module_exit(cleanup_dnpc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); +MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/ich2rom.c linux-2.5/drivers/mtd/maps/ich2rom.c --- bk-linus/drivers/mtd/maps/ich2rom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/ich2rom.c 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,302 @@ +/* + * ich2rom.c + * + * Normal mappings of chips in physical memory + * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESERVE_MEM_REGION 0 + +#define ICH2_FWH_REGION_START 0xFF000000UL +#define ICH2_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 ich2rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; +}; + +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 + ICH2_FWH_REGION_START; +} + +static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(addr(map, ofs)); +} + +static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(addr(map, ofs)); +} + +static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(addr(map, ofs)); +} + +static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, addr(map, from), len); +} + +static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + __raw_writeb(d, addr(map,ofs)); + mb(); +} + +static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs) +{ + __raw_writew(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs) +{ + __raw_writel(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(addr(map, to), from, len); +} + +static struct ich2rom_map_info ich2rom_map = { + map: { + name: "ICH2 rom", + size: 0, + buswidth: 1, + read8: ich2rom_read8, + read16: ich2rom_read16, + read32: ich2rom_read32, + copy_from: ich2rom_copy_from, + write8: ich2rom_write8, + write16: ich2rom_write16, + write32: ich2rom_write32, + copy_to: ich2rom_copy_to, + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in place programming + * needs to use a different method. + */ + }, + mtd: 0, + window_addr: 0, +}; + +enum fwh_lock_state { + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +static int ich2rom_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; + } + return 0; +} + +static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); +} + +static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, 0); +} + +static int __devinit ich2rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u16 word; + struct ich2rom_map_info *info = &ich2rom_map; + unsigned long map_size; + + /* For now I just handle the ich2 and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MB but it is very painful. Also since + * you can only really attach a FWH to an ICH2 there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MB window isn't enough + * but don't currently handle that case either. + */ + +#if RESERVE_MEM_REGION + /* Some boards have this reserved and I haven't found a good work + * around to say I know what I'm doing! + */ + if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) { + printk(KERN_ERR "ich2rom: cannot reserve rom window\n"); + goto err_out_none; + } +#endif /* RESERVE_MEM_REGION */ + + /* Enable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + if (!(word & 1) && (word & (1<<1))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n"); + goto err_out_none; + } + pci_write_config_word(pdev, BIOS_CNTL, word | 1); + + + /* Map the firmware hub into my address space. */ + /* Does this use to much virtual address space? */ + info->window_addr = (unsigned long)ioremap( + ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + + /* For now assume the firmware has setup all relavent firmware + * windows. We don't have enough information to handle this case + * intelligently. + */ + + /* FIXME select the firmware hub and enable a window to it. */ + + info->mtd = 0; + info->map.map_priv_1 = info->window_addr; + + map_size = ICH2_FWH_REGION_SIZE; + while(!info->mtd && (map_size > 0)) { + info->map.size = map_size; + info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map); + map_size -= 512*1024; + } + if (!info->mtd) { + goto err_out_iounmap; + } + /* I know I can only be a firmware hub here so put + * in the special lock and unlock routines. + */ + info->mtd->lock = ich2rom_lock; + info->mtd->unlock = ich2rom_unlock; + + info->mtd->module = THIS_MODULE; + add_mtd_device(info->mtd); + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +err_out_none: + return -ENODEV; +} + + +static void __devexit ich2rom_remove_one (struct pci_dev *pdev) +{ + struct ich2rom_map_info *info = &ich2rom_map; + u16 word; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + 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(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +} + +static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, +}; + +MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl); + +#if 0 +static struct pci_driver ich2rom_driver = { + name: "ich2rom", + id_table: ich2rom_pci_tbl, + probe: ich2rom_init_one, + remove: ich2rom_remove_one, +}; +#endif + +static struct pci_dev *mydev; +int __init init_ich2rom(void) +{ + struct pci_dev *pdev; + pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0); + if (pdev) { + mydev = pdev; + return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&ich2rom_driver); +#endif +} + +static void __exit cleanup_ich2rom(void) +{ + ich2rom_remove_one(mydev); +} + +module_init(init_ich2rom); +module_exit(cleanup_ich2rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman "); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/l440gx.c linux-2.5/drivers/mtd/maps/l440gx.c --- bk-linus/drivers/mtd/maps/l440gx.c 2002-11-21 02:15:58.000000000 +0000 +++ linux-2.5/drivers/mtd/maps/l440gx.c 2002-11-21 17:59:07.000000000 +0000 @@ -1,7 +1,9 @@ /* - * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $ * * BIOS Flash chip on Intel 440GX board. + * + * Bugs this currently does not work under linuxBIOS. */ #include @@ -12,12 +14,14 @@ #include #include +#define PIIXE_IOBASE_RESOURCE 11 #define WINDOW_ADDR 0xfff00000 #define WINDOW_SIZE 0x00100000 #define BUSWIDTH 1 -#define IOBASE 0xc00 +static u32 iobase; +#define IOBASE iobase #define TRIBUF_PORT (IOBASE+0x37) #define VPP_PORT (IOBASE+0x28) @@ -66,12 +70,17 @@ void l440gx_copy_to(struct map_info *map memcpy_toio(map->map_priv_1 + to, from, len); } +/* Is this really the vpp port? */ void l440gx_set_vpp(struct map_info *map, int vpp) { unsigned long l; l = inl(VPP_PORT); - l = vpp?(l | 1):(l & ~1); + if (vpp) { + l |= 1; + } else { + l &= ~1; + } outl(l, VPP_PORT); } @@ -87,44 +96,86 @@ struct map_info l440gx_map = { write16: l440gx_write16, write32: l440gx_write32, copy_to: l440gx_copy_to, +#if 0 + /* FIXME verify that this is the + * appripriate code for vpp enable/disable + */ set_vpp: l440gx_set_vpp +#endif }; static int __init init_l440gx(void) { - struct pci_dev *dev; - unsigned char b; - __u16 w; + struct pci_dev *dev, *pm_dev; + struct resource *pm_iobase; + __u16 word; + + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - NULL); - if (!dev) { + pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + + if (!dev || !pm_dev) { printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n"); return -ENODEV; } - l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); if (!l440gx_map.map_priv_1) { - printk("Failed to ioremap L440GX flash region\n"); + printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); return -ENOMEM; } + printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1); + + /* Setup the pm iobase resource + * This code should move into some kind of generic bridge + * driver but for the moment I'm content with getting the + * allocation correct. + */ + pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; + if (!(pm_iobase->flags & IORESOURCE_IO)) { + pm_iobase->name = "pm iobase"; + pm_iobase->start = 0; + pm_iobase->end = 63; + pm_iobase->flags = IORESOURCE_IO; + + /* Put the current value in the resource */ + pci_read_config_dword(pm_dev, 0x40, &iobase); + iobase &= ~1; + pm_iobase->start += iobase & ~1; + pm_iobase->end += iobase & ~1; + + /* Allocate the resource region */ + if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { + printk(KERN_WARNING "Could not allocate pm iobase resource\n"); + iounmap((void *)l440gx_map.map_priv_1); + return -ENXIO; + } + } + /* Set the iobase */ + iobase = pm_iobase->start; + pci_write_config_dword(pm_dev, 0x40, iobase | 1); + + /* Set XBCS# */ - pci_read_config_word(dev, 0x4e, &w); - w |= 0x4; - pci_write_config_word(dev, 0x4e, w); + pci_read_config_word(dev, 0x4e, &word); + word |= 0x4; + pci_write_config_word(dev, 0x4e, word); + + /* Supply write voltage to the chip */ + l440gx_set_vpp(&l440gx_map, 1); /* Enable the gate on the WE line */ - b = inb(TRIBUF_PORT); - b |= 1; - outb(b, TRIBUF_PORT); + outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); - mymtd = do_map_probe("jedec", &l440gx_map); + mymtd = do_map_probe("jedec_probe", &l440gx_map); if (!mymtd) { printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n"); mymtd = do_map_probe("map_rom", &l440gx_map); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/mbx860.c linux-2.5/drivers/mtd/maps/mbx860.c --- bk-linus/drivers/mtd/maps/mbx860.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/mbx860.c 2002-11-21 17:59:07.000000000 +0000 @@ -0,0 +1,144 @@ +/* + * $Id: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $ + * + * Handle mapping of the flash on MBX860 boards + * + * Author: Anton Todorov + * Copyright: (C) 2001 Emness Technology + * + * 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 +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x00200000 + +/* Flash / Partition sizing */ +#define MAX_SIZE_KiB 8192 +#define BOOT_PARTITION_SIZE_KiB 512 +#define KERNEL_PARTITION_SIZE_KiB 5632 +#define APP_PARTITION_SIZE_KiB 2048 + +#define NUM_PARTITIONS 3 + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]={ + { name: "MBX flash BOOT partition", + offset: 0, + size: BOOT_PARTITION_SIZE_KiB*1024 }, + { name: "MBX flash DATA partition", + offset: BOOT_PARTITION_SIZE_KiB*1024, + size: (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { name: "MBX flash APPLICATION partition", + offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } +}; + + +static struct mtd_info *mymtd; + +__u8 mbx_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +__u16 mbx_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +__u32 mbx_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +void mbx_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +void mbx_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +void mbx_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + +struct map_info mbx_map = { + name: "MBX flash", + size: WINDOW_SIZE, + buswidth: 4, + read8: mbx_read8, + read16: mbx_read16, + read32: mbx_read32, + copy_from: mbx_copy_from, + write8: mbx_write8, + write16: mbx_write16, + write32: mbx_write32, + copy_to: mbx_copy_to +}; + +int __init init_mbx(void) +{ + printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!mbx_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("jedec_probe", &mbx_map); + if (mymtd) { + mymtd->module = THIS_MODULE; + add_mtd_device(mymtd); + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)mbx_map.map_priv_1); + return -ENXIO; +} + +static void __exit cleanup_mbx(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (mbx_map.map_priv_1) { + iounmap((void *)mbx_map.map_priv_1); + mbx_map.map_priv_1 = 0; + } +} + +module_init(init_mbx); +module_exit(cleanup_mbx); + +MODULE_AUTHOR("Anton Todorov "); +MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/pb1xxx-flash.c linux-2.5/drivers/mtd/maps/pb1xxx-flash.c --- bk-linus/drivers/mtd/maps/pb1xxx-flash.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/pb1xxx-flash.c 2002-11-21 17:59:08.000000000 +0000 @@ -0,0 +1,253 @@ +/* + * Flash memory access on Alchemy Pb1xxx boards + * + * (C) 2001 Pete Popov + * + * $Id: pb1xxx-flash.c,v 1.5 2002/02/01 23:08:50 ppopov Exp $ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define WINDOW_ADDR 0x1F800000 +#define WINDOW_SIZE 0x800000 +#endif + +__u8 physmap_read8(struct map_info *map, unsigned long ofs) +{ + __u8 ret; + ret = __raw_readb(map->map_priv_1 + ofs); + DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u16 physmap_read16(struct map_info *map, unsigned long ofs) +{ + __u16 ret; + ret = __raw_readw(map->map_priv_1 + ofs); + DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u32 physmap_read32(struct map_info *map, unsigned long ofs) +{ + __u32 ret; + ret = __raw_readl(map->map_priv_1 + ofs); + DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); + memcpy_toio(map->map_priv_1 + to, from, len); +} + + + +static struct map_info pb1xxx_map = { + name: "Pb1xxx flash", + read8: physmap_read8, + read16: physmap_read16, + read32: physmap_read32, + copy_from: physmap_copy_from, + write8: physmap_write8, + write16: physmap_write16, + write32: physmap_write32, + copy_to: physmap_copy_to, +}; + + +#ifdef CONFIG_MIPS_PB1000 + +static unsigned long flash_size = 0x00800000; +static unsigned char flash_buswidth = 4; +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "yamon env", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE + },{ + name: "User FS", + size: 0x003e0000, + offset: 0x20000, + },{ + name: "boot code", + size: 0x100000, + offset: 0x400000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw/kernel", + size: 0x300000, + offset: 0x500000 + } +}; + +#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) + +static unsigned char flash_buswidth = 4; +#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +/* both 32MB banks will be used. Combine the first 32MB bank and the + * first 28MB of the second bank together into a single jffs/jffs2 + * partition. + */ +static unsigned long flash_size = 0x04000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x4000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x3c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x3c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x3d00000 + } +}; +#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1E000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x1c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x1d00000 + } +}; +#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1e00000, + offset: 0x0000000 + },{ + name: "raw kernel", + size: 0x0200000, + offset: 0x1e00000, + } +}; +#else +#error MTD_PB1500 define combo error /* should never happen */ +#endif +#else +#error Unsupported board +#endif + + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_partition *parsed_parts; +static struct mtd_info *mymtd; + +int __init pb1xxx_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type; + + /* Default flash buswidth */ + pb1xxx_map.buswidth = flash_buswidth; + + /* + * Static partition definition selection + */ + part_type = "static"; + parts = pb1xxx_partitions; + nb_parts = NB_OF(pb1xxx_partitions); + pb1xxx_map.size = flash_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", + pb1xxx_map.buswidth*8); + pb1xxx_map.map_priv_1 = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + mymtd = do_map_probe("cfi_probe", &pb1xxx_map); + if (!mymtd) return -ENXIO; + mymtd->module = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit pb1xxx_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(pb1xxx_mtd_init); +module_exit(pb1xxx_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Pb1xxx CFI map driver"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/sc520cdp.c linux-2.5/drivers/mtd/maps/sc520cdp.c --- bk-linus/drivers/mtd/maps/sc520cdp.c 2002-11-21 02:15:58.000000000 +0000 +++ linux-2.5/drivers/mtd/maps/sc520cdp.c 2002-11-21 17:59:08.000000000 +0000 @@ -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.9 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -25,13 +25,14 @@ * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html */ +#include #include #include #include #include #include #include - +#include /* ** The Embedded Systems BIOS decodes the first FLASH starting at @@ -171,6 +172,7 @@ static struct map_info sc520cdp_map[] = #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) static struct mtd_info *mymtd[NUM_FLASH_BANKS]; +static struct mtd_info *merged_mtd; #ifdef REPROGRAM_PAR @@ -307,19 +309,26 @@ static int __init init_sc520cdp(void) } mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); if(!mymtd[i]) - mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]); + mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); if(!mymtd[i]) mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); if (mymtd[i]) { mymtd[i]->module = THIS_MODULE; - add_mtd_device(mymtd[i]); ++devices_found; } else { iounmap((void *)sc520cdp_map[i].map_priv_1); } } + if(devices_found >= 2) { + /* Combine the two flash banks into a single MTD device & register it: */ + merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1"); + if(merged_mtd) + add_mtd_device(merged_mtd); + } + if(devices_found == 3) /* register the third (DIL-Flash) device */ + add_mtd_device(mymtd[2]); return(devices_found ? 0 : -ENXIO); } @@ -327,11 +336,16 @@ static void __exit cleanup_sc520cdp(void { int i; + if (merged_mtd) { + del_mtd_device(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + if (mymtd[2]) + del_mtd_device(mymtd[2]); + for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (mymtd[i]) { - del_mtd_device(mymtd[i]); + if (mymtd[i]) map_destroy(mymtd[i]); - } if (sc520cdp_map[i].map_priv_1) { iounmap((void *)sc520cdp_map[i].map_priv_1); sc520cdp_map[i].map_priv_1 = 0; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/solutionengine.c linux-2.5/drivers/mtd/maps/solutionengine.c --- bk-linus/drivers/mtd/maps/solutionengine.c 2002-11-21 02:15:58.000000000 +0000 +++ linux-2.5/drivers/mtd/maps/solutionengine.c 2002-11-21 17:59:08.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -15,6 +15,7 @@ #include #include #include +#include extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); @@ -57,20 +58,38 @@ struct map_info soleng_flash_map = { write32: soleng_write32, }; +#ifdef CONFIG_MTD_SUPERH_RESERVE +static struct mtd_partition superh_se_partitions[] = { + /* Reserved for boot code, read-only */ + { + name: "flash_boot", + offset: 0x00000000, + size: CONFIG_MTD_SUPERH_RESERVE, + mask_flags: MTD_WRITEABLE, + }, + /* All else is writable (e.g. JFFS) */ + { + name: "Flash FS", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL, + } +}; +#endif /* CONFIG_MTD_SUPERH_RESERVE */ + static int __init init_soleng_maps(void) { - int nr_parts; + int nr_parts = 0; /* First probe at offset 0 */ soleng_flash_map.map_priv_1 = P2SEGADDR(0); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000); + soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000); - printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n"); + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Not there. Try swapping */ - printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n"); - soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000); + printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); + soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000); soleng_eprom_map.map_priv_1 = P1SEGADDR(0); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { @@ -90,9 +109,23 @@ static int __init init_soleng_maps(void) add_mtd_device(eprom_mtd); } +#ifdef CONFIG_MTD_REDBOOT_PARTS nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + if (nr_parts > 0) + printk(KERN_NOTICE "Found RedBoot partition table.\n"); + else if (nr_parts < 0) + printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); +#endif /* CONFIG_MTD_REDBOOT_PARTS */ +#if CONFIG_MTD_SUPERH_RESERVE + if (nr_parts == 0) { + printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", + CONFIG_MTD_SUPERH_RESERVE); + parsed_parts = superh_se_partitions; + nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); + } +#endif /* CONFIG_MTD_SUPERH_RESERVE */ - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/maps/tsunami_flash.c linux-2.5/drivers/mtd/maps/tsunami_flash.c --- bk-linus/drivers/mtd/maps/tsunami_flash.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.5/drivers/mtd/maps/tsunami_flash.c 2002-11-21 17:59:08.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * tsunami_flash.c + * + * flash chip on alpha ds10... + * $Id: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $ + */ +#include +#include +#include + +#define FLASH_ENABLE_PORT 0x00C00001 +#define FLASH_ENABLE_BYTE 0x01 +#define FLASH_DISABLE_BYTE 0x00 + +#define MAX_TIG_FLASH_SIZE (12*1024*1024) +static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset) +{ + return tsunami_tig_readb(offset); +} + +static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset) +{ + tsunami_tig_writeb(value, offset); +} + +static void tsunami_flash_copy_from( + struct map_info *map, void *addr, unsigned long offset, ssize_t len) +{ + unsigned char *dest; + dest = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + *dest = tsunami_tig_readb(offset); + offset++; + dest++; + len--; + } +} + +static void tsunami_flash_copy_to( + struct map_info *map, unsigned long offset, + const void *addr, ssize_t len) +{ + const unsigned char *src; + src = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + tsunami_tig_writeb(*src, offset); + offset++; + src++; + len--; + } +} + +/* + * Deliberately don't provide operations wider than 8 bits. I don't + * have then and it scares me to think how you could mess up if + * you tried to use them. Buswidth is correctly so I'm safe. + */ +static struct map_info tsunami_flash_map = { + .name = "flash chip on the Tsunami TIG bus", + .size = MAX_TIG_FLASH_SIZE, + .buswidth = 1, + .read8 = tsunami_flash_read8, + .read16 = 0, + .read32 = 0, + .copy_from = tsunami_flash_copy_from, + .write8 = tsunami_flash_write8, + .write16 = 0, + .write32 = 0, + .copy_to = tsunami_flash_copy_to, + .set_vpp = 0, + .map_priv_1 = 0, + +}; + +static struct mtd_info *tsunami_flash_mtd; + +static void __exit cleanup_tsunami_flash(void) +{ + struct mtd_info *mtd; + mtd = tsunami_flash_mtd; + if (mtd) { + del_mtd_device(mtd); + map_destroy(mtd); + } + tsunami_flash_mtd = 0; +} + + +static int __init init_tsunami_flash(void) +{ + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; + char **type; + + tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); + + tsunami_flash_mtd = 0; + type = rom_probe_types; + for(; !tsunami_flash_mtd && *type; type++) { + tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); + } + if (tsunami_flash_mtd) { + tsunami_flash_mtd->module = THIS_MODULE; + add_mtd_device(tsunami_flash_mtd); + return 0; + } + return -ENXIO; +} + +module_init(init_tsunami_flash); +module_exit(cleanup_tsunami_flash); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/mtdcore.c linux-2.5/drivers/mtd/mtdcore.c --- bk-linus/drivers/mtd/mtdcore.c 2002-11-21 02:15:54.000000000 +0000 +++ linux-2.5/drivers/mtd/mtdcore.c 2002-11-21 17:59:04.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -296,7 +296,7 @@ done: up(&mtd_table_mutex); if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/mtd/mtdpart.c linux-2.5/drivers/mtd/mtdpart.c --- bk-linus/drivers/mtd/mtdpart.c 2002-11-21 02:15:54.000000000 +0000 +++ linux-2.5/drivers/mtd/mtdpart.c 2002-11-21 17:59:04.000000000 +0000 @@ -5,7 +5,11 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $ + * - with protection register access removed until that code is merged in 2.4. + * + * 02-21-2002 Thomas Gleixner + * added support for read_oob, write_oob */ #include @@ -28,6 +32,7 @@ struct mtd_part { u_int32_t offset; int index; struct list_head list; + int registered; }; /* @@ -54,6 +59,18 @@ static int part_read (struct mtd_info *m len, retlen, buf); } +static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->read_oob (part->master, from + part->offset, + len, retlen, buf); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -68,6 +85,20 @@ static int part_write (struct mtd_info * len, retlen, buf); } +static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write_oob (part->master, to + part->offset, + len, retlen, buf); +} + static int part_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -148,7 +179,8 @@ int del_mtd_partitions(struct mtd_info * if (slave->master == master) { struct list_head *prev = node->prev; __list_del(prev, node->next); - del_mtd_device(&slave->mtd); + if(slave->registered) + del_mtd_device(&slave->mtd); kfree(slave); node = prev; } @@ -198,18 +230,21 @@ int add_mtd_partitions(struct mtd_info * slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; - slave->mtd.module = master->module; slave->mtd.read = part_read; slave->mtd.write = part_write; + + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } - if (master->writev) slave->mtd.writev = part_writev; if (master->readv) @@ -225,6 +260,15 @@ int add_mtd_partitions(struct mtd_info * if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + u_int32_t emask = master->erasesize-1; + slave->offset = (cur_offset + emask) & ~emask; + if (slave->offset != cur_offset) { + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", i, + cur_offset, slave->offset); + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; cur_offset = slave->offset + slave->mtd.size; @@ -279,8 +323,17 @@ int add_mtd_partitions(struct mtd_info * parts[i].name); } - /* register our partition */ - add_mtd_device(&slave->mtd); + if(parts[i].mtdp) + { /* store the object pointer (caller may or may not register it */ + *parts[i].mtdp = &slave->mtd; + slave->registered = 0; + } + else + { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } } return 0; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/include/linux/mtd/partitions.h linux-2.5/include/linux/mtd/partitions.h --- bk-linus/include/linux/mtd/partitions.h 2002-11-21 02:24:14.000000000 +0000 +++ linux-2.5/include/linux/mtd/partitions.h 2002-11-21 18:04:59.000000000 +0000 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: partitions.h,v 1.6 2001/03/17 17:10:21 dwmw2 Exp $ + * $Id: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $ */ #ifndef MTD_PARTITIONS_H @@ -26,14 +26,14 @@ * will extend to the end of the master MTD device. * offset: absolute starting position within the master MTD device; if * defined as MTDPART_OFS_APPEND, the partition will start where the - * previous one ended. + * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. * mask_flags: contains flags that have to be masked (removed) from the * master MTD flag set for the corresponding MTD partition. * For example, to force a read-only partition, simply adding * MTD_WRITEABLE to the mask_flags will do the trick. * * Note: writeable partitions require their size and offset be - * erasesize aligned. + * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). */ struct mtd_partition { @@ -41,8 +41,10 @@ struct mtd_partition { u_int32_t size; /* partition size */ u_int32_t offset; /* offset within the master MTD space */ u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + struct mtd_info **mtdp; /* pointer to store the MTD object */ }; +#define MTDPART_OFS_NXTBLK (-2) #define MTDPART_OFS_APPEND (-1) #define MTDPART_SIZ_FULL (0)