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