blob: 956e2e4f30ea687b666fd4e41dd8225142c8d144 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* fortunet.c memory map
2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 */
4
5#include <linux/module.h>
6#include <linux/types.h>
7#include <linux/kernel.h>
8#include <linux/init.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -08009#include <linux/string.h>
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/mtd/mtd.h>
12#include <linux/mtd/map.h>
13#include <linux/mtd/partitions.h>
14
Tim Schmielau4e57b682005-10-30 15:03:48 -080015#include <asm/io.h>
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#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
27struct 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
38static struct map_region map_regions[MAX_NUM_REGIONS];
39static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
40static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
41
42
43
44struct map_info default_map = {
45 .size = DEF_WINDOW_SIZE,
46 .bankwidth = 4,
47};
48
49static 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
99static 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
144static 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
Dmitri Vorobieve63b3f92008-11-25 02:54:57 +0200184static int __init init_fortunet(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
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
Thomas Gleixner69f34c92005-11-07 11:15:40 +0000214 map_regions[ix].map_info.virt =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 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 {
Amol Lad25f0c652006-09-21 18:12:43 +0530220 int j = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
222 map_regions[ix].map_info.name);
Amol Lad25f0c652006-09-21 18:12:43 +0530223 for (j = 0 ; j < ix; j++)
224 iounmap(map_regions[j].map_info.virt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 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;
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100246 mtd_device_register(map_regions[ix].mymtd,
247 map_regions[ix].parts,
248 map_regions_parts[ix]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 }
250 }
251 if(iy)
252 return 0;
253 return -ENXIO;
254}
255
256static 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 {
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100265 mtd_device_unregister(map_regions[ix].mymtd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 map_destroy( map_regions[ix].mymtd );
267 }
268 iounmap((void *)map_regions[ix].map_info.virt);
269 }
270 }
271}
272
273module_init(init_fortunet);
274module_exit(cleanup_fortunet);
275
276MODULE_AUTHOR("FortuNet, Inc.");
277MODULE_DESCRIPTION("MTD map driver for FortuNet boards");