1/* fortunet.c memory map
2 *
3 * $Id: fortunet.c,v 1.1.1.1 2007/08/03 18:52:43 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
28struct 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
39static struct map_region	map_regions[MAX_NUM_REGIONS];
40static int			map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
41static int			map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
42
43
44
45struct map_info default_map = {
46	.size = DEF_WINDOW_SIZE,
47	.bankwidth = 4,
48};
49
50static 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
100static 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
145static 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
185int __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
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			{
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
273module_init(init_fortunet);
274module_exit(cleanup_fortunet);
275
276MODULE_AUTHOR("FortuNet, Inc.");
277MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
278