1/* linux/drivers/mtd/maps/bast-flash.c 2 * 3 * Copyright (c) 2004-2005 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * Simtec Bast (EB2410ITX) NOR MTD Mapping driver 7 * 8 * Changelog: 9 * 20-Sep-2004 BJD Initial version 10 * 17-Jan-2005 BJD Add whole device if no partitions found 11 * 12 * $Id: bast-flash.c,v 1.1.1.1 2007/08/03 18:52:43 Exp $ 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27*/ 28 29#include <linux/module.h> 30#include <linux/types.h> 31#include <linux/init.h> 32#include <linux/kernel.h> 33#include <linux/string.h> 34#include <linux/ioport.h> 35#include <linux/device.h> 36#include <linux/slab.h> 37#include <linux/platform_device.h> 38#include <linux/mtd/mtd.h> 39#include <linux/mtd/map.h> 40#include <linux/mtd/partitions.h> 41 42#include <asm/io.h> 43#include <asm/mach/flash.h> 44 45#include <asm/arch/map.h> 46#include <asm/arch/bast-map.h> 47#include <asm/arch/bast-cpld.h> 48 49#ifdef CONFIG_MTD_BAST_MAXSIZE 50#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M) 51#else 52#define AREA_MAXSIZE (32 * SZ_1M) 53#endif 54 55#define PFX "bast-flash: " 56 57struct bast_flash_info { 58 struct mtd_info *mtd; 59 struct map_info map; 60 struct mtd_partition *partitions; 61 struct resource *area; 62}; 63 64static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; 65 66static void bast_flash_setrw(int to) 67{ 68 unsigned int val; 69 unsigned long flags; 70 71 local_irq_save(flags); 72 val = __raw_readb(BAST_VA_CTRL3); 73 74 if (to) 75 val |= BAST_CPLD_CTRL3_ROMWEN; 76 else 77 val &= ~BAST_CPLD_CTRL3_ROMWEN; 78 79 pr_debug("new cpld ctrl3=%02x\n", val); 80 81 __raw_writeb(val, BAST_VA_CTRL3); 82 local_irq_restore(flags); 83} 84 85static int bast_flash_remove(struct platform_device *pdev) 86{ 87 struct bast_flash_info *info = platform_get_drvdata(pdev); 88 89 platform_set_drvdata(pdev, NULL); 90 91 if (info == NULL) 92 return 0; 93 94 if (info->map.virt != NULL) 95 iounmap(info->map.virt); 96 97 if (info->mtd) { 98 del_mtd_partitions(info->mtd); 99 map_destroy(info->mtd); 100 } 101 102 kfree(info->partitions); 103 104 if (info->area) { 105 release_resource(info->area); 106 kfree(info->area); 107 } 108 109 kfree(info); 110 111 return 0; 112} 113 114static int bast_flash_probe(struct platform_device *pdev) 115{ 116 struct bast_flash_info *info; 117 struct resource *res; 118 int err = 0; 119 120 info = kmalloc(sizeof(*info), GFP_KERNEL); 121 if (info == NULL) { 122 printk(KERN_ERR PFX "no memory for flash info\n"); 123 err = -ENOMEM; 124 goto exit_error; 125 } 126 127 memzero(info, sizeof(*info)); 128 platform_set_drvdata(pdev, info); 129 130 res = pdev->resource; /* assume that the flash has one resource */ 131 132 info->map.phys = res->start; 133 info->map.size = res->end - res->start + 1; 134 info->map.name = pdev->dev.bus_id; 135 info->map.bankwidth = 2; 136 137 if (info->map.size > AREA_MAXSIZE) 138 info->map.size = AREA_MAXSIZE; 139 140 pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, 141 info->map.phys, info->map.size); 142 143 info->area = request_mem_region(res->start, info->map.size, 144 pdev->name); 145 if (info->area == NULL) { 146 printk(KERN_ERR PFX "cannot reserve flash memory region\n"); 147 err = -ENOENT; 148 goto exit_error; 149 } 150 151 info->map.virt = ioremap(res->start, info->map.size); 152 pr_debug("%s: virt at %08x\n", __FUNCTION__, (int)info->map.virt); 153 154 if (info->map.virt == 0) { 155 printk(KERN_ERR PFX "failed to ioremap() region\n"); 156 err = -EIO; 157 goto exit_error; 158 } 159 160 simple_map_init(&info->map); 161 162 /* enable the write to the flash area */ 163 164 bast_flash_setrw(1); 165 166 /* probe for the device(s) */ 167 168 info->mtd = do_map_probe("jedec_probe", &info->map); 169 if (info->mtd == NULL) 170 info->mtd = do_map_probe("cfi_probe", &info->map); 171 172 if (info->mtd == NULL) { 173 printk(KERN_ERR PFX "map_probe() failed\n"); 174 err = -ENXIO; 175 goto exit_error; 176 } 177 178 /* mark ourselves as the owner */ 179 info->mtd->owner = THIS_MODULE; 180 181 err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); 182 if (err > 0) { 183 err = add_mtd_partitions(info->mtd, info->partitions, err); 184 if (err) 185 printk(KERN_ERR PFX "cannot add/parse partitions\n"); 186 } else { 187 err = add_mtd_device(info->mtd); 188 } 189 190 if (err == 0) 191 return 0; 192 193 /* fall through to exit error */ 194 195 exit_error: 196 bast_flash_remove(pdev); 197 return err; 198} 199 200static struct platform_driver bast_flash_driver = { 201 .probe = bast_flash_probe, 202 .remove = bast_flash_remove, 203 .driver = { 204 .name = "bast-nor", 205 .owner = THIS_MODULE, 206 }, 207}; 208 209static int __init bast_flash_init(void) 210{ 211 printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n"); 212 return platform_driver_register(&bast_flash_driver); 213} 214 215static void __exit bast_flash_exit(void) 216{ 217 platform_driver_unregister(&bast_flash_driver); 218} 219 220module_init(bast_flash_init); 221module_exit(bast_flash_exit); 222 223MODULE_LICENSE("GPL"); 224MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 225MODULE_DESCRIPTION("BAST MTD Map driver"); 226