Commit dcfb81d61da1367e52f7f7e3ceff0d0044c3c7ee

Authored by David Griego
Committed by David Woodhouse
1 parent a321590246

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>

Showing 4 changed files with 311 additions and 0 deletions Side-by-side Diff

drivers/mtd/maps/Kconfig
... ... @@ -552,5 +552,14 @@
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
drivers/mtd/maps/Makefile
... ... @@ -59,4 +59,5 @@
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
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");
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