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