Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: NOR flash driver for OMAP-L137/AM17x

OMAP-L137/AM17x has limited number of dedicated EMIFA
address pins, enough to interface directly to an SDRAM.
If a device such as an asynchronous flash needs to be
attached to the EMIFA, then either GPIO pins or a chip
select may be used to control the flash device's upper
address lines.

This patch adds support for the NOR flash on the OMAP-L137/
AM17x user interface daughter board using the latch-addr-flash
MTD mapping driver which allows flashes to be partially
physically addressed. The upper address lines are set by
a board specific code which is a separate patch.

Signed-off-by: David Griego <dgriego@mvista.com>
Signed-off-by: Aleksey Makarov <amakarov@ru.mvista.com>
Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Savinay Dharmappa <savinay.dharmappa@ti.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

David Griego and committed by
David Woodhouse
dcfb81d6 a3215902

+311
+9
drivers/mtd/maps/Kconfig
··· 552 552 553 553 When built as a module, it will be called pismo.ko 554 554 555 + config MTD_LATCH_ADDR 556 + tristate "Latch-assisted Flash Chip Support" 557 + depends on MTD_COMPLEX_MAPPINGS 558 + help 559 + Map driver which allows flashes to be partially physically addressed 560 + and have the upper address lines set by a board specific code. 561 + 562 + If compiled as a module, it will be called latch-addr-flash. 563 + 555 564 endmenu
+1
drivers/mtd/maps/Makefile
··· 59 59 obj-$(CONFIG_MTD_VMU) += vmu-flash.o 60 60 obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o 61 61 obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o 62 + obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+272
drivers/mtd/maps/latch-addr-flash.c
··· 1 + /* 2 + * Interface for NOR flash driver whose high address lines are latched 3 + * 4 + * Copyright © 2000 Nicolas Pitre <nico@cam.org> 5 + * Copyright © 2005-2008 Analog Devices Inc. 6 + * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public License 9 + * version 2. This program is licensed "as is" without any warranty of any 10 + * kind, whether express or implied. 11 + */ 12 + 13 + #include <linux/init.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/mtd/mtd.h> 17 + #include <linux/mtd/map.h> 18 + #include <linux/mtd/partitions.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/mtd/latch-addr-flash.h> 21 + #include <linux/slab.h> 22 + 23 + #define DRIVER_NAME "latch-addr-flash" 24 + 25 + struct latch_addr_flash_info { 26 + struct mtd_info *mtd; 27 + struct map_info map; 28 + struct resource *res; 29 + 30 + void (*set_window)(unsigned long offset, void *data); 31 + void *data; 32 + 33 + /* cache; could be found out of res */ 34 + unsigned long win_mask; 35 + 36 + int nr_parts; 37 + struct mtd_partition *parts; 38 + 39 + spinlock_t lock; 40 + }; 41 + 42 + static map_word lf_read(struct map_info *map, unsigned long ofs) 43 + { 44 + struct latch_addr_flash_info *info; 45 + map_word datum; 46 + 47 + info = (struct latch_addr_flash_info *)map->map_priv_1; 48 + 49 + spin_lock(&info->lock); 50 + 51 + info->set_window(ofs, info->data); 52 + datum = inline_map_read(map, info->win_mask & ofs); 53 + 54 + spin_unlock(&info->lock); 55 + 56 + return datum; 57 + } 58 + 59 + static void lf_write(struct map_info *map, map_word datum, unsigned long ofs) 60 + { 61 + struct latch_addr_flash_info *info; 62 + 63 + info = (struct latch_addr_flash_info *)map->map_priv_1; 64 + 65 + spin_lock(&info->lock); 66 + 67 + info->set_window(ofs, info->data); 68 + inline_map_write(map, datum, info->win_mask & ofs); 69 + 70 + spin_unlock(&info->lock); 71 + } 72 + 73 + static void lf_copy_from(struct map_info *map, void *to, 74 + unsigned long from, ssize_t len) 75 + { 76 + struct latch_addr_flash_info *info = 77 + (struct latch_addr_flash_info *) map->map_priv_1; 78 + unsigned n; 79 + 80 + while (len > 0) { 81 + n = info->win_mask + 1 - (from & info->win_mask); 82 + if (n > len) 83 + n = len; 84 + 85 + spin_lock(&info->lock); 86 + 87 + info->set_window(from, info->data); 88 + memcpy_fromio(to, map->virt + (from & info->win_mask), n); 89 + 90 + spin_unlock(&info->lock); 91 + 92 + to += n; 93 + from += n; 94 + len -= n; 95 + } 96 + } 97 + 98 + static char *rom_probe_types[] = { "cfi_probe", NULL }; 99 + 100 + static char *part_probe_types[] = { "cmdlinepart", NULL }; 101 + 102 + static int latch_addr_flash_remove(struct platform_device *dev) 103 + { 104 + struct latch_addr_flash_info *info; 105 + struct latch_addr_flash_data *latch_addr_data; 106 + 107 + info = platform_get_drvdata(dev); 108 + if (info == NULL) 109 + return 0; 110 + platform_set_drvdata(dev, NULL); 111 + 112 + latch_addr_data = dev->dev.platform_data; 113 + 114 + if (info->mtd != NULL) { 115 + if (mtd_has_partitions()) { 116 + if (info->nr_parts) { 117 + del_mtd_partitions(info->mtd); 118 + kfree(info->parts); 119 + } else if (latch_addr_data->nr_parts) { 120 + del_mtd_partitions(info->mtd); 121 + } else { 122 + del_mtd_device(info->mtd); 123 + } 124 + } else { 125 + del_mtd_device(info->mtd); 126 + } 127 + map_destroy(info->mtd); 128 + } 129 + 130 + if (info->map.virt != NULL) 131 + iounmap(info->map.virt); 132 + 133 + if (info->res != NULL) 134 + release_mem_region(info->res->start, resource_size(info->res)); 135 + 136 + kfree(info); 137 + 138 + if (latch_addr_data->done) 139 + latch_addr_data->done(latch_addr_data->data); 140 + 141 + return 0; 142 + } 143 + 144 + static int __devinit latch_addr_flash_probe(struct platform_device *dev) 145 + { 146 + struct latch_addr_flash_data *latch_addr_data; 147 + struct latch_addr_flash_info *info; 148 + resource_size_t win_base = dev->resource->start; 149 + resource_size_t win_size = resource_size(dev->resource); 150 + char **probe_type; 151 + int chipsel; 152 + int err; 153 + 154 + latch_addr_data = dev->dev.platform_data; 155 + if (latch_addr_data == NULL) 156 + return -ENODEV; 157 + 158 + pr_notice("latch-addr platform flash device: %#llx byte " 159 + "window at %#.8llx\n", 160 + (unsigned long long)win_size, (unsigned long long)win_base); 161 + 162 + chipsel = dev->id; 163 + 164 + if (latch_addr_data->init) { 165 + err = latch_addr_data->init(latch_addr_data->data, chipsel); 166 + if (err != 0) 167 + return err; 168 + } 169 + 170 + info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL); 171 + if (info == NULL) { 172 + err = -ENOMEM; 173 + goto done; 174 + } 175 + 176 + platform_set_drvdata(dev, info); 177 + 178 + info->res = request_mem_region(win_base, win_size, DRIVER_NAME); 179 + if (info->res == NULL) { 180 + dev_err(&dev->dev, "Could not reserve memory region\n"); 181 + err = -EBUSY; 182 + goto free_info; 183 + } 184 + 185 + info->map.name = DRIVER_NAME; 186 + info->map.size = latch_addr_data->size; 187 + info->map.bankwidth = latch_addr_data->width; 188 + 189 + info->map.phys = NO_XIP; 190 + info->map.virt = ioremap(win_base, win_size); 191 + if (!info->map.virt) { 192 + err = -ENOMEM; 193 + goto free_res; 194 + } 195 + 196 + info->map.map_priv_1 = (unsigned long)info; 197 + 198 + info->map.read = lf_read; 199 + info->map.copy_from = lf_copy_from; 200 + info->map.write = lf_write; 201 + info->set_window = latch_addr_data->set_window; 202 + info->data = latch_addr_data->data; 203 + info->win_mask = win_size - 1; 204 + 205 + spin_lock_init(&info->lock); 206 + 207 + for (probe_type = rom_probe_types; !info->mtd && *probe_type; 208 + probe_type++) 209 + info->mtd = do_map_probe(*probe_type, &info->map); 210 + 211 + if (info->mtd == NULL) { 212 + dev_err(&dev->dev, "map_probe failed\n"); 213 + err = -ENODEV; 214 + goto iounmap; 215 + } 216 + info->mtd->owner = THIS_MODULE; 217 + 218 + if (mtd_has_partitions()) { 219 + 220 + err = parse_mtd_partitions(info->mtd, 221 + (const char **)part_probe_types, 222 + &info->parts, 0); 223 + if (err > 0) { 224 + add_mtd_partitions(info->mtd, info->parts, err); 225 + return 0; 226 + } 227 + if (latch_addr_data->nr_parts) { 228 + pr_notice("Using latch-addr-flash partition information\n"); 229 + add_mtd_partitions(info->mtd, latch_addr_data->parts, 230 + latch_addr_data->nr_parts); 231 + return 0; 232 + } 233 + } 234 + add_mtd_device(info->mtd); 235 + return 0; 236 + 237 + iounmap: 238 + iounmap(info->map.virt); 239 + free_res: 240 + release_mem_region(info->res->start, resource_size(info->res)); 241 + free_info: 242 + kfree(info); 243 + done: 244 + if (latch_addr_data->done) 245 + latch_addr_data->done(latch_addr_data->data); 246 + return err; 247 + } 248 + 249 + static struct platform_driver latch_addr_flash_driver = { 250 + .probe = latch_addr_flash_probe, 251 + .remove = __devexit_p(latch_addr_flash_remove), 252 + .driver = { 253 + .name = DRIVER_NAME, 254 + }, 255 + }; 256 + 257 + static int __init latch_addr_flash_init(void) 258 + { 259 + return platform_driver_register(&latch_addr_flash_driver); 260 + } 261 + module_init(latch_addr_flash_init); 262 + 263 + static void __exit latch_addr_flash_exit(void) 264 + { 265 + platform_driver_unregister(&latch_addr_flash_driver); 266 + } 267 + module_exit(latch_addr_flash_exit); 268 + 269 + MODULE_AUTHOR("David Griego <dgriego@mvista.com>"); 270 + MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper " 271 + "address lines being set board specifically"); 272 + MODULE_LICENSE("GPL v2");
+29
include/linux/mtd/latch-addr-flash.h
··· 1 + /* 2 + * Interface for NOR flash driver whose high address lines are latched 3 + * 4 + * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> 5 + * 6 + * This file is licensed under the terms of the GNU General Public License 7 + * version 2. This program is licensed "as is" without any warranty of any 8 + * kind, whether express or implied. 9 + */ 10 + #ifndef __LATCH_ADDR_FLASH__ 11 + #define __LATCH_ADDR_FLASH__ 12 + 13 + struct map_info; 14 + struct mtd_partition; 15 + 16 + struct latch_addr_flash_data { 17 + unsigned int width; 18 + unsigned int size; 19 + 20 + int (*init)(void *data, int cs); 21 + void (*done)(void *data); 22 + void (*set_window)(unsigned long offset, void *data); 23 + void *data; 24 + 25 + unsigned int nr_parts; 26 + struct mtd_partition *parts; 27 + }; 28 + 29 + #endif