1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Common code to handle map devices which are simple RAM |
4 | * (C) 2000 Red Hat. |
5 | */ |
6 | |
7 | #include <linux/module.h> |
8 | #include <linux/types.h> |
9 | #include <linux/kernel.h> |
10 | #include <asm/io.h> |
11 | #include <asm/byteorder.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/init.h> |
15 | #include <linux/mtd/mtd.h> |
16 | #include <linux/mtd/map.h> |
17 | |
18 | |
19 | static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
20 | static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
21 | static int mapram_erase (struct mtd_info *, struct erase_info *); |
22 | static void mapram_nop (struct mtd_info *); |
23 | static struct mtd_info *map_ram_probe(struct map_info *map); |
24 | static int mapram_point (struct mtd_info *mtd, loff_t from, size_t len, |
25 | size_t *retlen, void **virt, resource_size_t *phys); |
26 | static int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len); |
27 | |
28 | |
29 | static struct mtd_chip_driver mapram_chipdrv = { |
30 | .probe = map_ram_probe, |
31 | .name = "map_ram" , |
32 | .module = THIS_MODULE |
33 | }; |
34 | |
35 | static struct mtd_info *map_ram_probe(struct map_info *map) |
36 | { |
37 | struct mtd_info *mtd; |
38 | |
39 | /* Check the first byte is RAM */ |
40 | #if 0 |
41 | map_write8(map, 0x55, 0); |
42 | if (map_read8(map, 0) != 0x55) |
43 | return NULL; |
44 | |
45 | map_write8(map, 0xAA, 0); |
46 | if (map_read8(map, 0) != 0xAA) |
47 | return NULL; |
48 | |
49 | /* Check the last byte is RAM */ |
50 | map_write8(map, 0x55, map->size-1); |
51 | if (map_read8(map, map->size-1) != 0x55) |
52 | return NULL; |
53 | |
54 | map_write8(map, 0xAA, map->size-1); |
55 | if (map_read8(map, map->size-1) != 0xAA) |
56 | return NULL; |
57 | #endif |
58 | /* OK. It seems to be RAM. */ |
59 | |
60 | mtd = kzalloc(size: sizeof(*mtd), GFP_KERNEL); |
61 | if (!mtd) |
62 | return NULL; |
63 | |
64 | map->fldrv = &mapram_chipdrv; |
65 | mtd->priv = map; |
66 | mtd->name = map->name; |
67 | mtd->type = MTD_RAM; |
68 | mtd->size = map->size; |
69 | mtd->_erase = mapram_erase; |
70 | mtd->_read = mapram_read; |
71 | mtd->_write = mapram_write; |
72 | mtd->_panic_write = mapram_write; |
73 | mtd->_sync = mapram_nop; |
74 | mtd->flags = MTD_CAP_RAM; |
75 | mtd->writesize = 1; |
76 | |
77 | /* Disable direct access when NO_XIP is set */ |
78 | if (map->phys != NO_XIP) { |
79 | mtd->_point = mapram_point; |
80 | mtd->_unpoint = mapram_unpoint; |
81 | } |
82 | |
83 | mtd->erasesize = PAGE_SIZE; |
84 | while(mtd->size & (mtd->erasesize - 1)) |
85 | mtd->erasesize >>= 1; |
86 | |
87 | __module_get(THIS_MODULE); |
88 | return mtd; |
89 | } |
90 | |
91 | static int mapram_point(struct mtd_info *mtd, loff_t from, size_t len, |
92 | size_t *retlen, void **virt, resource_size_t *phys) |
93 | { |
94 | struct map_info *map = mtd->priv; |
95 | |
96 | if (!map->virt) |
97 | return -EINVAL; |
98 | *virt = map->virt + from; |
99 | if (phys) |
100 | *phys = map->phys + from; |
101 | *retlen = len; |
102 | return 0; |
103 | } |
104 | |
105 | static int mapram_unpoint(struct mtd_info *mtd, loff_t from, size_t len) |
106 | { |
107 | return 0; |
108 | } |
109 | |
110 | static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) |
111 | { |
112 | struct map_info *map = mtd->priv; |
113 | |
114 | map_copy_from(map, buf, from, len); |
115 | *retlen = len; |
116 | return 0; |
117 | } |
118 | |
119 | static int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) |
120 | { |
121 | struct map_info *map = mtd->priv; |
122 | |
123 | map_copy_to(map, to, buf, len); |
124 | *retlen = len; |
125 | return 0; |
126 | } |
127 | |
128 | static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr) |
129 | { |
130 | /* Yeah, it's inefficient. Who cares? It's faster than a _real_ |
131 | flash erase. */ |
132 | struct map_info *map = mtd->priv; |
133 | map_word allff; |
134 | unsigned long i; |
135 | |
136 | allff = map_word_ff(map); |
137 | for (i=0; i<instr->len; i += map_bankwidth(map)) |
138 | map_write(map, allff, instr->addr + i); |
139 | return 0; |
140 | } |
141 | |
142 | static void mapram_nop(struct mtd_info *mtd) |
143 | { |
144 | /* Nothing to see here */ |
145 | } |
146 | |
147 | static int __init map_ram_init(void) |
148 | { |
149 | register_mtd_chip_driver(&mapram_chipdrv); |
150 | return 0; |
151 | } |
152 | |
153 | static void __exit map_ram_exit(void) |
154 | { |
155 | unregister_mtd_chip_driver(&mapram_chipdrv); |
156 | } |
157 | |
158 | module_init(map_ram_init); |
159 | module_exit(map_ram_exit); |
160 | |
161 | MODULE_LICENSE("GPL" ); |
162 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>" ); |
163 | MODULE_DESCRIPTION("MTD chip driver for RAM chips" ); |
164 | |