11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Common code to handle map devices which are simple RAM 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 2000 Red Hat. GPL'd. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/map.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_erase (struct mtd_info *, struct erase_info *); 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mapram_nop (struct mtd_info *); 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *map_ram_probe(struct map_info *map); 23402d326519c1a4859c527702383f4e60f606ef52David Howellsstatic unsigned long mapram_unmapped_area(struct mtd_info *, unsigned long, 24402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long, unsigned long); 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_chip_driver mapram_chipdrv = { 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = map_ram_probe, 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "map_ram", 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .module = THIS_MODULE 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *map_ram_probe(struct map_info *map) 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mtd_info *mtd; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the first byte is RAM */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_write8(map, 0x55, 0); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map_read8(map, 0) != 0x55) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_write8(map, 0xAA, 0); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map_read8(map, 0) != 0xAA) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the last byte is RAM */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_write8(map, 0x55, map->size-1); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map_read8(map, map->size-1) != 0x55) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_write8(map, 0xAA, map->size-1); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map_read8(map, map->size-1) != 0xAA) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK. It seems to be RAM. */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5895b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mtd) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map->fldrv = &mapram_chipdrv; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd->priv = map; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd->name = map->name; 6521c8db9eff95260e543535dfc6f27164c4c0c0ffDavid Woodhouse mtd->type = MTD_RAM; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd->size = map->size; 673c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_erase = mapram_erase; 683c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_get_unmapped_area = mapram_unmapped_area; 693c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_read = mapram_read; 703c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_write = mapram_write; 713c3c10bba1e4ccb75b41442e45c1a072f6cded19Artem Bityutskiy mtd->_sync = mapram_nop; 72a6c591eda3078f92e7a3ff3db55f6841e4819fb5Jörn Engel mtd->flags = MTD_CAP_RAM; 7317ffc7ba6d7ea68b8d5f55a5ca1b87163e69720dArtem B. Bityutskiy mtd->writesize = 1; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd->erasesize = PAGE_SIZE; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(mtd->size & (mtd->erasesize - 1)) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd->erasesize >>= 1; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __module_get(THIS_MODULE); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mtd; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84402d326519c1a4859c527702383f4e60f606ef52David Howells/* 85402d326519c1a4859c527702383f4e60f606ef52David Howells * Allow NOMMU mmap() to directly map the device (if not NULL) 86402d326519c1a4859c527702383f4e60f606ef52David Howells * - return the address to which the offset maps 87402d326519c1a4859c527702383f4e60f606ef52David Howells * - return -ENOSYS to indicate refusal to do the mapping 88402d326519c1a4859c527702383f4e60f606ef52David Howells */ 89402d326519c1a4859c527702383f4e60f606ef52David Howellsstatic unsigned long mapram_unmapped_area(struct mtd_info *mtd, 90402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long len, 91402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long offset, 92402d326519c1a4859c527702383f4e60f606ef52David Howells unsigned long flags) 93402d326519c1a4859c527702383f4e60f606ef52David Howells{ 94402d326519c1a4859c527702383f4e60f606ef52David Howells struct map_info *map = mtd->priv; 95402d326519c1a4859c527702383f4e60f606ef52David Howells return (unsigned long) map->virt + offset; 96402d326519c1a4859c527702383f4e60f606ef52David Howells} 97402d326519c1a4859c527702383f4e60f606ef52David Howells 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_info *map = mtd->priv; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_copy_from(map, buf, from, len); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *retlen = len; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_info *map = mtd->priv; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_copy_to(map, to, buf, len); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *retlen = len; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Yeah, it's inefficient. Who cares? It's faster than a _real_ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flash erase. */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct map_info *map = mtd->priv; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_word allff; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long i; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds allff = map_word_ff(map); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<instr->len; i += map_bankwidth(map)) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map_write(map, allff, instr->addr + i); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds instr->state = MTD_ERASE_DONE; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd_erase_callback(instr); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mapram_nop(struct mtd_info *mtd) 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Nothing to see here */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init map_ram_init(void) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_mtd_chip_driver(&mapram_chipdrv); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit map_ram_exit(void) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_mtd_chip_driver(&mapram_chipdrv); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(map_ram_init); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(map_ram_exit); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MTD chip driver for RAM chips"); 154