special usb hub handling, IDE disks, and retries all over the place
[linux-2.4.git] / drivers / mtd / maps / ocelot.c
1 /*
2  * $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
3  *
4  * Flash on Momenco Ocelot
5  */
6
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/kernel.h>
10 #include <asm/io.h>
11 #include <linux/mtd/mtd.h>
12 #include <linux/mtd/map.h>
13 #include <linux/mtd/partitions.h>
14
15 #define OCELOT_PLD 0x2c000000
16 #define FLASH_WINDOW_ADDR 0x2fc00000
17 #define FLASH_WINDOW_SIZE 0x00080000
18 #define FLASH_BUSWIDTH 1
19 #define NVRAM_WINDOW_ADDR 0x2c800000
20 #define NVRAM_WINDOW_SIZE 0x00007FF0
21 #define NVRAM_BUSWIDTH 1
22
23 extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
24
25 static unsigned int cacheflush = 0;
26
27 static struct mtd_info *flash_mtd;
28 static struct mtd_info *nvram_mtd;
29
30 __u8 ocelot_read8(struct map_info *map, unsigned long ofs)
31 {
32         return __raw_readb(map->map_priv_1 + ofs);
33 }
34
35 void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr)
36 {
37         cacheflush = 1;
38         __raw_writeb(d, map->map_priv_1 + adr);
39         mb();
40 }
41
42 void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len)
43 {
44         if (cacheflush) {
45                 dma_cache_inv(map->map_priv_2, map->size);
46                 cacheflush = 0;
47         }
48         memcpy_fromio(to, map->map_priv_1 + from, len);
49 }
50
51 void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
52 {
53         memcpy_fromio(to, map->map_priv_1 + from, len);
54 }
55
56 void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
57 {
58         /* If we use memcpy, it does word-wide writes. Even though we told the 
59            GT64120A that it's an 8-bit wide region, word-wide writes don't work.
60            We end up just writing the first byte of the four to all four bytes.
61            So we have this loop instead */
62         while(len) {
63                 __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
64                 from++;
65                 to++;
66                 len--;
67         }
68 }
69
70 static struct mtd_partition *parsed_parts;
71
72 struct map_info ocelot_flash_map = {
73         name: "Ocelot boot flash",
74         size: FLASH_WINDOW_SIZE,
75         buswidth: FLASH_BUSWIDTH,
76         read8: ocelot_read8,
77         copy_from: ocelot_copy_from_cache,
78         write8: ocelot_write8,
79 };
80
81 struct map_info ocelot_nvram_map = {
82         name: "Ocelot NVRAM",
83         size: NVRAM_WINDOW_SIZE,
84         buswidth: NVRAM_BUSWIDTH,
85         read8: ocelot_read8,
86         copy_from: ocelot_copy_from,
87         write8: ocelot_write8,
88         copy_to: ocelot_copy_to
89 };
90
91 static int __init init_ocelot_maps(void)
92 {
93         void *pld;
94         int nr_parts;
95         unsigned char brd_status;
96
97         printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", 
98                FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
99
100         /* First check whether the flash jumper is present */
101         pld = ioremap(OCELOT_PLD, 0x10);
102         if (!pld) {
103                 printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
104                 return -EIO;
105         }
106         brd_status = readb(pld+4);
107         iounmap(pld);
108
109         /* Now ioremap the NVRAM space */
110         ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
111         if (!ocelot_nvram_map.map_priv_1) {
112                 printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
113                 return -EIO;
114         }
115         //      ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
116
117         /* And do the RAM probe on it to get an MTD device */
118         nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
119         if (!nvram_mtd) {
120                 printk("NVRAM probe failed\n");
121                 goto fail_1;
122         }
123         nvram_mtd->module = THIS_MODULE;
124         nvram_mtd->erasesize = 16;
125
126         /* Now map the flash space */
127         ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
128         if (!ocelot_flash_map.map_priv_1) {
129                 printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
130                 goto fail_2;
131         }
132         /* Now the cached version */
133         ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
134
135         if (!ocelot_flash_map.map_priv_2) {
136                 /* Doesn't matter if it failed. Just use the uncached version */
137                 ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1;
138         }
139
140         /* Only probe for flash if the write jumper is present */
141         if (brd_status & 0x40) {
142                 flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
143         } else {
144                 printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
145         }
146         /* If that failed or the jumper's absent, pretend it's ROM */
147         if (!flash_mtd) {
148                 flash_mtd = do_map_probe("map_rom", &ocelot_flash_map);
149                 /* If we're treating it as ROM, set the erase size */
150                 if (flash_mtd)
151                         flash_mtd->erasesize = 0x10000;
152         }
153         if (!flash_mtd)
154                 goto fail3;
155
156         add_mtd_device(nvram_mtd);
157
158         flash_mtd->module = THIS_MODULE;
159         nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
160
161         if (nr_parts)
162                 add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
163         else
164                 add_mtd_device(flash_mtd);
165
166         return 0;
167         
168  fail3: 
169         iounmap((void *)ocelot_flash_map.map_priv_1);
170         if (ocelot_flash_map.map_priv_2 &&
171             ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
172                         iounmap((void *)ocelot_flash_map.map_priv_2);
173  fail_2:
174         map_destroy(nvram_mtd);
175  fail_1:
176         iounmap((void *)ocelot_nvram_map.map_priv_1);
177
178         return -ENXIO;
179 }
180
181 static void __exit cleanup_ocelot_maps(void)
182 {
183         del_mtd_device(nvram_mtd);
184         map_destroy(nvram_mtd);
185         iounmap((void *)ocelot_nvram_map.map_priv_1);
186
187         if (parsed_parts)
188                 del_mtd_partitions(flash_mtd);
189         else
190                 del_mtd_device(flash_mtd);
191         map_destroy(flash_mtd);
192         iounmap((void *)ocelot_flash_map.map_priv_1);
193         if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
194                 iounmap((void *)ocelot_flash_map.map_priv_2);
195 }
196
197 module_init(init_ocelot_maps);
198 module_exit(cleanup_ocelot_maps);
199
200 MODULE_LICENSE("GPL");
201 MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
202 MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board");