1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <linux/ioport.h>
21#include <linux/init.h>
22#include <linux/spinlock.h>
23#include <asm/io.h>
24
25#include <linux/mtd/map.h>
26#include <linux/mtd/mtd.h>
27
28
29#define WINDOW_START 0xd8000
30#define WINDOW_LENGTH 0x2000
31#define WINDOW_SHIFT 25
32#define WINDOW_MASK 0x1FFF
33
34
35
36
37
38
39
40static DEFINE_SPINLOCK(vmax301_spin);
41
42static void __vmax301_page(struct map_info *map, unsigned long page)
43{
44 writew(page, map->map_priv_2 - WINDOW_LENGTH);
45 map->map_priv_1 = page;
46}
47
48static inline void vmax301_page(struct map_info *map,
49 unsigned long ofs)
50{
51 unsigned long page = (ofs >> WINDOW_SHIFT);
52 if (map->map_priv_1 != page)
53 __vmax301_page(map, page);
54}
55
56static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
57{
58 map_word ret;
59 spin_lock(&vmax301_spin);
60 vmax301_page(map, ofs);
61 ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
62 spin_unlock(&vmax301_spin);
63 return ret;
64}
65
66static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
67{
68 while(len) {
69 unsigned long thislen = len;
70 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
71 thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
72 spin_lock(&vmax301_spin);
73 vmax301_page(map, from);
74 memcpy_fromio(to, map->map_priv_2 + from, thislen);
75 spin_unlock(&vmax301_spin);
76 to += thislen;
77 from += thislen;
78 len -= thislen;
79 }
80}
81
82static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
83{
84 spin_lock(&vmax301_spin);
85 vmax301_page(map, adr);
86 writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
87 spin_unlock(&vmax301_spin);
88}
89
90static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
91{
92 while(len) {
93 unsigned long thislen = len;
94 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
95 thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
96
97 spin_lock(&vmax301_spin);
98 vmax301_page(map, to);
99 memcpy_toio(map->map_priv_2 + to, from, thislen);
100 spin_unlock(&vmax301_spin);
101 to += thislen;
102 from += thislen;
103 len -= thislen;
104 }
105}
106
107static struct map_info vmax_map[2] = {
108 {
109 .name = "VMAX301 Internal Flash",
110 .phys = NO_XIP,
111 .size = 3*2*1024*1024,
112 .bankwidth = 1,
113 .read = vmax301_read8,
114 .copy_from = vmax301_copy_from,
115 .write = vmax301_write8,
116 .copy_to = vmax301_copy_to,
117 .map_priv_1 = WINDOW_START + WINDOW_LENGTH,
118 .map_priv_2 = 0xFFFFFFFF
119 },
120 {
121 .name = "VMAX301 Socket",
122 .phys = NO_XIP,
123 .size = 0,
124 .bankwidth = 1,
125 .read = vmax301_read8,
126 .copy_from = vmax301_copy_from,
127 .write = vmax301_write8,
128 .copy_to = vmax301_copy_to,
129 .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
130 .map_priv_2 = 0xFFFFFFFF
131 }
132};
133
134static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
135
136static void __exit cleanup_vmax301(void)
137{
138 int i;
139
140 for (i=0; i<2; i++) {
141 if (vmax_mtd[i]) {
142 del_mtd_device(vmax_mtd[i]);
143 map_destroy(vmax_mtd[i]);
144 }
145 }
146 iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
147}
148
149static int __init init_vmax301(void)
150{
151 int i;
152 unsigned long iomapadr;
153
154 printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
155 WINDOW_START+4*WINDOW_LENGTH);
156
157 iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
158 if (!iomapadr) {
159 printk("Failed to ioremap memory region\n");
160 return -EIO;
161 }
162
163
164
165
166
167 vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
168 vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
169
170 for (i=0; i<2; i++) {
171 vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
172 if (!vmax_mtd[i])
173 vmax_mtd[i] = do_map_probe("jedec", &vmax_map[i]);
174 if (!vmax_mtd[i])
175 vmax_mtd[i] = do_map_probe("map_ram", &vmax_map[i]);
176 if (!vmax_mtd[i])
177 vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
178 if (vmax_mtd[i]) {
179 vmax_mtd[i]->owner = THIS_MODULE;
180 add_mtd_device(vmax_mtd[i]);
181 }
182 }
183
184 if (!vmax_mtd[0] && !vmax_mtd[1]) {
185 iounmap((void *)iomapadr);
186 return -ENXIO;
187 }
188
189 return 0;
190}
191
192module_init(init_vmax301);
193module_exit(cleanup_vmax301);
194
195MODULE_LICENSE("GPL");
196MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
197MODULE_DESCRIPTION("MTD map driver for Tempustech VMAX SBC301 board");
198