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 
get_string_option(char * dest,int dest_size,char * sor)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 
MTD_New_Region(char * line)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 
MTD_New_Partition(char * line)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 
init_fortunet(void)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 			mtd_device_register(map_regions[ix].mymtd,
247 					    map_regions[ix].parts,
248 					    map_regions_parts[ix]);
249 		}
250 	}
251 	if(iy)
252 		return 0;
253 	return -ENXIO;
254 }
255 
cleanup_fortunet(void)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 				mtd_device_unregister(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");
278