Merge branch 'topic/jack' into for-linus
[linux-2.6] / drivers / mtd / maps / fortunet.c
1 /* fortunet.c memory map
2  *
3  */
4
5 #include <linux/module.h>
6 #include <linux/types.h>
7 #include <linux/kernel.h>
8 #include <linux/init.h>
9 #include <linux/string.h>
10
11 #include <linux/mtd/mtd.h>
12 #include <linux/mtd/map.h>
13 #include <linux/mtd/partitions.h>
14
15 #include <asm/io.h>
16
17 #define MAX_NUM_REGIONS         4
18 #define MAX_NUM_PARTITIONS      8
19
20 #define DEF_WINDOW_ADDR_PHY     0x00000000
21 #define DEF_WINDOW_SIZE         0x00800000              // 8 Mega Bytes
22
23 #define MTD_FORTUNET_PK         "MTD FortuNet: "
24
25 #define MAX_NAME_SIZE           128
26
27 struct map_region
28 {
29         int                     window_addr_physical;
30         int                     altbankwidth;
31         struct map_info         map_info;
32         struct mtd_info         *mymtd;
33         struct mtd_partition    parts[MAX_NUM_PARTITIONS];
34         char                    map_name[MAX_NAME_SIZE];
35         char                    parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
36 };
37
38 static struct map_region        map_regions[MAX_NUM_REGIONS];
39 static int                      map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
40 static int                      map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
41
42
43
44 struct map_info default_map = {
45         .size = DEF_WINDOW_SIZE,
46         .bankwidth = 4,
47 };
48
49 static char * __init get_string_option(char *dest,int dest_size,char *sor)
50 {
51         if(!dest_size)
52                 return sor;
53         dest_size--;
54         while(*sor)
55         {
56                 if(*sor==',')
57                 {
58                         sor++;
59                         break;
60                 }
61                 else if(*sor=='\"')
62                 {
63                         sor++;
64                         while(*sor)
65                         {
66                                 if(*sor=='\"')
67                                 {
68                                         sor++;
69                                         break;
70                                 }
71                                 *dest = *sor;
72                                 dest++;
73                                 sor++;
74                                 dest_size--;
75                                 if(!dest_size)
76                                 {
77                                         *dest = 0;
78                                         return sor;
79                                 }
80                         }
81                 }
82                 else
83                 {
84                         *dest = *sor;
85                         dest++;
86                         sor++;
87                         dest_size--;
88                         if(!dest_size)
89                         {
90                                 *dest = 0;
91                                 return sor;
92                         }
93                 }
94         }
95         *dest = 0;
96         return sor;
97 }
98
99 static int __init MTD_New_Region(char *line)
100 {
101         char    string[MAX_NAME_SIZE];
102         int     params[6];
103         get_options (get_string_option(string,sizeof(string),line),6,params);
104         if(params[0]<1)
105         {
106                 printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
107                         " name,region-number[,base,size,bankwidth,altbankwidth]\n");
108                 return 1;
109         }
110         if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
111         {
112                 printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
113                         params[1],MAX_NUM_REGIONS-1);
114                 return 1;
115         }
116         memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
117         memcpy(&map_regions[params[1]].map_info,
118                 &default_map,sizeof(map_regions[params[1]].map_info));
119         map_regions_set[params[1]] = 1;
120         map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
121         map_regions[params[1]].altbankwidth = 2;
122         map_regions[params[1]].mymtd = NULL;
123         map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
124         strcpy(map_regions[params[1]].map_info.name,string);
125         if(params[0]>1)
126         {
127                 map_regions[params[1]].window_addr_physical = params[2];
128         }
129         if(params[0]>2)
130         {
131                 map_regions[params[1]].map_info.size = params[3];
132         }
133         if(params[0]>3)
134         {
135                 map_regions[params[1]].map_info.bankwidth = params[4];
136         }
137         if(params[0]>4)
138         {
139                 map_regions[params[1]].altbankwidth = params[5];
140         }
141         return 1;
142 }
143
144 static int __init MTD_New_Partition(char *line)
145 {
146         char    string[MAX_NAME_SIZE];
147         int     params[4];
148         get_options (get_string_option(string,sizeof(string),line),4,params);
149         if(params[0]<3)
150         {
151                 printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
152                         " name,region-number,size,offset\n");
153                 return 1;
154         }
155         if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
156         {
157                 printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
158                         params[1],MAX_NUM_REGIONS-1);
159                 return 1;
160         }
161         if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
162         {
163                 printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
164                 return 1;
165         }
166         map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
167                 map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
168         strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
169         map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
170                 params[2];
171         map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
172                 params[3];
173         map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
174         map_regions_parts[params[1]]++;
175         return 1;
176 }
177
178 __setup("MTD_Region=", MTD_New_Region);
179 __setup("MTD_Partition=", MTD_New_Partition);
180
181 /* Backwards-spelling-compatibility */
182 __setup("MTD_Partion=", MTD_New_Partition);
183
184 static int __init init_fortunet(void)
185 {
186         int     ix,iy;
187         for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
188         {
189                 if(map_regions_parts[ix]&&(!map_regions_set[ix]))
190                 {
191                         printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
192                                 ix);
193                         memset(&map_regions[ix],0,sizeof(map_regions[ix]));
194                         memcpy(&map_regions[ix].map_info,&default_map,
195                                 sizeof(map_regions[ix].map_info));
196                         map_regions_set[ix] = 1;
197                         map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
198                         map_regions[ix].altbankwidth = 2;
199                         map_regions[ix].mymtd = NULL;
200                         map_regions[ix].map_info.name = map_regions[ix].map_name;
201                         strcpy(map_regions[ix].map_info.name,"FORTUNET");
202                 }
203                 if(map_regions_set[ix])
204                 {
205                         iy++;
206                         printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
207                                 " address %x size %x\n",
208                                 map_regions[ix].map_info.name,
209                                 map_regions[ix].window_addr_physical,
210                                 map_regions[ix].map_info.size);
211
212                         map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
213
214                         map_regions[ix].map_info.virt =
215                                 ioremap_nocache(
216                                 map_regions[ix].window_addr_physical,
217                                 map_regions[ix].map_info.size);
218                         if(!map_regions[ix].map_info.virt)
219                         {
220                                 int j = 0;
221                                 printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
222                                         map_regions[ix].map_info.name);
223                                 for (j = 0 ; j < ix; j++)
224                                         iounmap(map_regions[j].map_info.virt);
225                                 return -ENXIO;
226                         }
227                         simple_map_init(&map_regions[ix].map_info);
228
229                         printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
230                                 map_regions[ix].map_info.name,
231                                 map_regions[ix].map_info.virt);
232                         map_regions[ix].mymtd = do_map_probe("cfi_probe",
233                                 &map_regions[ix].map_info);
234                         if((!map_regions[ix].mymtd)&&(
235                                 map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
236                         {
237                                 printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
238                                         "for %s flash.\n",
239                                         map_regions[ix].map_info.name);
240                                 map_regions[ix].map_info.bankwidth =
241                                         map_regions[ix].altbankwidth;
242                                 map_regions[ix].mymtd = do_map_probe("cfi_probe",
243                                         &map_regions[ix].map_info);
244                         }
245                         map_regions[ix].mymtd->owner = THIS_MODULE;
246                         add_mtd_partitions(map_regions[ix].mymtd,
247                                 map_regions[ix].parts,map_regions_parts[ix]);
248                 }
249         }
250         if(iy)
251                 return 0;
252         return -ENXIO;
253 }
254
255 static void __exit cleanup_fortunet(void)
256 {
257         int     ix;
258         for(ix=0;ix<MAX_NUM_REGIONS;ix++)
259         {
260                 if(map_regions_set[ix])
261                 {
262                         if( map_regions[ix].mymtd )
263                         {
264                                 del_mtd_partitions( map_regions[ix].mymtd );
265                                 map_destroy( map_regions[ix].mymtd );
266                         }
267                         iounmap((void *)map_regions[ix].map_info.virt);
268                 }
269         }
270 }
271
272 module_init(init_fortunet);
273 module_exit(cleanup_fortunet);
274
275 MODULE_AUTHOR("FortuNet, Inc.");
276 MODULE_DESCRIPTION("MTD map driver for FortuNet boards");