| 1 | --- a/drivers/mtd/maps/Kconfig |
| 2 | +++ b/drivers/mtd/maps/Kconfig |
| 3 | @@ -249,6 +249,15 @@ config MTD_LANTIQ |
| 4 | help |
| 5 | Support for NOR flash attached to the Lantiq SoC's External Bus Unit. |
| 6 | |
| 7 | +config MTD_BCM47XX_PFLASH |
| 8 | + tristate "bcm47xx parallel flash support" |
| 9 | + default y |
| 10 | + depends on BCM47XX |
| 11 | + select MTD_PARTITIONS |
| 12 | + select MTD_BCM47XX_PARTS |
| 13 | + help |
| 14 | + Support for bcm47xx parallel flash |
| 15 | + |
| 16 | config MTD_DILNETPC |
| 17 | tristate "CFI Flash device mapped on DIL/Net PC" |
| 18 | depends on X86 && MTD_CFI_INTELEXT && BROKEN |
| 19 | --- a/drivers/mtd/maps/Makefile |
| 20 | +++ b/drivers/mtd/maps/Makefile |
| 21 | @@ -57,3 +57,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o |
| 22 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o |
| 23 | obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o |
| 24 | obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o |
| 25 | +obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o |
| 26 | --- /dev/null |
| 27 | +++ b/drivers/mtd/maps/bcm47xx-pflash.c |
| 28 | @@ -0,0 +1,196 @@ |
| 29 | +/* |
| 30 | + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
| 31 | + * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> |
| 32 | + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) |
| 33 | + * |
| 34 | + * original functions for finding root filesystem from Mike Baker |
| 35 | + * |
| 36 | + * This program is free software; you can redistribute it and/or modify it |
| 37 | + * under the terms of the GNU General Public License as published by the |
| 38 | + * Free Software Foundation; either version 2 of the License, or (at your |
| 39 | + * option) any later version. |
| 40 | + * |
| 41 | + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 42 | + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 43 | + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| 44 | + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 45 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 46 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| 47 | + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 48 | + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 49 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 50 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 51 | + * |
| 52 | + * You should have received a copy of the GNU General Public License along |
| 53 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 54 | + * 675 Mass Ave, Cambridge, MA 02139, USA. |
| 55 | + * |
| 56 | + * Copyright 2001-2003, Broadcom Corporation |
| 57 | + * All Rights Reserved. |
| 58 | + * |
| 59 | + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
| 60 | + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
| 61 | + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
| 62 | + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
| 63 | + * |
| 64 | + * Flash mapping for BCM947XX boards |
| 65 | + */ |
| 66 | + |
| 67 | +#define pr_fmt(fmt) "bcm47xx_pflash: " fmt |
| 68 | +#include <linux/init.h> |
| 69 | +#include <linux/module.h> |
| 70 | +#include <linux/types.h> |
| 71 | +#include <linux/kernel.h> |
| 72 | +#include <linux/sched.h> |
| 73 | +#include <linux/mtd/mtd.h> |
| 74 | +#include <linux/mtd/map.h> |
| 75 | +#include <linux/mtd/partitions.h> |
| 76 | +#include <linux/io.h> |
| 77 | +#include <asm/mach-bcm47xx/bcm47xx.h> |
| 78 | +#include <linux/platform_device.h> |
| 79 | + |
| 80 | +#define WINDOW_ADDR 0x1fc00000 |
| 81 | +#define WINDOW_SIZE 0x400000 |
| 82 | +#define BUSWIDTH 2 |
| 83 | + |
| 84 | +static struct mtd_info *bcm47xx_mtd; |
| 85 | + |
| 86 | +static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
| 87 | +{ |
| 88 | + if (len == 1) { |
| 89 | + memcpy_fromio(to, map->virt + from, len); |
| 90 | + } else { |
| 91 | + int i; |
| 92 | + u16 *dest = (u16 *) to; |
| 93 | + u16 *src = (u16 *) (map->virt + from); |
| 94 | + for (i = 0; i < (len / 2); i++) |
| 95 | + dest[i] = src[i]; |
| 96 | + if (len & 1) |
| 97 | + *((u8 *)dest+len-1) = src[i] & 0xff; |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +static struct map_info bcm47xx_map = { |
| 102 | + name: "Physically mapped flash", |
| 103 | + size : WINDOW_SIZE, |
| 104 | + bankwidth : BUSWIDTH, |
| 105 | + phys : WINDOW_ADDR, |
| 106 | +}; |
| 107 | + |
| 108 | +static const char *probes[] = { "bcm47xx", NULL }; |
| 109 | + |
| 110 | +static int bcm47xx_pflash_probe(struct platform_device *pdev) |
| 111 | +{ |
| 112 | +#ifdef CONFIG_BCM47XX_SSB |
| 113 | + struct ssb_mipscore *ssb_mcore; |
| 114 | +#endif |
| 115 | +#ifdef CONFIG_BCM47XX_BCMA |
| 116 | + struct bcma_drv_cc *bcma_cc; |
| 117 | +#endif |
| 118 | + int ret = 0; |
| 119 | + |
| 120 | + switch (bcm47xx_bus_type) { |
| 121 | +#ifdef CONFIG_BCM47XX_SSB |
| 122 | + case BCM47XX_BUS_TYPE_SSB: |
| 123 | + ssb_mcore = &bcm47xx_bus.ssb.mipscore; |
| 124 | + if (!ssb_mcore->pflash.present) |
| 125 | + return -ENODEV; |
| 126 | + |
| 127 | + bcm47xx_map.phys = ssb_mcore->pflash.window; |
| 128 | + bcm47xx_map.size = ssb_mcore->pflash.window_size; |
| 129 | + bcm47xx_map.bankwidth = ssb_mcore->pflash.buswidth; |
| 130 | + break; |
| 131 | +#endif |
| 132 | +#ifdef CONFIG_BCM47XX_BCMA |
| 133 | + case BCM47XX_BUS_TYPE_BCMA: |
| 134 | + bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc; |
| 135 | + if (!bcma_cc->pflash.present) |
| 136 | + return -ENODEV; |
| 137 | + |
| 138 | + bcm47xx_map.phys = bcma_cc->pflash.window; |
| 139 | + bcm47xx_map.size = bcma_cc->pflash.window_size; |
| 140 | + bcm47xx_map.bankwidth = bcma_cc->pflash.buswidth; |
| 141 | + break; |
| 142 | +#endif |
| 143 | + } |
| 144 | + |
| 145 | + pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size); |
| 146 | + bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size); |
| 147 | + |
| 148 | + if (!bcm47xx_map.virt) { |
| 149 | + pr_err("Failed to ioremap\n"); |
| 150 | + return -EIO; |
| 151 | + } |
| 152 | + |
| 153 | + simple_map_init(&bcm47xx_map); |
| 154 | + /* override copy_from routine */ |
| 155 | + bcm47xx_map.copy_from = bcm47xx_map_copy_from; |
| 156 | + |
| 157 | + bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map); |
| 158 | + if (!bcm47xx_mtd) { |
| 159 | + pr_err("Failed to do_map_probe\n"); |
| 160 | + ret = -ENXIO; |
| 161 | + goto err_unmap; |
| 162 | + } |
| 163 | + bcm47xx_mtd->owner = THIS_MODULE; |
| 164 | + |
| 165 | + pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR); |
| 166 | + |
| 167 | + ret = mtd_device_parse_register(bcm47xx_mtd, probes, NULL, NULL, 0); |
| 168 | + |
| 169 | + if (ret) { |
| 170 | + pr_err("Flash: mtd_device_register failed\n"); |
| 171 | + goto err_destroy; |
| 172 | + } |
| 173 | + return 0; |
| 174 | + |
| 175 | +err_destroy: |
| 176 | + map_destroy(bcm47xx_mtd); |
| 177 | +err_unmap: |
| 178 | + iounmap(bcm47xx_map.virt); |
| 179 | + return ret; |
| 180 | +} |
| 181 | + |
| 182 | +static int __devexit bcm47xx_pflash_remove(struct platform_device *pdev) |
| 183 | +{ |
| 184 | + mtd_device_unregister(bcm47xx_mtd); |
| 185 | + map_destroy(bcm47xx_mtd); |
| 186 | + iounmap(bcm47xx_map.virt); |
| 187 | + return 0; |
| 188 | +} |
| 189 | + |
| 190 | +static const struct platform_device_id bcm47xx_pflash_table[] = { |
| 191 | + { "bcm47xx-pflash", 0 }, |
| 192 | + { } |
| 193 | +}; |
| 194 | +MODULE_DEVICE_TABLE(platform, bcm47xx_pflash_table); |
| 195 | + |
| 196 | +static struct platform_driver bcm47xx_pflash_driver = { |
| 197 | + .id_table = bcm47xx_pflash_table, |
| 198 | + .probe = bcm47xx_pflash_probe, |
| 199 | + .remove = __devexit_p(bcm47xx_pflash_remove), |
| 200 | + .driver = { |
| 201 | + .name = "bcm47xx-pflash", |
| 202 | + .owner = THIS_MODULE, |
| 203 | + }, |
| 204 | +}; |
| 205 | + |
| 206 | +static int __init init_bcm47xx_pflash(void) |
| 207 | +{ |
| 208 | + int ret = platform_driver_register(&bcm47xx_pflash_driver); |
| 209 | + |
| 210 | + if (ret) |
| 211 | + pr_err("error registering platform driver: %i\n", ret); |
| 212 | + return ret; |
| 213 | +} |
| 214 | + |
| 215 | +static void __exit exit_bcm47xx_pflash(void) |
| 216 | +{ |
| 217 | + platform_driver_unregister(&bcm47xx_pflash_driver); |
| 218 | +} |
| 219 | + |
| 220 | +module_init(init_bcm47xx_pflash); |
| 221 | +module_exit(exit_bcm47xx_pflash); |
| 222 | + |
| 223 | +MODULE_LICENSE("GPL"); |
| 224 | +MODULE_DESCRIPTION("BCM47XX parallel flash driver"); |
| 225 | |