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 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 184static 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 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 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 273module_init(init_fortunet); 274module_exit(cleanup_fortunet); 275 276MODULE_AUTHOR("FortuNet, Inc."); 277MODULE_DESCRIPTION("MTD map driver for FortuNet boards"); 278