18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Common code to handle map devices which are simple RAM 38c2ecf20Sopenharmony_ci * (C) 2000 Red Hat. GPL'd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <asm/io.h> 108c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 158c2ecf20Sopenharmony_ci#include <linux/mtd/map.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 198c2ecf20Sopenharmony_cistatic int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 208c2ecf20Sopenharmony_cistatic int mapram_erase (struct mtd_info *, struct erase_info *); 218c2ecf20Sopenharmony_cistatic void mapram_nop (struct mtd_info *); 228c2ecf20Sopenharmony_cistatic struct mtd_info *map_ram_probe(struct map_info *map); 238c2ecf20Sopenharmony_cistatic int mapram_point (struct mtd_info *mtd, loff_t from, size_t len, 248c2ecf20Sopenharmony_ci size_t *retlen, void **virt, resource_size_t *phys); 258c2ecf20Sopenharmony_cistatic int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct mtd_chip_driver mapram_chipdrv = { 298c2ecf20Sopenharmony_ci .probe = map_ram_probe, 308c2ecf20Sopenharmony_ci .name = "map_ram", 318c2ecf20Sopenharmony_ci .module = THIS_MODULE 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct mtd_info *map_ram_probe(struct map_info *map) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct mtd_info *mtd; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Check the first byte is RAM */ 398c2ecf20Sopenharmony_ci#if 0 408c2ecf20Sopenharmony_ci map_write8(map, 0x55, 0); 418c2ecf20Sopenharmony_ci if (map_read8(map, 0) != 0x55) 428c2ecf20Sopenharmony_ci return NULL; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci map_write8(map, 0xAA, 0); 458c2ecf20Sopenharmony_ci if (map_read8(map, 0) != 0xAA) 468c2ecf20Sopenharmony_ci return NULL; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Check the last byte is RAM */ 498c2ecf20Sopenharmony_ci map_write8(map, 0x55, map->size-1); 508c2ecf20Sopenharmony_ci if (map_read8(map, map->size-1) != 0x55) 518c2ecf20Sopenharmony_ci return NULL; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci map_write8(map, 0xAA, map->size-1); 548c2ecf20Sopenharmony_ci if (map_read8(map, map->size-1) != 0xAA) 558c2ecf20Sopenharmony_ci return NULL; 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci /* OK. It seems to be RAM. */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); 608c2ecf20Sopenharmony_ci if (!mtd) 618c2ecf20Sopenharmony_ci return NULL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci map->fldrv = &mapram_chipdrv; 648c2ecf20Sopenharmony_ci mtd->priv = map; 658c2ecf20Sopenharmony_ci mtd->name = map->name; 668c2ecf20Sopenharmony_ci mtd->type = MTD_RAM; 678c2ecf20Sopenharmony_ci mtd->size = map->size; 688c2ecf20Sopenharmony_ci mtd->_erase = mapram_erase; 698c2ecf20Sopenharmony_ci mtd->_read = mapram_read; 708c2ecf20Sopenharmony_ci mtd->_write = mapram_write; 718c2ecf20Sopenharmony_ci mtd->_panic_write = mapram_write; 728c2ecf20Sopenharmony_ci mtd->_point = mapram_point; 738c2ecf20Sopenharmony_ci mtd->_sync = mapram_nop; 748c2ecf20Sopenharmony_ci mtd->_unpoint = mapram_unpoint; 758c2ecf20Sopenharmony_ci mtd->flags = MTD_CAP_RAM; 768c2ecf20Sopenharmony_ci mtd->writesize = 1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci mtd->erasesize = PAGE_SIZE; 798c2ecf20Sopenharmony_ci while(mtd->size & (mtd->erasesize - 1)) 808c2ecf20Sopenharmony_ci mtd->erasesize >>= 1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci __module_get(THIS_MODULE); 838c2ecf20Sopenharmony_ci return mtd; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int mapram_point(struct mtd_info *mtd, loff_t from, size_t len, 878c2ecf20Sopenharmony_ci size_t *retlen, void **virt, resource_size_t *phys) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct map_info *map = mtd->priv; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!map->virt) 928c2ecf20Sopenharmony_ci return -EINVAL; 938c2ecf20Sopenharmony_ci *virt = map->virt + from; 948c2ecf20Sopenharmony_ci if (phys) 958c2ecf20Sopenharmony_ci *phys = map->phys + from; 968c2ecf20Sopenharmony_ci *retlen = len; 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct map_info *map = mtd->priv; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci map_copy_from(map, buf, from, len); 1108c2ecf20Sopenharmony_ci *retlen = len; 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct map_info *map = mtd->priv; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci map_copy_to(map, to, buf, len); 1198c2ecf20Sopenharmony_ci *retlen = len; 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci /* Yeah, it's inefficient. Who cares? It's faster than a _real_ 1268c2ecf20Sopenharmony_ci flash erase. */ 1278c2ecf20Sopenharmony_ci struct map_info *map = mtd->priv; 1288c2ecf20Sopenharmony_ci map_word allff; 1298c2ecf20Sopenharmony_ci unsigned long i; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci allff = map_word_ff(map); 1328c2ecf20Sopenharmony_ci for (i=0; i<instr->len; i += map_bankwidth(map)) 1338c2ecf20Sopenharmony_ci map_write(map, allff, instr->addr + i); 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void mapram_nop(struct mtd_info *mtd) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci /* Nothing to see here */ 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int __init map_ram_init(void) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci register_mtd_chip_driver(&mapram_chipdrv); 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void __exit map_ram_exit(void) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci unregister_mtd_chip_driver(&mapram_chipdrv); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cimodule_init(map_ram_init); 1548c2ecf20Sopenharmony_cimodule_exit(map_ram_exit); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1578c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 1588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MTD chip driver for RAM chips"); 159